mirror of
https://github.com/gonum/gonum.git
synced 2025-10-06 15:47:01 +08:00
dsp/window: add lookup table window functions
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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]
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user