Audio FFT
Eventual goal of project:
Create an environmental noise monitoring solution.
Use a measurement microphone into the ADC, analyse data (1/3 octave results per IEC 61260, FFT, A weighted, LEQ's over different times).
Log to SD card or USB stick.
Use GPS clock to synchronise two systems, and log location data too.
History
SndRecorder
First tried running sndRecorder from Cook book, storing samples as we take them into the filesystem using a ticker.
First error - audio signal goes + and - from ground, and ADV input needs to be from ground to +ve reference. Add decoupling capacitor and two resistors to the input - nearly no dc offset now :)
sndrecorder is 8 kHz sampling and 8 bit resolution, nowhere near enough. So change code to store full resolution of ADC (12 bits) in unsigned 16 bit array.
Increase sample frequency - and discover filesystem throughput is nowhere near good enough...
ADC Library
Use Simon Blandford's library to set up interrupts at 48 kHz. Read data into a buffer and don't try to do anything with it (apart from some LEDs, so I know the audio is connected...) in the interrupt - leave that for main().
For logging the actual audio we need a faster and larger storage medium than either filesystem or flash. So future plans include SD card (have ordered a breakout board for micro SD...)
For the moment we're working in RAM, so can't store a huge buffer. Will investigate using the flash library functions to store the buffer there.
So we now have a very brief (.1s) sample - and write that out to the filesystem. Feeding in some signals (sine waves, white noise etc), we can load them back onto the PC and check what's happening.
High frequency response is a little poor. Need to pay more attention to the input stage. Better screened cable helps a lot (and response is probably flat enough now already) - future plan includes an active input stage with anti-aliaising filter and proper decoupling. Driving it from a headphone out from the PC until we have an active buffer with some gain.
FFT
Couldn't get the STM code port to compile for 1024 points - 256 works OK. So using the Ivan Mellen code. 1024 point seems to be working and giving the right results. Tried 4096 with no luck - probably running out of RAM trying to store the buffer there and the FFT inputs and outputs. Maybe put the buffer in flash, but then might have to reqwrite bits of the library :(
STOP PRESS: Just found this from the writer of the FFT library Ivan Mellen:
Does real only FFT (will speed up the FFT by a factor of 2), calculates the real / imaginary magnitude (currently I'm doing that in main()) - does windowing (no need for me to write that code now ;)) - stores coeffs in flash.... Just need to port the library now and start tweaking the code. Good news...
Current Code
Code works OK. Sending in white noise and looking at the FFT - response is very 'lumpy', but actually at pretty low level, so probably OK. Four sine waves as the source gives a good looking output graph when the FFT file is plotted in excel. Looking good... Should be of equal amplitude, not sure why not... Also frequencies aren't quite right - probably calculating them wrong when writing to file, maybe mixing up the centre freq. with the band edges...
Future Plans
1. Better memory useage - probably store buffer in flash. Need to make more space for the FFT routines. Ideally FFT will operate directly on the buffer rather than transferring data from buffer into an FFT input array. Also get 4096 point FFT working.
2. Aggregate the FFT buckets into octave band data. This will give an approximation to 1/3 octave sound level analysis, but isn't perfect.
3. Keep the interrupts going into a circular buffer rather than just stopping, carrying out periodic FFTs and logging time averaged data.
4. Use a windowing function before the FFT, and overlap (maybe Hann plus 50% overlap) to get FFT improved.
5. Build active audio input stage with low pass filter for anti aliasing and high pass filter to block dc with some gain and more accurate dc bias.
6. Instead of doing FFT and then computing octave bands, do an IIR butterworth filter for each octave band directly. Have ported STM IIR code, but so far unsure how to use butterworth filter coefficients in the STM generic IIR (4 cascaded biquads needing 20 coeffs).
7. Calculate A weighted result from the FFT or the 1/3 octaves.
8. Calculate A weight directly with a suitable IIR filter.
5 comments
You need to log in to post a comment
Hi James
We seem to have been working on parallel paths. I've also been modifying the recorder code and using Ivan Mellen's FFT code. I've been outputting his x,y,z results to a two line LCD display, so not yet possible to understand the output, save to say some numbers change with audio i/p. My aim is to produce a VLF receiver which outputs the amplitude of particular frequencies to a serial or USB port. A long way to go yet. I've downloaded your code for inspiration. I have the mbed beta and wonder how its speed compares with the production unit for such processor intensive calculations.
Will keep in touch.
Tony