dsp/window: add Values.TransformTo window functions and example
MODIFY
dsp/window/window_example_test.go
dsp/window/window_example_test.go
@@ -118,3 +118,42 @@ func ExampleValues() {
//
// dst: [0.000000 0.164595 0.324699 0.475947 0.614213 0.735724 0.837166 0.915773 0.969400 0.996584 0.996584 0.969400 0.915773 0.837166 0.735724 0.614213 0.475947 0.324699 0.164595 0.000000]
}
+
+func ExampleValues_TransformTo_gabor() {
+ src := []float64{1, 2, 1, 0, -1, -1, -2, -2, -1, -1,
+ 0, 1, 1, 2, 1, 0, -1, -2, -1, 0}
+
+ // Create a Gaussian Window lookup table for 4 samples.
+ gaussian := window.NewValues(window.Gaussian{0.5}.Transform, 4)
+
+ // Prepare a destination.
+ dst := make([]float64, 8)
+
+ // Apply the transformation to the src, placing it in dst.
+ for i := 0; i < len(src)-len(gaussian); i++ {
+ gaussian.TransformTo(dst[0:len(gaussian)], src[i:i+len(gaussian)])
+
+ // To perform the Gabor transform, we would calculate
+ // the FFT on dst for each iteration.
+ fmt.Printf("FFT(%f)\n", dst)
+ }
+
+ // Output:
+ //
+ // FFT([0.135335 1.601475 0.800737 0.000000 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.270671 0.800737 0.000000 -0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.135335 0.000000 -0.800737 -0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.000000 -0.800737 -0.800737 -0.270671 0.000000 0.000000 0.000000 0.000000])
+ // FFT([-0.135335 -0.800737 -1.601475 -0.270671 0.000000 0.000000 0.000000 0.000000])
+ // FFT([-0.135335 -1.601475 -1.601475 -0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([-0.270671 -1.601475 -0.800737 -0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([-0.270671 -0.800737 -0.800737 0.000000 0.000000 0.000000 0.000000 0.000000])
+ // FFT([-0.135335 -0.800737 0.000000 0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([-0.135335 0.000000 0.800737 0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.000000 0.800737 0.800737 0.270671 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.135335 0.800737 1.601475 0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.135335 1.601475 0.800737 0.000000 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.270671 0.800737 0.000000 -0.135335 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.135335 0.000000 -0.800737 -0.270671 0.000000 0.000000 0.000000 0.000000])
+ // FFT([0.000000 -0.800737 -1.601475 -0.135335 0.000000 0.000000 0.000000 0.000000])
+}

MODIFY
dsp/window/window_parametric.go
dsp/window/window_parametric.go
@@ -147,6 +147,24 @@ func (v Values) Transform(seq []float64) []float64 {
return seq
}
+// TransformTo applies the weights in the receiver to src placing the result
+// in dst. If v is nil, TransformTo is a no-op, otherwise the length of v must
+// match the length of src and dst.
+func (v Values) TransformTo(dst, src []float64) {
+ if v == nil {
+ return
+ }
+ if len(v) != len(src) {
+ panic("window: seq length mismatch")
+ }
+ if len(v) != len(dst) {
+ panic("window: dst length mismatch")
+ }
+ for i, w := range v {
+ dst[i] = w * src[i]
+ }
+}
+
// TransformComplex applies the weights in the receiver to seq in place, returning
// the result. If v is nil, TransformComplex is a no-op, otherwise the length of v
// must match the length of seq.
@@ -163,3 +181,22 @@ func (v Values) TransformComplex(seq []complex128) []complex128 {
}
return seq
}
+
+// TransformComplexTo applies the weights in the receiver to src placing the
+// result in dst. If v is nil, TransformComplexTo is a no-op, otherwise the
+// length of v must match the length of src and dst.
+func (v Values) TransformComplexTo(dst, src []complex128) {
+ if v == nil {
+ return
+ }
+ if len(v) != len(src) {
+ panic("window: seq length mismatch")
+ }
+ if len(v) != len(dst) {
+ panic("window: dst length mismatch")
+ }
+ for i, w := range v {
+ sv := src[i]
+ dst[i] = complex(w*real(sv), w*imag(sv))
+ }
+}

MODIFY
dsp/window/window_test.go
dsp/window/window_test.go
@@ -174,7 +174,18 @@ func TestWindows(t *testing.T) {
src[i] = 1
}
- dst = NewValues(test.fn, len(src)).Transform(src)
+ vals := NewValues(test.fn, len(src))
+ dst = vals.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)
+ }
+
+ for i := range src {
+ src[i] = 1
+ }
+
+ dst = make([]float64, len(src))
+ vals.TransformTo(dst, 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)
}
@@ -202,7 +213,18 @@ func TestWindowsComplex(t *testing.T) {
src[i] = complex(1, 1)
}
- dst = NewValues(test.fn, len(src)).TransformComplex(src)
+ vals := NewValues(test.fn, len(src))
+ dst = vals.TransformComplex(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)
+ }
+
+ for i := range src {
+ src[i] = complex(1, 1)
+ }
+
+ dst = make([]complex128, len(src))
+ vals.TransformComplexTo(dst, 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 Values.TransformTo window functions and example