COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 01-11-2016, 11:44 AM   #1
mrbloom
Human being with feelings
 
Join Date: Oct 2014
Posts: 16
Default Spectrum Analyser

Hello WDL'ers,

I am trying to put together a simple spectrum analyser using WDL's fft.h but I am getting magnitude values of the fft totally out of range.

I found the IPlugSpectFFT example by witmerm amid the pull requests of WDL-OL on github and I saw that they calculate the magnitude this way:

Code:
vOutPut[i] = std::sqrt(2. * (re * re + im * im) / (S1*S1));
where S1 is calculated this way:
Code:
void CalculateSValues() {
        S1 = 0.;
        S2 = 0.;
        for (int i = 0; i < fftSize; i++) {
            double v = 0.5 * (1. - std::cos(pi2 * i / (double)(fftSize - 1)));
            S1 += v;
            S2 += v*v;
        }
    }

With this normalization the values are way more meaningful and the fft seems to work with my tests! but I can't really figure out what S1 represents and why I need to divide the magnitude by S1*S1

any idea ?
mrbloom is offline   Reply With Quote
Old 01-11-2016, 07:34 PM   #2
random_id
Human being with feelings
 
random_id's Avatar
 
Join Date: May 2012
Location: PA, USA
Posts: 356
Default

I wish I was a math guy and could tell you something intelligent, but I am not.
I did a lot of trial and error until everything "looked right". This appeared to do the trick, and is something I took from https://holometer.fnal.gov/GH_FFT.pdf
__________________
Website: LVC-Audio
random_id is offline   Reply With Quote
Old 01-12-2016, 12:16 AM   #3
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,652
Default

I guess S1 and S2 are scaling factors, probably for FFT size and/or window, and maybe also to convert from ratio to dB.
Tale is offline   Reply With Quote
Old 01-12-2016, 07:58 PM   #4
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

I'm not a WDL user, but I recently messed with the fft in JS, and Tale mentioned that it might be based on the WDL code, so just in case it's useful, you could see this thread:

http://forum.cockos.com/showthread.php?t=169701

In the JS I was looking at, I learned that the JS FFT requires inputs to be scaled by 1/fftsize before doing the FFT. The demo code accomplished this within the "windowing" function. If you were using a rectangular window (i.e. no alteration of the input) the code would indirectly just compute 1/fftsize for the scaling factor. If you used some other window shape the math would somehow calculate a different scaling factor to be used (I guess the scaling factor must be based on the overall potential magnitude of the audio being FFT'd and a window obviously reduces that, so it's some computational method to do the integral?)

CalculateSValues seems to be calculating some scaling factors derived from a simple sinusoidal windowing function?

The code you posted seems to be doing that scaling after the FFT as opposed to the JSFX I saw which did it before, but maybe the math works out that you can scale the values before or after the FFT is done, at your discretion? Just a wild guess.

Applying this all to the code you posted, if you imagine that the window function was unity gain and rectangular (i.e. "double v = 1;"), S1 would just come out to be the fftsize. The calculation of the magnitude includes that term within sqrt() as S1^2 for some reason, but if you pull the term out of sqrt() as "S1", you see that it's just dividing by S1 (aka fftsize if it was a rectangular window). So that lines up.

In summary: for a rectangular window, you just want to scale the inputs by 1/fftsize. Then you can calculate the magnitude with:

mag = 2*sqrt(real^2 + imag^2)

...and I'm theorizing that if you didn't do the scaling before the FFT maybe you can also calculate it as

mag = 2*sqrt(real^2 + imag^2) / fftsize

And if not a rectangular window, then instead of "fftsize" you have an appropriate scale factor based on the window.
clepsydrae is offline   Reply With Quote
Old 01-13-2016, 09:49 AM   #5
mrbloom
Human being with feelings
 
Join Date: Oct 2014
Posts: 16
Default

thank you all guys for your replies
@random_id: hey there you are, thank you for your spectrum example !

So it turns out that I was getting out of range errors just because I was not doing the normalization after the FFT and plotting values in the range [0,1]. I totally overlooked it because I was thinking one has to normalize only when doing the inverse FFT. But in fact the reason you do the normalization is that the FFT is defined as a sum so all the values pile up and grow proportionally to the length of the FFT block. Hence the normalization to get the values in the range of the original signal.

So yeah a bit of a dumb mistake of mine. Nevertheless it was useful to read the document that random_id posted (thanks!). And, as far as I understood, S1 is a normalization factor that takes into account the fact that the signal has been hann-windowed before being given to the FFT. Indeed the formula is exactly the same as the one for calculating the Hanning window. Even in your code :

Code:
if (wType == win_Hann)  vWindowFx[i] = 0.5 * (1. - std::cos(pi2 * i / M));
this is the same as S1, isn't it? So this makes me wonder: is this normalization correct when other window envelopes are used ?

cheers
mrbloom is offline   Reply With Quote
Old 01-13-2016, 10:39 AM   #6
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,652
Default

Quote:
Originally Posted by mrbloom View Post
So this makes me wonder: is this normalization correct when other window envelopes are used ?
Well, the rule of the thumb seems to be that if you add up all values of a certain window function, then the sum should be equal to its length i.e. the sum divided by the length should be 1. If it isn't then you should scale it to compensate.
Tale is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 12:38 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.