I'm trying to understand how to take the results of an FFT calculation and bin them to one-third octave bands. As my questions aren't about the code but about fundamentally understanding the arguments to and results from FFT, I assume this question fits better in electronics than in stackoverflow.
I start by calculating the center point and lower/upper range of each one-third octave band in Python:
freqs = [10**(0.1 * i) for i in range(12, 43)] # center frequency for 31 bands fd = 10 ** 0.05 # 1.12201845 freqs_l = [freq / fd for freq in freqs] # lower freqs_u = [freq * fd for freq in freqs] # upper
The minimum (
freqs_l == 14.125375446227551) and maximum (
freqs_u[-1] == 17782.794100389234) values here give me the overall range of signals I'm interested in. Then I read in samples from my 16-bit, 48kHz WAV file using
hound and run
rustfft's forward-FFT on one second (48000 samples) of data:
const SAMPLE_RATE : usize = 48_000; const NUM_BANDS : usize = 31; // this is the len(freqs) of the Python freqs above let mut planner = FFTplanner::new(false); let fft = planner.plan_fft(SAMPLE_RATE); let reader = hound::WavReader::open(filename).unwrap(); let mut signal = reader .samples::<i16>() .take(SAMPLE_RATE) // just take one second of data for now .map(|samp| num::complex::Complex::new(samp.unwrap() as f32, 0f32)) .collect::<Vec<_>>(); assert_eq!(signal.len(), SAMPLE_RATE); // Convert time-domain signal to frequency-domain spectrum let mut spectrum = signal.clone(); self.fft.process(&mut signal[..], &mut spectrum);
My main question here is around the frequency granuarlity of
spectrum and how I can bucket these values into one-third octave bands. Both
spectrum are of size 48000, but does this cover the full Nyquist frequency range (0 - 24000 Hz), making each value 0.5Hz in width? For each input, I set an imaginary value of 0 (because all examples I've seen do this), but I have no idea if this affects the output in any important way.
Trying to find info on this, I read this SO question on finding the average FFT value of each frequency band and saw some code that pointed to
numpy.fft.fftfreq that generates FFT frequencies for the sample length and sample spacing. From the former, It looks like I would calculate:
If I plug this into NumPy,
numpy.fft.fftfreq(n=48000, d=0.14129655308810293), I get 48000 values, the first half non-negative (because it's symmetrical); the max value here is 3.538; I was expecting it would be closer to the Nyquist frequency.
I'm sure I'm way off here. How should I understand and adjust the FFT output frequencies?