EE265 Lab 2: Working with Hardware
Winter 2008-2009
Instructor: Teresa Meng
I. Purpose:
This lab
introduces real-time programming on the C5509 EVM board. Hardware-related
issues, real-time programming concepts, constraints, and limitations will be
discussed. We will take a closer look at the EVM board by generating a waveform
and observing the output. The waveform that is generated will also be fed back
to the input of the EVM board to be digitized and analyzed. This effectively
measures the distortion introduced by the Analog Interface Circuitry (AIC) on
the EVM board. This lab will attempt to relate these experiments to what you learned
from the lecture on analog interface and signal reconstruction. Finally, this
lab will introduce some experiments on sampling theory and quantization to give
you an idea of how they affect the signals.
II. Introduction:
A. Real-Time Processing
The main
purpose of this lab is to introduce real-time programming on the TI C5509
evaluation module (EVM) board. The method we introduce here will be used in the
rest of this lab course. In order to do real-time programming, we must be able
to acquire real-time inputs and generate real-time outputs. In the lab
exercises we will do, we want to use analog signals (such as an audio source)
as our input and we would like to generate analog signals (audio signal) as our
output. The C5509 itself does not have any analog inputs or outputs, so it can
only deal with digital input and outputs. This means that any inputs must be
converted to digital form before being passed to the C5509. Also, any output
from the C5509 can only be digital, so some external hardware must be needed to
convert the digital output to analog form. This means that the analog
interfacing is actually handled by hardware on the EVM board.
- Hardware for Real-Time
Processing:
- EVM Board:
The
EVM board contains many devices other than the C5509, which allows for
much more functionality than the C5509 alone. In fact, the EVM board is
very expensive and is not often sold as a consumer product. It is
intended to be used by system engineers to test and evaluate DSP
algorithms before integrating the DSP processor with the peripheral
hardware. The EVM board gives you access to the hardware and tells you
exactly what the processor can do (more than what the simulator can show
you, especially with real-time interrupts). This facilitates
hardware-level debugging and confirms interoperability between the DSP
processor and peripheral components. Furthermore, the EVM board works
with physical (analog) inputs and outputs that are acquired, processed,
and generated in real-time. This allows the designer to identify the limitations
of real-time signal processing through implementation.
- Analog Interface Circuitry
(AIC):
The
EVM board's Analog Interface Circuitry (AIC) converts the physical
signals to digital signals and vice versa. The AIC can sustain a sampling
rate of up to 96 KHz. TI's C5509 DSP processor runs at a clock rate of
200 MHz. As a result, real-time development using the C5509 EVM is most
suitable for data communications and audio signal processing as opposed
to image or video processing.
- Low-level details of Signal
Acquisition and Generation:
- Interconnected Components:
The
concept of real-time coding is quite simple, but in practice it involves
coordinating several different components (not just the C5509) and you
have to consider how these different components communicate data to each
other. On the EVM board, the C5509 DSP chip is the primary computational
component. Its job is to process digitized data. Real-time signal
processing applications typically make use of peripheral ADC and
digital-to-analog (DAC) converters optimized for the particular
application. The EVM provides these and other input-output (I/O)
peripherals.
- Communicating with
Peripherals:
- Serial Ports:
The
C5509a has a variety of I/O capabilities, including general purpose
(GPIO), parallel, and serial ports. Serial ports are commonly used to
handle asynchronous chip-to-chip data communication. Serial ports
communicate data at the bit level. The Multichannel Buffered Serial
Ports (McBSP) of the C55x DSPs actually comprise six pins: clock, frame-sync,
and data for both transmit and receive paths. In addition to
functioning as traditional buffered serial ports (a complete frame of
data is buffered in the serial port before the DSP has to deal with it),
the C55x McBSPs also have a direct memory access (DMA) interface.
- Interrupts:
It is possible to program the DSP to interface with the serial port
using a polling interface, where the DSP periodically asks the serial
port, Have you received data (input) or are you ready to transfer more
(output)?, and then either transfers available data or waits before
asking again. This technique has two flaws - first, if the DSP waits too
long before polling the serial port, data can be lost. Second, if the
DSP polls too frequently, it is wasting valuable computational cycles
unnecessarily. Thus, we typically use interrupts to communicate with
peripherals. For example, an interrupt may be used to notify the C5509
that a frame of data has been received by the serial port. (The interrupt process is described in detail in Lab 1. Please
refer to the Lab 1 web page for additional information.)
- Direct Memory
Access (DMA):
Common DSP processing requires a block of data to be transferred from
some external source (e.g., an external memory). This can be implemented
using a block repeat of the DSP code required to transfer each word of
data. However, an attractive alternative is the DMA interface. Using
DMA, rather than executing each move instruction, the CPU needs only
specify source, destination, and the amount of data to be transferred.
Then, the DMA controller takes secondary control of the memory bus,
using it to transfer data without the active control of the CPU. In
addition to external memories, as mentioned above, the McBSP ports allow
DMA control for block data transfer through the serial ports.
- Process from
Analog to Digital:
Thus,
in our implementation, the entire process of going from an analog signal
to DSP processing in software goes as follows:
- First, analog data is sampled
by the AIC unit on the EVM board. In most cases, each data sample is
digitized as two (stereo) 16-bit words.
- Once a data sample is
acquired, the AIC transmits the data to the C55x DSP chip. The data are
serialized and transmitted one bit at a time on the receive serial line
of one of the C55x's serial ports. The C55x DSP chip's serial port unit
detects that there is data on the serial line and proceeds to buffer
the bits one bit at a time. When a full word (8,16, or 32 bits) is
received, the word is copied into another register (so that the
original register can be reused to buffer new incoming bits).
- If DMA access has been
enabled, the serial port copies the received data to the receive memory
buffer specified by the DMA pointer, and increments the pointer.
- When the specified block
of output memory has been filled, the DMA controller uses a hardware
interrupt to signal the CPU that a block of input samples has been
received. (Not using DMA is equivalent to a block size of one - in this
case, the McBSP triggers the interrupt rather than the DMA controller.)
Note that this interrupt stops data transfer.
- The hardware interrupt
breaks the processing that is currently taking place. This is done by
first pushing the PC (program counter) onto the stack, setting the INTM
bit (the global interrupt mask used to disable servicing of additional
hardware interrupts from interrupting), and then jumping to a
predefined hardware interrupt vector corresponding to the DMA
controller. The hardware interrupt vector addresses are predefined so
as to allow immediate handling of the hardware interrupts. Each
interrupt's interrupt vector is only 4 words long. This is enough for
performing simple calculations that requires less than 4 instruction
words. What is more commonly done is to implement a branch in the
interrupt vector to branch to a larger routine for servicing the
interrupt. This larger routine is commonly referred to as the interrupt
service routine (ISR).
- The new data sample is
handled by the ISR for the DMA controller, which reads the data stored
in the receive memory buffer and then processes it. Normally, the ISR
simply needs to reset the DMA controller to point to a new receive
buffer and re-enable data transfer. The ISR also typically signals the
interrupted code that new data is available to be processed.
- After the ISR completes
(which could be a simple store into memory), it returns control to the
processor, resets the INTM bit (enables servicing of hardware
interrupts), and the interrupted process is then resumed.
- Process from
Digital to Analog:
A
similar process may occur in going from a digital output to an analog
signal. In general, the DSP algorithm produces an output buffer in
digital form which is transferred to the AIC over a serial port using
DMA. The output word could be sent directly to the AIC for
digital-to-analog conversion as soon as it is ready, but this is not
usually done. Rather, most real-time systems usually operate with DAC at
a fixed sampling rate, so they should be output at this fixed rate (not
as soon as they are ready). The fixed sampling rate is enabled by the
initial setup of the AIC, which requests samples from the transmit
serial port at the appropriate intervals. The transmit McBSP uses DMA to
read data from a block of memory in contrast the receive (ADC) McBSP
which uses DMA to write data.
- Possible
pitfalls:
The concept of interrupts is fairly straight-forward, but implementation
of the process can be difficult to implement. One catch is that
real-time data require real-time handling. If the above hardware
interrupt was unable to be serviced, then the data stored in the copy
register would have been completely overwritten by next data sample.
Another potential problem is that real-time interrupts are hard to
simulate and it is hard to see what actually goes on in the chip.
Consider the case where a hardware interrupt occurs while you are still
servicing one (which does not have to be for the same device). How would
you handle this? Since interrupts are automatically disabled while
servicing an interrupt, you would automatically lose data. It is
possible to enable servicing interrupts in an ISR but is not
recommended. (You will encounter many more interrupt related issues
throughout this course. A good imagination and experience is key to
writing a working code.)
- Dealing with Signal
Acquisition/Generation at a Higher Level:
- DSP/BIOS
Library:
To
help make the job of developing DSP applications easier, TI has provided
the DSP/BIOS, which is a library of functions that perform tasks related
to real-time coding. This library helps the developer perform many
low-level functions so that you don't have to worry about all the
details. The capabilities of the DSP/BIOS include memory partitioning,
configuring the processor upon startup, handling interrupts, and
handling serial communication between the processor and peripherals
(such as the AIC). By helping perform some of the programming tasks, the
DSP/BIOS lets the programmer operate at a slightly higher level, which
can make things much easier to deal with.
- Software
Interrupts:
One
of the capabilities provided by the DSP/BIOS is a structure of software
interrupts. Software interrupts are like hardware interrupts in that
when one is triggered, execution of lower level processes stops until
the software interrupt returns. However, they are triggered in software
rather than being triggered by a peripheral signal such as the DMA
controller or a timer. The benefit of software interrupts lies in code
organization. Higher priority or real-time processes can occur as
necessary and independently of lower priority process such as user
interface. We will use a software interrupt to handle full blocks
generated by DMA transfer from ADC and to fill blocks for DMA transfer
to DAC.
- Synchronization
Details (Mailboxes):
While ADC and DAC are initialized to operate at the same sampling rates,
the reading and writing processes may take different amounts of time to
fill the input buffer and empty the output buffer. However, you will
process input and output buffers synchronously. The DSP/BIOS solves this
problem of synchronizing multiple events by using something called a
mailbox. The mailbox keeps track of multiple events by using its bits as
flags. The mailbox process works as follows:
- The mailbox is initialized
to some non-zero value, where each 1 bit corresponds to an event that
needs to occur. These bits can be viewed as flags.
- Each event is associated
with a particular flag. Whenever an event occurs, its associated flag
is cleared to 0 in the mailbox.
- When all the necessary
events occur, the mailbox value finally becomes 0. When this occurs, a
software interrupt is generated to notify the application that all
conditions are now met.
- After the software
interrupt is issued, the mailbox is reset to its initial value and the
entire process is repeated.
This
process ensures that the application is not notified until all required
conditions are met, so the input and output pipes are effectively synchronized.
B. Analog Interface
The C5509 EVM board
uses the AIC23B. Detailed information on the AIC is given in TLV320 AIC23B Data Sheet. You will
not need most of the information given in the data sheet as the data sheet is
intended for the board designers.
III. Readings:
- Read the entire lab and pay
special attention to places where you need to write your own code. Have
some of your code ready before you come in to do the lab. You may need to
spend time debugging!
- An Audio Example
Section 2.2, "Pipe or PIP Module"
Section 3.1, "About the Example"
Section 3.3.2 "Audio Sampling Rate"
IV. Lab Exercises:
This lab will
take you step by step through setting up a real-time DSP code capable of
processing audio-band signals. Once the framework for handling real-time data
is setup, you will then implement a waveform generator to generate a sine wave
to the output of the DSP. You will also write a waveform recorder to record
signals and see the effect of the sampling/quantization process on their
spectrum. Finally, you will play with different sampling rates and quantization
schemes to see for yourself what kind of effects they introduce.
A. Setup
Although the
DSP/BIOS can assist you in configuring the processor, the interrupts, and the
serial ports, the DSP/BIOS still requires a fair amount of setup work in order
to get it working correctly. This section goes through the setup step by step.
We could have provided you an entire project template with all of this done for
you, but it is important for you to understand what goes on behind the scene
since you will be repeating the same procedure in later labs. The following
sections describe how to set up the DSP/BIOS to read data to/from the analog
interface chip, and how to configure the various program elements that are used
for the rest of the lab.
Setting up
the Project
Follow the procedure given in lab 1 to start CCS.
Create
a new project in the lab2/audio directory
and call it audio.
The assembly
template is provided in audio_tmpl.zip.
First, download and decompress these
files to your
lab2/audio directory.
Do not put the files in an "audio_tmpl" subfolder.
Add the
following source files to the project. Select Project->Add
Files to Project... to add source files. If you don't see the source
files listed, change the field Files of type: to
the appropriate type. For example, for .s55 (linear
assembly) codes, set the type as Asm Source Files (*.a*,*.s*).
- audio.c
- adc_setup.c
- aic23.c
- audio.cdb
- userlinker.cmd
Notice that the
automatically generated audiocfg* files are added to your
source code when you add audio.cdb.
Select Project->Scan All Dependencies. What this does is it
updates the include folder to reflect any header files that you have included
in your source codes. If you expand the include folder by clicking on the plus next to the Include folder, you will
see a very long list of files. Most of this is from DSP/BIOS. Remark:
From here on for the sake of conciseness, the term "expand" will be
used to denote the action of clicking on the "plus" symbol next to the item to be
expanded.
Completing
the DSP/BIOS Configuration
We need to
finish configuring the DSP/BIOS. Double click on the
audio.cdb file (located
under the DSP/BIOS Config folder).
- Under Scheduling,
expand the HWI - Hardware Interrupt Service Routine
Manager. This will list the interrupt vector table.
- Change the properties of HWI_INT14, (by right clicking). If you look up the
interrupt table C5509, this interrupt corresponds to the DMA #0 receive
interrupt.
- Enter _dmaHwiRcv
for the function: field.
Explanation: What you are doing here is
associating the hardware interrupt for the serial port with the function dmaHwiRcv (which is defined in the file adc_setup.c).
When the DMA buffer is full, it will cause the hardware interrupt to be
generated, which will execute the interrupt vector that is associated with
it. When you specify a function for this interrupt, you are essentially
redirecting the interrupt vector to the function dmaHwiRcv
to service the interrupt.
- Repeat for HWI_INT15,
associating it with the function _dmaHwiXmt.
- Be sure that Use Dispatcher
is selected in HWI dispatcher tab.
- Under Scheduling,
- Insert a software interrupt
in the SWI - Software Interrupt Manager
module (right click and select Insert SWI).
- Rename SWI0
to processBufferSwi.
- Right
click on the processBufferSwi module and change the
following settings:
- function: to _processBuffer
- mailbox: to 3
- arg0: to 0 (the default)
- arg1: to 0 (the default)
- Explanation: The function _processBufferSwi is a software interrupt handler. The
concept of software interrupt is similar to hardware interrupts except
that the SWI is actually generated by the software. What you have defined
above is the means of generating the software interrupt. The _processBufferSwi handler is associated with a mailbox
value that is initialized (to 3 in this particular case) at the beginning
of the program and also after each time this software interrupt has been
serviced. When the mailbox value is set to 0, the software interrupt to _processBufferSwi is said to be posted. This means that
the next time the _processBufferSwi handler runs and
sees that its mailbox is 0, it will generate its software interrupt
service routine (which is defined later to be _processBuffer,
which is a function we define in C code that will be called each time this
software interrupt occurs). The arguments you defined for the pipes
specify how the mailbox value gets processed. The mailbox is first
initialized to 3, or 11b. When the DMA receive buffer has a new frame that
is ready for reading, this mailbox value is updated by the function _SWI_andn. _SWI_andn is a function
that masks the mailbox with not(2), i.e. not(..0010b)=..1101b. As a result,
the mailbox will be set from 3 to 1. Similarly, when the DMA transmit
buffer empties a frame, freeing one up for writing, the mailbox value is
masked by not(1), which will effectively set the mailbox value to 0 (if it
has been set by the receive DMA to 1). In essence, regardless of which DMA
interrupt gets executed first, the mailbox value is set to 0 when both
buffers have been executed. This guarantees that the incoming buffer is
full and the outgoing buffer is empty, which is the appropriate condition
for notifying the main application (the _processBuffer
function that will be defined later).
- That is it for the DSP/BIOS
setup. Save and close the configuration window.
- To set compiler options, go
to Project->Build Options menu
- Add c:\CCStudio_v3.1\boards\dsk5509a_v1\include to
Preprocessor-> Include Search Path
- Replace
_DEBUG with _DEBUG;CHIP_5509A in Preprocessor->Pre-Defined Symbol
- Change Memory Model to Large in Advanced
- Add c:\CCStudio_v3.1\boards\dsk5509a_v1\lib to Library Search
Path
- Add dsk5509bsl.lib; csl5509ax.lib to Include Libraries
- Completing the Setup for this
Project
- You should examine the source
codes at this point. We will start with audio.c and
do some last modifications to get the code to work. Double
click on audio.c in the
navigation panel. Enable
the loopback operation by changing the #if (0) to #if (1) in processBuffer function .
- At this point, all source
codes have been properly setup and you are ready to build the executable. Click on the rebuild all icon or select Project->Rebuild All. You
should get 0 errors after compilation.
B. Digital Audio Loop-back
This exercise will be the first to use IO in this lab, so
we will merely verify their use. An audio source is generated on the host
computer and this is connected to the input of the EVM board. The loop-back is
done digitally by copying the data from the receive serial port to the transmit
serial port. You can check the functionality of this loop-back by listening to
the output of the EVM board. A better way to check the functionality is to
verify numerically that the input samples are copied to the output (the source
(src) buffer frame gets copied to the destination
(dst) buffer frame).
- In audio.c,
observe that the function main() is used only for initialization. After
main() completes, the DSP goes into an idle loop, which waits for things
to happen (such as hardware and software interrupts).
- Examine the
processBuffer() function. This function is called by
the software interrupt processBufferSwi whenever
the receive data buffer is full and the transmit data buffer is empty.
Examine the for-loop. Notice that src
and dst point to the receive and transmit
buffers, respectively filled and emptied by DMA.
- Connect an audio
source from the PC to the EVM input and connect headphones to the output
(as done in Lab 1). Now start the music.
- Load the compiled
executable, audio.out (in
the Debug folder).
- Run the program.
This can be done by pressing <F5>, selecting Run from the menus, or
by clicking the Run icon.
- After you have verified that
the audio loop-back code works, stop the program. This
can be done by pressing <Shift>-<F5>, selecting Halt from the
menus, or by clicking on the Halt icon.
- Browse through the source
codes to get a good understanding of how the different components
interact.
C. Sine Wave
Generator
In this portion of the lab, you will write a sine wave
generator to output a pure digital sine wave from the EVM board. This section
is intended to exercise your assembly programming skills with a simple exercise
of copying data from the data memory into the data transmit buffer, pointed to
by dst. A template for the assembly routine is
provided for you but you must complete the code and generate a sine wave at the
output of the EVM.
1. Setup
- The assembly template is
provided in sinegen.zip.
First, download this file and decompress to your
account, preferably under lab2/sinegen.
- To complete the setup, copy the entire lab2/audio/
directory (including subdirectories audio.CS_ and Debug) into this directory.
The sinegen files and the audio source files should be in the same
directory. This is so you can reuse as much of the
code as possible since you have already configured the audio project to
do real-time processing.
- Start a new CCS
session.
- Open the lab2/sinegen/audio.pjt
project. We will keep audio.pjt as the project name for the sake of
convenience.
- Add the file, sinegen_proc.s55, to the project.
- The main code, audio.c, must be modified in order to call the functions
defined in sinegen_proc.s55. Open
the file, audio.c, and
do the following modifications.
- Add extern
definitions for sinegen_proc_init() and sinegen_proc():
extern Void sinegen_proc_init(Void);
extern Void sinegen_proc(Void);
- In
the main()
function, add the following statement right before
IRQ_globalDisable();
sinegen_proc_init();
Note that there is no
underscore, "_", preceding the function name, sinegen_proc_init,
but in sinegen_proc.s55, this function does have the
underscore. This is simply the convention used to call C functions from
assembly, but the underscore is not needed in C.
In the processBuffer
() function, replace the for
loop with the following statement:
sinegen_proc();
So rather than copying
the data from the src buffer to the dst
buffer in the C code, you are calling a function (which in this case is written
in assembly), sinegen_proc(), to process the src and dst buffers.
- Open the header
file, sinegen_proc.h55. A convenient way of opening this is first select Project->Scan All Dependencies, and then expand the
include folder to find this include file. What you will see in this file
is a list of .global statements. This is
similar to the extern statements in C where the globalized variables can
be seen and read by codes in other files. Note also the underscore used
to reference variables defined in C as well as in the assembly code.
- Open the assembly
file, sinegen_proc.s55. A number of things are already provided to you:
- sinegen_proc.h55 is included at
the top.
- BUFSIZE is set to 0x80 = 128. This is the number of samples of the sine
wave that is stored in memory.
- An uninitialized section (.usect, meaning that you are not providing this section
with data until run-time) is defined to be allocated in the memory
section coefSect, 128 words large (second
argument). For more information on the .usect
directive, see Assembly Language Tool.
- An initialized section, .sect "coefDat", contains two sine waves,
addressable by sine1St and sine2St,
of different frequencies. You are to output either one of these sine
waves, each consisting of 128 samples, and analyze their frequency
characteristic during measurement.
- The .mmregs
assembler directive is REQUIRED. Without
it, you cannot reference MMR registers by their abbreviations, such as AC0, AC1, AR0,
AR3, BRC0, etc.
- A .text
section. Currently, the program is empty. You will write down your
sine wave generation codes.
- Compile the codes
as is, you should get no compilation errors at this
point. If so, fix them before you go on.
2. Coding
- Complete the
subroutines _sinegen_proc_init and _sinegen_proc to implement the
sinewave generator. _sinegen_proc_init is intended for any
initialization that needs to be performed, and _sinegen_proc
will used to copy the sine wave coefficients stored in the data memory to
the dst buffer. (At this point, you do not
need to be concerned with the _src buffer since you
are not operating on the receive buffer.) NOTE:
The size of output buffer and that of sine wave table are not the same.
This means that the sine wave should be addressed in circular manner, and
you should manage the circular buffer of sine wave table.
- Compile and test
your sine wave generator by listening to the EVM
output. If it sounds right, go on. You may have to come back to debug the
generator if you find that the measured waveform is not correct.
3. Debugging with the
CCS Graphing Feature
·
One of the most helpful debugging tools that we have
available is the graphing feature of Code Composer Studio. This allows us to
graphically plot out the values in region of memory (which can be very helpful
for sinewave generation). Here is a brief description of how to graph the dst buffer:
o
Select
View->Graph->Time/Frequency. A Graph
Property dialog box will pop up. Change the following settings:
§
Graph Title - dst
buffer. This is the label you have chosen to identify the graph window.
§
Start Address - dst. This is the label you
have chosen for starting address of your data buffer.
§
Acquisition Buffer Size - 192. This is the size of
the data buffer.
§
Display Data Size - 96. This specifies the
portion of the data buffer you would like to have plotted. The number specified
here must be smaller than the acquisition buffer size.
§
DSP Data Type - 16-bit
signed integer. This is the default type for digitized samples.
§
Click on OK to close this dialog
box. The data in your dst pipe frame will be
plotted with respect to time.
o
This will allow you to view the frame pointed to by dst. Keep in mind that dst
switches between input frames, so the graph will actually show you different
frames at different times.
o
The receive pipe can be viewed by graphing src.
4. Profiling
- To accurately profile a
section of your code, you need to subtract out the overhead associated
with extracting profiling statistics from the EVM board and transferring
them to the host computer. A procedure for accurate profiling is
described in the CCS User's
Guide accessible
through the EE265 Navigation Toolbar - On-Line Programming
Reference.
Read the section Profiler->Profile Clock Accuracy.
- Now, profile
and report your sine wave generator code.
- It may help to add NOPs to
either your assembly or C code to perform the profiling described in the
Profiling Help. To add NOPs (or any other assembly instruction to your C
code you can use the following format: asm(" NOP"); (Don't forget that
the NOP must be preceded by a "tab" to place it in the second
column of the assembly code.)
D. Audio Recorder
Once you have completed
and tested your sine wave generator, you will implement an audio recorder. You will
then analyze the audio samples using the CCS graphing tool to view the time and
frequency spectrum of the samples. You will also perform some simple
experiments to analyze the physical signals.
1. Coding
Specifications
- Copy the lab2/sinegen
directory to a new directory, call it lab2/recorder. Work in this new
directory. (You can start from a different project if you know of one
that is more appropriate than lab2/sinegen).
- Modify the code
so that it can do two things:
- record the input
to a buffer (for observation and also so we can do frequency
analysis on something larger than a single frame)
- copy the input
to the output (so that the incoming signal can be listened to)
- sinegen_proc_init may
or may not serve any purpose, so whether or not you keep it in your code is
up to you.
- Recorder
requirements:
- The audio recorder data
buffer will be 512 words for each channel (so it’s
512*2 = 1024 words) and should be a circular buffer that is continually
filled with samples from the src buffer
(received from the serial port). In other words, in addition to copying
the data stored in the src buffer to the
output dst buffer, you will also copy the
input samples to a data buffer that you specify.
- You will need to define
your own data section. You can do this with either the .sect
or the .usect directive. Don't forget to associate
this data section to a memory section in the linker command file! Do not
use the buffer_sect section that is already there.
- You will need to debug your
code in CCS and later you will use MATLAB to verify that your recorder
works properly (as described below).
2. Debugging using CCS
Features
·
Graphing:
As described
above, the graphing feature of CCS can be one of the most helpful debugging
tools that we have available. You can use the graphing feature to plot the
values directly, or you can also make other plots (such as the FFT of the
values). The following steps will guide you through the process of plotting the
recorded signal directly and also plotting its FFT magnitude:
o
To test your code, connect an audio
source and start the music, as described previously.
o
Compile, reset DSP, load the program
onto the EVM, and run the program.
o
Stop the program shortly (after few seconds -
to be sure that the buffer is filled with data samples).
o
Select View->Graph->Time/Frequency. A Graph Property dialog box
will pop up. Change the following settings:
§
Graph Title - Amplitude
vs. Time
§
Start Address - recordData.
This is the label you have chosen for starting address of your data buffer.
§
Acquisition Buffer Size - 1024.
This is the size of the data buffer.
§
Index Increment - 2.
This is because the buffer format is stereo, L/R interleaved format.
§
Display Data Size - 512.
This specifies the portion of the data buffer you would like to have plotted.
The number specified here must be smaller than the acquisition buffer size.
§
DSP Data Type - 16-bit
signed integer. This is the default type for digitized samples.
o
Click on OK to close this dialog
box. The data in your record buffer will be plotted with respect to time.
- To look at the frequency
spectrum of the received data, select View->Graph->Time/Frequency again and fill in
the following settings:
- Display Type - FFT Magnitude
- Graph Title - FFT Magnitude
- Start Address - recordData
- Acquisition
Buffer Size - 1024
- Index Increment - 2
- FFT
Framesize - 512
- DSP Data Type - 16-bit signed integer
- Click OK to close the
dialog box. The FFT magnitude plot of the record buffer will be plotted.
- Saving Data to File:
Another useful debugging option is to use an external program (such
as MATLAB) for analysis. You can do this by saving the data acquired in
memory onto the computer. One reason you might want to do this is if you
want to make a printout of the data plot. CCS does not support graph
printing, so it will need to be handled by another program. The following
steps will guide you through the process of storing your recorded data to
a file that can be opened in MATLAB:
- Select File->Data->Save...
- A Store
Data dialog box will pop up. For the
Save as type: field, select Integer (*.dat).
- Enter the
filename for the data to be stored (let's call it datarec.dat - you don't need to enter the .dat extension
since it will be added for you).
- Click on Save. The Store Data dialog box will close and the Storing Memory Into File dialog box will open.
- Enter the Address, Length, and
Page of the data you wish to store.
- Click OK to store the
data and to close the dialog box.
- Before you can load this
file into MATLAB, you must remove the first line of the data file. Note: Windows will treat this file as a Windows registry file,
so you will need to use some program such as Notepad or WordPad to edit
the file, instead of simply left-clicking on the file to open it. To do
this, you can Right-click the file and select Open With, and then choose
an editor. Open datarec.dat, delete the first line, and save datarec.dat.
- You may now load datarec.dat into MATLAB and generate a plot from there.
3. Verification using
MATLAB
Although CCS has many
useful debugging features, it cannot help you with all types of analysis that you
may wish to perform. For example, in Lab 1 you were asked to write code that
implemented an FIR filter. The CCS debugging features were helpful in verifying
individual operations, but ultimately CCS could not verify that the computed
result was correct since it has no way of computing the FIR result on its own.
Most of you probably used MATLAB to determine what the FIR output should have
been and then used this to compare to the output that your code generated.
Indeed, MATLAB is almost ideal for verifying code, since it has plenty of
computational power to perform all sorts of analyses on data. In this lab we
will introduce a method for using MATLAB to verify your DSP code to ensure that
it is working correctly. The verification can be used to determine with great
certainty whether or not your algorithms are computationally correct. This
method may be useful for debugging, but since it is less interactive than
working in CCS, it may be most useful for verification only after you are
pretty sure that the code is working correctly.
MATLAB/CCS Link:
You
will be performing the verification of your DSP code by using the MATLAB Link
for Code Composer Studio. The Link for Code Composer Studio is a toolbox
available for MATLAB that lets you link to your DSP processor so that you can
run and test your programs from within MATLAB. The link allows you to do many
CCS actions: you can run CCS, load projects, build executables, load
executables, execute code, set breakpoints, read memory and write to memory on
the DSP. These capabilities allow us to write MATLAB scripts that perform
verification of our CCS projects. A typical script will perform the following
actions:
- Choose a DSP board and
processor to link to (only one choice in our system)
- Start Code Composer Studio
(if not already running) with a link to the chosen board/processor
- Load a specific project into
CCS
- Build the project in CCS
- Load the executable onto the
selected processor
- Set breakpoints in the code
- Run to the breakpoints
- Read or write to memory on
the DSP processor
- Perform calculations on the
data to determine the expected values for variables in the DSP code
- Verify that the values read
from memory are equal to the expected values
CCS Tutorial:
There are
several tutorials for the Link to CCS that are built in to MATLAB. The simplest
of which is a script named ccstutorial.m and it
can be run from the MATLAB command prompt by typing ccstutorial.
The tutorial covers the basic operations that are outlined above, but it also
goes into detail about how to access data from C language constructs such as
structs and strings. Since this is beyond the scope of this lab, you will run a
modified version of this script, ccstutorial_brief.m.
Here are instructions on how to run the script:
- Download matlab_verification.zip and
decompress it to your lab2 folder.
- Run MATLAB and
change the current directory to your lab2/matlab_verification
directory. (This can be done by typing cd z:\labs\lab2\matlab_verification in the
MATLAB command prompt).
- Open the editor
window in MATLAB. (This can be done by typing edit
in the MATLAB command prompt).
- From the editor
window, open the script ccstutorial_brief.m
from your lab2/matlab_verification
directory.
- You may need to
modify the variable projfile appropriately if you copied the matlab_verification
folder to any location other than z:\labs\lab2\.
- Type ccstutorial_brief
at the command prompt to run the shortened tutorial.
- Follow the
instructions that are printed to the MATLAB Command Window to go through
the tutorial.
MATLAB/CCS Help:
Now
that you’ve seen some of the MATLAB involved in verification, you may want to
take a look at the documentation for the functions. There is a fair amount of
documentation available for the CCS Link functions (and any MATLAB function in
general). We do not suggest that you look through the documentation first,
because you will probably learn faster by going through the tutorial above and
the two examples that will follow below. However, as you go through the next
two examples, you may have some questions about the details of a function or
you might want to know what other capabilities are available in the CCS Link.
Here are some suggestions of where to look for help in MATLAB:
- If you ever need info about
a particular function type help function_name
in the MATLAB Command Window.
- Example: for info about build, type help build.
- For certain functions, you
may have to type help ccsdebug/function_name.m
to get the help that is specific to the CCS Link toolbox, since the
function may have meaning in some other context (such as load).
- For info about the functions
that are available to a CCS Link, type help ccsdsp
- For info about the ccsdsp function itself, you need to type help ccsdebug/ccsdsp.m
- For graphical help, start
the MATLAB Help Window by typing helpwin in
the Command Window or selecting Help->Matlab Help
from the MATLAB menus. The Contents section
of the help window has a section named MATLAB Link for
Code Composer Studio which contains a lot of info (that may or
may not be useful).
Lab 1 Example Script:
The
tutorial script should familiarize you with the basic operations for verifying
DSP code. To give you better example of how to apply this to your lab
assignments, we have provided a script that verifies the operations of a
particular solution to the Lab 1 assignment. You will be expected to execute
this example script and also to step through it in the MATLAB debugger so that
you can see the commands used for the verification. Here are instructions for
this:
- Remove
all breakpoints from your lab1 code in CCS.
- Open the editor
window in MATLAB. (This can be done by typing edit
in the MATLAB command prompt).
- From the editor
window, open the script lab1_ccs_matlab_example.m
from your lab2/matlab_verification
directory.
- You may need to
modify the variable projfile appropriately if you copied the matlab_verification
folder to any location other than z:\labs\lab2\.
- You may need to
modify the variables linenum_after_coef_copy
(the
line number of the first line of your lab1 code) and linenum_after_fir_procedure
(the
line number of one of the nops after your lab1 code) appropriately.
- Run the code from
the editor window by selecting the Run command from the Debug menu (Debug->Run)
to verify that the script executes without any errors.
- Now that you have observed
the operation of the script, you should step through it in the editor
window to see what it does in greater detail:
- Set a breakpoint
on the first line of the script (using the Breakpoints menu). This will allow
you to step through the script in Debug mode.
- Step through the
script one line at a time and try your best to understand what each line
does (hopefully the comments in the code
will help).
Note that the board
selection process in this example is much simpler than the process demonstrated
in the tutorial. This is because we only have one board and one processor, so
we can choose them as board 0 and processor 0 without checking what is
available on our system. In order to fully understand the verification script,
there are three places to keep your eye on:
- The MATLAB editor window
(where you'll step through the script)
- The MATLAB Command Window
(where messages may appear)
- Code Composer Studio (where operations
are taking place, such as the setting of breakpoints and the execution of
the DSP program)
Lab 2 Loopback Example
Script:
The
Lab 1 example script should give you a pretty good idea of how to use the CCS
Link to verify your code. However, it did not use the data pipes so it is not a
great example of how this can be applied to real-time code. To help you with
verifying real-time code, we have also provided another example script that
uses the pipes. This script will verify a basic loopback example which copies
the input frame directly to the output frame (the lab2b code). Here are instructions to use the
script:
- Remove
all breakpoints from all files open in CCS.
- Open the editor
window in MATLAB. (This can be done by typing edit
in the MATLAB command prompt).
- From the editor
window, open the script loopback_ccs_matlab_example.m
from your lab2/matlab_verification
directory.
- You may need to
modify the variable projfile. Make sure that the project file path correctly specifies the
location you copied it to. (This applies to any file
specified in your scripts).
- Run the code from
the editor window by selecting the Run command from the Debug menu (Debug->Run)
to verify that the script executes without any errors.
- Now set a
breakpoint on the first line of the script and step through the script
one line at a time.
- Note that the script
overwrites the input pipe with data that is generated in MATLAB. This is done so
that we have complete control of the input to our algorithms. It also
lets us test our real-time code in a non-real-time fashion, since we are
no longer relying on real-time inputs, but our code uses the pipes
nonetheless. This can be very powerful, since stopping the code at
breakpoints usually ruins the continuity of a real-time input. (We will
come back to this point in later labs.)
Verifying the Recorder
code:
By
now, you should have a pretty good idea of how the MATLAB/CCS Link can be used
to verify code. You now must create your own script (or modify one we’ve
provided to you) to verify your recorder code. Here are the requirements of the
script:
- Initialize your
recorder buffer to all 0s.
- Replace the input
buffer with some random data before the frame gets copied to the recorder
buffer.
- Let your Recorder
code run for 8 iterations, copying 8 input frames to the buffer.
- Verify that after
copying 8 frames, the recorder buffer contains the correct data. You
may verify either one iteration at a time or the entire 8 iterations all at
once. If you do the latter, you would need to concatenate the 8 input frames
together and the 8 output frames together.
- Your verification script
should verify that the circular buffering works
correctly (8 frames is enough to force the circular buffer to
wrap around).
Hints and possible
problems:
- File paths must be precise
(project files, executable output files, source files)
Many problems can occur if these are not specified correctly in your
script, since the script is not smart enough to find the exact file you
intend for it to use. For example, for some projects, the executable
resides in a Debug directory inside the
project folder, and other times it resides in the project folder itself.
Make sure that the location specified in your script is the location of
the actual executable that gets built when you rebuild your project. One
possible problem: if your script specifies your executable program to be
located at ./Debug/audio.out but the
executable that is actually built/rebuilt by your project is located at ./audio.out, then your script will try to load
and use the wrong executable. This can make your verification act very strange,
since the executable in ./Debug/audio.out may
not have been generated from the project you are debugging (it may have
been copied from some other project directory). This can lead to all
kinds of problems. The rule of thumb here is that if your script produces
strange errors, double check to see if the script is accessing the
correct files.
- Global/Static Variables vs.
Local Variables
Verification is easiest if you are only accessing global variables as
opposed to variables that are local to a particular C function. Examples
of global variables are C variables that have been defined outside of all
functions and also any variable defined in assembly. These are considered
global because they always exist at the same fixed memory address. In
contrast, local variables in C functions are created each time a function
runs, and these variables are created on the stack. This means that the
address of a variable can be different for each call to the function
(depending on what is currently on the stack). Global variables are nice
for using in scripts because we can determine their address once and this
address will not change while the code is running. On the other hand, the
address of local variables will change, so it must be recalculated each
time the variable is accessed. If you do not
recalculate the addresses of local variables, you might be using an old
address that is no longer valid. This can be very difficult to
debug.
Solutions for local/global variable problems
- Define your variables so
that they are global, so that the address can be determined once and for
all.
- Re-compute the address of a
variable each time you access it. This is always safe to do, since you
are assured that the address you are using is valid at the time you read
data from that address (when stopped at a certain breakpoint, for
example).
4. Profiling
There are a number of
metrics for determining the performance of DSP codes. First, the code must meet
real-time requirements meaning that it has to work without missing real-time
data. Another metric is code size. Code size is important in large systems
where program memory is limited. Code size is also closely related to execution
cycles in programmable processors. Smaller code size requires less cycles to
execute. But the execution time is also determined by other factors such as the
choice of algorithm. And the choice of algorithm is also closely related to the
output precision of your code (as we will see in later labs). There is no
clear-cut boundary between these metrics and writing good DSP codes require
taking everything into consideration.
This section goes
through how you would profile your code to determine its execution time. You
will use the profiling tools to analyze your code and report the results in
your write-up.
Profiling has been
discussed in the CCS tutorial. CCS supports many ways of performance evaluation
but most of them cannot be used in real-time since they would interfere with
real-time data transfer. In addition, the profiling mechanism introduces significant
amount of overhead that makes it difficult to determine an accurate cycle count
between the profiling points.
For complex systems,
profiling will be done on a non-real-time code first (as discussed in the CCS
tutorial) and the code will then be rewritten to incorporate real-time data
transfer. In this course, the labs will be simple enough that you will not need
to write different codes and profiling will be done primarily on the critical
sections. You will do profiling one block at a time to report the execution
time.
To accurately profile a
section of your code, you need to subtract out the overhead associated with
extracting profiling statistics from the EVM board and transferring them to the
host computer. A procedure for accurate profiling is described in the CCS User's
Guide accessible
through the EE265 Navigation Toolbar - On-Line Line Programming
Reference.
Read the section Profiler->Profile Clock Accuracy.
When you measure the
cycles of a function, there may be possibility of interrupt during the
execution of your function. Since what you need to profile is just the
execution cycles of your own function, it isn’t a good situation. In C55x.h (
it is in C:\CCStudio_v3.1\C5500\cgtools\include ), the following two functions
are defined.
¡
void
_enable_interrupts(void);
¡
unsigned int
_disable_interrupts(void);
_disable_interrupts()
function disables all the interrupts, while _enable_interrupts() re-enable the
disabled interrupts. For the profiling purpose only, you could disable interrupts,
measure the cycles from your function call to the _enable_interrupts() call, and enable interrupts again. This will give you more
accurate cycles. (without this, the cycles measured may vary significantly from
time to time). Don’t forget to remove these interrupts things after measuring
cycles.
E. Sampling and
Quantization
At this point, there is
a lot of things you can do with the DSP board. Here, you will experiment with
the different sampling rates and implement a couple of quantization schemes to
see how these affect the signals.
1. Changing the
Sampling Rate
In this exercise you
will get experience with changing the sampling rate of the DSP processor. The
procedure for changing the sampling rate of the AD50C AIC is provided below.
- Create a new
directory called lab2/sampling.
- Copy
everything from lab2/recorder to
this directory.
- Start a new CCS
session.
- Load the audio.pjt
project and open the file audio.c.
- The DSK5509_AIC23_SAMPLERATE
register sets the sampling rate of the AIC. Its value is set as part of
the AIC23_Params_config structure.
- Use the
AIC Data
Sheet to determine the actual sampling frequencies for the different
register values. See 3.3.2 and 3.3.2.1.
- Setup the EVM
board
- Connect the
audio source from the PC to the EVM input
- Connect the
headphones to the EVM output
- Play the
following audio test sample.
- Determine and
report the frequency of the sinewave(s) in unknown.wav
using 48kHz,
44.1kHz, 32 KHz, and 8 KHz sampling frequencies.
- Use the Graph
feature of CCS to look at the spectrum of the recorded data.
- It may also interest
you to know that the AIC input is filtered by a lowpass filter in order
to prevent aliasing with a cutoff frequency of around 0.42*Fs, where Fs
is the sampling frequency (see
AIC23B data manual for the exact cut off frequency).
- For fun, play some music and
listen to it at different sampling frequencies. This can give you an
intuitive feel for how audio signals are affected by sampling frequency.
2. Quantization
Here, you will look at
the effects of quantization on a signal. You will use MATLAB to code a uniform
quantizer and compare it to a non-uniform quantizer. You will then examine the
frequency contents of the output of both types of quantizers and discuss the
results.
·
o
Create a new directory called lab2/u-quan.
o
Download the file uniform.m to
your lab2/u-quan directory.
§
This is a starter script for your quantizer. (Read the
comments in the code for more info.)
§
This script reads in a signal from a wavefile and also
writes the quantized data to a wavefile so that the quantized signal can be
compared to the original.
o
Download the files sample1.wav, sample2.wav , and sample3.wav to your
lab2/u-quan directory.
o
Modify the uniform.m script to
implement a uniform quantizer with the specified number of bits (see the starter file).
§
The number of bits used for quantization limits the number
of discrete levels in the quantized signal. Your
quantizer must ensure that the signal cannot assume any more than 2^(quantBits)
discrete values.
§
The starter script creates an input signal (un-quantized)
within the range of -1.0 to +1.0. Your quantizer should convert this to some
range of integer values. For example, an 8-bit quantizer should have quantized
samples in the range of -128 to +127.
§
CAUTION: MATLAB does all calculations in floating point,
so you will need to make sure that your values are properly quantized as
integers (using the floor, ceil, or round functions).
§
The quantized signal must be converted back to the range
of -1.0 to +1.0 before writing the signal out as a wavefile (wavwrite).
- A Note On
Amplitude: It is important to recognize that the amplitude of
the input can affect the quality of quantized signals. This is because
we assume that the input values are within a certain range when we
perform quantization. For example, we may have an A/D converter that
expects an input voltage within -1.0V to +1.0V. This defines the dynamic
range of our A/D input, so that a signal of -1.0V can be assigned to the
most negative quantized value and an input of +1.0V will get assigned to
the most positive quantized value. For any quantizer, each quantized
sample can have some quantization noise which is proportional the size
of the step in between two levels of quantization. When the actual input
signal does not use the full dynamic range, then the quantization noise
can appear to be large relative to the actual signal. For example, the
step size of a uniform quantizer is fixed, so the quantization error
will appear larger for smaller inputs.
o
Quantize the audio files, sample1.wav, sample2.wav , and sample3.wav.
o
For each audio file, vary the number of
bits used for encoding and report the number of
bits used with which you can distinctly hear artifacts of quantization.
- Non-Uniform Quantizer: You will compare
your uniform quantizer to a non-uniform quantizer in this section.
o
Write a MATLAB script to perform
non-uniform quantization (mu-law companding) as specified below. Name this file, lab2/u-quan/mulaw.m (i.e. same directory as the uniform
quantizer MATLAB code). Refer to TI's appnote for more information on the details of the
non-uniform quantizer (mu-Law compression and expanding).
§
Compression:
1.
The input/output relation is given by the following
expression (for -1 <= x <= 1):
c(x) = sign(x)*ln(1 + µ · abs(x))
/ ln(1 + µ)
2.
Set µ = 255.
3.
The output c(x)
will be a normalized, compressed value, taking on values from -1.0
to 1.0.
§
Quantization:
Now that the signal has been compressed, it can be quantized linearly to a
fixed number of levels. By linearly quantizing the compressed input, we
effectively perform non-uniform quantization on the original input. This is the
critical step in which we force our input values (which are still continuous)
to take on a fixed number of output values.
1.
We will assume an 8-bit output
(i.e. there are a total of 256 output levels), which means that c(x)
should be linearly quantized to take on 256 values.
1.
One way to do the quantization is to assume that 1 bit is
used for the sign of c(x) and the
remaining 7 bits are used to represent and integer between 0 and 127. This is
the method used in the TI's appnote.
2.
Alternatively, this could be done using something
equivalent to the uniform quantizer.
2.
Scale and linearly quantize the normalized c(x)
so that it takes on the range of -128 to 127 (in integer form).
3.
This gives us the input compressed into an 8-bit encoded
form.
§
Expansion:
In
order to retrieve the original waveform, we will need to reverse the above
processes. This will restore the waveform to its natural (uncompressed) format
so that we can compare the resulting signal to the un-quantized signal as well
as the uniformly-quantized signal.
1.
First, convert the quantized c(x)
back to the range from -1.0 to 1.0
2.
Now apply the inverse of the compression formula shown
above to restore the signal. Make sure you handle the case for negative x
correctly!
o
Use the non-uniform quantizer to quantize
the audio test samples, sample1.wav,
sample2.wav , and sample3.wav with your MATLAB script. Note: you only
need to do 8-bit mu-law quantization.
o
For each of the audio examples, report
the effective number of bits the uniform quantizer would require to achieve the
same (subjective) quality output as the 8-bit non-uniform quantizer.
o
Side note: You can do a lot of interesting analysis with the
MATLAB codes. For example, you can analyze the error introduced by quantization
(using the mean-square error of the quantized
results, for example). Note that the error introduced is itself a function of
the signal statistics.
- Frequency Spectrum:
What does the spectrum of a quantized signal look like? Here, you will
add to the MATLAB scripts to observe the effects of quantization in the
frequency domain.
·
- Copy lab2/u-quan/uniform.m
and lab2/u-quan/mulaw.m
to a new directory, lab2/quan_matlab/. You will need to modify uniform.m
and mulaw.m to
plot the frequency spectrum of the original and the quantized signals
(the requirements are described below).
- You will now generate
several plots that compare the two quantization schemes for different
types of signals, but using the same number of bits.
- Generate three
time-domain plots that clearly show a
comparison of 8-bit uniform quantization versus 8-bit non-uniform
quantization. Consider , sample1.wav, and
sample3.wav as your un-quantized inputs and plot all three signals on
the same graph for comparison.
- Generate one
frequency-domain plot that clearly shows the effects of uniform and
non-uniform quantization in the frequency domain. You should use
an FFT size of 1024 points. (You may have to extract a
1024-point section from the signal in order to do this).
- The goal of
these plots is to show the strengths and weaknesses of the two
quantization schemes, and you will be graded according to how well you
do this. Therefore, each of your plots should demonstrate a
meaningful comparison of the performance of the quantization schemes
under different conditions.
- The different
quantization schemes may perform best on certain types of inputs
(music vs. voice vs. tones).
- For
time-domain plots, the non-uniform quantizer will change its
quantization step size based on the amplitude, so you will want to
zoom in on regions of different amplitude to compare the different
quantization schemes. Try zooming in on regions of the signal that are
quiet (close to 0.0) and loud (closer to 1.0).
- Plotting the
frequency-domain signals in decibels can help accentuate portions of
the spectrum that have low amplitudes.
- You can plot
two different signals on the same graph by using the hold on
command. You can also specify plotting different signals in different
colors with different line types (dashed, dotted, solid, etc.). Check
the help for plot for more info. Here is a quick example:
- figure(100); % create a
new figure and give it a unique number
- clf; % clear the
figure (in case it has been used before, particularly with hold
specified)
- plot(x,b+); % plot x in
blue as a solid line with + symbols at the data points
- hold on; % don't overwrite previous plot
- plot(y, r:); % plot x in
red with a dashed line
- Zoom in on the
graphs to show a portion of the graph that demonstrates the effects of
quantization. This can be done by selecting the magnifying glass in
the figure window and dragging this tool over the portion of the graph
that you want to zoom in on.
- Alternatively,
you could use the axis function to limit the displayed region
of the graph.
- The fft
function in MATLAB produces a complex output, but you will only need
to view its magnitude (use the abs function).
- You can plot
the signals in decibels using the formula: (20*log10(x)). This may
require that you add a small value to the argument of the logarithm,
since it cannot take the log of 0. The easiest workaround is to add eps
(epsilon), which is the smallest value that MATLAB can represent. In
decibels, eps is about -313 dB, so no value will drop below
this if eps is added.
- Generate your
final plots as requested above, and submit these with your lab report.
- Now that you have generated
several plots, comment on how well uniform
quantization works with a single sinewave versus music. Compare this to
non-uniform quantization. Can you observe any strengths and weaknesses
of the different quantization schemes?
- We would now like you to
observe the effect of using a different FFT size for the plots. Generate the frequency spectrum plots using a 64-point FFT
(NOTE: you do not have to submit these plots in your lab write-up). Using different FFT sizes produces different
resolutions in the frequency domain, so you should be able to see a
difference in the signal spectrum representation. Observe these
differences.
- From the plots
you generated you should be able to compare the frequency spectrum of
the original and the quantized signals. Answer the following
questions in your write-up: Is the quantization system linear? Is it
time-invariant? NOTE: the un-quantized
signals we use are from wave-files, which are already quantized to
16-bit samples. Therefore, they have already been affected by
quantization. Think about how truly un-quantized signals are affected by
quantization.
- Explain in your write-up
how various levels of quantization affect the signals spectrum
and/or bandwidth.
Last modified: 9:00
am 02/24/2007