RENEW Project Documentation

Version 1.0

Reconfigurable Ecosystem for Next-generation End-to-end Wireless

Sounder

Sounder provides a framework to record the received signal from all clients at all antennas in the massive MIMO base station. This includes orthogonal pilot signals from each configured client and uplink signals sent at common subframes by those clients. These signals are recorded as multi-dimensional matrices in HDF5 format. The recorded files can then be analyzed with RENEW python tools for various statistics and channel behavior analysis as well as offline demultiplexing of the uplink signals.

The same binary can be used to configure all SDRs in the base station as well as all clients. The configuration is defined in json format and passed as an input argument to the binary.

In this document, we provide an extensive tutorial on the configuration and usage of the Sounder framework. First, let’s look at how to build the code.

Build the code

There are a few dependencies for running this code base. This includes muFFT and C++ json library. The install_cclibs.sh script installs all dependencies, except muFFT. If you running the sounder on POWDER, this script will be automatically installed at start of the experiments. However if you are running the sounder locally and on your own Iris nodes, install it first as the following.

$ ./install_cclibs.sh

The remaining muFFT, however, is submodule that needs to be independently pulled and built. Simply go to the mufft folder in sounder directory and run

$ cd mufft
$ git submodule update --init
$ cmake .
$ make -j

To build the sounder code, go back to the sounder directory and run the following:

$ cd ..
$ cmake .
$ make -j

Once the code builds successfully, you’ll get a binary sounder executable in the same folder. Now let’s start looking at the configuration file and editing it. Some sample configuration files are in files.

Create configuration file

Open powder-conf-two-client-2.5g.json. You see two json tags, BaseStations and Clients. Let’s look at BaseStations first:

  • cells determines how many BaseStations and therefore physical cells are used in the experiment. Currently only a single cell is supported.

  • hub id specifies the file name containing the list of hub serials used at all BaseStations. Each hub serial must be listed in a separate line. Note, a hub device is used to trigger all SDRs in a BaseStation.

  • sdr id specifies the list of filenames including SDR serial numbers for each BaseStation. An example of such file is in the files directory. Serial numbers must be listed with one serial per line. If hub serial file is empty the first sdr serial in sdr id file is used to trigger the reset of the devices. This only work if only a single daisy-chained SDR array is used. In this case, you have to make sure the first SDR serial in the sdr id file is the first physical SDR in the daisy-chain. For more information on this, please see the Hardware section

  • frequency sets the band the SDRs will operate on. The driver accepts the range [30e6-3800e6] Hz, but the usable range depends on the flavor of the base station (front-end type and antenna).

  • rate set the sample rate on the channel of all SDRs. Current hardware supported range for sample rate is 1-40MHz.

  • channel allows you to choose either “A”, “B” or “AB”. Note, each SDR in the base station has two TX/RX channels (A and B) and each one is attached to different a different antenna polarization. So, this key also determines the number of antennas used in the BaseStation during the experiment.

  • rxgainA, txgainA, rxgainB, txgainB set the RX and TX gains on each SDR channel respectively. Current ranges for RX gain and TX gain are [0,100] and [0,100] respectively.

  • calTxGainA, calTxGainB These are the calibration factors for txGainA and txGainB at BS antennas. They shall be used during sample_calibrate. The defaults are 25, 25. The defaults are 20, 40, 20, 40.

  • frame_schedule defines the structure of a TDD frame that will be followed during the experiment. Details on the TDD framer and its configuration, can be found in the python design flow. The difference here is the letters are changed to unify the config for both BaseStation and Clients. ‘B’ represents a subframe used to broadcast beacons from the base station. ‘P’ represents a pilot subframe that is transmitted by Client and received by the BaseStation. ‘D’ and ‘U’ represent Downlink and uplink frames respectively. ‘G’ is kept as default (Guard interval or no TX or RX by anyone). The schedule is configured on all BaseStation SDR at the beginning of experiment.

  • frame_mode defines the frame counting mode. For the base station, this is set to free_running.

  • max_frame specifies the maximum number of frames after which the sounder app stops. If 0, the app continues until stopped with ctrl-c key. For any other positive value, the sounder app counts up to that number of frames.

  • subframe_size specifies the number of samples in each subframe (generic symbol). Each subframe can include multiple OFDM symbols.

  • fft_size defines the size of fft used for OFDM symbol in subframes.

  • cp_size defines the cyclic prefix size for each OFDM symbol.

  • prefix specifies the number of padding samples in the beginning of each subframe.

  • postfix specifies the number of padding samples at the end of each subframe.

  • beacon_seq selects from multiple existing pseudo-noise sequences. Currently only “gold ifft” is supported.

  • beamsweep specifies whether the beacons are beamsweeped using open-loop precoding. If true, M hadamard sequences are generated, with M being the number of antennas, and sent to all SDRs to be applied duing the beacon subframe. This way M distinguished beacon beams are generated in every M consecutive frames.

  • sample_calibrate It specifies the sample offset calibration. There could be a sample offset from one BS Iris module to the next even with the synchronization. The Sounder will look at that offset with respect to one reference Iris module and align all other Iris modules to it. The default is false.

  • imbalance_calibrate specifies whether to calibrate the base station array DC offset and IQ imbalance. Note, depending on the number of antennas on the base station this process is slow.

  • beacon_antenna is used when beamsweep is false. In this case only the identified antenna index at the BaseStation is used to send the beacon.

  • pilot_seq selects a signal type to be used for pilots. Wee currently only support 802.11 LTS-type pilots, so this key has no effect.

