This repository has been archived on 2019-12-11. You can view files and clone it, but cannot push or open issues/pull-requests.
jlaudio/lib/extractfreq/harmonicfit.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)
}