Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Finally I have figured this out; really I had to derive it from scratch. I knew there would be some simple way to derive it, my (usual) mistake was to attempt to follow other people's logic rather than use my own common sense.</p> <p>This puzzle takes <strong>two keys</strong> to unlock it.</p> <ul> <li><p><strong>The first key</strong> is to understand how over-sampling introduces a rotation on bin phase.</p></li> <li><p><strong>The second key</strong> comes from Graph 3.3 &amp; 3.4 here: <a href="http://www.dspdimension.com/admin/pitch-shifting-using-the-ft/">http://www.dspdimension.com/admin/pitch-shifting-using-the-ft/</a></p></li> </ul> <p>...</p> <pre><code>for (int k = 0; k &lt;= 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 &lt;-- 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 bin0Freq = (double)sampleRate / (double)fftFrameSize; bins[k].idealFreq = (double)k * bin0Freq; // Consider Δϕ for bin[k] between hops. // write as 2π / m. // so after m hops, Δϕ = 2π, ie 1 extra cycle has occurred &lt;-- 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 // =&gt; 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; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload