Learning VHDL: Processing some audio Part 2
Post date: Sep 13, 2015 11:45:14 PM
Video demonstration.
This project extends the previous project with an implementation of a low-pass FIR Filter to remove some of the noise inherent to the audio system. The Filter is built assuming the audio system will be used for processing voice. For this post, I skip over the explanation on the hardware and sources, and instead focus on the filter’s design and implementation.
SIMULATION. The design of the filter is entirely done in MATLAB, taking advantage of MATLAB’s DSP Toolbox. However, because the Xilinx FIP Compiler can only accept whole numbers for the coefficients of the Filter, the coefficients generated from MATLAB are modified to produce a similar Filter more suitable for the FPGA.
The Filter is designed to pass only low frequencies and have an order of 30. Considering the bandwidth of speech is around 8 kHz, the common cutoff frequency (Fc) of 9.6 kHz is chosen. Recall, 48 kilo-samples per second was chosen as the sample rate (Fs) in the previous post. Below is a figure showing the impulse response of both the ideal low-pass Filter and actual low-pass Filter.
Prior to modifying the low-pass Filter for the FPGA, I ran a test signal composed of multiple sinusoids at different frequencies. Below is a figure that shows the spectrum of the test signal.
The response of the Filter is the following.
The idea is to remove the noise in the higher frequencies, of course, assuming the noise is close to white noise. I admit I’m really making a guess here, since I haven’t analyzed any of the data acquired from the PmodMIC peripheral. In a later project, I will implement a way by which data can be captured and then analyzed over a PC.
The snippet below describes the algorithm that modifies the original Filter into the FPGA Filter.
The idea is simply to keep increase the coefficients of the original Filter by powers of two until enough of the coefficients are above 0. The response of the FPGA Filter is then divided by the power of two to reduce the magnitude of the response.
Here are the final results of the simulation.
***FPGA Responses are divided by a power of two (i.e. the variable "mul" from the code snippet) to reduce magnitude.
For my application, the FPGA-related are close enough to what I want! Onto the FPGA implementation!
The resultant coefficients of the FPGA Filter. The "mul" value is important in correcting the magnitude of the filter's output.
IMPLEMENTATION. Instead of creating the FPGA Filter from scratch, I simply took advantage of the Xilinx FIR Compiler. Since the IP does most of the work, I only had to write control modules that take the audio samples and pass them to the appropriate modules. I added one of the Atlys board’s slide switches for either enabling or disabling the FPGA Filter.
State machine for the controller that accepts an audio sample from the microphone as input and either outputs it or sends it to the FPGA Filter.
In addition to the signal processing, I added a “ResetModule” for resetting my modules. Before, the instantiations for modules such as the PmodMIC and PmodAMP3 had logic zeros assigned to their resets. In order to reset the entire system, the FPGA needed to be reconfigured. The reason for not including any way to reset the design was simply because there are other clocking frequencies, separate from the master clock signal. For instance, the PmodMIC requires a serial clock, and the PmodAMP3 requires several clocks in order to drive the Pmod. Resetting the DownSampler instantiations that create the new clock signals is easy enough. The challenging part was to also reset the process blocks driven by those clock signals, while not relying on asynchronous resets. I pretty much always avoid asynchronous resets. From past experiences, I had issues whenever I tried to implement asynchronous resets, so now I avoid them like the plague and instead create modules specific to resetting the system. Sure, I waste a few clock cycles here and there. But that’s only a small price to pay for a system that doesn’t fall into a random, unpredictable state.
Below is a screenshot of the RTL Schematic, which for me is one of the most rewarding aspects of completing a project on a FPGA!
RTL schematic of system.
OBSERVATIONS / CONCLUDING THOUGHTS. The system does precisely what I programmed it to do! Unfortunately, my assumptions about the noise are either wrong or not entirely accurate, seeing as the output audio is still very noisy. As I briefly mentioned earlier, there will have to be another project in which I implement a way to capture and transmit data from the FPGA to another computer for processing. However, I want to take a break from the Atlys board for a bit, and instead post projects on the Zynq chip. It recently occurred to me I haven’t posted any projects on building AXI-based IP with the Vivado Design Suite. Plus, I want to start doing more with Linux on Zynq.
The sources for the PmodMIC and PmodAMP3 now have their own repository.
The "FilterCore" module is only a wrapper; you will need the xco for the Xilinx FIR Compiler.