Discussion:
Grappling again with FFT
James Harkins
2014-09-29 05:45:29 UTC
Permalink
Partly for my own understanding, and partly to be able to explain digital audio theory more comprehensively to students, I'm trying to understand what we actually get back from FFT. (Bear with me -- I'm writing this on my phone, so I can't post complete code bits just now.)

I've gotten as far as: 'fft' on a Signal returns a Complex whose real and imaginary parts are Signals. The real values are, essentially, x coordinates and the imaginary values are y coordinates. Converting these x,y pairs into polar coordinates gives the magnitudes (rho) and phases (theta).

a = aSignal.fft(.....);
m = a.rho;
p = a.theta;

So then I tried by brute force to calculate sine waves for each element, where m[0] is the DC component, m[1] corresponds to 1 sine cycle within the window, m[2] to 2 cycles in the window and so on, scaling and offsetting each component according to mag and phase. Well, the sum of those waves was a complete hash -- garbage.

So I conclude that I've misunderstood something somewhere (though it seems, at least naively, that I'm following the formal definitions). What have I got wrong?
Thanks,
hjh
Scott Wilson
2014-09-29 06:29:18 UTC
Permalink
James, IIRC on the server side at least the order is DC, nyquist, real 1f, imag 1f, real 2f, imag 2f …

The first two are special cases (since you can’t know the phase) and so are grouped together. Could that be it?

S.
Post by James Harkins
Partly for my own understanding, and partly to be able to explain digital audio theory more comprehensively to students, I'm trying to understand what we actually get back from FFT. (Bear with me -- I'm writing this on my phone, so I can't post complete code bits just now.)
I've gotten as far as: 'fft' on a Signal returns a Complex whose real and imaginary parts are Signals. The real values are, essentially, x coordinates and the imaginary values are y coordinates. Converting these x,y pairs into polar coordinates gives the magnitudes (rho) and phases (theta).
a = aSignal.fft(.....);
m = a.rho;
p = a.theta;
So then I tried by brute force to calculate sine waves for each element, where m[0] is the DC component, m[1] corresponds to 1 sine cycle within the window, m[2] to 2 cycles in the window and so on, scaling and offsetting each component according to mag and phase. Well, the sum of those waves was a complete hash -- garbage.
So I conclude that I've misunderstood something somewhere (though it seems, at least naively, that I'm following the formal definitions). What have I got wrong?
Thanks,
hjh
_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/
James Harkins
2014-09-29 06:38:38 UTC
Permalink
------------------ Original ------------------
From: "Scott Wilson";<***@scottwilson.ca>;
Date: Sep 29, 2014
To: "sc-users"<sc-***@lists.bham.ac.uk>;

Subject: Re: [sc-users] Grappling again with FFT



James, IIRC on the server side at least the order is DC, nyquist, real 1f, imag 1f, real 2f, imag 2f ¡­
~~~


I'm using client-side FFT here, so they are not interleaved. The result is a Complex with N real values and N imaginary values.




I think I figured it out anyway -- above Nyquist, you need to negate the magnitude, and I think I need to use cosines rather than sines. I'll post code when I'm convinced this is right.


hjh
mark hadman
2014-09-29 06:45:26 UTC
Permalink
James, any chance you could post a brief tutorial once you understand
it? I'd like to use this knowledge to make a dual channel fft with
phase trace for measurement purposes, because as far as I'm aware
there isn't a free one for Linux yet.
mH
Post by James Harkins
------------------ Original ------------------
Date: Sep 29, 2014
Subject: Re: [sc-users] Grappling again with FFT
James, IIRC on the server side at least the order is DC, nyquist, real 1f,
imag 1f, real 2f, imag 2f …
~~~
I'm using client-side FFT here, so they are not interleaved. The result is a
Complex with N real values and N imaginary values.
I think I figured it out anyway -- above Nyquist, you need to negate the
magnitude, and I think I need to use cosines rather than sines. I'll post
code when I'm convinced this is right.
hjh
_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/
Andrea Valle
2014-09-29 07:08:09 UTC
Permalink
I think FFT implementation is a black hole for users, I remember I wrote to the mailing list about it.
Please James post a brief toot!
:)

Best

-a-


--------------------------------------------------
Andrea Valle
--------------------------------------------------
CIRMA - StudiUm
Università degli Studi di Torino
--> http://www.cirma.unito.it/andrea/
--> http://www.fonurgia.unito.it/andrea/
--> http://www.flickr.com/photos/vanderaalle/sets/
--> http://vimeo.com/vanderaalle
--> andrea.valle-Ob+***@public.gmane.org
--------------------------------------------------

"This is a very complicated case, Maude. You know, a lotta ins, a lotta outs, a lotta what-have-yous."
(Jeffrey 'The Dude' Lebowski)
Post by mark hadman
James, any chance you could post a brief tutorial once you understand
it? I'd like to use this knowledge to make a dual channel fft with
phase trace for measurement purposes, because as far as I'm aware
there isn't a free one for Linux yet.
mH
Post by James Harkins
------------------ Original ------------------
Date: Sep 29, 2014
Subject: Re: [sc-users] Grappling again with FFT
James, IIRC on the server side at least the order is DC, nyquist, real 1f,
imag 1f, real 2f, imag 2f …
~~~
I'm using client-side FFT here, so they are not interleaved. The result is a
Complex with N real values and N imaginary values.
I think I figured it out anyway -- above Nyquist, you need to negate the
magnitude, and I think I need to use cosines rather than sines. I'll post
code when I'm convinced this is right.
hjh
_______________________________________________
sc-users mailing list
info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/
James Harkins
2014-09-29 08:13:53 UTC
Permalink
Sure, I will, but it will take a couple of days. I need the rest of today to prepare my sound design class lecture, and tomorrow, I'm teaching all afternoon and into the evening.

A teaser for now -- a brute force IFFT (where the answer was actually *not* to negate the magnitudes in the upper half, and use cosine instead of sine).

d = Signal.sineFill(128, (1..5).reciprocal);

a = d.fft(Signal.newClear(d.size), Signal.fftCosTable(d.size));

r = a.rho; // magnitudes -- note r[1] ~= 40, r[2] ~= 40/2, r[3] ~= 40/3 etc.
t = a.theta; // phases -- note t[1] == t[2] == t[3] == t[4] == t[5] == -0.5pi
// A cosine with phase -0.5pi is the same as a sine with phase 0, matching sineFill

(
b = Signal.newClear(d.size);
r.do { |mag, i|
var freq = i, // 'i' cycles per 'd.size' samples
phase = t[i],
increment = (2pi * freq / d.size),
sine = Signal.fill(d.size, { |j| mag * cos(phase + (increment * j)) });
b = b + sine;
};
b = b / d.size;
)

b.plot; // looks familiar!

hjh




_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/

Loading...