# AFF3CT based DVB-S2 benchmark example This tutorial runs a DVB-S2 transmission between two nodes in CorteXlab. It uses the [[https://github.com/aff3ct/dvbs2|DVB-S2 SDR Transciever]] developed as part of the [[https://github.com/aff3ct/aff3ct|AFF3CT]] project. It is mostly used as a way to demonstrate that it is possible to run AFF3CT based projects in CorteXlab. But can also be a starting example to run more advanced experiments. ## The docker image A docker image containing all the pre-built components is available at `ghcr.io/notou/dvbs2:0.1`, from [[https://github.com/Notou/dvbs2|this repo]] The rest of this section is intended for those curious about what is in this image. It is not necessary for the execution of the tutorial. ---- The image is build from the following [[https://github.com/Notou/dvbs2/blob/cxlb/docker/deploy_imag_0.1/Dockerfile|Dockerfile]]. ``` FROM m1mbert/cxlb-gnuradio-3.10:1.2 SHELL [ "/bin/bash", "-lc" ] RUN git clone -b cxlb https://github.com/Notou/dvbs2.git RUN cd dvbs2 && git submodule update --init --recursive --remote RUN cd dvbs2 && mkdir build RUN cd dvbs2/build && cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-Wall -funroll-loops -msse4.1" -DAFF3CT_LINK_HWLOC=OFF -DAFF3CT_OVERRIDE_VERSION=0.1.0 -DCMAKE_INSTALL_PREFIX=/cortexlab/toolchains/current .. RUN cd dvbs2/build && make install -j$(nproc) && ldconfig ``` It thus derives from the [[https://hub.docker.com/r/m1mbert/cxlb-gnuradio-3.10|m1mbert/cxlb-gnuradio-3.10:1.2]] image that contains everything necessary to run code with the hardware of CorteXlab (especially the UHD Drivers for the USRPs). (It also contains GNU Radio 3.10, but we won't be making use of it here). It then pulls code from a branch of a fork of the AFF3Ct DVB-S2 repo, compiles and installs it. This is done to apply a few modifications to allow proper execution on the platform: * Reduction of the number of threads to better fit the 4 cores CPUs available * Disable thread pinning (in code and with -DAFF3CT_LINK_HWLOC=OFF) * Set the instruction set to the one available to the CPUs of the platform: SSE4.1 ---- ## The scenario For the following, the ''task'' will refer to the instructions given by Airlock, the scenario file and minus. The ''experiment'' will refer to the DVB-S2 transmission. Create on your machine a folder ''dvbs2_task'' and in it a file ''scenario.yaml'' which will indicate the nodes to use and how to use them. It should look like this : ``` # Example scenario description file # # All lines starting with "#" and empty lines are ignored # Scenario textual description # simple string (a one liner) description: DVB-S2 with AFF3CT # Experiment maximum duration # Time after which the experiment is forced to stop # integer (seconds) duration: 1800 # Node list # # format: # # (machine): # entry (entry point script relative to the task root) # exit (exit point script relative to the task root. Use "none" for none) nodes: node14: container: - image: ghcr.io/notou/dvbs2:0.1 node16: container: - image: ghcr.io/notou/dvbs2:0.1 ``` The file is self-explanatory, but for now let's ignore all but the indented lines following ''node14:'' and ''node16:''. You'll have the opportunity to understand the rest better later on. Let's go over each said line now: * ''node14:'': This opens the node14 declaration of options * ''image:'': This indicates which image to download and run on the node The same reasoning applies for node 16. For more info on where these nodes are located inside the platform, please check the node position map at the home of this wiki. Assuming your account has been correctly created, you can now copy the folder with the scenario file into the Airlock SSH front-end: you@yourpc:~$ scp -P 2269 -v [-i path/to/your/key] [-r] path/to/local/folder/dvbs2_task username@gw.cortexlab.fr:/cortexlab/homes/[YOUR CORTEXLAB USERNAME]/workspace/ ### Non interactive scenario (No SSH) The example of this tutorial demonstrates an ssh connection to the nodes. But know that you can also use the ''command'' option in a different way, by directly giving the parameters of your experience and not going through ssh. When developing an experiment (trials and errors, parameter tweaking, ...), working interactively through ssh is more practical. But when the experiment is running well and you want to reproduce it several times, it is best to automatize, so that you don't need to ssh to each node and run commands manually. It's also possible, for example, that you adjust interactively a receiver first, and when it's done, you run it automatically, and you keep the interactive sessions only for adjusting and tuning the emitter node(s). In this situation, you might want to directly call the program to run on the nodes via the ''command'' option, with a scenario file looking like the following. ``` # Example scenario description file # # All lines starting with "#" and empty lines are ignored # Scenario textual description # simple string (a one liner) description: DVB-S2 with AFF3CT # Experiment maximum duration # Time after which the experiment is forced to stop # integer (seconds) duration: 120 # Node list # # format: # # (machine): # entry (entry point script relative to the task root) # exit (exit point script relative to the task root. Use "none" for none) nodes: node14: container: - image: ghcr.io/notou/dvbs2:0.1 command: bash -lc "/root/dvbs2/build/bin/dvbs2_rx --sim-stats --rad-threaded --rad-ip-addr 192.168.10.2 --rad-rx-subdev-spec "A:0" --rad-rx-rate 5e6 --rad-rx-freq 1100e6 --rad-rx-gain 20 -F 16 --src-type USER --src-path ../conf/src/K_14232.src --mod-cod QPSK-S_8/9 --dec-implem NMS --dec-ite 10 --dec-simd INTER" node16: container: - image: ghcr.io/notou/dvbs2:0.1 command: bash -lc "sleep 5 && /root/dvbs2/build/bin/dvbs2_tx --sim-stats --rad-threaded --rad-ip-addr 192.168.10.2 --rad-tx-subdev-spec "A:0" --rad-tx-rate 5e6 --rad-tx-freq 1100e6 --rad-tx-gain 30 -F 8 --src-type USER --src-path ../conf/src/K_14232.src --mod-cod QPSK-S_8/9" ``` Note that, **the rest of this tutorial uses the ssh method**, not the one mentioned in the current section. Also note that the command must point to the file to be executed, either with a relative path, from the ''WORKDIR'' defined in your docker image (here it is ''/root''), or with an absolute path. ## Access Airlock You can now access the Airlock SSH server that will allow you to manage your task. you@yourpc:~$ ssh -X -v [-i path/to/the/key] username@gw.cortexlab.fr ## Creating the task file On airlock, before submitting the task to the nodes, we need first to put the task into a format that can be readily understood by Minus. Minus is the experiment controller code, responsible for doing the dirty stuff for you: * Firing up the right nodes to be used * Copying the code onto the nodes * Starting everything at the same instant * Waiting until everything finishes, and stop stubborn code from running forever * Copying results, error and output messages to airlock, so that you can access it * Turning off everything and cleaning up Let's prepare the task, but first we need to go back to the folder containing the task: you@srvairlock:~/ cd /cortexlab/homes/[YOUR CORTEXLAB USERNAME]/workspace/ And now, instruct Minus to create a task file: you@srvairlock:~/workspace$ minus task create dvbs2_task you@srvairlock:~/workspace$ ls dvbs2_task dvbs2_task.task And now we have a new file called ''dvbs2\_task.task'' which is ready to be submitted. Warning, do not leave a slash after the directory task name (i.e. ''dvbs2_task'' ) or the command will fail. ## Submitting the task Now we need to give the task to Minus, so that it can operate its magic. First we need to reserve the CorteXlab room, and the nodes we want to use (in this case, 14 and 16). Please refer to the the "Submitting the task" section of [[gnu_radio_docker_benchmark_example|Tutorial 1]]. Back to the airlock terminal screen, we now can submit the minus task: you@srvairlock:~/workspace$ minus task submit my_task.task 21743. You'll see that Minus gives you a task number (21743 in this example). You'll want to __write down the number__ of the task as it will be important for checking its status or to abort it, if necessary. ## Run the experiment Now the node we want to use are up and running with the docker image we set up earlier. We can access them with ssh to run our experiment. To do so, open a new terminal per node you want to use, here two, access Airlock and run the following command, here for node 14 : you@srvairlock:~/workspace$ ssh -p 2222 root@mnode14 You are now connected to the node with the docker environment you set up earlier. You can then start running commands. First, let's chack that the DVB-S2 chain is properly compiled by running a simulated transmission on one node: # From node 14 root@mnode14:~/ /root/dvbs2/build/bin/dvbs2_tx_rx -m 3.4 -M 3.81 -s 0.1 --chn-max-freq-shift 0 --chn-max-delay 4.0 This is one of the reference parameters [[https://github.com/aff3ct/dvbs2/blob/daeaab141f3326dc8f1598ab74e110713d8bf506/refs/TX_RX/QPSK_8_9_freq_000_delay_40.txt#L2|from the original repository]]. You should see in the console something similar to this: ``` root@mnode14:~/ /root/dvbs2/build/bin/dvbs2_tx_rx -m 3.4 -M 3.81 -s 0.1 --chn-max-freq-shift 0 --chn-max-delay 4.0 [trace] # * DVB-S2 ---------------------------------------- # ** Modulation and coding = QPSK-S_8/9 # ** Min Eb/N0 = 3.400000 # ** Max Eb/N0 = 3.810000 # ** Step Eb/N0 = 0.100000 # ** Max frame errors = 100 # ** Type of channel = AWGN # ** Maximum Channel Delay = 4.000000 # ** LDPC implem = SPA # ** LDPC n iterations = 50 # ** LDPC simd = # ** Path to sink file = sink.out # ** Type of source = RAND # ** Path to source file = ../conf/src/K_14232.src # ** Perfect synchronization = NO # ** Estimator type = DVBS2 # * Shaping_filter -------------------------------- # ** N. complex samples = 16740 # ** N. complex symbols = 8370 # ** Oversampling Factor = 2 # ** Rolloff Factor = 0.200000 # ** Group Delay = 20 # * Synchronizer_freq_coarse ---------------------- # ** N. samples = 16740 # ** Type = NORMAL # ** Damping Factor = 0.707107 # ** Normalized Bandwidth = 0.000100 # * Synchronizer_timing --------------------------- # ** N. complex samples = 16740 # ** Type = FAST # ** Damping Factor = 0.707107 # ** Normalized Bandwidth = 0.000050 # * Synchronizer_frame ---------------------------- # ** N. complex samples = 8370 # ** Type = FAST # ** Alpha = 0.900000 # ** Trigger = 30.000000 # * Synchronizer_freq_fine ------------------------ # ** N. samples = 8370 # ** Type = NORMAL # ** L&R Alpha = 0.999000 Cloning the modules of the parallel sequence... Done (11.4372s). # --------------------------------||------------------------------------------------------||--------------------- # Signal Noise Ratio || Bit Error Rate (BER) and Frame Error Rate (FER) || Global throughput # (SNR) || || and elapsed time # --------------------------------||------------------------------------------------------||--------------------- # ----------|----------|----------||----------|----------|----------|----------|----------||----------|---------- # Sigma | Es/N0 | Eb/N0 || FRA | BE | FE | BER | FER || SIM_THR | ET/RT # | (dB) | (dB) || | | | | || (Mb/s) | (hhmmss) # ----------|----------|----------||----------|----------|----------|----------|----------||----------|---------- 0.3607 | 5.85 | 3.40 || 100 | 19585 | 100 | 1.38e-02 | 1.00e+00 || 0.160 | 00h00'08 0.3565 | 5.95 | 3.50 || 122 | 16489 | 100 | 9.50e-03 | 8.20e-01 || 0.291 | 00h00'05 0.3524 | 6.05 | 3.60 || 196 | 13485 | 100 | 4.83e-03 | 5.10e-01 || 0.390 | 00h00'07 0.3484 | 6.15 | 3.70 || 535 | 12390 | 100 | 1.63e-03 | 1.87e-01 || 0.719 | 00h00'10 0.3444 | 6.25 | 3.80 || 4395 | 11015 | 100 | 1.76e-04 | 2.28e-02 || 1.492 | 00h00'41 ``` Now, let's run an actual over-the-air transmission by running these commands on each node: # From node 14 root@mnode14:~/ /root/dvbs2/build/bin/dvbs2_rx --sim-stats --rad-threaded --rad-ip-addr 192.168.10.2 --rad-rx-subdev-spec "A:0" --rad-rx-rate 5e6 --rad-rx-freq 1100e6 --rad-rx-gain 20 -F 16 --src-type USER --src-path ../conf/src/K_14232.src --mod-cod QPSK-S_8/9 --dec-implem NMS --dec-ite 10 --dec-simd INTER # From node 16 root@mnode16:~/ /root/dvbs2/build/bin/dvbs2_tx --sim-stats --rad-threaded --rad-ip-addr 192.168.10.2 --rad-tx-subdev-spec "A:0" --rad-tx-rate 5e6 --rad-tx-freq 1100e6 --rad-tx-gain 30 -F 8 --src-type USER --src-path ../conf/src/K_14232.src --mod-cod QPSK-S_8/9 To ensure reliable transmission, it is best to run the dvbs2_rx command (node 14 here) first, then the tx. These commands are based on the examples from the official [[https://github.com/aff3ct/dvbs2#ber--fer|readme]], modified to point to the exact IP addresses of the USRP, and to reduce the operating sample rate to 5Msps. You should again see a dump of the transmission parameters, and on the reciever (node 14 here), something similar to: ``` ... # * Radio ----------------------------------------- # ** N. samples = 16740 # ** Type = USRP # ** Threaded = YES # ** Fifo size = 10000000000 # ** Clk rate = 125000000.000000 # ** Rx rate = 5000000.000000 # ** Rx subdev = A:0 # ** Rx antenna = RX2 # ** Rx freq = 1100000000.000000 # ** Rx gain = 20.000000 # ** Rx File = # ** Tx File = # ** Tx subdev = A:0 # ** Tx antenna = TX/RX # ** Tx rate = 0.000000 # ** Tx freq = 1090000000.000000 # ** Tx gain = 10.000000 [INFO] [UHD] linux; GNU C++ version 10.2.1 20210110; Boost_107400; UHD_4.3.0.0-6-g5aa6bc44 [INFO] [USRP2] Opening a USRP2/N-Series device... [INFO] [USRP2] Current recv frame size: 1472 bytes [INFO] [USRP2] Current send frame size: 1472 bytes [WARNING] [UDP] The send buffer could not be resized sufficiently. Target sock buff size: 2500000 bytes. Actual sock buff size: 1048576 bytes. See the transport application notes on buffer resizing. Please run: sudo sysctl -w net.core.wmem_max=2500000 [WARNING] [UDP] The send buffer could not be resized sufficiently. Target sock buff size: 2500000 bytes. Actual sock buff size: 1048576 bytes. See the transport application notes on buffer resizing. Please run: sudo sysctl -w net.core.wmem_max=2500000 [WARNING] [UDP] The send buffer could not be resized sufficiently. Target sock buff size: 2500000 bytes. Actual sock buff size: 1048576 bytes. See the transport application notes on buffer resizing. Please run: sudo sysctl -w net.core.wmem_max=2500000 Cloning the modules of the parallel sequence... Done (1.47306s). Waiting phase... Done (3.0949s). Learning phase... Done (1.74851s). # ---------------------||------------------------------------------------------||--------------------- # Signal Noise Ratio || Bit Error Rate (BER) and Frame Error Rate (FER) || Global throughput # (SNR) || || and elapsed time # ---------------------||------------------------------------------------------||--------------------- # ----------|----------||----------|----------|----------|----------|----------||----------|---------- # Es/N0 | Eb/N0 || FRA | BE | FE | BER | FER || SIM_THR | ET/RT # (dB) | (dB) || | | | | || (Mb/s) | (hhmmss) # ----------|----------||----------|----------|----------|----------|----------||----------|---------- 14.62 | 12.17 || 7744 | 32254 | 12 | 2.93e-04 | 1.55e-03 || 4.231 | 00h00'26 ``` Notice that after a while (about 25-30s), the transmitter starts printing "UUUUUUUU", and eventually finishes. At the same time, the estimated SNR values at the reciever drop down to about 0, and the error rates increase. That is simply because the transmitter has finished sending its file, so there is nothing but noise to receive. Note that the receiver needs to be shutdown with Ctrl-C, and may hang at shutdown with an error message like: ``` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ``` In that case, either wait for it to terminate on its own (may take a few minutes), or kill it directly. ## Exercises Feel free to experiment with these commands. For instance, try to increase (or decrease) the sample rate (`--rad-tx-rate 5e6`) to see what is feasible by the platform. Note that only integer divisers of the USRP master clock rate (100Msps for the USRP 2032 and 200Msps for the 2944) are possible. Read the console output for errors or warnings. Try to communicate between other pairs of nodes, at various distances, and with different USRP types (2932 or 2944). You may need to make a specific reservation to activate the desired nodes, and change the scenario file accordingly. Play with the command parameters, according to the info available in the [[https://github.com/aff3ct/dvbs2|original repo]], and the help command (`/root/dvbs2/build/bin/dvbs2_rx -h`)