Sunday, December 1, 2013

Week 14/15: Realtime FFT and Mic Issues

As a good portion of week 15 was spent digitizing my research effort, this posting will summarize my efforts over Thanksgiving break in addition to the week subsequent.

As I am home for Thanksgiving break, I do not have as much access to tools or equipment. Consequently I spent this week looking into a way to implement realtime FFT on the Arduino. If you recall my earlier assessments upon starting this research I was somewhat hesitant to perform any realtime signal processing. This feeling was compounded by having switched from the 80 Mhz chipkit processor to the reference 16 Mhz AVR earlier in development. However upon some cursory googling into the possibility of something simple like pitch recognition, it seems that something such as FFT is completely doable.

****An aside to clarify the reason for FFT research: I decided upon the tone recognition sensor concept detailed in a previous post. The reason for this is that it seems simple enough to implement, while avoiding possible complexities with communications on the 6 DOF position and movement tracker.

Having taken the ECE intro DSP course, I was somewhat familiar with the concept of pitch recognition via Fourier analysis of a sampled signal. However it had been awhile, and I saw fit to review it. After scrounging up some books, I found that the following link makes a pretty good summary without delving too deep into the complexity of the thing. (Reminder: Our goal is an easily implemented FFT, which is a computer-optimized DTFT, which will perform pitch identification).

http://www.arduinoos.com/2010/10/fast-fourier-transform-fft/
(All pages are interesting, but I don't think I'm going to use the code provided)

Now having explored that link, while the explanation of the concepts and algorithms is good, I am opting away from using his PlainFFT library. The reason for this being that it seems to be developed for more "hardcore" signal processing than we need, and it appears somewhat overcomplicated given that all we need is basic pitch recognition. Instead I decided upon using the ArduinoFFT library (http://wiki.openmusiclabs.com/wiki/ArduinoFFT) as it is simpler and much more straightforward to understand directly from the sample code. This covers the hard part, the software implementation of FFT. From here we just need to get the hardware up to speed.

The configuration for this only requires some form of audio input to be available to the arduino. The solution? A nice prototyping-centric electret mic from sparkfun! I happened to have one on hand, however upon testing it out it was returning garbage values, oh well back to software. (Plot spoiler: the mic was broken and I couldn't get one before the end of the semester)

Presuming that the ArduinoFFT library works smoothly, I'm going to overview the sample code for the library, posted here. This code performs fourier analysis on a sampled signal by repeatedly sampling the A0 channel of the Arduino's ADC during the execution loop. 256 total samples are collected, formatted, and then processed into a 128 element array. The output resides in fft_log_out and is transmitted to the Serial lines. Now having given the high-level picture, this code is very interesting and I want to point out some cool bits.
  • The entire thing is performance based, and revolves around squeezing every bit of processing time out of the Arduino as possible. This is very critical to achieving high accuracy during signal sampling, incorrect or time-skewed data could lead to false results.
    • This manifests itself through the use of multiple low-level statements throughout the code. All of the capitalized variables represent internal controls on the Arduino's ATMega328 MCU.
    • In the initialization section, "TIMSK0 = 0" forcibly disables the Arduino's internal timing mechanisms, and also prevents any timer interrupts from engaging the processor. This optimization improves performance however, as the code will note, processes dependent on this function will be impaired. The delay() function is the victim here, and given this function's common use in Arduino development it may be prudent to store the value of TIMSK0, and restore it back to re-enable timing function OUTSIDE of the sampling function.
    • The ADMUX control register determines the ADC channel to poll. As the code has it, 0x40 corresponds to analog channel 0. This isn't doable as we have A0 reserved for our I2C communication. As per the AtMega328 spec, the lower 4 bits of this register correspond to the MUX controlling the ADC channel, so the lower hex digit must be modified if another channel is selected. For example, 0x42 will set channel 2.
    • cli() and sei() control the interrupt gating on the AtMega. This effectively shuts out all external interrupts from engaging the processor, preventing the sampling code from being interrupted. This has the potential to cause issues with our I2C comms, so I'm hesitant to leave it in. Receiving an I2C interrupt during sampling will cause it to be ignored, so the NXT side will have to implement some control cases in the event the Arduino fails to respond.
    • The for loop performing the signal sampling appears to zero every other entry. I could be wrong, but I believe this is an optimization taking advantage of the fact that several signal terms are zeroed during the DTFT process. Either way, hooray because it's faster this way.
  • Additional processing will need to be performed on the fft_log_out data set in order to extract a tone. The FFT will process the signal into its constituent frequencies, identification of the majority frequency should be easy enough to do.
In fact, this code itself is a strong base for what we're trying to accomplish. Adding in the relevant pieces for I2C communication, and processing of the returned array of output FFT values should be the primary goal.