// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package signal import ( "testing" core "sourcedock.dev/petrbalvin/tensor/internal/core" ) // Signal bulk-path benchmarks: the wavelet filter banks, the spectral // estimators and the finite-difference stencils at analysis-like sizes. func benchWave(b *testing.B, seed, n int, shape ...int) *core.Array { b.Helper() v := make([]float64, n) for i := range v { v[i] = float64(i%31)*float64(seed%5)*0.25 + float64(i%13) - 6 } a, err := core.FromFloats(v, shape...) if err != nil { b.Fatal(err) } return a } func BenchmarkDWT4096(b *testing.B) { x := benchWave(b, 1, 4096, 4096) b.ReportAllocs() for b.Loop() { if _, err := DWT(x, 8); err != nil { b.Fatal(err) } } } func BenchmarkIDWT4096(b *testing.B) { x := benchWave(b, 2, 4096, 4096) coef, err := DWT(x, 8) if err != nil { b.Fatal(err) } b.ResetTimer() b.ReportAllocs() for b.Loop() { if _, err := IDWT(coef, 8); err != nil { b.Fatal(err) } } } func BenchmarkCWTMorlet(b *testing.B) { x := benchWave(b, 3, 4096, 4096) scales := make([]float64, 32) for i := range scales { scales[i] = float64(int(1) << (i / 4)) } b.ReportAllocs() for b.Loop() { if _, err := CWT(x, Morlet, scales, 1.0/512); err != nil { b.Fatal(err) } } } func BenchmarkWelchPSD(b *testing.B) { x := benchWave(b, 4, 1<<16, 1<<16) b.ReportAllocs() for b.Loop() { if _, _, err := WelchPSD(x, 1024, 1024, 512, "hann"); err != nil { b.Fatal(err) } } } func BenchmarkLombScargle(b *testing.B) { t := benchWave(b, 5, 2048, 2048) y := benchWave(b, 6, 2048, 2048) b.ReportAllocs() for b.Loop() { if _, _, err := LombScargle(t, y, 0.01, 1, 512); err != nil { b.Fatal(err) } } } func BenchmarkSavitzkyGolay(b *testing.B) { x := benchWave(b, 7, 1<<18, 1<<18) b.ReportAllocs() for b.Loop() { if _, err := SavitzkyGolay(x, 11, 3); err != nil { b.Fatal(err) } } } func BenchmarkFilterApply(b *testing.B) { x := benchWave(b, 8, 1<<18, 1<<18) coefB, coefA, err := ButterworthLowPass(4, 1024, 64) if err != nil { b.Fatal(err) } b.ResetTimer() b.ReportAllocs() for b.Loop() { if _, err := FilterApply(coefB, coefA, x); err != nil { b.Fatal(err) } } } func BenchmarkLaplacian2D(b *testing.B) { g := benchWave(b, 9, 512*512, 512, 512) b.ReportAllocs() for b.Loop() { if _, err := Laplacian(g, 1, 1); err != nil { b.Fatal(err) } } } func BenchmarkARMASpectrum(b *testing.B) { res := &ARMAResult{ AR: []float64{0.75, -0.5, 0.2, -0.1}, MA: []float64{0.4, -0.25, 0.1}, InnovationVariance: 1.5, } b.ReportAllocs() for b.Loop() { if _, _, err := ARMASpectrum(res, 4096); err != nil { b.Fatal(err) } } } func BenchmarkNUFFTType1(b *testing.B) { const n = 4096 xv := make([]float64, n) cv := make([]complex128, n) for i := range n { xv[i] = float64(i%1024)/1024 - 0.5 cv[i] = complex(float64(i%7)*0.5-1, float64(i%5)*0.25) } xs, err := core.FromFloats(xv, n) if err != nil { b.Fatal(err) } cs, err := core.FromComplexes(cv, n) if err != nil { b.Fatal(err) } b.ReportAllocs() for b.Loop() { if _, err := NUFFTType1(xs, cs, 2048); err != nil { b.Fatal(err) } } }