ECE 230B: Lab 2
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 ece230b.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 your main script (e.g., main.py) using the following.
from ece230b import *Now, within ece230b.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 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: The QAM symbols from above.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 symbol durations spanned by the pulse, not including the symbol at .sps: Samples per symbol.
- Output:
pulse: A raised cosine pulse (normalized such that its peak value is unity), symmetric and centered at . The number of zero crossings should be equal tospan.
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.
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 on separate subplots.
You should have one figure per .
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 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.