This directory contains several scripts based on gnuradio and custom python code to generate, transmit, receive and decode a 2x2 single-carrier MIMO waveform.
These scripts can either use a simulated channel, use two USRP x3x0 as transmitter and receiver, or use an IQ trace captured by a TSMW.
The MIMO waveform requires a patched version of gnuradio for the frequency and timing clock recovery blocks
generate_symbols.py
: creates a series measurement symbols (should be eventually replaced by custom gnuradio modules)generate_waveform.py
: creates a pulse-shaped waveform (e.g. upsampled); can take a binary file of symbols as input or use a BPSK/QPSK constellationtransmit_waveform_synthetic_channel.py
: simulates a (baseband) channel; takes the output ofgenerate_waveform.py
transmit_symbols_synthetic_channel.py
: combine pulse-shaping and baseband channel. Designed to directly take output fromgenerate_symbols.py
.transmit_symbols_x300.py
: transmits symbol sequences generated bygenerate_symbols.py
. Does not take input fromgenerate_waveform.py
.receive_waveform.py
: receives a waveform (generated viagenerate_waveform.py
,transmit_waveform_synthetic_channel.py
or from a USRP); can directly decode BPSK/QPSK symbols or write the symbols to a binary file; performs frequency and timing recoveryreceive_symbols.py
: performs frame recovery, channel estimation and symbol decoding
For the frequency offset and timing offset compensation, it is critical to bring the input signal at a reasonable level. Therefore some level of gain control is necessary, whether this is automatic or manual.
By default, the first stream uses pilot ID -1 and the second stream uses pilot ID -2 (or 15, 14, respectively). This example decodes each stream independently
./generate_symbols.py -r 7 -m 2
./generate_waveform.py -l measurement_symbols_0.bin -i 0 && ./generate_waveform.py -l measurement_symbols_1.bin -i 1
./transmit_waveform_synthetic_channel.py -m -f 0.2 s_pulse_shaped_signal_sps4_0.bin s_pulse_shaped_signal_sps4_1.bin
./receive_Nx2_waveform.py -f rx_channel_s_pulse_shaped_signal_sps4_0.bin rx_channel_s_pulse_shaped_signal_sps4_1.bin --to-file rx_0.bin rx_1.bin
./receive_symbols.py rx_0.bin --sync -c -i -1 -2
./receive_symbols.py rx_1.bin --sync -c -i -2 -1
Only the steps different from the previous example are shown: this example clearly shows the canonical 2x2 MIMO channel matrix used in transmit_waveform_synthetic_channel.py
./transmit_waveform_synthetic_channel.py -m s_pulse_shaped_signal_sps4_0.bin s_pulse_shaped_signal_sps4_1.bin
./receive_Nx2_waveform.py rx_channel_s_pulse_shaped_signal_sps4_0.bin rx_channel_s_pulse_shaped_signal_sps4_1.bin --to-file rx_0.bin rx_1.bin
./receive_symbols.py rx_0.bin rx_1.bin --sync -c -i -1 -2
The system will break with a noise voltage reaching 0.5. With a noise voltage of 0.25, frame synchronization can function successfully.
./transmit_waveform_synthetic_channel.py -m -f 0.2 -t 1.01 -v 0.1 s_pulse_shaped_signal_sps4_0.bin s_pulse_shaped_signal_sps4_1.bin
./receive_Nx2_waveform.py -f rx_channel_s_pulse_shaped_signal_sps4_0.bin rx_channel_s_pulse_shaped_signal_sps4_1.bin --to-file rx_0.bin rx_1.bin --plot-offset-correction
./receive_symbols.py rx_0.bin rx_1.bin --sync -c -i -1 -2
Here is another example that allows for bypassing generate_waveform.py
./generate_symbols.py -r 7 -m 2
./transmit_symbols_synthetic_channel.py measurement_symbols_0.bin measurement_symbols_1.bin -m -f 0.2 -t 1.0001 -v 0.1
./receive_Nx2_waveform.py -f rx_channel_sps4_measurement_symbols_0.bin rx_channel_sps4_measurement_symbols_1.bin --to-file rx_0.bin rx_1.bin --plot-offset-correction
./receive_symbols.py rx_0.bin rx_1.bin --sync -c -i -1 -2
In this case, generate_symbols.py
is first used to generate symbol sequences. Pulse-shaping is then performed directly before transmission with the x300/x310.
./generate_symbols.py -r 7 -m 2
- TBD
The workflow needs to convert the samples captured with the TSMW to a binary file that can be loaded into gnuradio for processing with receive_Nx2_waveform.py
. For instance, using the read_stream_iq_trace.py
utility (this assumes that samples were captured with stream_iq.exe
and converted via extract_iq.exe
):
NUM=5 && ./read_stream_iq_trace.py -a ~/host/20150610_outdoor_test/iq_data_"$NUM".bin_channel_0.dat ~/host/20150610_outdoor_test/iq_data_"$NUM".bin_channel_1.dat --to-file ../../../sdr-utils.git/gnuradio/mimo_single_carrier_waveform/rx_samples_0.bin ../../../sdr-utils.git/gnuradio/mimo_single_carrier_waveform/rx_samples_1.bin --plot_spectral --gain 30 && echo $NUM