This blog is a sequel of “Tears of Rainbow”. Using the same hardware set-up of Gigantic RGB LED display, I decided to re-work software a little bit, in order to display the true RMS amplitude of musical content. Video clip on youtube: VU_Meter 640×480 VU_Meter_HD
- Stereo input, process both channel;
- Full audio band, 40 Hz – 20 kHz;
- Fast update rate of visual output.
- Precision Full-Wave measurements.
To process stereo input, this time arduino is switching ADC multiplexer every time when it finish sampling input data array (size=128). Two channels “interleaved” with frame rate 78 Hz, so during each frame only one channel sampled / processed, and update rate per channel is equals to 78 / 2 = 39 Hz, which is more than enough for most audio applications.
I’m using FFT Radix-4 to extract RMS magnitude of audio waveform, and this is why:
1. Sampling rate in this application is 10 kHz. How I achieved 20 kHz stated in objective section, doing sampling only 10 ksps? >>>Aliasing!<<< What is considered to be nightmare when we need spectral information from FFT output, aliasing in this project is really helpful, reflecting all spectral components around axis – 10 kHz back “to the field”. As all bins going to be sum-up there is no issue, only benefits. Due aliasing, I’m able to use low sampling rate, and reduce CPU workload down to 52%.
2. In order to get accurate magnitude calculation of RMS, which is defined as square root of the sum of squares divided by number of samples per specified period of time: V(rms) = √ ( ∑ Vi ^2 ) / N) DC offset must be subtracted from the input raw data of each sample Vi = Vac + Vdc (if you remember, AtMega328 ADC needs DC offset to read AC negative half-wave). The problem here, DC offset value is never known with high accuracy due bunch of reason, like voltage stability of PSU, thermal effects, resistors tolerance (+/- 1 or 5 %), ADC internal non-linearity etc. Cure for this, which works quite well for monitoring electrical grid power, high pass filter (HPF). Only instead of single 50/60 Hz frequency of power line, I have a wide frequency range, starting from 20 Hz and ending at 20 kHz. When I feed specification of the HPF:
- Sample Rate (Hz) ? [0 to 20000] ? 10000
- Desired stop-band attenuation (dB) [10 to 200] ? 40
- Stop-band edge frequency Fa [0 to 5000] ? 0
- Pass-band edge frequency Fp [0 to 5000] ? 40
to Parks-McClellan FIR filter design algorithm (one of the most popular, and probably, the best) it provides the result:
- …filter length: 551 …beta: 3.395321
551 coefficient to be multiplied and sum up (MAC-ed) every 100 usec! No way. I’m not sure, if it could be done on 32-bits 100 MHz platform with build-in MAC hardware, but there is no way for 8-bit 16 MHz Arduino.
IIR filter wouldn’t make much difference here. It has lower quantity of multiplications, but more sensitive for truncation and rounding error, so I’d have to use longer (32-bits?) variables, which is not desirable on 8-bit microprocessor at all.
And here comes FFT Radix-4, which easily fulfill this extra-tough requirements in the most efficient and elegant way. All I have to do, is just NOT include bin in final sum, and all DONE!. TOP-FLAT linear frequency response 40 Hz – 20 kHz ( -3 dB ), with complete suppression of DC, and low frequency rumble below 20 Hz attenuation. Linearity is better than +-1 dB between 80 – 9960 Hz.
Last things, audio front-end. As VU meter was designed in stereo version, I’ve build another “line-in” pre-amplifier based on this kit: Super Ear Amplifier Kit
Modified Stereo VU meter, Logarithmic scale, 8 bars per channel, spacing 6 dB.