Tôi đã gặp rất nhiều khó khăn với vấn đề chính xác này một vài năm trước đây.
Tôi đã đăng câu hỏi này:
/programming/4633203/extracting-precise-frequencies-from-fft-bins-USE-phase-change-b between-framework
Tôi đã kết thúc việc tính toán từ đầu, và đăng một câu trả lời cho câu hỏi của riêng tôi.
Tôi ngạc nhiên rằng tôi không thể tìm thấy bất kỳ giải trình tương tự nào trên Internet.
Tôi sẽ đăng câu trả lời một lần nữa ở đây; lưu ý rằng mã được thiết kế cho một kịch bản trong đó tôi chồng chéo cửa sổ FFT của mình lên gấp 4 lần.
π
Câu đố này có hai chìa khóa để mở khóa nó.
Biểu đồ 3.3:
Biểu đồ 3,4:
Mã số:
for (int k = 0; k <= fftFrameSize/2; k++)
{
// compute magnitude and phase
bins[k].mag = 2.*sqrt(fftBins[k].real*fftBins[k].real + fftBins[k].imag*fftBins[k].imag);
bins[k].phase = atan2(fftBins[k].imag, fftBins[k].real);
// Compute phase difference Δϕ fo bin[k]
double deltaPhase;
{
double measuredPhaseDiff = bins[k].phase - gLastPhase[k];
gLastPhase[k] = bins[k].phase;
// Subtract expected phase difference <-- FIRST KEY
// Think of a single wave in a 1024 float frame, with osamp = 4
// if the first sample catches it at phase = 0, the next will
// catch it at pi/2 ie 1/4 * 2pi
double binPhaseExpectedDiscrepancy = M_TWOPI * (double)k / (double)osamp;
deltaPhase = measuredPhaseDiff - binPhaseExpectedDiscrepancy;
// Wrap delta phase into [-Pi, Pi) interval
deltaPhase -= M_TWOPI * floor(deltaPhase / M_TWOPI + .5);
}
// say sampleRate = 40K samps/sec, fftFrameSize = 1024 samps in FFT giving bin[0] thru bin[512]
// then bin[1] holds one whole wave in the frame, ie 44 waves in 1s ie 44Hz ie sampleRate / fftFrameSize
double bin1Freq = (double)sampleRate / (double)fftFrameSize;
bins[k].idealFreq = (double)k * bin1Freq;
// Consider Δϕ for bin[k] between hops.
// write as 2π / m.
// so after m hops, Δϕ = 2π, ie 1 extra cycle has occurred <-- SECOND KEY
double m = M_TWOPI / deltaPhase;
// so, m hops should have bin[k].idealFreq * t_mHops cycles. plus this extra 1.
//
// bin[k].idealFreq * t_mHops + 1 cycles in t_mHops seconds
// => bins[k].actualFreq = bin[k].idealFreq + 1 / t_mHops
double tFrame = fftFrameSize / sampleRate;
double tHop = tFrame / osamp;
double t_mHops = m * tHop;
bins[k].freq = bins[k].idealFreq + 1. / t_mHops;
}