github.com/gopherd/gonum@v0.0.4/dsp/window/window_parametric.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 "math" 8 9 // Gaussian can modify a sequence using the Gaussian window and return the 10 // result. 11 // See https://en.wikipedia.org/wiki/Window_function#Gaussian_window 12 // and https://www.recordingblogs.com/wiki/gaussian-window for details. 13 // 14 // The Gaussian window is an adjustable window. 15 // 16 // The sequence weights are 17 // w[k] = exp(-0.5 * ((k-M)/(σ*M))² ), M = (N-1)/2, 18 // for k=0,1,...,N-1 where N is the length of the window. 19 // 20 // The properties of the window depend on the value of σ (sigma). 21 // It can be used as high or low resolution window, depending of the σ value. 22 // 23 // Spectral leakage parameters are summarized in the table: 24 // | σ=0.3 | σ=0.5 | σ=1.2 | 25 // -------|---------------------------| 26 // ΔF_0 | 8 | 3.4 | 2.2 | 27 // ΔF_0.5 | 1.82 | 1.2 | 0.94 | 28 // K | 4 | 1.7 | 1.1 | 29 // ɣ_max | -65 | -31.5 | -15.5 | 30 // β | -8.52 | -4.48 | -0.96 | 31 type Gaussian struct { 32 Sigma float64 33 } 34 35 // Transform applies the Gaussian transformation to seq in place, using the 36 // value of the receiver as the sigma parameter, and returning the result. 37 func (g Gaussian) Transform(seq []float64) []float64 { 38 a := float64(len(seq)-1) / 2 39 for i := range seq { 40 x := -0.5 * math.Pow((float64(i)-a)/(g.Sigma*a), 2) 41 seq[i] *= math.Exp(x) 42 } 43 return seq 44 } 45 46 // TransformComplex applies the Gaussian transformation to seq in place, 47 // using the value of the receiver as the sigma parameter, and returning 48 // the result. 49 func (g Gaussian) TransformComplex(seq []complex128) []complex128 { 50 a := float64(len(seq)-1) / 2 51 for i, v := range seq { 52 x := -0.5 * math.Pow((float64(i)-a)/(g.Sigma*a), 2) 53 w := math.Exp(x) 54 seq[i] = complex(w*real(v), w*imag(v)) 55 } 56 return seq 57 } 58 59 // Tukey can modify a sequence using the Tukey window and return the result. 60 // See https://en.wikipedia.org/wiki/Window_function#Tukey_window 61 // and https://www.recordingblogs.com/wiki/tukey-window for details. 62 // 63 // The Tukey window is an adjustable window. 64 // 65 // The sequence weights are 66 // w[k] = 0.5 * (1 + cos(π*(|k - M| - αM)/((1-α) * M))), |k - M| ≥ αM 67 // = 1, |k - M| < αM 68 // with M = (N - 1)/2 for k=0,1,...,N-1 where N is the length of the window. 69 // 70 // Spectral leakage parameters are summarized in the table: 71 // | α=0.3 | α=0.5 | α=0.7 | 72 // -------|--------------------------| 73 // ΔF_0 | 1.33 | 1.22 | 1.13 | 74 // ΔF_0.5 | 1.28 | 1.16 | 1.04 | 75 // K | 0.67 | 0.61 | 0.57 | 76 // ɣ_max | -18.2 | -15.1 | -13.8 | 77 // β | -1.41 | -2.50 | -3.74 | 78 type Tukey struct { 79 Alpha float64 80 } 81 82 // Transform applies the Tukey transformation to seq in place, using the 83 // value of the receiver as the Alpha parameter, and returning the result. 84 func (t Tukey) Transform(seq []float64) []float64 { 85 switch { 86 case t.Alpha <= 0: 87 return Rectangular(seq) 88 case t.Alpha >= 1: 89 return Hann(seq) 90 default: 91 alphaL := t.Alpha * float64(len(seq)-1) 92 width := int(0.5*alphaL) + 1 93 for i := range seq[:width] { 94 w := 0.5 * (1 - math.Cos(2*math.Pi*float64(i)/alphaL)) 95 seq[i] *= w 96 seq[len(seq)-1-i] *= w 97 } 98 return seq 99 } 100 } 101 102 // TransformComplex applies the Tukey transformation to seq in place, using 103 // the value of the receiver as the Alpha parameter, and returning the result. 104 func (t Tukey) TransformComplex(seq []complex128) []complex128 { 105 switch { 106 case t.Alpha <= 0: 107 return RectangularComplex(seq) 108 case t.Alpha >= 1: 109 return HannComplex(seq) 110 default: 111 alphaL := t.Alpha * float64(len(seq)-1) 112 width := int(0.5*alphaL) + 1 113 for i, v := range seq[:width] { 114 w := 0.5 * (1 - math.Cos(2*math.Pi*float64(i)/alphaL)) 115 v = complex(w*real(v), w*imag(v)) 116 seq[i] = v 117 seq[len(seq)-1-i] = v 118 } 119 return seq 120 } 121 } 122 123 // Values is an arbitrary real window function. 124 type Values []float64 125 126 // NewValues returns a Values of length n with weights corresponding to the 127 // provided window function. 128 func NewValues(window func([]float64) []float64, n int) Values { 129 v := make(Values, n) 130 for i := range v { 131 v[i] = 1 132 } 133 return window(v) 134 } 135 136 // Transform applies the weights in the receiver to seq in place, returning the 137 // result. If v is nil, Transform is a no-op, otherwise the length of v must 138 // match the length of seq. 139 func (v Values) Transform(seq []float64) []float64 { 140 if v == nil { 141 return seq 142 } 143 if len(v) != len(seq) { 144 panic("window: length mismatch") 145 } 146 for i, w := range v { 147 seq[i] *= w 148 } 149 return seq 150 } 151 152 // TransformTo applies the weights in the receiver to src placing the result 153 // in dst. If v is nil, TransformTo is a no-op, otherwise the length of v must 154 // match the length of src and dst. 155 func (v Values) TransformTo(dst, src []float64) { 156 if v == nil { 157 return 158 } 159 if len(v) != len(src) { 160 panic("window: seq length mismatch") 161 } 162 if len(v) != len(dst) { 163 panic("window: dst length mismatch") 164 } 165 for i, w := range v { 166 dst[i] = w * src[i] 167 } 168 } 169 170 // TransformComplex applies the weights in the receiver to seq in place, 171 // returning the result. If v is nil, TransformComplex is a no-op, otherwise 172 // the length of v must match the length of seq. 173 func (v Values) TransformComplex(seq []complex128) []complex128 { 174 if v == nil { 175 return seq 176 } 177 if len(v) != len(seq) { 178 panic("window: length mismatch") 179 } 180 for i, w := range v { 181 sv := seq[i] 182 seq[i] = complex(w*real(sv), w*imag(sv)) 183 } 184 return seq 185 } 186 187 // TransformComplexTo applies the weights in the receiver to src placing the 188 // result in dst. If v is nil, TransformComplexTo is a no-op, otherwise the 189 // length of v must match the length of src and dst. 190 func (v Values) TransformComplexTo(dst, src []complex128) { 191 if v == nil { 192 return 193 } 194 if len(v) != len(src) { 195 panic("window: seq length mismatch") 196 } 197 if len(v) != len(dst) { 198 panic("window: dst length mismatch") 199 } 200 for i, w := range v { 201 sv := src[i] 202 dst[i] = complex(w*real(sv), w*imag(sv)) 203 } 204 }