Difference between revisions of "S14: Spectrum Analyzer for Audio Frequency Signals"
Proj user13 (talk | contribs) (→Hardware Design) |
(→Project Source Code) |
||
(114 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
== Spectrum Analyzer for Audio Frequency Signals == | == Spectrum Analyzer for Audio Frequency Signals == | ||
== Abstract == | == Abstract == | ||
− | We plan to build a Spectrum Analyzer for Audio Frequency signals. Our device is able to display frequencies in audio of up to 4 kHz, which covers the most of the of the frequency range of typical music. The main inspiration for our project was applications of | + | We plan to build a Spectrum Analyzer for Audio Frequency signals. Our device is able to display frequencies in audio of up to 4 kHz, which covers the most of the of the frequency range of typical music. The main inspiration for our project was applications of music visualizers which are seen in much software like Windows Media Player. Our spectrum analyzer will try to mimic such visualizers using an audio amplifier and a LED display. The display will light up a range of LEDs from low to high according to audio frequency using FFT as the algorithm for analyzing audio input. This gives a fully dynamic LED display for audio frequency. |
=== Introduction === | === Introduction === | ||
Line 22: | Line 10: | ||
The display of a Spectrum analyzer has frequency on the horizontal axis and the amplitude displayed on the vertical axis. In general observation, a Spectrum analyzer looks like an oscilloscope and, in fact, some lab instruments can function either as an oscilloscope or a spectrum analyzer. | The display of a Spectrum analyzer has frequency on the horizontal axis and the amplitude displayed on the vertical axis. In general observation, a Spectrum analyzer looks like an oscilloscope and, in fact, some lab instruments can function either as an oscilloscope or a spectrum analyzer. | ||
+ | |||
+ | |||
+ | '''Fast Fourier Transform''' | ||
+ | |||
+ | A fast Fourier transform (FFT) is an algorithm to compute the discrete Fourier transform (DFT) and its inverse. Fourier analysis converts time (or space) to frequency and vice versa; an FFT rapidly computes such transformations by factorizing the DFT matrix into a product of sparse (mostly zero) factors.[1] As a result, fast Fourier transforms are widely used for many applications in engineering, science, and mathematics. | ||
+ | The best-known FFT algorithms depend upon the factorization of N, but there are FFTs with O(N log N) complexity for all N, even for prime N. Many FFT algorithms only depend on the fact that e^{-2*pi/ N}} is an N-th primitive root of unity, and thus can be applied to analogous transforms over any finite field, such as number-theoretic transforms. | ||
+ | We modified the Fortran FFT code from Digital Signal Processing by A.V. Oppenheim and R.W. Schafer to C code for 16-point FFT. | ||
+ | |||
+ | |||
+ | '''Analog to Digital Converters''' | ||
+ | |||
+ | An ADC is used to convert a continous physical quantity to a digital number that represents the quantity's amplitude. | ||
+ | The conversion involves quantization of the input, so it necessarily introduces a small amount of error. Instead of doing a single conversion, it periodically samples the given input data and provides a sequence of digital outputs. Thus, it converts continous time signals to discrete time domain. | ||
+ | We define any ADC by its bandwidth and its signal to noise ratio(the accuracy of measurement). The actual bandwidth of an ADC is characterized by its sampling rate and to a lesser extent by how it handles errors. | ||
+ | If an ADC operates at a sampling rate greater than twice the bandwidth of the signal, then perfect reconstruction is possible given an ideal ADC and neglecting quantization error. The presence of quantization error limits the dynamic range of even an ideal ADC, however, if the dynamic range of the ADC exceeds that of the input signal, its effects may be neglected resulting in an essentially perfect digital representation of the input signal. | ||
+ | |||
+ | [[File:Cmpe244_s14_Spectrumanalyzer11.jpg]] | ||
== Objectives == | == Objectives == | ||
Line 35: | Line 40: | ||
=== Team Members & Responsibilities === | === Team Members & Responsibilities === | ||
* Anand Dumbre | * Anand Dumbre | ||
− | ** ADC interfacing | + | ** ADC interfacing + LED Interfacing + UART communication + Fast Fourier Transforms analysis |
* Chinmay Vaidya | * Chinmay Vaidya | ||
− | ** Fast Fourier | + | ** Fast Fourier Transforms analysis + Hardware + LED Interfacing |
* Kevin Beadle | * Kevin Beadle | ||
− | ** LED interfacing | + | ** LED interfacing + Wikipedia update |
== Schedule == | == Schedule == | ||
− | |||
{| class="wikitable" | {| class="wikitable" | ||
Line 89: | Line 93: | ||
| 05/01/14 | | 05/01/14 | ||
| Finalize project firmware. | | Finalize project firmware. | ||
− | | | + | | ADC working fine. FFT output coming out properly. The communication through UART is working. LED porting still going on. LED strip flashes light but not lighting individual pixels. Working on getting correct color output. We suspect the LED display is defective. In process of trying with different LED display. |
|- | |- | ||
! scope="row"| 9 | ! scope="row"| 9 | ||
| 05/08/14 | | 05/08/14 | ||
| Finalize project demonstration. | | Finalize project demonstration. | ||
− | | | + | | Working on the LED Matrix with a different board. Color output is correct. The row selection is working, however, column selection still not working. |
|- | |- | ||
! scope="row"| 10 | ! scope="row"| 10 | ||
| 05/13/14 | | 05/13/14 | ||
| Finalize project report. | | Finalize project report. | ||
− | | | + | | Project report completion started. Still working on the LED Matrix column selection. Verified the original LED matrix board we worked with is burnt since different boards are working with the Rasberry Pi code given from Adrafruit. |
|} | |} | ||
== Parts List & Cost == | == Parts List & Cost == | ||
− | |||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 130: | Line 133: | ||
| 0.5$ | | 0.5$ | ||
| 25$ | | 25$ | ||
+ | |- | ||
+ | ! scope="row"| Resistors | ||
+ | | 2 | ||
+ | | None | ||
+ | | None | ||
+ | |- | ||
+ | ! scope="row"| Capacitors | ||
+ | | 5 | ||
+ | | None | ||
+ | | None | ||
+ | |- | ||
+ | ! scope="row"| 5V power supply | ||
+ | | 1 | ||
+ | | 10 | ||
+ | | 10 | ||
+ | |- | ||
+ | ! scope="row"| | ||
+ | | | ||
+ | | '''Total''' | ||
+ | | '''235$''' | ||
|} | |} | ||
Line 135: | Line 158: | ||
=== Hardware Design === | === Hardware Design === | ||
− | The flow of our Hardware datapath is very linear. The audio board with Mic was interfaced with the LPC1758 board by connecting the audio | + | The flow of our Hardware datapath is very linear. The audio board with Mic and an Op-Amp with a default gain of 100 was interfaced with the LPC1758 board by connecting the audio, Vcc and Ground ports to the board. The input from mic is pre-amplified and is fed to the ADC on the LPC 1758. The FFT calculations are done on the board and the output of the FFT is given to other LPC1758 board by UART communication. The LPC1758 board is interfaced with the LED matrix. The block diagram of our Spectrum analyzer hardware is shown below. |
+ | |||
+ | [[File:spring14_Spectrum Analyzer.jpg]] | ||
+ | |||
+ | |||
+ | Each block diagram hardware design will be explained as follows: | ||
+ | |||
+ | * '''Audio Input''' : The audio input can be provided by playing a song or even just by talking into the mic | ||
+ | |||
+ | * '''Audio Amp & Filter design''': The audio amp board had an in-built mic which provided the input. Filter design was implemented and the filter was direct connected to the audio board. The filter design was implemented as shown in the image. | ||
+ | |||
+ | [[File:Cmpe244_s14_SpectrumAnalyzer5.jpg]] | ||
+ | |||
+ | *'''LPC1758 Board (ADC + FFT)''': The LPC1758 board has an in-built ADC. The output from audio board is connected to ADC of the board. The audio, envelope, gate, Vcc and ground ports from audio board will be connected to ADC ports. All the FFT calculations are software based and computed directly on the processor. | ||
+ | |||
+ | *'''LPC1758 Board (for LED matrix interfacing)''' : The communication between the two LPC1758 boards is done by UART. The UART communication uses Tx and Rx ports of both the boards. | ||
+ | |||
+ | *'''16 x 32 LED Matrix''' : The LED matrix is connected to LPC1758 board by connecting the A,B,C,R1,B1,R2,B2,G1,G2,Clk,OE and Latency of the Matrix to the port pins of LPC1758 board. The connections is as shown in the image below. | ||
+ | |||
+ | [[File:spring14_Spectrum Analyzer_LEDMatrix.jpg]] [[File:Cmpe244_s14_SpectrumAnalyzer6.jpg]] | ||
=== Hardware Interface === | === Hardware Interface === | ||
− | + | ||
+ | The Hardware Interface mostly consisted of pin connections to LPC1758 board from Audio Amp board, LPC1758 to LPC1758 UART connections and LPC1758 to LED Matrix. The schematic of the connections is given below. | ||
+ | |||
+ | [[File:Cmpe244_s14_SpectrumAnalyzer4.jpg]] | ||
+ | |||
+ | ''' Pin Connections ''' | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! scope="col"|Sl. No | ||
+ | ! scope="col"|Port and Pin Number | ||
+ | ! scope="col"|Pin Type | ||
+ | ! scope="col"|Function | ||
+ | |- | ||
+ | | scope="row"|1||P1.31||ADC||Audio amp input | ||
+ | |- | ||
+ | | scope="row"|2||P2.8, P2.9||UART2||Serial transmission between SJOne boards | ||
+ | |- | ||
+ | | scope="row"|3||P0.0, P0.1, P0.29, P0.30, P1.19, P1.20,P2.0 - P2.5 ||GPIO Output||LED matrix output | ||
+ | |- | ||
+ | |} | ||
=== Software Design === | === Software Design === | ||
− | + | ||
+ | |||
+ | The Software design implementation was done in 4 parts. | ||
+ | |||
+ | * '''ADC configuration:''' | ||
+ | |||
+ | The ADC is configured using timer 1. Timer 1 is used to achieve precise sampling at 8 KHz. Timer 1 has the capability to generate square waves on internal pin Mat1.1. The ADC is configured to sample at every rising edge of Mat1.1. The interrupts for ADC are enabled so that we do not have to poll for completion of conversion. The ISR for ADC stores the digital values into a 1D matrix which is needed as an input for FFT calculations. The ISR uses a semaphore to signal the FFT function to start its process(as the conversion is completed). We use ARM wizard tool for calculating the values for PR. The timer initialization for the ADC is given below for reference. | ||
+ | |||
+ | <syntaxhighlight lang="c"> | ||
+ | void timer_initiate_adc() | ||
+ | { | ||
+ | printf("Timer Initialized"); | ||
+ | //configure Timer for Adc sampling | ||
+ | lpc_pconp(pconp_timer1,true); //Timer enable | ||
+ | lpc_pclk(pclk_timer1,clkdiv_1); //CCLK/1 | ||
+ | LPC_TIM1->TCR =0x2; //Timer in reset mode | ||
+ | LPC_TIM1->CTCR=0x0; //Timer mode | ||
+ | LPC_TIM1->PR=0x00000BB7; //Timer set at 44Khz | ||
+ | LPC_TIM1->MCR =(1<<4); | ||
+ | LPC_TIM1->MR1=1; //Match the count with time count | ||
+ | LPC_TIM1->EMR=(3<<6); //generates rising edge on MAT1.1 | ||
+ | |||
+ | //configure ADC to sample on timer | ||
+ | printf("ADC Initialized"); | ||
+ | lpc_pconp(pconp_adc, true); | ||
+ | lpc_pclk(pclk_adc, clkdiv_4); | ||
+ | LPC_ADC->ADCR = (1 << 21); // Enable ADC | ||
+ | LPC_ADC->ADCR |= (0 << 8); //clock divider set to 1 | ||
+ | LPC_ADC->ADCR |=(1<<5); //select channel 5 | ||
+ | LPC_ADC->ADCR &=~(1<<16); //software controlled conversions | ||
+ | LPC_ADC->ADCR |=(7<<24); //starts ADC on rising edge of MAT1.1 signal | ||
+ | LPC_ADC->ADCR &=~(1<<27); //ADC samples on rising edge of MAT1.1 signal | ||
+ | LPC_ADC->ADINTEN |=(1<<5); //enabling ADC interrputs on completion of conversion on channel five | ||
+ | NVIC_EnableIRQ(ADC_IRQn); //enabling the nested interrupt | ||
+ | LPC_PINCON->PINSEL3 |= (3 << 30); //set the pin to ADC mode | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | * '''FFT calculations:''' | ||
+ | The main method of the FFT program was to wait for the ADC buffer to get full. According to the FFT algorithm, we considered a real and imaginary numbers as the input to the FFT matrix. A function for FFT was created which calculates the FFT matrix depending upon the inputs provided. In the main program, depending upon the size of array we use, it prints out the real and imaginary values of the Fast Fourier Transform. These values are to be sent to other board via Tx pin of UART. The steps in calculating FFT were as follows | ||
+ | ** Create a structure which includes the real and imaginary parts. It also includes declaration of matrix parameters | ||
+ | ** As the matrix is 3 dimensional, consider i,j,k parameters and calculate the FFT for every i,j and k value using nested 'for' loops. | ||
+ | ** Output the real and imaginary values of the FFT calculations. However as we need only the real values for spectrum analyzer,we can neglect the imaginary value while UART communication. | ||
+ | |||
+ | * '''UART communication :''' | ||
+ | The UART communication between the two boards is solely for the purpose of providing the FFT values to LED matrix. There is only one way communications in this arrangement. The FFT values are sent through Tx pin and received by the other baord at Rx pin. We decided to use the UART as it is easy to implement in our case as we just had to send an 8 bit data over the bus.The UART was set to transmit with 8-bit character sizes, which takes a byte and transmit 8 bits serially. UART offers different frame formats including different character sizes, parity bits, and multiple stop bits, but we opted to use a 10-bit frame for simplicity and speed of transmission with 1 start bit, 8 character bits, and 1 stop bit. The initialisation for uart0 is shown below for reference purpose. | ||
+ | <syntaxhighlight lang="c"> | ||
+ | void uart0_init(void) | ||
+ | { | ||
+ | LPC_SC->PCONP |= (1 << 3); // Enable power to UART0 | ||
+ | LPC_SC->PCLKSEL0 &= ~(3 << 6); | ||
+ | LPC_SC->PCLKSEL0 |= (1 << 6); // Uart clock = CPU / 1 | ||
+ | |||
+ | LPC_PINCON->PINSEL0 &= ~(0xF << 4); // Clear values | ||
+ | LPC_PINCON->PINSEL0 |= (0x5 << 4); // Set values for UART0 Rx/Tx | ||
+ | |||
+ | LPC_UART0->LCR = (1 << 7); // Enable DLAB | ||
+ | LPC_UART0->DLM = 0; | ||
+ | /* See the formula picture to get more info. | ||
+ | * Default values of fractional dividers simplifies the equation */ | ||
+ | LPC_UART0->DLL = CPU_CLOCK / (16 * 9600) + 0.5); | ||
+ | LPC_UART0->LCR = 3; // 8-bit data | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | * '''Interfacing the LED Matrix:''' | ||
+ | The main problem in configuration of the LED Matrix was that its library was in Arduino. Also, the data sheet for the matrix was not available. Hence, we had to port it to the LPC1758. The pseudo code which we implemented in C is given as follows | ||
+ | The various ports for A,B,C,OE,Clk,R1,R2,G1,G2,B1 and B2 were set depending upon the port on which they were connected to LPC board. | ||
+ | |||
+ | **We used #define to make each pin correspond to the required port.Initially we have to clear the display, then set the pins for A,B and C depending upon the row or column we need to select. | ||
+ | **For that, the bit masking for Apin, Bpin and Cpin was used. We used a 'for' loop to access all 32 columns of the LED matrix. | ||
+ | **Also, we need to clear the interrupt flag after every operation of the display. | ||
+ | **Then we set the required pins to output. After that, the timer frequency was allocated, the reset mode was configured. | ||
+ | **The following code is an example of how to set rows in top half of the screen. For accessing the bottom half of the screen use the R2, B2, G2 pins to display colors. | ||
+ | |||
+ | <syntaxhighlight lang="c"> | ||
+ | void led_matrix_init() | ||
+ | { | ||
+ | /* Set pins as output */ | ||
+ | LPC_GPIO1->FIODIR |= (1 << BPIN) | (1 << APIN); | ||
+ | LPC_GPIO0->FIODIR |= (1 << CLOCKPIN) | (1 << LATCHPIN) | (1 << OEPIN)| (1 << CPIN); | ||
+ | LPC_GPIO2->FIODIR |= (1 << R1PIN) | (1 << R2PIN) | (1 << G1PIN) | (1 << G2PIN) | (1 << B1PIN) | (1 << B2PIN); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="c"> | ||
+ | |||
+ | { | ||
+ | LPC_GPIO0->FIOPIN |= (1 << OEPIN); // Disable LED output | ||
+ | |||
+ | /* Select row */ | ||
+ | LPC_GPIO1->FIOPIN = ((row & 0x1)==1) ? LPC_GPIO1->FIOPIN |= (1 << APIN) : LPC_GPIO1->FIOPIN &= ~(1 << APIN); | ||
+ | LPC_GPIO1->FIOPIN = ((row & 0x2)==0x2) ? LPC_GPIO1->FIOPIN |= (1 << BPIN) : LPC_GPIO1->FIOPIN &= ~(1 << BPIN); | ||
+ | LPC_GPIO0->FIOPIN = ((row & 0x4)==0x4) ? LPC_GPIO0->FIOPIN |= (1 << CPIN) : LPC_GPIO0->FIOPIN &= ~(1 << CPIN); | ||
+ | |||
+ | /* Output color */ | ||
+ | LPC_GPIO2->FIOPIN |= (1 << R1PIN)| (1<<G1PIN); | ||
+ | LPC_GPIO0->FIOPIN |= ( 1 << CLOCKPIN); | ||
+ | LPC_GPIO0->FIOPIN &= ~(1 << CLOCKPIN); | ||
+ | |||
+ | LPC_GPIO0->FIOPIN |= (1 << LATCHPIN); // Enable latch and set data for led matrix | ||
+ | LPC_GPIO0->FIOPIN &= ~(1 << LATCHPIN); // Disable latch for next interrupt | ||
+ | LPC_GPIO0->FIOPIN &= ~(1 << OEPIN); // Output LED display | ||
+ | |||
+ | /* Increment row value */ | ||
+ | if (row<8) | ||
+ | row++; | ||
+ | else | ||
+ | row=0; | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
=== Implementation === | === Implementation === | ||
− | + | The overall algorithm to output to the LED matrix is: | |
+ | # Disable LED display | ||
+ | # Send row data (A, B, and C pins) | ||
+ | # Send color data (R1, R2, G1, G2, B1, and B2 pins) | ||
+ | # Send clock signal (high to low) | ||
+ | # Re-enable LED display | ||
+ | |||
+ | The overall implementation of how the Spectrum Analyzer includes: | ||
+ | # Get audio input from audio amplifier. | ||
+ | # Do FFT on audio the audio signal. | ||
+ | # Send FFT values to secondary SJOne board through UART. | ||
+ | # Process and output values through LED matrix display. | ||
== Testing & Technical Challenges == | == Testing & Technical Challenges == | ||
− | |||
− | |||
− | |||
− | |||
− | === | + | === Getting Correct Parts === |
The main issue was obtaining correct parts for the audio amplifier board and LED strip. The gain of amplifier needed to correct for required frequency. Also, the parts were not available on Websites. | The main issue was obtaining correct parts for the audio amplifier board and LED strip. The gain of amplifier needed to correct for required frequency. Also, the parts were not available on Websites. | ||
Resolution: checked the forums on the websites to obtain more information about the boards. Placed an order for deliver when available on the Adafruit and Sparkfun. | Resolution: checked the forums on the websites to obtain more information about the boards. Placed an order for deliver when available on the Adafruit and Sparkfun. | ||
− | === | + | === Timer for ADC === |
− | We required the timer1 for ADC. However, the timer1 was configured for the I2C bus. Hence, we changed the I2C bus ports to timer2 and used the timer1 for ADC | + | We required the timer1 for ADC. However, the timer1 was configured for the I2C bus. Hence, we changed the I2C bus ports to timer2 and used the timer1 for ADC. We also had to use a separate timer for the LED display board. |
− | === | + | === LED Matrix Porting === |
Adafruit Led strip had a library for Arduino. We need to port it to LPC in order to get our LED strip working.However, there are timing issues as the clock frequencies are not same for both. Issue is not resolved yet. | Adafruit Led strip had a library for Arduino. We need to port it to LPC in order to get our LED strip working.However, there are timing issues as the clock frequencies are not same for both. Issue is not resolved yet. | ||
+ | |||
+ | === Matrix Column === | ||
+ | The LED matrix did not have any datasheet available from which we could have learned which pins to access for Column selection. We got the row selection working however, the column selection was not working properly. We posted this topic on the AdaFruit forum and got some inputs from the support staff. We got the column working eventually. | ||
+ | |||
+ | === UART Limitations === | ||
+ | The range of FFT calculations values was more than 10K. However, we cannot send more than 8 bit data through UART. So, only the partial data was getting transferred over the line. To resolve this issue, we separated all FFT values into blocks and assigned a number to each block so that all the block numbers can be sent over the line in single transaction. | ||
+ | |||
+ | === Frequency Range === | ||
+ | We had initially decided to use range of frequencies upto 20K Hz which needed sampling of upto 44Khz. But, the frequency range was overwhelming for the CPU. Hence we had to decrease the frequency range depending upon the accepted value.Also we realized that most of the audio frequencies are upto 4 Khz. So we had to design a filter to filter out the noise. | ||
== Conclusion == | == Conclusion == | ||
− | + | The critical part of the project was to get the timings of all blocks right. Also, configuring the ADC and Testing of the FFT code was a challenging process. There was no documentation for LED matrix which made work hard to understand the Arduino code and port it our board. The key points which we learned from the project were: | |
+ | * We had to study working of ADC very properly in order to understand and implement the timer for it. Also, we had to find out if we needed to use the Filter. We learned the filter designing in order to decrease the gain. | ||
+ | * Having learned about how to calculate an FFT in undergraduate years, its actual implementation on the processor was a good learning experience. | ||
+ | * How to use timers to sample with the ADC and to generate signals to the LED matrix display. | ||
+ | * Interfacing between two SJOne boards using UART. | ||
=== Project Video === | === Project Video === | ||
Line 169: | Line 363: | ||
=== Project Source Code === | === Project Source Code === | ||
− | + | * [https://sourceforge.net/projects/sjsu/files/CmpE244_SJSU_S2014/ Sourceforge source code link] | |
== References == | == References == | ||
=== Acknowledgement === | === Acknowledgement === | ||
− | + | We obtained the components from ADAFruit and Sparkfun. We would like to thank Preet for teaching us this course and his guidance in the project as well as the coursework. We would also like to thank Preet for providing us with couple of extra LED boards so that we were able to work on it more efficiently. | |
=== References Used === | === References Used === | ||
List any references used in project. | List any references used in project. | ||
− | == | + | 1. Preetpal Kang, Lecture notes of CMPE 244, Computer Engineering, Charles W. Davidson College of Engineering, San Jose State University, Feb-May 2014. |
− | + | ||
+ | 2. [http://www.socialledge.com/sjsu/index.php?title=SJ_One_Board http://www.socialledge.com/sjsu/index.php?title=SJ_One_Board] | ||
+ | |||
+ | 3. Digital Signal Processing by A.V OppenHeim & R.W Schafer | ||
+ | |||
+ | 4. [http://en.wikipedia.org/wiki/Fast_Fourier_transform http://en.wikipedia.org/wiki/Fast_Fourier_transform] | ||
+ | |||
+ | 5. [https://www.wikipedia.org/ https://www.wikipedia.org/] | ||
+ | |||
+ | 6. [https://learn.adafruit.com/32x16-32x32-rgb-led-matrix/ https://learn.adafruit.com/32x16-32x32-rgb-led-matrix/] |
Latest revision as of 23:40, 6 August 2014
Contents
Spectrum Analyzer for Audio Frequency Signals
Abstract
We plan to build a Spectrum Analyzer for Audio Frequency signals. Our device is able to display frequencies in audio of up to 4 kHz, which covers the most of the of the frequency range of typical music. The main inspiration for our project was applications of music visualizers which are seen in much software like Windows Media Player. Our spectrum analyzer will try to mimic such visualizers using an audio amplifier and a LED display. The display will light up a range of LEDs from low to high according to audio frequency using FFT as the algorithm for analyzing audio input. This gives a fully dynamic LED display for audio frequency.
Introduction
A Spectrum analyzer is used in measuring the magnitude of an input signal versus a frequency for a certain frequency range of an instrument. The primary use of a Spectrum analyzer is to measure power of spectrum of unknown or known signals. An input signal that a spectrum analyzer measure is electrical, however, signals like acoustic pressure or optical waves can also be measured by use of an appropriate transducer.
By analyzing the spectra of electrical signals, dominant frequency, power, distortion, harmonics, bandwidth, and other spectral components of a signal can be observed that are not easily detectable in time domain waveforms. These parameters are useful in the characterization of electronic devices, such as wireless transmitters.
The display of a Spectrum analyzer has frequency on the horizontal axis and the amplitude displayed on the vertical axis. In general observation, a Spectrum analyzer looks like an oscilloscope and, in fact, some lab instruments can function either as an oscilloscope or a spectrum analyzer.
Fast Fourier Transform
A fast Fourier transform (FFT) is an algorithm to compute the discrete Fourier transform (DFT) and its inverse. Fourier analysis converts time (or space) to frequency and vice versa; an FFT rapidly computes such transformations by factorizing the DFT matrix into a product of sparse (mostly zero) factors.[1] As a result, fast Fourier transforms are widely used for many applications in engineering, science, and mathematics. The best-known FFT algorithms depend upon the factorization of N, but there are FFTs with O(N log N) complexity for all N, even for prime N. Many FFT algorithms only depend on the fact that e^{-2*pi/ N}} is an N-th primitive root of unity, and thus can be applied to analogous transforms over any finite field, such as number-theoretic transforms. We modified the Fortran FFT code from Digital Signal Processing by A.V. Oppenheim and R.W. Schafer to C code for 16-point FFT.
Analog to Digital Converters
An ADC is used to convert a continous physical quantity to a digital number that represents the quantity's amplitude. The conversion involves quantization of the input, so it necessarily introduces a small amount of error. Instead of doing a single conversion, it periodically samples the given input data and provides a sequence of digital outputs. Thus, it converts continous time signals to discrete time domain. We define any ADC by its bandwidth and its signal to noise ratio(the accuracy of measurement). The actual bandwidth of an ADC is characterized by its sampling rate and to a lesser extent by how it handles errors. If an ADC operates at a sampling rate greater than twice the bandwidth of the signal, then perfect reconstruction is possible given an ideal ADC and neglecting quantization error. The presence of quantization error limits the dynamic range of even an ideal ADC, however, if the dynamic range of the ADC exceeds that of the input signal, its effects may be neglected resulting in an essentially perfect digital representation of the input signal.
Objectives
The main objective of our project was to display the audio input given to the mic through an LED display. The range of frequency was kept to 4K Hz as it covers most of the frequency range for a typical musical instrument. The LED matrix will be able to display change in the audio signal correspondingly.
The scope of the project was divided into 3 main parts :
- ADC interfacing with the audio input through mic
- Performing FFT calculations on the LPC1758 board and communication of the same to LED matrix.
- Interfacing of the 16 X 32 LED matrix with LPC1758 board
Team Members & Responsibilities
- Anand Dumbre
- ADC interfacing + LED Interfacing + UART communication + Fast Fourier Transforms analysis
- Chinmay Vaidya
- Fast Fourier Transforms analysis + Hardware + LED Interfacing
- Kevin Beadle
- LED interfacing + Wikipedia update
Schedule
Week# | Date | Planned Task | Actual Task |
---|---|---|---|
1 | 03/13/14 | Order & receive parts. | Ordered the parts.late by 1 week as parts were not available |
2 | 03/20/14 | Interface microphone/LED strip to SJ One board. | Obtained the parts. Started work on Microphone and LED. |
3 | 03/27/14 | Design band pass filter to reduce noise. | Done |
4 | 04/03/14 | Analyze audio signals with Matlab using FFT. | The waveforms were not coming out properly. FFT code was working alright |
5 | 04/10/14 | Write code to process audio signal on SJ One board. | FFT code working fine. |
6 | 04/17/14 | Write algorithm to output audio signal to LED strip. | ADC and FFT output coming out properly |
7 | 04/24/14 | Test algorithm using different audio sources. | Tested using various Youtube audio. Still working on porting of LED strip. |
8 | 05/01/14 | Finalize project firmware. | ADC working fine. FFT output coming out properly. The communication through UART is working. LED porting still going on. LED strip flashes light but not lighting individual pixels. Working on getting correct color output. We suspect the LED display is defective. In process of trying with different LED display. |
9 | 05/08/14 | Finalize project demonstration. | Working on the LED Matrix with a different board. Color output is correct. The row selection is working, however, column selection still not working. |
10 | 05/13/14 | Finalize project report. | Project report completion started. Still working on the LED Matrix column selection. Verified the original LED matrix board we worked with is burnt since different boards are working with the Rasberry Pi code given from Adrafruit. |
Parts List & Cost
Component Name | Quantity | Cost per Item | Total Cost |
---|---|---|---|
Audio Amplifier Board | 1 | 25$ | 25$ |
LPC1758 Board | 2 | 70$ | 140$ |
LED Matrix (16 X 32) | 1 | 35$ | 35$ |
Wires | 50 | 0.5$ | 25$ |
Resistors | 2 | None | None |
Capacitors | 5 | None | None |
5V power supply | 1 | 10 | 10 |
Total | 235$ |
Design & Implementation
Hardware Design
The flow of our Hardware datapath is very linear. The audio board with Mic and an Op-Amp with a default gain of 100 was interfaced with the LPC1758 board by connecting the audio, Vcc and Ground ports to the board. The input from mic is pre-amplified and is fed to the ADC on the LPC 1758. The FFT calculations are done on the board and the output of the FFT is given to other LPC1758 board by UART communication. The LPC1758 board is interfaced with the LED matrix. The block diagram of our Spectrum analyzer hardware is shown below.
Each block diagram hardware design will be explained as follows:
- Audio Input : The audio input can be provided by playing a song or even just by talking into the mic
- Audio Amp & Filter design: The audio amp board had an in-built mic which provided the input. Filter design was implemented and the filter was direct connected to the audio board. The filter design was implemented as shown in the image.
- LPC1758 Board (ADC + FFT): The LPC1758 board has an in-built ADC. The output from audio board is connected to ADC of the board. The audio, envelope, gate, Vcc and ground ports from audio board will be connected to ADC ports. All the FFT calculations are software based and computed directly on the processor.
- LPC1758 Board (for LED matrix interfacing) : The communication between the two LPC1758 boards is done by UART. The UART communication uses Tx and Rx ports of both the boards.
- 16 x 32 LED Matrix : The LED matrix is connected to LPC1758 board by connecting the A,B,C,R1,B1,R2,B2,G1,G2,Clk,OE and Latency of the Matrix to the port pins of LPC1758 board. The connections is as shown in the image below.
Hardware Interface
The Hardware Interface mostly consisted of pin connections to LPC1758 board from Audio Amp board, LPC1758 to LPC1758 UART connections and LPC1758 to LED Matrix. The schematic of the connections is given below.
Pin Connections
Sl. No | Port and Pin Number | Pin Type | Function |
---|---|---|---|
1 | P1.31 | ADC | Audio amp input |
2 | P2.8, P2.9 | UART2 | Serial transmission between SJOne boards |
3 | P0.0, P0.1, P0.29, P0.30, P1.19, P1.20,P2.0 - P2.5 | GPIO Output | LED matrix output |
Software Design
The Software design implementation was done in 4 parts.
- ADC configuration:
The ADC is configured using timer 1. Timer 1 is used to achieve precise sampling at 8 KHz. Timer 1 has the capability to generate square waves on internal pin Mat1.1. The ADC is configured to sample at every rising edge of Mat1.1. The interrupts for ADC are enabled so that we do not have to poll for completion of conversion. The ISR for ADC stores the digital values into a 1D matrix which is needed as an input for FFT calculations. The ISR uses a semaphore to signal the FFT function to start its process(as the conversion is completed). We use ARM wizard tool for calculating the values for PR. The timer initialization for the ADC is given below for reference.
void timer_initiate_adc()
{
printf("Timer Initialized");
//configure Timer for Adc sampling
lpc_pconp(pconp_timer1,true); //Timer enable
lpc_pclk(pclk_timer1,clkdiv_1); //CCLK/1
LPC_TIM1->TCR =0x2; //Timer in reset mode
LPC_TIM1->CTCR=0x0; //Timer mode
LPC_TIM1->PR=0x00000BB7; //Timer set at 44Khz
LPC_TIM1->MCR =(1<<4);
LPC_TIM1->MR1=1; //Match the count with time count
LPC_TIM1->EMR=(3<<6); //generates rising edge on MAT1.1
//configure ADC to sample on timer
printf("ADC Initialized");
lpc_pconp(pconp_adc, true);
lpc_pclk(pclk_adc, clkdiv_4);
LPC_ADC->ADCR = (1 << 21); // Enable ADC
LPC_ADC->ADCR |= (0 << 8); //clock divider set to 1
LPC_ADC->ADCR |=(1<<5); //select channel 5
LPC_ADC->ADCR &=~(1<<16); //software controlled conversions
LPC_ADC->ADCR |=(7<<24); //starts ADC on rising edge of MAT1.1 signal
LPC_ADC->ADCR &=~(1<<27); //ADC samples on rising edge of MAT1.1 signal
LPC_ADC->ADINTEN |=(1<<5); //enabling ADC interrputs on completion of conversion on channel five
NVIC_EnableIRQ(ADC_IRQn); //enabling the nested interrupt
LPC_PINCON->PINSEL3 |= (3 << 30); //set the pin to ADC mode
}
- FFT calculations:
The main method of the FFT program was to wait for the ADC buffer to get full. According to the FFT algorithm, we considered a real and imaginary numbers as the input to the FFT matrix. A function for FFT was created which calculates the FFT matrix depending upon the inputs provided. In the main program, depending upon the size of array we use, it prints out the real and imaginary values of the Fast Fourier Transform. These values are to be sent to other board via Tx pin of UART. The steps in calculating FFT were as follows
- Create a structure which includes the real and imaginary parts. It also includes declaration of matrix parameters
- As the matrix is 3 dimensional, consider i,j,k parameters and calculate the FFT for every i,j and k value using nested 'for' loops.
- Output the real and imaginary values of the FFT calculations. However as we need only the real values for spectrum analyzer,we can neglect the imaginary value while UART communication.
- UART communication :
The UART communication between the two boards is solely for the purpose of providing the FFT values to LED matrix. There is only one way communications in this arrangement. The FFT values are sent through Tx pin and received by the other baord at Rx pin. We decided to use the UART as it is easy to implement in our case as we just had to send an 8 bit data over the bus.The UART was set to transmit with 8-bit character sizes, which takes a byte and transmit 8 bits serially. UART offers different frame formats including different character sizes, parity bits, and multiple stop bits, but we opted to use a 10-bit frame for simplicity and speed of transmission with 1 start bit, 8 character bits, and 1 stop bit. The initialisation for uart0 is shown below for reference purpose.
void uart0_init(void)
{
LPC_SC->PCONP |= (1 << 3); // Enable power to UART0
LPC_SC->PCLKSEL0 &= ~(3 << 6);
LPC_SC->PCLKSEL0 |= (1 << 6); // Uart clock = CPU / 1
LPC_PINCON->PINSEL0 &= ~(0xF << 4); // Clear values
LPC_PINCON->PINSEL0 |= (0x5 << 4); // Set values for UART0 Rx/Tx
LPC_UART0->LCR = (1 << 7); // Enable DLAB
LPC_UART0->DLM = 0;
/* See the formula picture to get more info.
* Default values of fractional dividers simplifies the equation */
LPC_UART0->DLL = CPU_CLOCK / (16 * 9600) + 0.5);
LPC_UART0->LCR = 3; // 8-bit data
}
- Interfacing the LED Matrix:
The main problem in configuration of the LED Matrix was that its library was in Arduino. Also, the data sheet for the matrix was not available. Hence, we had to port it to the LPC1758. The pseudo code which we implemented in C is given as follows The various ports for A,B,C,OE,Clk,R1,R2,G1,G2,B1 and B2 were set depending upon the port on which they were connected to LPC board.
- We used #define to make each pin correspond to the required port.Initially we have to clear the display, then set the pins for A,B and C depending upon the row or column we need to select.
- For that, the bit masking for Apin, Bpin and Cpin was used. We used a 'for' loop to access all 32 columns of the LED matrix.
- Also, we need to clear the interrupt flag after every operation of the display.
- Then we set the required pins to output. After that, the timer frequency was allocated, the reset mode was configured.
- The following code is an example of how to set rows in top half of the screen. For accessing the bottom half of the screen use the R2, B2, G2 pins to display colors.
void led_matrix_init()
{
/* Set pins as output */
LPC_GPIO1->FIODIR |= (1 << BPIN) | (1 << APIN);
LPC_GPIO0->FIODIR |= (1 << CLOCKPIN) | (1 << LATCHPIN) | (1 << OEPIN)| (1 << CPIN);
LPC_GPIO2->FIODIR |= (1 << R1PIN) | (1 << R2PIN) | (1 << G1PIN) | (1 << G2PIN) | (1 << B1PIN) | (1 << B2PIN);
}
{
LPC_GPIO0->FIOPIN |= (1 << OEPIN); // Disable LED output
/* Select row */
LPC_GPIO1->FIOPIN = ((row & 0x1)==1) ? LPC_GPIO1->FIOPIN |= (1 << APIN) : LPC_GPIO1->FIOPIN &= ~(1 << APIN);
LPC_GPIO1->FIOPIN = ((row & 0x2)==0x2) ? LPC_GPIO1->FIOPIN |= (1 << BPIN) : LPC_GPIO1->FIOPIN &= ~(1 << BPIN);
LPC_GPIO0->FIOPIN = ((row & 0x4)==0x4) ? LPC_GPIO0->FIOPIN |= (1 << CPIN) : LPC_GPIO0->FIOPIN &= ~(1 << CPIN);
/* Output color */
LPC_GPIO2->FIOPIN |= (1 << R1PIN)| (1<<G1PIN);
LPC_GPIO0->FIOPIN |= ( 1 << CLOCKPIN);
LPC_GPIO0->FIOPIN &= ~(1 << CLOCKPIN);
LPC_GPIO0->FIOPIN |= (1 << LATCHPIN); // Enable latch and set data for led matrix
LPC_GPIO0->FIOPIN &= ~(1 << LATCHPIN); // Disable latch for next interrupt
LPC_GPIO0->FIOPIN &= ~(1 << OEPIN); // Output LED display
/* Increment row value */
if (row<8)
row++;
else
row=0;
}
Implementation
The overall algorithm to output to the LED matrix is:
- Disable LED display
- Send row data (A, B, and C pins)
- Send color data (R1, R2, G1, G2, B1, and B2 pins)
- Send clock signal (high to low)
- Re-enable LED display
The overall implementation of how the Spectrum Analyzer includes:
- Get audio input from audio amplifier.
- Do FFT on audio the audio signal.
- Send FFT values to secondary SJOne board through UART.
- Process and output values through LED matrix display.
Testing & Technical Challenges
Getting Correct Parts
The main issue was obtaining correct parts for the audio amplifier board and LED strip. The gain of amplifier needed to correct for required frequency. Also, the parts were not available on Websites. Resolution: checked the forums on the websites to obtain more information about the boards. Placed an order for deliver when available on the Adafruit and Sparkfun.
Timer for ADC
We required the timer1 for ADC. However, the timer1 was configured for the I2C bus. Hence, we changed the I2C bus ports to timer2 and used the timer1 for ADC. We also had to use a separate timer for the LED display board.
LED Matrix Porting
Adafruit Led strip had a library for Arduino. We need to port it to LPC in order to get our LED strip working.However, there are timing issues as the clock frequencies are not same for both. Issue is not resolved yet.
Matrix Column
The LED matrix did not have any datasheet available from which we could have learned which pins to access for Column selection. We got the row selection working however, the column selection was not working properly. We posted this topic on the AdaFruit forum and got some inputs from the support staff. We got the column working eventually.
UART Limitations
The range of FFT calculations values was more than 10K. However, we cannot send more than 8 bit data through UART. So, only the partial data was getting transferred over the line. To resolve this issue, we separated all FFT values into blocks and assigned a number to each block so that all the block numbers can be sent over the line in single transaction.
Frequency Range
We had initially decided to use range of frequencies upto 20K Hz which needed sampling of upto 44Khz. But, the frequency range was overwhelming for the CPU. Hence we had to decrease the frequency range depending upon the accepted value.Also we realized that most of the audio frequencies are upto 4 Khz. So we had to design a filter to filter out the noise.
Conclusion
The critical part of the project was to get the timings of all blocks right. Also, configuring the ADC and Testing of the FFT code was a challenging process. There was no documentation for LED matrix which made work hard to understand the Arduino code and port it our board. The key points which we learned from the project were:
- We had to study working of ADC very properly in order to understand and implement the timer for it. Also, we had to find out if we needed to use the Filter. We learned the filter designing in order to decrease the gain.
- Having learned about how to calculate an FFT in undergraduate years, its actual implementation on the processor was a good learning experience.
- How to use timers to sample with the ADC and to generate signals to the LED matrix display.
- Interfacing between two SJOne boards using UART.
Project Video
Upload a video of your project and post the link here.
Project Source Code
References
Acknowledgement
We obtained the components from ADAFruit and Sparkfun. We would like to thank Preet for teaching us this course and his guidance in the project as well as the coursework. We would also like to thank Preet for providing us with couple of extra LED boards so that we were able to work on it more efficiently.
References Used
List any references used in project.
1. Preetpal Kang, Lecture notes of CMPE 244, Computer Engineering, Charles W. Davidson College of Engineering, San Jose State University, Feb-May 2014.
2. http://www.socialledge.com/sjsu/index.php?title=SJ_One_Board
3. Digital Signal Processing by A.V OppenHeim & R.W Schafer