96 lines
1.8 KiB
Go
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
|
|
}
|