dsp/window: add Values.TransformTo window functions and example

This commit is contained in:
Dan Kortschak
2021-01-08 18:18:09 +10:30
parent 1c2011e56d
commit 676e41577b
3 changed files with 100 additions and 2 deletions

View File

@@ -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] // 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])
}

View File

@@ -147,6 +147,24 @@ func (v Values) Transform(seq []float64) []float64 {
return seq 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 // 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 // the result. If v is nil, TransformComplex is a no-op, otherwise the length of v
// must match the length of seq. // must match the length of seq.
@@ -163,3 +181,22 @@ func (v Values) TransformComplex(seq []complex128) []complex128 {
} }
return seq 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))
}
}

View File

@@ -174,7 +174,18 @@ func TestWindows(t *testing.T) {
src[i] = 1 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) { 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) 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) 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) { if !equalApprox(dst, test.want, tol) {
t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want) t.Errorf("unexpected result for lookup window function %q:\ngot:%#.6v\nwant:%#.6v", test.name, dst, test.want)
} }