gonum.org/v1/gonum@v0.14.0/dsp/window/window_test.go (about)

     1  // Copyright ©2020 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package window
     6  
     7  import (
     8  	"testing"
     9  
    10  	"gonum.org/v1/gonum/floats"
    11  	"gonum.org/v1/gonum/floats/scalar"
    12  )
    13  
    14  var windowTests = []struct {
    15  	name    string
    16  	fn      func([]float64) []float64
    17  	fnCmplx func([]complex128) []complex128
    18  	want    []float64
    19  }{
    20  	{
    21  		name: "Rectangular", fn: Rectangular, fnCmplx: RectangularComplex,
    22  		want: []float64{
    23  			1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    24  			1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    25  		},
    26  	},
    27  	{
    28  		name: "Sine", fn: Sine, fnCmplx: SineComplex,
    29  		want: []float64{
    30  			0.000000, 0.164595, 0.324699, 0.475947, 0.614213, 0.735724, 0.837166, 0.915773, 0.969400, 0.996584,
    31  			0.996584, 0.969400, 0.915773, 0.837166, 0.735724, 0.614213, 0.475947, 0.324699, 0.164595, 0.000000,
    32  		},
    33  	},
    34  	{
    35  		name: "Lanczos", fn: Lanczos, fnCmplx: LanczosComplex,
    36  		want: []float64{
    37  			0.000000, 0.115514, 0.247646, 0.389468, 0.532984, 0.669692, 0.791213, 0.889915, 0.959492, 0.995450,
    38  			0.995450, 0.959492, 0.889915, 0.791213, 0.669692, 0.532984, 0.389468, 0.247646, 0.115514, 0.000000,
    39  		},
    40  	},
    41  	// This case tests Lanczos for a NaN condition. The Lanczos NaN condition is k=(N-1)/2, that is when N is odd.
    42  	{
    43  		name: "LanczosOdd", fn: Lanczos, fnCmplx: LanczosComplex,
    44  		want: []float64{
    45  			0.000000, 0.109292, 0.233872, 0.367883, 0.504551, 0.636620, 0.756827, 0.858394, 0.935489, 0.983632,
    46  			1.000000,
    47  			0.983632, 0.935489, 0.858394, 0.756827, 0.636620, 0.504551, 0.367883, 0.233872, 0.109292, 0.000000,
    48  		},
    49  	},
    50  	{
    51  		name: "Triangular", fn: Triangular, fnCmplx: TriangularComplex,
    52  		want: []float64{
    53  			0.000000, 0.105263, 0.210526, 0.315789, 0.421053, 0.526316, 0.631579, 0.736842, 0.842105, 0.947368,
    54  			0.947368, 0.842105, 0.736842, 0.631579, 0.526316, 0.421053, 0.315789, 0.210526, 0.105263, 0.000000,
    55  		},
    56  	},
    57  	{
    58  		name: "Hann", fn: Hann, fnCmplx: HannComplex,
    59  		want: []float64{
    60  			0.000000, 0.027091, 0.105430, 0.226526, 0.377257, 0.541290, 0.700848, 0.838641, 0.939737, 0.993181,
    61  			0.993181, 0.939737, 0.838641, 0.700848, 0.541290, 0.377257, 0.226526, 0.105430, 0.027091, 0.000000,
    62  		},
    63  	},
    64  	{
    65  		name: "BartlettHann", fn: BartlettHann, fnCmplx: BartlettHannComplex,
    66  		want: []float64{
    67  			0.000000, 0.045853, 0.130653, 0.247949, 0.387768, 0.537696, 0.684223, 0.814209, 0.916305, 0.982186,
    68  			0.982186, 0.916305, 0.814209, 0.684223, 0.537696, 0.387768, 0.247949, 0.130653, 0.045853, 0.000000,
    69  		},
    70  	},
    71  	{
    72  		name: "Hamming", fn: Hamming, fnCmplx: HammingComplex,
    73  		want: []float64{
    74  			0.08, 0.104924, 0.176995, 0.288404, 0.427077, 0.577986, 0.72478, 0.85155, 0.944558, 0.993726,
    75  			0.993726, 0.944558, 0.85155, 0.72478, 0.577986, 0.427077, 0.288404, 0.176995, 0.104924, 0.08,
    76  		},
    77  	},
    78  	{
    79  		name: "Blackman", fn: Blackman, fnCmplx: BlackmanComplex,
    80  		want: []float64{
    81  			0.000000, 0.010223, 0.045069, 0.114390, 0.226899, 0.382381, 0.566665, 0.752034, 0.903493, 0.988846,
    82  			0.988846, 0.903493, 0.752034, 0.566665, 0.382381, 0.226899, 0.114390, 0.045069, 0.010223, 0.000000,
    83  		},
    84  	},
    85  	{
    86  		name: "BlackmanHarris", fn: BlackmanHarris, fnCmplx: BlackmanHarrisComplex,
    87  		want: []float64{
    88  			0.000060, 0.002018, 0.012795, 0.046450, 0.122540, 0.256852, 0.448160, 0.668576, 0.866426, 0.984278,
    89  			0.984278, 0.866426, 0.668576, 0.448160, 0.256852, 0.122540, 0.046450, 0.012795, 0.002018, 0.000060,
    90  		},
    91  	},
    92  	{
    93  		name: "Nuttall", fn: Nuttall, fnCmplx: NuttallComplex,
    94  		want: []float64{
    95  			0.000000, 0.001706, 0.011614, 0.043682, 0.117808, 0.250658, 0.441946, 0.664015, 0.864348, 0.984019,
    96  			0.984019, 0.864348, 0.664015, 0.441946, 0.250658, 0.117808, 0.043682, 0.011614, 0.001706, 0.000000,
    97  		},
    98  	},
    99  	{
   100  		name: "BlackmanNuttall", fn: BlackmanNuttall, fnCmplx: BlackmanNuttallComplex,
   101  		want: []float64{
   102  			0.000363, 0.002885, 0.015360, 0.051652, 0.130567, 0.266629, 0.457501, 0.675215, 0.869392, 0.984644,
   103  			0.984644, 0.869392, 0.675215, 0.457501, 0.266629, 0.130567, 0.051652, 0.015360, 0.002885, 0.000363,
   104  		},
   105  	},
   106  	{
   107  		name: "FlatTop", fn: FlatTop, fnCmplx: FlatTopComplex,
   108  		want: []float64{
   109  			-0.000421, -0.003687, -0.017675, -0.045939, -0.070137, -0.037444, 0.115529, 0.402051, 0.737755, 0.967756,
   110  			0.967756, 0.737755, 0.402051, 0.115529, -0.037444, -0.070137, -0.045939, -0.017675, -0.003687, -0.000421,
   111  		},
   112  	},
   113  	{
   114  		name: "Gaussian{0.3}.Transform", fn: Gaussian{0.3}.Transform, fnCmplx: Gaussian{0.3}.TransformComplex,
   115  		want: []float64{
   116  			0.003866, 0.011708, 0.031348, 0.074214, 0.155344, 0.287499, 0.470444, 0.680632, 0.870660, 0.984728,
   117  			0.984728, 0.870660, 0.680632, 0.470444, 0.287499, 0.155344, 0.074214, 0.031348, 0.011708, 0.003866,
   118  		},
   119  	},
   120  	{
   121  		name: "Gaussian{0.5}.Transform", fn: Gaussian{0.5}.Transform, fnCmplx: Gaussian{0.5}.TransformComplex,
   122  		want: []float64{
   123  			0.135335, 0.201673, 0.287499, 0.392081, 0.511524, 0.638423, 0.762260, 0.870660, 0.951361, 0.994475,
   124  			0.994475, 0.951361, 0.870660, 0.762260, 0.638423, 0.511524, 0.392081, 0.287499, 0.201673, 0.135335,
   125  		},
   126  	},
   127  	{
   128  		name: "Gaussian{1.2}.Transform", fn: Gaussian{1.2}.Transform, fnCmplx: Gaussian{1.2}.TransformComplex,
   129  		want: []float64{
   130  			0.706648, 0.757319, 0.805403, 0.849974, 0.890135, 0.925049, 0.953963, 0.976241, 0.991381, 0.999039,
   131  			0.999039, 0.991381, 0.976241, 0.953963, 0.925049, 0.890135, 0.849974, 0.805403, 0.757319, 0.706648,
   132  		},
   133  	},
   134  	{
   135  		name: "Tukey{1}.Transform", fn: Tukey{1}.Transform, fnCmplx: Tukey{1}.TransformComplex,
   136  		want: []float64{ // Hann window case.
   137  			0.000000, 0.027091, 0.105430, 0.226526, 0.377257, 0.541290, 0.700848, 0.838641, 0.939737, 0.993181,
   138  			0.993181, 0.939737, 0.838641, 0.700848, 0.541290, 0.377257, 0.226526, 0.105430, 0.027091, 0.000000,
   139  		},
   140  	},
   141  	{
   142  		name: "Tukey{0}.Transform", fn: Tukey{0}.Transform, fnCmplx: Tukey{0}.TransformComplex,
   143  		want: []float64{ // Rectangular window case.
   144  			1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
   145  			1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
   146  		},
   147  	},
   148  	{
   149  		name: "Tukey{0.5}.Transform", fn: Tukey{0.5}.Transform, fnCmplx: Tukey{0.5}.TransformComplex,
   150  		want: []float64{
   151  			0.000000, 0.105430, 0.377257, 0.700847, 0.939737, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
   152  			1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.939737, 0.700847, 0.377257, 0.105429, 0.000000,
   153  		},
   154  	},
   155  }
   156  
   157  func TestWindows(t *testing.T) {
   158  	t.Parallel()
   159  	const tol = 1e-6
   160  
   161  	for _, test := range windowTests {
   162  		t.Run(test.name, func(t *testing.T) {
   163  			src := make([]float64, len(test.want))
   164  			for i := range src {
   165  				src[i] = 1
   166  			}
   167  
   168  			dst := test.fn(src)
   169  			if !floats.EqualApprox(dst, test.want, tol) {
   170  				t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#v", test.name, dst, test.want)
   171  			}
   172  
   173  			for i := range src {
   174  				src[i] = 1
   175  			}
   176  
   177  			vals := NewValues(test.fn, len(src))
   178  			dst = vals.Transform(src)
   179  			if !floats.EqualApprox(dst, test.want, tol) {
   180  				t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
   181  			}
   182  
   183  			for i := range src {
   184  				src[i] = 1
   185  			}
   186  
   187  			dst = make([]float64, len(src))
   188  			vals.TransformTo(dst, src)
   189  			if !floats.EqualApprox(dst, test.want, tol) {
   190  				t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
   191  			}
   192  		})
   193  	}
   194  }
   195  
   196  func TestWindowsComplex(t *testing.T) {
   197  	t.Parallel()
   198  	const tol = 1e-6
   199  
   200  	for _, test := range windowTests {
   201  		t.Run(test.name+"Complex", func(t *testing.T) {
   202  			src := make([]complex128, len(test.want))
   203  			for i := range src {
   204  				src[i] = complex(1, 1)
   205  			}
   206  
   207  			dst := test.fnCmplx(src)
   208  			if !equalApprox(dst, test.want, tol) {
   209  				t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
   210  			}
   211  
   212  			for i := range src {
   213  				src[i] = complex(1, 1)
   214  			}
   215  
   216  			vals := NewValues(test.fn, len(src))
   217  			dst = vals.TransformComplex(src)
   218  			if !equalApprox(dst, test.want, tol) {
   219  				t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
   220  			}
   221  
   222  			for i := range src {
   223  				src[i] = complex(1, 1)
   224  			}
   225  
   226  			dst = make([]complex128, len(src))
   227  			vals.TransformComplexTo(dst, src)
   228  			if !equalApprox(dst, test.want, tol) {
   229  				t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
   230  			}
   231  		})
   232  	}
   233  }
   234  
   235  func equalApprox(seq1 []complex128, seq2 []float64, tol float64) bool {
   236  	if len(seq1) != len(seq2) {
   237  		return false
   238  	}
   239  	for i := range seq1 {
   240  		if !scalar.EqualWithinAbsOrRel(real(seq1[i]), seq2[i], tol, tol) {
   241  			return false
   242  		}
   243  		if !scalar.EqualWithinAbsOrRel(imag(seq1[i]), seq2[i], tol, tol) {
   244  			return false
   245  		}
   246  	}
   247  	return true
   248  }