package extractfreq import ( "log" "gonum.org/v1/gonum/floats" "gonum.org/v1/gonum/stat" ) type HarmonicWindow struct { Harmonic float64 // 0.25, 0.5, 1, 2, 3, ... Amps []float64 Freqs []float64 IdxPeak int IdxPeakInterp float64 FreqPeakInterp float64 AmpPeak float64 AmpMean float64 AmpStd float64 } func NewHarmonicWindow( fFundamental float64, harmonic float64, rawAmps []float64, rawFreqs []float64, ) *HarmonicWindow { deltaF := rawFreqs[1] - rawFreqs[0] // TODO: At higher harmonic numbers, the harmonics are going to be spaced // more cloesly together. That means that the window size must shrink. //winSizeCents := float64(150) // To start, we create a window around the approximate harmonic location. idxPeak := int((fFundamental * harmonic) / deltaF) winSize := int(0.5 * fFundamental / deltaF) amps := rawAmps[idxPeak-winSize : idxPeak+winSize] freqs := rawFreqs[idxPeak-winSize : idxPeak+winSize] // Next, we refine the window be centering it on the actual peak. idxPeak += (floats.MaxIdx(amps) - winSize) amps = rawAmps[idxPeak-winSize : idxPeak+winSize] freqs = rawFreqs[idxPeak-winSize : idxPeak+winSize] idxPeak = winSize // Next we compute statistical properties to determine if this peak is worth // using. mean, std := stat.MeanStdDev(amps, nil) ampPeak := amps[idxPeak] log.Printf("%0.2f: %0.4f", harmonic, (ampPeak-mean)/std) // TODO: Actual interpolation. return &HarmonicWindow{ Harmonic: harmonic, Amps: amps, Freqs: freqs, IdxPeak: idxPeak, IdxPeakInterp: float64(idxPeak), FreqPeakInterp: freqs[idxPeak], AmpPeak: ampPeak, AmpMean: mean, AmpStd: std, } }