DSP Lab Book
DSP Lab Book
Spring 2020
Michael Stiber
Bilin Zhang Stiber
University of Washington Bothell
18115 Campus Way NE
Bothell, Washington 98011
Eric C. Larson
Southern Methodist University
Lyle School of Engineering
3145 Dyer Street
Dallas, TX 75205
Copyright © 2002–2016 by Michael and Bilin Stiber and Eric C. Larson
2 Hello, Digital! 12
2.1 Sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2 Analog to Digital Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3 Feed It Forward 15
3.1 Overview of Filtering and Matlab . . . . . . . . . . . . . . . . . . . . . . . . 15
3.1.1 From Filter Coefficients to Transfer Function and Frequency Response 17
3.1.2 From Zero Placement to Filter Coefficients . . . . . . . . . . . . . . . 17
3.2 Frequency Response and Pole-Zero Plots . . . . . . . . . . . . . . . . . . . . 18
3.3 Linearity and Cascading Filters . . . . . . . . . . . . . . . . . . . . . . . . . 20
2. Complex numbers:
3. Complex exponentials:
exp(j * pi)
exp(j * pi/2)
exp(j * pi/4)
4. Vectors:
v1 = [0 1 2 3] % Four elements
v2 = [0 : 2 : 10] % like a loop (start value : increment : end value)
v3 = pi * [−0.5 −0.25 0 0.25 0.5] % All operations are vectorized
exp(j * v3)
mistake = v1 * v1 % a mistake; vector mult doesn't work this way
dotproduct = v1 * v1' % transposing will work, if you want to do this
arrayprod = v1 .* v1 % element−by−element ops include: .+, .−, .*, ./
5. Simple plots (note that “;” suppresses outputting results to the command window —
useful if that would generate massive amounts of text, or just if you want things neat):
t = [0 : 0.01 : 2*pi];
x = sin(t);
plot(t, x); % default plots points connected by lines in blue
plot(t, x, 'r'); % change the line color
plot(t, x, 'r.'); % change the plot style; zoom in to see individual points
xlabel('t, ms'); % X axis label (all of your plots should have this)
ylabel('Mag'); % Y axis label (all of your plots should have this)
title('Triangle');% Graph title (all of your plots should have this)
If you take a sequence of commands and save them in a file with an extension of .m, the
result is a script. Assuming that the script is saved in a directory in the MATLAB search
path, you can then execute the script by just typing its name (without the .m), just as if it
were a command. If you want your code to take parameters, return a return value, and have
local variables, start your code with a line like:
function retval = funcname(parm1, parm2)
Your code is now a function. MATLAB functions can take variable numbers of arguments
and even return variable numbers of return values, but that’s getting beyond what we need
right now.
Also, explain the difference between the square bracket notation [1:2:12] and the par-
enthetical notation (1:2:12).
Write a single statement that will replace the odd-indexed elements of x with the constant
-10 (i.e., x(1), x(3), etc).
Step 1.3 One of the side benefits of learning Matlab is that it trains you to think in terms
of parallel operations — an increasingly important skill in a profession becoming dominated
by multi-core, GPU, and distributed computing. That doesn’t mean you can’t write loops in
Matlab; it’s just that your code will be more concise and efficient if you can avoid that. The
efficiency arises from the fact that the vectorized Matlab commands are mostly compiled;
while the loops you write are interpreted. Consider the following loop:
for k=0:7,
x(k+1) = cos(k*pi/4);
end
x
Why is x indexed by k+1 rather than k? What happens to the length of x for each iteration
of the loop? Rewrite this computation without using the loop (as in list item 5). Besides the
increase in efficiency from avoiding an interpreted loop, what other major efficiency results
from this change?
Use the MATLAB editor to create a script file called firstsin.m, verify that you’ve
saved it in a directory in the MATLAB path (or add that directory to the path), and test
its execution by typing firstsin at the MATLAB command prompt. Note that you can
also do:
If you included documentation for this script (comments at the beginning), the command
help firstsin would also produce useful output.
Add three lines of code to your script, so that it will plot a cosine using the same axes
as the sine (i.e., “on top of the sine”). Use the hold function to add a plot of
0.75*cos(2*pi*f*t)
to the plot. So, your final graph will have two functions plotted. Save the plot using the
MATLAB print command as a PNG file named step14.png by typing:
print −dpng step14
You should include all plots and code snippets in your lab report, following the instruc-
tions in the report rubric.
Step 1.5 You can also use Matlab to generate sounds. A pure tone is merely a sinusoid,
which you already know how to generate. Let’s generate one with a frequency of 3 kHz and
a duration of 1 second:
T = 1.0;
f = 3000;
fs = 8000;
t = [0 : (1/fs) : T];
x = sin(2*pi*f*t);
soundsc(x, fs)
The vector of numbers x are converted into a sound waveform at a certain rate, fs, called
the sampling rate (we will learn a lot more about this in this class). In this case, the sampling
rate was set to 8000 samples/second. What is the length of the vector x?
Step 1.6 Write a new function that performs the same task as the following function
without using any loops. Use the idea in step 1.3 and also consult the section on the find
function, relational operators, and vector logicals in the MATLAB documentation.
function B = denegify(A)
% DENEGIFY Replace negative elements of matrix with zeros
% Usage:
% B = denegify(A)
%
[W,H] = size(A);
for i=1:W
for j=1:H
if A(i,j) < 0
B(i,j) = 0;
else
B(i,j) = A(i,j);
This is a sum of cosines, all at the same frequency but with different phases and amplitudes.
Use the following function prototype to start you off:
function x = sumcos(f, phi, a, fs, dur)
% SUMCOS Synthesize a sum of cosine waves
% Usage:
% x = sumcos(f, phi, a, fs, dur)
% Returns sum of cosines at a single frequency f, sampling
% rate fs, and duration dur, each with a phase phi and
% amplitude a.
% f = frequency (scalar)
% phi = vector of phases
% a = vector of amplitudes
% fs = the sampling rate in Hz (scalar)
% dur = total time duration of signal (scalar)
Step 2.2 Now, let’s see how complex exponentials can simplify things. Re-implement your
sumcos function using complex exponentials. Take advantage of the fact that multiplying
a complex sinusoid ej2πf t by the complex amplitude ai ejφ will shift its phase and change
its amplitude. Thus, you should be able to create a single complex sinusoid at the given
frequency f and then multiply it by different a * exp(j * phi) to get multiple phase shifted
cosines. Remember that we want a real value to plot; the cosine is the real part of a complex
sinusoid. Include your code in your writeup and provide a plot that demonstrates that this
function produces the same result as the original implementation.
a. Make a single plot of all four signals together over a range of t that will generate
approximately 3 cycles. Make sure the plot includes negative time so that the phase
at t = 0 can be measured. In order to get a smooth plot make sure that your have at
least 20 samples per period of the wave. Include your plot in your writeup.
b. Verify that the phase of all four signals is correct at t = 0, and also verify that each
one has the correct maximum amplitude. Use subplot(3,2,i) to make a six-panel
subplot that puts all of these plots in the same figure, with space for two additional
plots at the bottom. Use the xlabel, ylabel, and title functions so that the reader
can figure out what the plots mean; reinforce this with your report’s figure caption.
(You should include the final figure, with all subplots, that results from finishing all of
the parts of this step.)
c. Create the sum sinusoid, x5 (t) = x1 (t) + x2 (t) + x3 (t) + x4 (t). Plot x5 (t) over the same
range of time as used in the last plot. Include this as the lower left panel in the plot
by using subplot(3,2,5).
d. Now do some complex arithmetic; create the complex amplitudes corresponding to the
sinusoids xi (t): zi = Ai ejφi , i = 1, 2, 3, 4, 5. Include a table in your report of the zi in
polar and rectangular form, showing Ai , φi , Re{zi }, and Im{zi }.
Figure 01: Example help screen for the AnalogSignal class. This example may be out-of-
date; use the Matlab doc AnalogSignal command to get current documentation.
You will get a lot more experience working with analog signals shortly in this class, so
for the time being just play with this a bit.
1.1 Beating
In this section, you will use the Matlab AnalogSignal class (described previously in lab 1
and its figure 01) to simulate an analog signal generator. The constructor takes the following
arguments:
% AnalogSignal(type, amplitude, frequency, dur)
% Where:
% type = 'sine', 'cosine', 'square', 'sawtooth', or 'triangle'
% amplitude = signal amplitude
% frequency = signal frequency
% dur = signal duration
Step 1.1 Verify that you can get a triangle wave. What is the code to generate and plot
a triangle wave ranging from -1 to 1 Volts with a frequency of 10Hz and a duration of 1
second?
Step 1.2 Next, verify that you can generate a sine wave of 1 second duration at a frequency
of 440Hz, ranging from -1 to +1. What is the Matlab code to do this? Use the AnalogSignal
soundsc method to play this as a sound. This pitch corresponds to “standard A” on a musical
scale — A above middle C. Use the Matlab set(gca, ’XLim’, [Xmin, Xmax]) function
call to set the X axis limits so that the waveform is apparent (i.e., you’re not just plotting
a solid blob).
Step 1.3 Generate three sine waves of identical range and duration, but with frequencies
of 442, 444, and 448 Hz. Next, generate the three sums of 440Hz and each of these new
signals separately (so, 440Hz + 442Hz, 440Hz + 444Hz, and 440Hz + 448Hz) to generate
beating akin to tuning an instrument against the 440Hz standard. Play each sum signal; can
you hear the beating? Plot each sum signal for its full 1s duration. The beating “envelope”
should be obvious. What is the beat frequency in each case? How does the beat frequency
and amplitude relate to the textbook discussion of beating?
In this case, in the analog domain, we are dealing with frequencies in Hz, and so ω0 = 2πf0 .
Notice that the Fourier Series of the triangle wave only uses odd harmonics (i.e., the only
non-zero frequencies are (2k + 1)ω0 = ω0 , 3ω0 , 5ω0 · · · ). Also notice that the resulting wave
will have zero mean because there is no “DC” term (i.e., 2k + 1 6= 0 for any integer k).
Write a Matlab script that approximates a triangle wave by summing together the first 7
harmonics of its Fourier series; plot the resultant signal (i.e., use f0 , 2f0 , 3f0 , · · · 7f0 , where
f0 =10 Hz). How does this signal compare to the triangle wave computed directly in the
previous step?
Step 2.2 Another way to view a signal is in the frequency domain. For a signal expressed
in terms of its Fourier series, the frequency representation is merely the coefficients of the
harmonics. Write a Matlab function or script to compute and plot the spectrum of a triangle
wave. You may find the MATLAB function stem useful. Note that you are not being asked
to plot the triangle wave as a function of time; you should plot the amplitudes of the
component sinusoids as a function of those sinusoids’ frequencies (like the vertical lines in
textbook figure 1.12). Use your code to plot the spectrum of the triangle wave from the
previous step (first 7 harmonics).
2.1 Sampling
The first step in digitization is sample and hold, in which the continuous analog signal is
converted to a discrete-time analog signal (an analog signal that only changes its value at
particular points in time). You will use the samplehold method to do this:
% samplehold Perform a sample and hold function on an AnalogSignal
% Usage:
% x = obj.samplehold(h)
% where obj = AnalogSignal
% h = hold time in sec (sampling interval)
% x = resultant sampled AnalogSignal
Step 1.1 Create an analog sine waveform ranging from -5 to 5V with a frequency of 200Hz
and a duration of 2 seconds. Produce a plot with X-axis limits set to make the waveform
visible (i.e., don’t just make a 2s plot that tries (and fails) to show 400 cycles of the sinusoid.
Step 1.2 Use the samplehold method to produce sampled versions of this signal at 300Hz,
500Hz, 1000Hz, and 2000Hz. Use the Matlab subplot command, and the discreteplot
function provided with this class’s Matlab code, to plot the original and all four sampled
signals together. One of the things that you will note from these plots is that the X axes of
these plots do not have units of continuous time; their units are not seconds. Instead, the X
axis values are sample count, starting with sample 1. You will want these plots to show their
signals over the same time duration, and so you’ll need to choose that duration, then figure
out, for each sampled signal, how many samples correspond to that duration, and then set
the X axis limits for each figure so that the plots show equal durations.
Clearly, the results are not the same, and none look identical to the original sine wave.
What are the two essential pieces of information about a sine wave that need to be preserved
when sampling it? Does it appear that all sampled versions are equally useful in achieving
this? Why or why not (in other words, your answer to this question should not be just “yes”
or “no”)?
Step 1.3 Let’s look at aliasing in a little more detail and with a lot more numerical
precision. You’ll recall from the text that, once we sample a signal, we have limited the
range of frequencies that we can represent in our discrete signal to the range 0 ≤ ω̂ ≤ π,
corresponding to a range of apparent frequencies in the physical world of 0 ≤ ω 0 ≤ ωs /2
(or 0 ≤ f 0 ≤ fs /2). Any frequency in the original signal above fs /2 will be aliased into the
Step 1.4 Sample this signal at 25Hz and use the discreteplot function to plot the sam-
pled signal in the middle. Sample it at 15Hz and similarly plot that sampled signal at the
bottom.
Step 1.5 Before examining the plots in detail, answer the following questions: For each
of the two sampling frequencies, what is the range of apparent frequencies that can be
represented? For each, will a sinusoid with f = 10Hz be aliased? If so, what will be the
digital frequency and the apparent frequency of a 10Hz sinusoid?
Step 1.6 Examine the plots and count the number of up-and-down cycles in each. Don’t
worry that each cycle doesn’t look the same, or that every other cycle seems different; just
count each. You should see 10 cycles in the top graph; how many do you see in the middle
and bottom? How does this compare to the theory you discussed in the previous step? If
there is any discrepancy, explain it.
Step 2.1 Write a Matlab function that compares two signals by computing the signal to
noise ratio (SNR) that results from changing one into the other (by quantization). Your
function should do this by first computing root mean squared (RMS) error between the two.
In this case, you will be comparing a sampled signal with a quantized version of it. To do
this, you should subtract the quantized signal from the sampled signal to produce a vector
of differences (errors), then square each difference value using the MATLAB .^ operator (to
Step 2.2 Use your code to compute the SNR for a quantized sinusoid. Generate an analog
signal with with a range of 0 to 5, frequency of 10Hz, and duration 2sec. Sample it at 25Hz.
Use 2, 4, 8, 12, and 16 bits quantization, and plot SNR on the Y-axis versus number of
quantization bits on the X-axis.
Step 2.3 Repeat Step 2.2 using a square waveform with the same parameters.
Step 2.4 Repeat Step 2.2 using a triangle waveform with the same parameters.
Step 2.5 As you double the number of bits used in quantization, how does the SNR change?
How does this compare to what your learned from the textbook? Refer to specific features
of your plots from Steps 2.2–2.4 to justify your answer.
Y = H(z)X
M
X
H(z) = bk z −k
k=0
| {z }
transfer function
Y = H(ω̂)X
M
X
H(ej ω̂ ) = H(ω̂) = bk e−j ω̂k
k=0
| {z }
frequency response
In these equations, x[n] and y[n] are the nth samples from the input and output, respec-
tively, while X and Y represent the entire input and output signal (all of the samples in
the signal). A k-sample time delay of a signal is produced by multiplication by the delay
operator, z −1 = e−j ω̂k . In all three cases (but most simply for the transfer function), we can
obtain insight into the filter’s operation from the coefficients, bk . We can do this by factoring
the transfer function polynomial: its roots are the zeros of the filter and they can be real
or complex. The placement of the zeros in the complex plane (most usefully expressed in
polar coordinates) will tell us which frequencies are suppressed and to what extent those
frequencies are suppressed (we can calculate each using the angle and magnitude of the zero,
respectively).
Matlab has a modest set of functions related to filtering (a much more substantial set of
tools comes along with the Matlab Signal Processing Toolbox, but we will confine ourselves
This allows us to define the bk coefficients for a filter and provide them to the filter function
as a vector so that it can filter the input signal.
We’d also like to specify a feedforward filter by indicating its zero locations, which we
can do by using the poly function to compute the coefficients from a set of roots. So, for
example, if we want a feedforward filter with zeros at 0.9+0j and 0.75e±jπ/4 , we can compute
the bk values as:
r = [ (0.9 + 0.0*j) (0.75*exp(j*pi/4)) (0.75*exp(−j*pi/4))];
b = poly(r);
a = [1];
y = filter(b, a, x);
(Where the definition of r is written a bit more verbosely than it has to be.) Note that, from
the documentation for poly, the vector of coefficients it produces are ordered from highest
to lowest powers; this corresponds to the same order as the coefficients in the b vector, after
dividing by z −M , the highest delay term.
You can visualize the zero locations with the following code:
plot(complex(r), 'o')
rectangle('Position', [−1 −1 2 2], 'Curvature', [1 1])
line([−1 1], [0 0], 'Color', [0 0 0])
line([0 0], [−1 1], 'Color', [0 0 0])
axis equal
Here, we use the unfortunately named rectangle function to draw the unit circle and the
line function to draw the real and imaginary axes. Note also that we have to make sure
that the value of r that we pass to the plot() function is complex (since we want to plot it
on the complex plane) using the complex() function, because the roots of a polynomial can
be real.
Finally, you can compute and plot the magnitude of the filter’s frequency response pretty
directly in Matlab:
omegahat = [0: 0.01: pi]; % define the frequency axis
z = exp(j*omegahat); % define the complex frequency axis
H = polyval(b, z); % evaluate the transfer function polynomial
plot(omegahat, 20*log10(abs(H)/max(abs(H))));
xlabel('$\hat{\omega}$, radians','Interpreter', 'latex');
ylabel('$|\mathcal{H}(\hat{\omega})|$, dB','Interpreter', 'latex')
You’ll note that the code above plots the ratio of the magnitude of the frequency response
to the maximum value of that magnitude. This is done because it is convention to ignore
At this point, we can rewrite the transfer function as the filter’s generating equation, using
the delay operator z −k , y[n] = x[n] − 2r cos(ω0 )x[n − 1] + r2 x[n − 2]. This allows us to read
off the filter coefficients: b0 = 1, b1 = −2r cos(ω0 ), and b2 = r2 .
c. Find and sketch the zero locations using pencil and paper, then use Matlab to verify
this.
d. From the plot of zero locations, sketch the magnitude of the frequency response as
a function of ω̂ by hand and verify this using Matlab. How does the minimum of
the magnitude of the frequency response relate to the polar representation of the zero
locations? What kind of filter would you say this is?
b. Derive the transfer function, H(z), for this filter. From this, determine the expression
for the frequency response, H(ω̂) = H(ej ω̂ ).
c. From the transfer function, determine the filter’s zero locations and sketch them. Check
your results with Matlab.
Step 1.3 Just as we can compute a discrete first derivative with a first-difference filter, we
can compute a discrete second derivative with a second difference filter.
a. Use your expression for the transfer function of the first difference filter and your
knowledge that the combined transfer function of two filters cascaded, or connected in
series, is the product of their individual transfer functions to determine the transfer
function for a second-difference filter.
b. Draw a block diagram for this filter.
c. Determine the filter’s zero locations and sketch them. Check your results using Matlab.
d. From the zero plot, sketch the magnitude of the filter’s frequency response as a function
of ω̂. Use Matlab to check your results. What kind of filter would you say this is?
Step 1.4 Consider a feedforward filter with complex conjugate zeros at z1,2 = −0.5 ± j0.5.
Step 2.2 In one of the self-test exercises in the textbook, two filters with transfer functions
H1 (z) = b0 + b1 z −1 and H2 (z) = b00 + b01 z −1 were connected in series, and it was shown that
they could be connected in either order to produce the same composite effect (the same
overall transfer function). Redo this exercise using the defining equations for the two filters,
i.e., y1 [n] = F1 (x[n]) for the filter with transfer function H1 (z) and y2 [n] = F2 (x[n]) for the
filter with transfer function H2 (z). In other words, show that F2 (F1 (x[n])) = F1 (F2 (x[n])).
Step 2.3 Use Matlab to implement a 50% duty cycle square wave with amplitude 1,
frequency 2Hz, and duration 1s. Sample and quantize it appropriately (to make your figures
look nicer, feel free to chose a sampling rate much higher than the minimum). Send the
resultant digital signal through the previously-defined three-point averager filter, and then
the output of that filter through the first difference filter. Plot the input and output. What
does the output of this combined filter look like?
Step 2.4 Now, switch the order you apply the filters so that the first difference filter is first
and the three-point averager is second. Plot the input and output. How does the output
of this configuration compare to that of the preceding step? Does this match what you
expected? Why or why not?
With this definition lets investigate a feed forward filter with ten coefficients, {b0 , b1 , · · · , b9 }.
Recall that the Matlab filter function allows us to specify a filter in terms of its coefficients,
but we can also think of it as being defined in terms of its transfer function. Considering the
bk coefficients of the above feed forward filter, the filter function implements the transfer
function:
X 9
H(z) = bk z −k (16)
k=0
In previous labs we have computed the transfer function using the delays of the defining
function. Mathematically, we were actually taking the z-transform of the impulse response!
In this example, the impulse response is:
9
X
h[n] = bk δ[n − k] (17)
k=0
where δ[k] is the unit impulse and only has a non-zero value at k = n. H(z) and h[n] form
z
a z-transform pair, h[n] ←
→ H(z). It should now be obvious why feedforward filters are also
known as finite impulse response filters — their impulse response only has a finite number
of values. To compute the output, y[n], using the impulse response we use convolution.
Namely, we convolve the input, x[n], by the impulse response, h[n],
9
X
y[n] = x[n] ∗ h[n] = x[k]h[n − k] (18)
k=0
And, indeed, Matlab has a conv function to do this convolution. Alternatively, we can
compute a filter’s output by multiplying the transfer function by the z-transform of the
input to yield the z-transform of the output:
4.2 Z-Transforms
Step 1.1 On paper, compute the z-transform, X(z), of
(−1)n n ≥ 0
x[n] = (20)
0 n<0
Note that this is an infinite geometric series. What are the locations of any pole(s) (roots of
the denominator polynomial) or zero(s) (roots of the numerator polynomial)?
Step 1.2 Evaluate the frequency response of X(z) from step 1.1, X(z)z=ejω̂ , by sketching
Step 2.2 What is the output sequence of the filter of Step 2.1 when the input is x[n] = δ[n]?
Verify this using Matlab.
Step 2.3 The impulse response of a filter is h[n] = δ[n] + 2δ[n − 1] + δ[n − 2] − δ[n − 3],
or equivalently, h[n] = {1, 2, 1, −1}, n = {0, 1, 2, 3}. Determine the response of the system
to the input signal x[n] = {1, 2, 3, 1}, n = {0, 1, 2, 3} by hand. Use Matlab to check your
results. Include a figure that shows both the input and output signals; make sure the reader
can clearly see what the signal values are (the stem plot function should help to ensure this
is the case).
Step 2.4 Change the input to the filter of Step 2.3 to be δ[n]. What are the output values?
How do they compare to the impulse response? Include plots of the filter input and output
values in your report.
Step 2.6 Create your own Matlab function, convolution, to implement a convolution
function. To test your function, make sure it works exactly like the Matlab conv and filter
functions by providing the same input to each and subtracting their outputs. Use the filter
{1/3, 1/3, 1/3}, n = {0, 1, 2} from step 2.5.
Step 3.1 Plot the frequency response for this filter. What are the zero locations?
Step 3.2 Use as an input to this filter the signal x[n] = sin ω̂n, using the two frequencies
ω̂ = π/2 and ω̂ = π/4. You will need to choose appropriate analog signals, with convenient
frequencies and durations, and then sample them appropriately so they have the correct
digital frequencies. Make sure to verify that you get the correct digital frequencies and that
plots you make are convenient for the reader (for example, neither too many nor too few
cycles)! Compute the filter in Matlab for each of these two inputs, plotting the input and
output of each. When do you get cancellation?
Step 3.3 Can you modify the filter coefficients to cancel the other sinusoid? If so, show
your work.
The coefficients used by filter, rather than being the a` from the defining equation (25)
are the negative a` from the transfer function (29) — the ratio of two polynomials. In other
words, to properly compute the above filter in Matlab, you will need to use:
a = [1.0 −a1 −a2];
b = [b0];
y = filter(b, a, x);
Note also that in this example the filter includes the a[0] coefficient (of course, per Mat-
lab one-based indices, as a(1)), which we will always leave as 1.0 (it’s the first “1” in the
denominator of the transfer function).
And finally, note that one form of the filter function takes a fourth argument, which
is the initial conditions for the feedback delays (used in computing the output values that
have delay terms which come before the first value in the x vector). These default to all zero
if not specified.
and we will get the Fibonacci sequence if we input an impulse (hence, the appearance of
the x[n] on the right hand side, which serves only to initialize the filter). In Matlab, this
can be done trivially by taking a vector of all zeros — let’s call this vector x — and setting
its first value only (x(1)) to C. This is also a very good demonstration of the first “I” in the
acronym “IIR”: the impulse response of this filter has infinite duration.
Step 1.1 If we set x[n] = δ[n] in (31), we should see that the impulse response of this filter
is indeed the Fibonacci sequence. Implement this filter in Matlab and verify that its impulse
response is the Fibonacci sequence. What are the values of the coefficients that you used?
Step 1.4 Let’s do something similar with the recurrence relation for computing the series
y[n] = 1/3n in the text (as always, remember that Matlab indices start at 1). Set the
coefficients for a feedback filter to implement equation (5-43) in the text, y[n] = 1/3y[n −
1] + x[n]. What are the filter coefficients?
Step 1.5 What are the pole location(s) for this filter?
Step 1.6 Now use Matlab to calculate the impulse repsonse. Set the amplitude of the
input impulse to be 0.99996. Is this filter stable? Is its impulse response consistent with the
result of iterating equation (5-42) in the notes?
The frequencies in the table above were chosen to avoid harmonics. No frequency is a
multiple of another, the difference between any two frequencies does not equal any of the
frequencies, and the sum of any two frequencies does not equal any of the frequencies.1 This
makes it easier to detect exactly which tones are present in the dial signal in the presence of
line distortions.
It is possible to decode such a signal by first using a filter bank composed of seven
bandpass filters, one for each of the frequencies above. When a button is pressed, it will
produce a combination of two tones, and thus, at the decoder end, two of the bandpass
filters will produce significantly higher outputs than the others. A good measure of the
output levels is the average power at the filter outputs. This is calculated by squaring the
filter outputs and averaging over a short time interval.
Step 2.1 First of all, please write a Matlab DTMFCoder function. This function should take
in one argument — a telephone key number — and return a digital waveform containing
the appropriate summed tones. Internally, it should do this by generating AnalogSignals,
summing them, and then sampling them at 8kHz and quantizing them at 16 bits. DTMF
signal duration should be 1s. For each of the seven tone frequencies in Hz, what is the
corresponding digital frequency in the range [0, π]?
Step 2.2 In this step, please construct a bandpass filter for the 697Hz tone. Use a feedback
filter with complex conjugate poles. Locate these complex conjugate poles at the correct
location for ±697Hz. Use equation (5-38) of section 5.1.4 of the text to set the radius of
those poles so that the closest other tone frequency, 770Hz, lies outside the passband (in
other words, to set the bandwidth so that it is significantly smaller than twice the difference
between 697Hz and 770Hz). What were your pole locations?
Compute the corresponding filter coefficients. You can verify your filter performance by
plotting its frequency response.
Verify that the filter output for DTMFCoder output for keys 1, 2, and 3 are pretty much
identical, and that all other buttons produce much lower amplitude output. In your report,
include a plot of the filter output for one of the buttons 1, 2, or 3 and a plot for one of the
buttons 4, 5, or 6.
Step 2.3 Now we are ready to decide whether a particular frequency is present. Write a
Matlab RMS function that takes a vector as input and returns a scalar root mean squared
value for it — this function should square each value of the vector, take the mean of those
1
More information can be found at: http://en.wikipedia.org/wiki/DTMF
Step 2.4 Now we will assemble a filter bank. Implement filters in Matlab for each of the
six other DTMF frequencies and verify that they work as expected. Now, write a Matlab
function DTMFDecoder that takes a single input — a vector (for which you will use the
DTMFCoder output). DTMFDecoder should compute the RMS value of the output of each of
the seven filters in the filter bank. It should output (to the Matlab console) these RMS
values, and then detect the two highest values. It should use a lookup table or equivalent
logic to decode which button was “pressed,” and output (to the Matlab console) that button.
The order of the implementation is O(N ) = N 2 . The following Java code outlines imple-
mentation of a 256-point DFT. It is written without any algorithmic speedup (i.e., it exactly
mirrors equation 32).
public class MyDFT
{
// x is the input and y is the magnitude of the complex DFT
public void computeDFT(double[] x, double[] y)
{
double[] yImag = new double[256];
double[] yReal = new double[256];
Step 1.1 Implement your own myFFT function in Matlab that takes a real-valued vector as
input, computes a 256-point FFT, and returns a real-valued vector that is the magnitude of
the (single-sided, i.e., only positive frequencies) FFT. Implement this function using loops
(i.e., do not use recursion). The first part of this code performs a bit reversal on the input
array. You can use the following code to perform the bit reversal efficiently (efficient bit
reversal algorithms in other languages are typically more complex):
% Assume that you want to do a bit reversal of the contents of the vector x
indices = [0 : length(x)−1]; % binary indices need to start at zero
revIndices = bin2dec(fliplr(dec2bin(indices, 8))); % bit reversed indices
revX = x(revIndices+1); % Add 1 to get Matlab indices
This code converts the vector of in-order indices to an array of 8-character strings (repre-
senting those indices as binary 8-bit numbers). Each string is then reversed, and converted
back to numbers. The resultant vector of indices (which is what they are after we add one
to each) is applied to the signal to pull its entries out into a new vector, with the order of
the entries in bit-reversed order.
Once you’ve done this, all you need to do is iterate over the array log2 N times! Remember
that you’re performing complex arithmetic and to compute the magnitude of the output array
once the FFT is computed. Include a copy of your Matlab code in your report.
Step 1.2 Check your results using the Matlab fft function. Your results should be quite
similar, if not identical; this should be apparent by comparing graphs of the outputs. Take the
FFT of a sinusoid with a frequency of π/4 radians per second using your FFT implementation
and the fft function.
Step 1.3 Prove that the number of complex multiplies performed by your code is O(N log N ).
Step 2.2 At what index (or indices) does the FFT magnitude reach its peak value(s)?
What frequency (or frequencies) does this correspond to?
Step 2.3 Change the frequencies of the sinusoids to 0.13π and 0.14π. Repeat steps 2.1
and 2.2. Do the results still make sense?
Step 2.4 Replace the sum of two sinusoids with your DTMFCoder function from lab 6. Input
a selection of button values. Do the FFT function and plot show the separate frequencies
for each button?
6.5 Spectrograms
Comparing FFT graphs (as in the step 2.4 above) can be difficult to do. But what if we
could analyze the frequency content of a signal as a function of time? That would make it
easier to see differences in frequency if a signal started changing (like a string of DTMF keys
pressed in turn). To do this we will need a new tool called the Spectrogram. The spectrogram
is simply an algorithm for computing the FFT of a signal at different times and plotting
them as a function of time. The spectrogram is computed in the following way:
1. A given signal is “windowed.” This means that we only take a certain number of points
from the signal (for this example assume we are using a window of length 128 points).
To start out, we take the first 128 points of the signal (points 1 through 128 of the
input vector).
2. Take the FFT of the window and save the it in a separate array.
3. Advance the window in time by a certain number of points. For instance we can
advance the window by 64 points so that we now have a window of indices 65 through
192 from the input signal array.
4. Repeat steps 1–3, saving the FFT of each window, until there are no longer any points
in the input array.
The result is called a spectrogram and is usually displayed as an RGB image where
blue represents small FFT magnitudes and red represents larger FFT magnitudes (the Jet
colormap if you are familiar with color visualizations). There is an art to choosing the correct
parameters of the spectrogram (i.e., window size, FFT size, how many points to advance
the FFT, etc.). Each parameter has tradeoffs for the time and frequency resolution of the
resulting spectrogram. For our purposes here, we will not be concerned with these tradeoffs.
Instead we will be more interested in getting familiar with analysis using spectrograms.
The Matlab Signal Processing Toolbox has a spectrogram function, but you can re-
trieve a drop-in replacement for it from http://www.ee.columbia.edu/ln/rosa/matlab/
sgram/ that will work without that toolbox. See the online Matlab documentation for the
spectrogram function to understand what the parameters to that function are (though, for
our purposes, you should just be able to use the call y = myspecgram(x).
Step 3.1 Use your DTMFCoder function again. Instead of computing its FFT, compute
its spectrogram instead. What does the spectrogram look like for button 1? Are both
frequencies present?
Step 3.2 For this step, use DTMFCoder to generate the codes for multiple buttons — at
least three — and concatenate them together to form a single vector. Does the spectrogram
make it easier to judge the frequency content of the keys? Can you clearly see when the
signal changes from one key to another?
audiorecorder Perform real-time audio capture. This may or may not work on your system;
it is critically dependent on your hardware and MATLAB’s support thereof. You may
find it simpler to record and edit audio files with other software and then save it to a
file later read into Matlab; this might give you greater control over the recording.
audioinfo Get information about an audio file, including number of channels, how com-
pressed, sampling rate, bits per sample, etc.
audioread Read part or all of an audio file, returning sampled data and sampling rate.
audiowrite Write an audio file; the format is indicated by the filename provided. All
platforms support wav, .ogg, and .flac; Windows and OS X support .m4a and .mp4,
too.
sound Play vector as a sound. This allows you to create arbitrary waveforms mathemati-
cally (e.g., individual sinusoids, sums of sinusoids) and then play them through your
speakers. This is the function to use if you’re values are scaled within the range of -1
to +1.
soundsc This function works like sound, but first it scales the vector values to fall within
the range of -1 to +1. Much of the time, you won’t have your waveforms pre-scaled,
and you’ll use this function.
imfinfo Provides information about an image file, including dimensions, bit depth, etc.
imread Read image from graphics file. This function (and imwrite) supports many file
types.
image Display image. The image is displayed within normal Matlab axes, which you can
label or otherwise modify as usual. Any 2D array can be displayed as an image (for
example, this is what’s done with the output of myspecgram). You can alter the
colormap used for this display, if you like. There are other functions that plot 2D data
as wire meshes and surfaces.
imagesc Like image, but scales the image values first so that they span the full range of
the current colormap.
The (color) image is read into A, which, as you can see from the output of the whos command,
is a 100x55x3 unsigned, 8-bit integer array (the third dimension for the red, green, and blue
image color components). I convert the image to gray-scale by taking the mean of the
three colors at each pixel (the overall brightness), producing a B array that is double. The
imagesc function displays the image, the colormap function determines how the array values
translate into screen colors, and the axis equal command ensures that the pixels will be
square on the screen.
Much of the time, we will just perform our calculations using double data types. However,
we can use functions like uint8 to convert our data.
At the very least, you can get real audio files from http://faculty.washington.edu/
stiber/pubs/Signal-Computing/; I assume that you’ll have no trouble locating interesting
images (please keep your work G-rated). Don’t use ones that are too big, to avoid issues
with Canvas uploads of large lab report files.
Step 1.1 Write a MATLAB script to read an image in, convert it to gray-scale if the image
array is 3-D, and scale the image values so they are in the range [1, 255] (note the absence of
zero). Verify that this has worked by using the min and max functions. Convert the results
to uint8 and display each using imagesc.
Step 1.2 At this point, you should have in each case a 2-D array with values in the range
[1, 255] inclusive. To simplify matters, we will treat each array as though it were one-
dimensional. This is easy in MATLAB, as we can index a 2-D array with a single index
ranging from 1 to N × M (the array size). Write a RLE function that takes in a 2-D array
and scans it for runs of pixels with the same value, producing a RLE vector on its output.
When fewer than four pixels in a row have the same value, they should just appear in the
vector. When four or more (up to 255) pixels in a row have the same value, they should be
replaced with three vector elements: a zero (indicating that the next two elements are a run
code, rather than ordinary pixel values), a count (should contain 4 to 255), and the pixel
value for the run. Verify that your RLE function works by implementing a RLD function
(RLE decoder) that takes in a RLE vector, N , and M and outputs a 2-D N × M array.
The RLD output should be identical to the RLE input (subtracting them should produce an
array of zeros); verify that this is the case. For each image type, compute the compression
factor by dividing the number of elements in the RLE vector by the number of elements in
the original array. What compression factors do you get for each image?
Step 2.1 Find a sound to work with; you can use http://faculty.washington.edu/
stiber/pubs/Signal-Computing/amoriole2.mat if you like. Likely, it will have values
that are not integers; convert the values to 16-bit integer values by scaling (to [0, 216 − 1])
and rounding (reminder: the vector’s type will still be double; we’re just changing the values
Step 2.2 Now write a DPCM function, DPCM, that takes the sound vector and the number
of bits for each difference and outputs a DPCM-coded vector. Note that the MATLAB diff
function will compute the differences between sequential elements of a vector. Your DPCM
function should:
2. limit each difference value to be in the range [−2bits−1 − 1, 2bits−1 − 1], producing
a quantized vector and a vector of “residues” (you will generate two vectors). For
each quantized difference, the “residues” vector will be zero if the difference, ∆xi , is
within the above range. Otherwise, it will contain the amount that ∆xi exceeds that
range (i.e., the difference between ∆xi and its quantized value, either −2bits−1 − 1 or
2bits−1 − 1).
3. “make up for” each nonzero value in the “residues” vector. For each such value, scan
the quantized difference vector from that index onward, and modify its entries, up to
the quantization limits above, until all of the residue has been “used up”.
4. The final result is a single coded vector that your function should return.
For example, let’s say that we’re using 4 bit DPCM and that some sequence of differences
is (∆x1 = 10, ∆x2 = 5, ∆x3 = −3). The range of quantized differences is [−7, +7], and so
the quantized differences are (7, 5, −3) and the residues are (3, 0, 0). Since the first residue
is nonzero, we proceed to modify quantized differences starting with the second one, until
we’ve added three to them. The resulting final quantized differences are (7, 7, −2).
Step 2.3 Implement an inverse DPCM function IDPCM that takes the first value from the
original sound vector and the DPCM vector and returns a decoded sound vector. There’s
no way for us to know where the losses in the encoding occurred, so we just use the DPCM
values as differences. Note that the MATLAB cumsum function computes a vector with
elements being the cumulative sum of the elements of its input vector, and that you can add
a constant to all of the elements of a vector using the normal addition operator.
Step 2.4 Test your DPCM and IDPCM functions by coding your sound using 15, 14, 12,
and 10 bit differences. At what point does the coding process produce noticeable degrada-
tion? To investigate further, see how few bits you can use to encode the sound and still
detect some aspect of the original sound. Is this surprising to you?
Step 3.2 Use ifft2() to convert the FFT back and plot the result versus the original
gray-scale image (use imagesc()) to check that everything is working fine. Analyze the
difference between the two images (i.e., actually subtract them) to satisfy yourself that any
changes are merely small errors attributable to finite machine precision). Repeat this process
for the other images.
Step 3.3 Let’s quantize the image’s spectral content. First, find the number of zero ele-
ments in the FFT, using something like origZero=length(find(abs(origX)==0));, where
origX is the FFT. Remember to exclude the DC value in the fft2 output in figuring out
this range. Then, zero out additional frequency components by zeroing out all with mag-
nitudes below some threshold. You’ll want to set the threshold somewhere between the
min and max magnitudes of origX, which you can get as mn=min(min(abs(origX))); and
mx=max(max(abs(origX)));. Let’s make four tests, with thresholds 5%, 10%, 20%, and
50% of the way between the min and max, i.e., th=0.05*(mx-mn)+mn;. Zero out all FFT
values below the threshold using something like:
compX = origX;
compX(abs(origX)<th) = 0; % Uses logical array indexing
You can count the number of elements thresholded by finding the number of zero elements
in compX at this point and subtracting the number that were originally zero (i.e., origZero).
This is an estimate of the amount the image could be compressed with an entropy coder.
Express the number of thresholded elements as a fraction of the total number of pixels in
the original image and make a table or plot of this value versus threshold level.
Optional. Note that the FFT may have very high values for just a few elements, and low
values for others. You might plot a histogram to verify this. Not including the DC value
likely will eliminate the highest value in the FFT. However, some of the other values may
still be large enough to produce too large of a range. Can you suggest an approach that will
take this into account? How does the JPEG algorithm deal with or avoid this problem?