Files
2026-07-13 11:17:57 +05:00

96 lines
1.8 KiB
Go

package series
import (
"math"
"gonum.org/v1/gonum/dsp/fourier"
)
type SpectrumPoint struct {
Frequency float64 `json:"frequency"`
Amplitude float64 `json:"amplitude"`
}
func AverageDelta(times []float64) float64 {
if len(times) < 2 {
return 0
}
total := 0.0
count := 0
for i := 1; i < len(times); i++ {
delta := times[i] - times[i-1]
if delta <= 0 {
continue
}
total += delta
count++
}
if count == 0 {
return 0
}
return total / float64(count)
}
func SpectrumPoints(values []float64, dt float64) []SpectrumPoint {
if len(values) < 2 || dt <= 0 {
return []SpectrumPoint{}
}
centered := Centered(values)
fft := fourier.NewFFT(len(centered))
coeffs := fft.Coefficients(nil, centered)
limit := len(coeffs) / 2
points := make([]SpectrumPoint, 0, limit+1)
for i := 0; i <= limit; i++ {
points = append(points, SpectrumPoint{
Frequency: float64(i) / (float64(len(centered)) * dt),
Amplitude: math.Hypot(real(coeffs[i]), imag(coeffs[i])) / float64(len(centered)),
})
}
return points
}
func MainAngularFrequency(times, values []float64) float64 {
if len(values) < 2 || len(times) < 2 {
return 0
}
dt := AverageDelta(times)
if dt <= 0 {
return 0
}
centered := Centered(values)
fft := fourier.NewFFT(len(centered))
coeffs := fft.Coefficients(nil, centered)
if len(coeffs) < 2 {
return 0
}
bestIndex := 1
bestAmp := 0.0
for i := 1; i < len(coeffs); i++ {
amp := math.Hypot(real(coeffs[i]), imag(coeffs[i]))
if amp > bestAmp {
bestAmp = amp
bestIndex = i
}
}
frequencyHz := fft.Freq(bestIndex) / dt
return 2 * math.Pi * frequencyHz
}
func Centered(values []float64) []float64 {
centered := make([]float64, len(values))
mean := 0.0
for _, value := range values {
mean += value
}
mean /= float64(len(values))
for i, value := range values {
centered[i] = value - mean
}
return centered
}