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