ECE 132A: Lab 2
Due: Wednesday, February 18, 2026 at 11:59 PM via Gradescope
Throughout this lab and future ones, you may reference the tutorial on this page as needed.
- Create essential functions for digital communication in Python.
- Visualize a raised cosine pulse shape for various rolloff factors.
- Generate a complex baseband transmit signal using a raised cosine pulse shape.
- Visualize the generated complex baseband signal for various rolloff factors.
- Transmit a pulse-shaped signal and receive a near-perfect copy.
- Plot the FFT of the received signal and draw observations.
Part I: Creating Some Essential Functions
Let us begin by creating some essential functions that you will use throughout this lab and future ones.
To house these functions, create a Python file ece132a.py that will serve as a Python module (library) of all the functions developed in this lab and future ones.
This module and its functions can be imported into a main script (e.g., main.py) by placing the following at the top of your script.
from ece132a import *Now, within ece132a.py, create implementations of the following functions.
You should exercise a certain degree of creative liberty in these implementations, especially where you feel the provided instructions are open-ended.
A. Generate Random QAM Symbols
Create the following function which generates N random symbols from a square M-QAM constellation that is normalized to unit average symbol energy.
symbols, constellation = gen_rand_qam_symbols(N, M=4)- Inputs:
N: Number of random symbols to generate.M: Order of the QAM constellation (e.g., 4 for QPSK, 16 for 16-QAM).
- Outputs:
symbols:Nrandomly selectedM-QAM symbols.constellation: The fullM-QAM constellation.
B. Create Pulse Train
Create the following function which forms a pulse train from a sequence of symbols by inserting zeros between the symbols.
pulse_train = create_pulse_train(symbols, sps)- Inputs:
symbols: A sequence of symbols.sps: Samples per symbol, i.e., the number of discrete-time samples from one symbol to the next.
- Output:
pulse_train: A discrete-time signal where each symbol is separated by (sps-1) zeros.
- Note:
- The zeroth element of the output pulse train should be the zeroth symbol (not a zero).
C. Generate Raised Cosine Pulse
Create the following function which generates a raised cosine pulse shape.
pulse = get_rc_pulse(beta, span, sps)- Inputs:
beta: Rolloff factor (between 0 and 1, inclusive).span: The integer number of symbols spanned by the pulse, not including the symbol at .sps: Samples per symbol, as defined previously.
- Output:
pulse: A truncated raised cosine pulse, symmetric and centered at . The number of zero crossings should be equal tospan. The pulse should be normalized such that its energy is equal to one.
Part II: Perform Pulse Shaping
With the functions of Part I created, let us now visualize some of their outputs and, eventually, the pulse-shaped transmit signal. To begin, generate 200 random QPSK symbols. Then, create a list of rolloff factors as follows.
beta_list = [0.0, 0.25, 0.5, 0.75, 1.0]In the following, wherever you generate a plot, include it in your lab report.
You can export plots using Matplotlib’s plt.savefig(filename) in formats like .pdf, .svg, etc.
A. Visualize the QPSK Constellation
Plot the QPSK constellation on the complex plane.
B. Visualize the Pulse Shape for Various Rolloff Factors
On a single figure, plot the raised cosine pulse shape for different values of the rolloff factor .
In doing so, use a span of span = 8 symbols and sps = 10 samples per symbol.
Put small dot markers at each point in the pulse shape, so that you can clearly see its values.
Be sure to include a legend indicating each value of .
C. Visualize the Pulse Train of Symbols
Create a pulse train from the generated QPSK symbols using sps = 10.
Then, plot the real and imaginary components of the generated pulse train.
You should plot the real and imaginary components on two subplots within the same figure.
D. Generate and Visualize the Pulse-Shaped Transmit Signal
For each rolloff factor , generate the pulse-shaped transmit signal (i.e., ) using your randomly generated QPSK symbols and your pulse shape.
Plot the real and imaginary parts of on separate subplots, and when doing so, divide by the peak value of the pulse shape.
You can have one figure per or you can plot them atop one another.
Confirm there is no inter-symbol interference by placing a dot marker at points corresponding to the symbol instances, i.e., where the receiver should sample to recover the symbol.
Part III: Compare the FFT for Various Rolloff Factors
For each rolloff factor , complete the following.
Transmit the pulse-shaped transmit signal (using a cyclic transmit buffer) from any of the Pluto SDRs connected to the RemoteRF Platform using sdr.tx().
Then, on the same Pluto SDR, fetch a capture of received samples using sdr.rx().
Take the FFT of the (entire) received signal; a default FFT size should be suitable.
On a single figure, overlay all FFTs atop one another in dB scale, i.e., your y-axis should be , where is the FFT of the received signal evaluated at frequency . The lines should be overlaid so that is in increasing order.
Now, on another figure, repeat this with the lines overlaid so that is in decreasing order.
From these two plots, what observations can you make about the spectrum and how it varies with the rolloff factor ? Perhaps you can play around with the span of the pulse shape to see the effects of truncation.