67 lines
1.1 KiB
Go
67 lines
1.1 KiB
Go
package extractfreq
|
|
|
|
import (
|
|
"math"
|
|
|
|
"gonum.org/v1/gonum/optimize"
|
|
)
|
|
|
|
func harmonicModel(A, B, n float64) float64 {
|
|
return A * n * math.Sqrt(B*n*n+1)
|
|
}
|
|
|
|
// Fit spectrum peaks to function:
|
|
//
|
|
// f(n) = A*n * sqrt(1+B*n**2)
|
|
func fitSpectrumPeaks(
|
|
f1 float64, // Approximate fundamental.
|
|
ns []float64,
|
|
freqs []float64, // Peak frequencies.
|
|
amps []float64, // Peak amplitudes.
|
|
) (
|
|
A float64,
|
|
B float64,
|
|
err error,
|
|
) {
|
|
// Error function weights each harmonic error by its amplitude.
|
|
errFunc := func(x []float64) float64 {
|
|
A := math.Abs(x[0])
|
|
B := math.Abs(x[1])
|
|
|
|
sum := float64(0)
|
|
|
|
for i, fPeak := range freqs {
|
|
n := ns[i]
|
|
e := fPeak - harmonicModel(A, B, n)
|
|
e *= e
|
|
e *= amps[i]
|
|
sum += e
|
|
}
|
|
|
|
return sum
|
|
}
|
|
|
|
// Initial guess.
|
|
x := []float64{f1, 0}
|
|
|
|
problem := optimize.Problem{
|
|
Func: errFunc,
|
|
}
|
|
|
|
result, err := optimize.Minimize(problem, x, nil, nil)
|
|
|
|
return result.X[0], result.X[1], err
|
|
}
|
|
|
|
func ApproxHarmonicNumber(fFun, fPeak float64) float64 {
|
|
if fPeak < fFun {
|
|
switch math.Round(fFun / fPeak) {
|
|
case 2:
|
|
return 0.5
|
|
case 4:
|
|
return 0.25
|
|
}
|
|
}
|
|
return math.Round(fPeak / fFun)
|
|
}
|