mikeash.com pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html commentshttp://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsmikeash.com Recent CommentsMon, 23 May 2022 02:23:44 GMTPyRSS2Gen-1.0.0http://blogs.law.harvard.edu/tech/rssStephan Müller - 2014-04-08 13:42:21http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#comments<div class="blogcommentquote"><div class="blogcommentquoteinner">[…] and sometimes with inverted components […]</div></div>
<br /><code>float imag = buf[i] * sin(-angle);</code>
<br />
<br />Its a convolution… one of the signals needs to go "backwards". 99a6e7ba177d0901ac331d919f9aab72Tue, 08 Apr 2014 13:42:21 GMTStephan Müller - 2014-04-08 13:33:34http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsWhat helped me understand the discrete fourier transform was looking at easy examples: A signal consisting of only two samples. Such a signal contains two frequencies, <code>[1,1]</code> (the DC offset) and <code>[1,-1]</code> (the Nyquist component). It is pretty obvious that by combining those two vectors, any two samples can be "created".
<br />
<br />Larger signals require phase offsets (hence the complex numbers): <code>[0,1,0,-1]</code> (sampled sine) can be shifted to create <code>[1,0,-1,0]</code> (sampled cosine).
<br />
<br />And the final missing link to understanding fourier (at least for me) was realising that different frequencies are orthogonal: if you multiply two different frequencies sample by sample and sum up the results, the sum will always be 0. Hence if you do this with a complex signal and a single frequency, all other frequencies in the signal sum up to 0. (try summing up <code>[0,1,0,-1]</code> and <code>[1,-1,1,-1]</code>). 32c6aa902816927318b1674cf552a1a0Tue, 08 Apr 2014 13:33:34 GMTStephan Müller - 2014-04-08 13:02:26http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#comments<div class="blogcommentquote"><div class="blogcommentquoteinner">[…] for reasons I don't fully understand, the results of this function are off by a factor of two […]</div></div>
<br />(Note that the whole article is not about the fourier transform, but the <i>discrete</i> fourier transform. But anyway…)
<br />
<br />While the scaling of the transformed result is nothing but convention, it can still be helpful to understand where the 2 comes from. Lets take an easy signal, say <code>sin(x)</code> over a whole period (<code>x in [0, 2pi]</code>).
<br />
<br />This signal contains exactly one frequency. So the transformation basically becomes summing up <code>sin(angle)*sin(angle)</code>. Lets just assume the sampling rate is really high and integrate the function from 0 to 2pi (which gives us pi). Now I want the result to only depend on the signal amplitude and not the signal length, so I divide by the signal length of 2pi, which gives us our famous 1/2 (even though the original amplitude was 1).
<br />
<br />In short: the factor of 2 is created by squaring the sine! The transformed signal has more direct meaning if it is multiplied by 2, but any scaling is just convention. bb3147b6779e3a0dddf4688cddbd5e50Tue, 08 Apr 2014 13:02:26 GMTtgree - 2014-02-10 00:56:01http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsYour spinny description of the FFT was fantastic, and breaking it down into sin/cos instead of complex exponential arithmetic really helped to clarify what is going on for me.
<br />
<br />Thanks for your article!dfb523da2a1942ce5211a5d16b2a42cfMon, 10 Feb 2014 00:56:01 GMT:) - 2013-10-12 20:42:40http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#comments*Of course* it'll be twice as large.
<br />
<br />It's a sine wave; it has a positive and a negative peak. During the positive peak you're facing in the right direction, during the negative peak you're facing the opposite direction and walking backwards.
<br />
<br />So you're walking in the same direction with a speed corresponding to the sampled intensity twice per cycle -- and that works out to a speed corresponding to one times the amplitude.
<br />
<br />The inverted sign can be explained just as easily: you're in the *negative* halfwave when you think you are in the *positive* halfwave, and the other way around.265dbd4ba283f143093e5578e81e336dSat, 12 Oct 2013 20:42:40 GMTJarryd - 2013-06-03 20:50:24http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsThanks for the great explanation of the FFT.
<br />
<br />Should all of these steps be done.
<br />
<br /> vDSP_ctoz((COMPLEX *)data, 2, &out, 1, bufferFrames / 2);
<br /> vDSP_fft_zrip(fftSetup, &out, 1, bufferlog2, FFT_FORWARD);
<br /> vDSP_fft_zrip(fftSetup, &out, 1, bufferlog2, FFT_INVERSE);
<br /> float outData[bufferFrames];
<br /> vDSP_ztoc(&out, 1, (COMPLEX *)outData, 2, bufferFrames / 2);
<br /> cblas_sscal(bufferFrames, 1.0 / (bufferFrames * 2), outData, 1);
<br />
<br />I dont get where the dominant frequency can be found.eb9a75e5506ee3386816ab521c4201cfMon, 03 Jun 2013 20:50:24 GMTmikeash - 2012-11-09 21:40:26http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#comments<b>SSteve:</b> Yes, I can imagine. The fun thing about this bug is that, since OS X's audio pipeline is all floating-point, values in excess of 1.0 will, at least on some hardware, be louder than your set output volume. I had my speakers turned all the way down, but this stuff still came out at full blast.3b90b9ac5c5f3e7e2da2c8600ec90a25Fri, 09 Nov 2012 21:40:26 GMTSSteve - 2012-11-09 21:18:01http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#comments"This needs to be removed before treating the result as audio data, unless you like frightening everybody in the restaurant with the sudden blast of sound from your MacBook (ask me how I know this)."
<br />
<br />I was doing beta testing for an audio software company during the PPC to Intel transition. The occasional endian bug could be deafening when we started playback.8ad332ca686acc8ff08c40d4dc96a2c1Fri, 09 Nov 2012 21:18:01 GMTjamie - 2012-11-01 22:36:23http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsBy the way, your narrative description of the Fourier transform is the best I've read. I've been trying to come up with a slightly more memorable one involving two turtles on a beach arguing over how long the tide lasts :)759b635849345159c034552b007b912cThu, 01 Nov 2012 22:36:23 GMTnevyn - 2012-10-28 08:55:05http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsYay, thank you! Will have to experiment more using this knowledge...70416d995130dbfa6aa1c6e9b6c022b3Sun, 28 Oct 2012 08:55:05 GMTTJ Usiyan - 2012-10-27 00:54:07http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsThe reason that they are scaled and how is explained here
<br />
<br /><a href="http://developer.apple.com/library/mac/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH202-15952">http://developer.apple.com/library/mac/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH202-15952</a>c5b446e6d39a7104f921cf1261247dfeSat, 27 Oct 2012 00:54:07 GMTmikeash - 2012-10-26 20:37:08http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#comments<b>vasi:</b> Sorry, a bit of habitual shorthand there. <code>rate</code> refers to the sample rate of the audio, e.g. <code>44100</code>. <code>hz</code> is the target frequency for the analysis.1188d75d3f8069ed5f311ba9a7664a16Fri, 26 Oct 2012 20:37:08 GMTjamie - 2012-10-26 19:54:47http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#comments"rate" is the sample rate of the float *.
<br />
<br />"The result of this inverse transformation, for reasons I don't fully understand, comes out multiplied by a factor of bufferFrames * 2."
<br />
<br />A bare FFT always gives amplitudes as a product of the block size. You might be getting the 2 from the fact that the output is the real part of an analytic signal? I dunno the conventions for veclib, my FFT experience is completely from Pure Data (which is great for learning but a bit tough for making polished products).
<br />
<br />Also while you could definitely use something like this for cool visualization, you're just doing a straight rectangular window here, so you're going to end up with a lot of spectral leakage in the forward transform and when you resynthesize it'll sound distorted.bf6d5a10eb75156f70ff8372a52f7ddbFri, 26 Oct 2012 19:54:47 GMTvasi - 2012-10-26 16:33:59http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsThe signature for Rotate() is really confusing:
<br />
<br />COMPLEX Rotate(float *buf, int samples, float hz, float rate)
<br />
<br />It's not clear to me what the last two parameters mean: 'hz' is presumably a rate, and 'rate' is presumably measured in Hertz. I guess one of them indicates the frequency of our rotation, but which one, and what does the other one mean?c5b36b0c83f21325e570eadc8e964f80Fri, 26 Oct 2012 16:33:59 GMTClark - 2012-10-26 15:31:56http://www.mikeash.com/?page=pyblog/friday-qa-2012-10-26-fourier-transforms-and-ffts.html#commentsNext up spherical bessel functions for fun and profit…
<br />
<br />More seriously, do you know what the two other main classes of functions for analysis aren't in vDSP? Admittedly they aren't used quite as much but still. Spheres and cylinders are very useful for anlayzing symmetries and the like.42c366183655e98e8eaee1a6905ec0deFri, 26 Oct 2012 15:31:56 GMT