"BaseStations" : {
         "cells" : 1,
         "hub_id" : "conf/hub_serials.txt",
         "sdr_id" : ["conf/iris_serials.txt"],
         "frequency" : 2.5e9,
         "rate" : 5e6,
         "channel" : "AB",
         "rxgainA" : 50,
         "txgainA" : 50,
         "rxgainB" : 50,
         "txgainB" : 50,
         "frame_schedule" : [
             "BGPPUGGGGGGGGGGGGGGG"
         ],
         "frame_mode" : "free_running",
         "max_frame" : 0, 
         "subframe_size" : 640,
         "fft_size" : 64,
         "cp_size" : 16,
         "prefix" : 82,
         "postfix" : 68,
         "beacon_seq" : "gold_ifft",
         "beamsweep" : false,
         "beacon_antenna" : 0,
         "pilot_seq" : "lts"
}
  • sdr_id specifies the list of SDR serial numbers for each Client.

  • frequency same as BaseStation.

  • channel same as BaseStation this determines the channels to be used on the

  • clients. If “AB” is picked, there needs to be two pilot (“P”) subframes in the schedule. So an orthogonal pilot is sent from each channel

  • rxgainA, txgainA, rxgainB, txgainB same as BaseStation. However, here we have the possiblity to set these variables as an array, with each index being used for an individual client.

  • rate same as BaseStation

  • frame_schedule same as BaseStation except ‘B’ is not used for Clients and the equivalent subframe as ‘B’ in the BaseStation is set as ‘G’ for all clients. During this subframe the internal correlator at the Clients, tries to detect the beacon and set the frame time accordingly to synchronize with the BaseStation. Note, each Clients needs its own schedule and the number of array entries must match the number of Client serial numbers in the sdr id key. Additionally if ‘U’ or uplink is used, make sure you include a ‘D’ or Downlink subframe in the schedule. This will act as a dummy receive so the transmit streaming (for uplink) can use the timestamps from receive (downlink) stream. Since this is a dummy receive, the corresponding subframe at the BaseStation is just a Guard interval.

  • frame_mode defines the frame counting mode. For the clients, this is set to either “continuous_resync” or “triggered”. In “triggered” mode, clients wait to receive a beacon to start a new frame. In “continuous_resync” mode, clients keep counting frames after the first received beacon and upon detection of every new beacon they resync their time to a preset value (symbol number/sample number). The preset value is set during setup using “setHardwareTime” Soapy function. This means that if a beacon is missed, client still sends pilots and data.

  • subframe_size specifies the number of samples in each subframe (generic symbol). Each subframe can include multiple OFDM symbols.

  • fft_size defines the size of fft used for OFDM symbol in subframes.

  • cp_size defines the cyclic prefix size for each OFDM symbol.

  • prefix specifies the number of padding samples in the beginning of each subframe.

  • postfix specifies the number of padding samples at the end of each subframe.

  • agc_en will enable the AGC logic in the clients. For more details on AGC see [here]

  • beacon_seq selects from multiple existing pseudo-noise sequences. Currently only “gold ifft” is supported. The sequence is used to fill in the correlator taps implemented at the Clients.

  • modulation specifies the type the modulation in used in the uplink data.

  • pilot_seq selects from multiple existing signal types. Currently only “lts” is supported. Corresponding pilot signal is sent by each Client during its designated pilot subframe.

  • tx_davance It controls how much time in advance the client needs to send its uplink pilot and data in a frame to be exactly synchronized with the timing at the base station. This advance is due to the RF path delay. The default is 250.

  • hw_framer It specifies whether to use the hardware correlator (true) or the software one (false). It means to control whether the synchronization and frame time keeping is done is hardware or software. In the software framer mode, it shall take a few tens of frames to find synchronization. The software framer works relatively better than the hardware framer. The default is false.

"Clients" : {
         "sdr_id" : [
             "RF3E000029",
             "RF3E000040"
         ],
         "frequency" : 2.5e9,
         "rate" : 5e6,
         "channel" : "A",
         "rxgainA" : [20, 20],
         "txgainA" : [40, 40],
         "rxgainB" : [20, 20],
         "txgainB" : [40, 40],
         "frame_schedule" : [
             "GDPGUGGGGGGGGGGGGGGG",
             "GDGPUGGGGGGGGGGGGGGG"
         ],
         "frame_mode" : "continuous_resync",
         "subframe_size" : 640,
         "fft_size" : 64,
         "cp_size" : 16,
         "prefix" : 82,
         "postfix" : 68,
         "agc_en" : false,
         "beacon_seq" : "gold_ifft",
         "pilot_seq" : "lts",
         "modulation" : "QPSK"
}

