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 }