// Algorithm: first interpolate the spectral peak corresponding to fApprox, // then locate the (near-)integer multiples of its frequency Spectrum Analyzer::findHarmonics(const Spectrum spectrum, qreal fApprox) const { Spectrum harmonics; if (fApprox <= 0 || std::isinf(fApprox)) return harmonics; const auto peaks = spectrum.findPeaks(0.01); if (peaks.isEmpty()) return harmonics; harmonics.reserve(peaks.size()); const auto iFund = std::floor(fApprox / m_binFreq) + 1; const auto fundamental = quadraticInterpolation(&spectrum[iFund]); harmonics.append(fundamental); for (const auto peak : peaks) { if (peak->frequency > fundamental.frequency) { const Tone t = quadraticInterpolation(peak); const qreal ratio = t.frequency / fundamental.frequency; if (qAbs(1200 * std::log2(ratio / qRound(ratio))) < 10) harmonics.append(t); } } return harmonics; }
//------------------------------------------------------------------------ //--- calculates the correction ------------------------------------------ //------------------------------------------------------------------------ float SimpleJetCorrector::correction(const std::vector<float>& fX,const std::vector<float>& fY) const { float result = 1.; float tmp = 0.0; float cor = 0.0; int bin = mParameters->binIndex(fX); if (bin<0) return result; if (!mDoInterpolation) result = correctionBin(bin,fY); else { for(unsigned i=0;i<mParameters->definitions().nBinVar();i++) { float xMiddle[3]; float xValue[3]; int prevBin = mParameters->neighbourBin(static_cast<unsigned>(bin),i,false); int nextBin = mParameters->neighbourBin(static_cast<unsigned>(bin),i,true); if (prevBin>=0 && nextBin>=0) { xMiddle[0] = mParameters->record(prevBin).xMiddle(i); xMiddle[1] = mParameters->record(bin).xMiddle(i); xMiddle[2] = mParameters->record(nextBin).xMiddle(i); xValue[0] = correctionBin(prevBin,fY); xValue[1] = correctionBin(bin,fY); xValue[2] = correctionBin(nextBin,fY); cor = quadraticInterpolation(fX[i],xMiddle,xValue); tmp+=cor; } else { cor = correctionBin(bin,fY); tmp+=cor; } } result = tmp/mParameters->definitions().nBinVar(); } return result; }
Tone Analyzer::determineSnacFundamental(const Spectrum snac) const { Tone result; const auto peaks = snac.findPeaks(); if (peaks.isEmpty()) return result; // First find the highest peak other than the first SNAC value, which // should be 1.0, then pick the first peak after the first zero crossing // that exceeds 0.8 times that value const auto maxPeak = *std::max_element(peaks.constBegin(), peaks.constEnd(), [](const Tone *t1, const Tone *t2) { return *t1 < *t2; }); const auto zeros = snac.findZeros(1); auto pick = std::find_if(peaks.begin(), peaks.end(), [&](const Tone *t) { return t > zeros.first() && t->amplitude > 0.8 * maxPeak->amplitude; }); if (pick != peaks.end()) { result = quadraticInterpolation(*pick); Q_ASSERT(result.frequency > 0); } return result; }