Edit the above configuration according to your desired experiment setup. Make sure, BaseStation and Client configurations match so that your experiment runs properly. In particular, pay close attention to the schedules for all Clients and the BaseStation.

Run the experiment

$ ./sounder files/<configFile>.json

With running above, the framework starts recording the received raw samples in HDF5 file in the logs/ directory. Below is a sample shell output:

Set HDF5 File to logs/trace-2019-2-18-15-23-21_1x8x2.hdf5 and group to /
dim pilot chunk = 5
New Pilot Dataset Dimension 5,2000,1,2,8,1100
dim data chunk = 5
New Data Dataset Dimension 5,2000,1,1,8,1100
PGRRRGGGGGGGGGGGGGGG
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
[INFO] Wrote TDD config: symbol_size=550, num_frames=1, trigger_out=0, wait_trigger=0, dual_pilot=0, max_frame=0
waiting for receive frames... 
waiting for receive frames... 
[WARNING] Could not set thread priority 1.0 in acquireWriteBuffer: Operation not permitted
[WARNING] Could not set thread priority 1.0 in acquireWriteBuffer: Operation not permitted
package receiver thread 3 start
pinning thread 3 to core 4
package receiver thread 2 start
pinning thread 2 to core 3
receiver thread 3 has 2 radios
[WARNING] Could not set thread priority 1.0 in acquireReadBuffer: Operation not permitted
receiver thread 2 has 2 radios
[WARNING] Could not set thread priority 1.0 in acquireReadBuffer: Operation not permitted
package receiver thread 1 start
pinning thread 1 to core 2
package receiver thread 0 start
pinning thread 0 to core 1
receiver thread 0 has 2 radios
receiver thread 1 has 2 radios
[WARNING] Could not set thread priority 1.0 in acquireReadBuffer: Operation not permitted
[WARNING] Could not set thread priority 1.0 in acquireReadBuffer: Operation not permitted
FrameId 2000, (Pilot) Extent to 2400 Frames
(Data) Extent to 2400 Frames
Closing HDF5, 2001 frames saved.
dim pilot chunk = 5
New Pilot Dataset Dimension 5,2000,1,2,8,1100
dim data chunk = 5
New Data Dataset Dimension 5,2000,1,1,8,1100

Stop the recording with Ctrl+C at any time. Use the tools in Python design flow to read back and analyze the output HDF5 file.

Analyze the HDF5 dataset

Use plot_hdf5.py and MMIMO_RECEIVER.py to analyze of datasets collected from the Sounder framework. Example usage of these tools is shown as below. Note: Please replace below HDF5 files with your own files.

  1. A quick analysis plot: Navigate to the renew-software/PYTHON/IrisUtils directory and run

     python3 plot_hdf5.py ../../CC/Sounder/logs/trace-uplink-2020-6-25-14-47-56_1x16x2.hdf5
    
  2. Analyze certain BS antenna performance: For example, BS Antenna 6, Client 1, and a particular frame 140.

     python3 plot_hdf5.py ../../CC/Sounder/logs/trace-2020-5-27-19-25-7_1x8x3.hdf5 --ref-ant 6 --ref-user 1 --ref-frame 140
    
  3. Analyze the achievable bit rate of the system:

     python3 plot_hdf5.py ../../CC/Sounder/logs/trace-2020-5-27-19-25-7_1x8x3.hdf5 --analyze-trace
    
  4. Deep analysis: You can find out the number of good and bad frames output on the terminal.

     python3 plot_hdf5.py logs/trace-uplink-2020-6-25-14-47-56_1x16x2.hdf5 --deep-inspect
    
  5. Use the RENEWLab Python demo tool, MMIMO_RECEIVER.py: Navigate to the renew-software/PYTHON/DEMO directory.

    a. Check the TX samples in the AWGN simulation mode. Below two commands do the same thing.

     python3 MMIMO_RECEIVER.py --file=../../CC/Sounder/logs/trace-uplink-2020-6-25-14-47-56_1x16x2.hdf5
     python3 MMIMO_RECEIVER.py --file=../../CC/Sounder/logs/trace-uplink-2020-6-25-14-47-56_1x16x2.hdf5 --mode=AWGN
    

    b. Analyze both TX and RX samples in REPLAY mode.

     python3 MMIMO_RECEIVER.py --file=../../CC/Sounder/logs/trace-uplink-2020-6-25-14-47-56_1x16x2.hdf5 --mode=REPLAY
    

    c. Analyze 5 frames from Frame 5 to Frame 9.

     python3 MMIMO_RECEIVER.py --file=../../CC/Sounder/logstrace-uplink-2020-6-25-14-47-56_1x16x2.hdf5 --mode=REPLAY --frame=5:10
    
Last updated on 1 Jul 2020 / Published on 12 Feb 2019