dsp/window: add lookup table window functions
MODIFY
dsp/window/window.go
dsp/window/window.go
@@ -323,3 +323,32 @@ func Gaussian(seq []float64, sigma float64) []float64 {
}
return seq
}
+
+// Values is an arbitrary real window function.
+type Values []float64
+
+// NewValues returns a Values of length n with weights corresponding to the
+// provided window function.
+func NewValues(window func([]float64) []float64, n int) Values {
+ v := make(Values, n)
+ for i := range v {
+ v[i] = 1
+ }
+ return window(v)
+}
+
+// Transform applies the weights in the receiver to seq in place, returning the
+// result. If v is nil, Transform is a no-op, otherwise the length of v must
+// match the length of seq.
+func (v Values) Transform(seq []float64) []float64 {
+ if v == nil {
+ return seq
+ }
+ if len(v) != len(seq) {
+ panic("window: length mismatch")
+ }
+ for i, w := range v {
+ seq[i] *= w
+ }
+ return seq
+}

MODIFY
dsp/window/window_complex.go
dsp/window/window_complex.go
@@ -323,3 +323,32 @@ func GaussianComplex(seq []complex128, sigma float64) []complex128 {
}
return seq
}
+
+// ValuesComplex is an arbitrary complex window function.
+type ValuesComplex []complex128
+
+// NewValuesComplex returns a ValuesComplex of length n with weights corresponding
+// to the provided window function.
+func NewValuesComplex(window func([]complex128) []complex128, n int) ValuesComplex {
+ v := make(ValuesComplex, n)
+ for i := range v {
+ v[i] = 1
+ }
+ return window(v)
+}
+
+// Transform applies the weights in the receiver to seq in place, returning the
+// result. If v is nil, Transform is a no-op, otherwise the length of v must
+// match the length of seq.
+func (v ValuesComplex) Transform(seq []complex128) []complex128 {
+ if v == nil {
+ return seq
+ }
+ if len(v) != len(seq) {
+ panic("window: length mismatch")
+ }
+ for i, w := range v {
+ seq[i] *= w
+ }
+ return seq
+}

MODIFY
dsp/window/window_example_test.go
dsp/window/window_example_test.go
@@ -103,3 +103,18 @@ func ExampleHamming() {
// srcCpy: [0.092577 0.136714 0.220669 0.336222 0.472063 0.614894 0.750735 0.866288 0.950242 0.994379 0.994379 0.950242 0.866288 0.750735 0.614894 0.472063 0.336222 0.220669 0.136714 0.092577]
// dst: [0.092577 0.136714 0.220669 0.336222 0.472063 0.614894 0.750735 0.866288 0.950242 0.994379 0.994379 0.950242 0.866288 0.750735 0.614894 0.472063 0.336222 0.220669 0.136714 0.092577]
}
+
+func ExampleValues() {
+ src := []float64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+
+ // Create a Sine Window lookup table.
+ sine := window.NewValues(window.Sine, len(src))
+
+ // Apply the transformation to the src.
+ fmt.Printf("dst: %f\n", sine.Transform(src))
+
+ // Output:
+ //
+ // dst: [0.078459 0.233445 0.382683 0.522499 0.649448 0.760406 0.852640 0.923880 0.972370 0.996917 0.996917 0.972370 0.923880 0.852640 0.760406 0.649448 0.522499 0.382683 0.233445 0.078459]
+}

MODIFY
dsp/window/window_test.go
dsp/window/window_test.go
@@ -150,10 +150,18 @@ func TestWindows(t *testing.T) {
}
dst := test.fn(src)
-
if !floats.EqualApprox(dst, test.want, tol) {
t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#v", test.name, dst, test.want)
}
+
+ for i := range src {
+ src[i] = 1
+ }
+
+ dst = NewValues(test.fn, len(src)).Transform(src)
+ if !floats.EqualApprox(dst, test.want, tol) {
+ t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
+ }
})
}
}
@@ -161,20 +169,29 @@ func TestWindows(t *testing.T) {
func TestGausWindows(t *testing.T) {
const tol = 1e-6
+ for _, test := range gausWindowTests {
+ t.Run(fmt.Sprintf("%s (sigma=%.1f)", test.name, test.sigma), func(t *testing.T) {
src := make([]float64, 20)
for i := range src {
src[i] = 1
}
- for _, test := range gausWindowTests {
- t.Run(fmt.Sprintf("%s (sigma=%.1f)", test.name, test.sigma), func(t *testing.T) {
- srcCpy := make([]float64, len(src))
- copy(srcCpy, src)
- dst := Gaussian(srcCpy, test.sigma)
-
+ dst := Gaussian(src, test.sigma)
if !floats.EqualApprox(dst, test.want, tol) {
t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#v", test.name, dst, test.want)
}
+
+ for i := range src {
+ src[i] = 1
+ }
+
+ sigma := test.sigma
+ dst = NewValues(func(seq []float64) []float64 {
+ return Gaussian(seq, sigma)
+ }, len(src)).Transform(src)
+ if !floats.EqualApprox(dst, test.want, tol) {
+ t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
+ }
})
}
}
@@ -190,10 +207,18 @@ func TestWindowsComplex(t *testing.T) {
}
dst := test.fnCmplx(src)
-
if !equalApprox(dst, test.want, tol) {
t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
}
+
+ for i := range src {
+ src[i] = complex(1, 1)
+ }
+
+ dst = NewValuesComplex(test.fnCmplx, len(src)).Transform(src)
+ if !equalApprox(dst, test.want, tol) {
+ t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
+ }
})
}
}
@@ -201,20 +226,29 @@ func TestWindowsComplex(t *testing.T) {
func TestGausWindowComplex(t *testing.T) {
const tol = 1e-6
+ for _, test := range gausWindowTests {
+ t.Run(fmt.Sprintf("%sComplex (sigma=%.1f)", test.name, test.sigma), func(t *testing.T) {
src := make([]complex128, 20)
for i := range src {
src[i] = complex(1, 1)
}
- for _, test := range gausWindowTests {
- t.Run(fmt.Sprintf("%sComplex (sigma=%.1f)", test.name, test.sigma), func(t *testing.T) {
- srcCpy := make([]complex128, len(src))
- copy(srcCpy, src)
- dst := GaussianComplex(srcCpy, test.sigma)
-
+ dst := GaussianComplex(src, test.sigma)
if !equalApprox(dst, test.want, tol) {
t.Errorf("unexpected result for window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
}
+
+ for i := range src {
+ src[i] = complex(1, 1)
+ }
+
+ sigma := test.sigma
+ dst = NewValuesComplex(func(seq []complex128) []complex128 {
+ return GaussianComplex(seq, sigma)
+ }, len(src)).Transform(src)
+ if !equalApprox(dst, test.want, tol) {
+ t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
+ }
})
}
}

dsp/window: add lookup table window functions