Changes between Initial Version and Version 1 of Tutorials/Wireless/Measurement Tool


Ignore:
Timestamp:
May 14, 2019, 6:37:49 PM (5 years ago)
Author:
nilanjan
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Tutorials/Wireless/Measurement Tool

    v1 v1  
     1== Measurement tools ==
     2This tutorial will demonstrate data collection method using the OML interface.
     3
     4== Prerequisites ==
     5 1. Accounts, ssh keys
     6 2. Reservation
     7 3. Familiarity with USRPs.
     8
     9=== Description ===
     10This tutorial utilizes an existing application provided by the UHD driver. The application used is ''rx_multi_sample'' which is a c++ application that configures and reads samples from multiple the USRPs. A c++ based OML-wrapper has been added to this application to store FFTed blocks of samples to an OML database server.
     11
     12=== Set up ===
     13 1. First ssh into the console that you made a reservation.
     14 2. Use the ''omf stat'' to find all the experiment servers and SDRs that are seen by OMF.
     15{{{
     16console> omf stat -t all
     17 INFO NodeHandler: OMF Experiment Controller 5.4 (git 861d645)
     18 INFO NodeHandler: Slice ID: default_slice (default)
     19 INFO NodeHandler: Experiment ID: default_slice-2019-05-14t10.58.59.167-04.00
     20 INFO NodeHandler: Message authentication is disabled
     21 INFO property.resetDelay: resetDelay = 200 (Fixnum)
     22 INFO property.resetTries: resetTries = 1 (Fixnum)
     23 INFO property.nodes: nodes = "system:topo:all" (String)
     24 INFO property.summary: summary = false (FalseClass)
     25 INFO Topology: Loaded topology 'system:topo:all'.
     26
     27Talking to the CMC service, please wait
     28-----------------------------------------------
     29 Node: mob1.sb1.cosmos-lab.org           State: POWERON
     30 Node: mob2.sb1.cosmos-lab.org           State: POWERON
     31 Node: mob3.sb1.cosmos-lab.org           State: POWERON
     32 Node: sdr1-lg1.sb1.cosmos-lab.org       State: POWERON
     33 Node: sdr1-md1.sb1.cosmos-lab.org       State: POWERON
     34 Node: sdr2-lg1.sb1.cosmos-lab.org       State: POWERON
     35 Node: sdr2-md1.sb1.cosmos-lab.org       State: POWERON
     36 Node: srv1-lg1.sb1.cosmos-lab.org       State: POWERON
     37 Node: srv2-lg1.sb1.cosmos-lab.org       State: POWERON
     38-----------------------------------------------
     39
     40 INFO EXPERIMENT_DONE: Event triggered. Starting the associated tasks.
     41 INFO NodeHandler:
     42 INFO NodeHandler: Shutting down experiment, please wait...
     43 INFO NodeHandler:
     44 INFO run: Experiment default_slice-2019-05-14t10.58.59.167-04.00 finished after 0:5
     45}}}
     46
     47 3. Load the ''baseline-sdr.ndz'' image onto the experiment server. This image has the UHD driver and other pertinent libraries  pre-installed. For this tutoral we'll use ''srv1-lg1.sb1.cosmos-lab.org'' as the experiment server.
     48{{{
     49console> omf load -i baseline-sdr.ndz -t srv1-lg1.sb1.cosmos-lab.org
     50}}}
     51
     52 4. After loading is complete turn on the experiment server. We'll also use the ''sdr1-lg1.sb1.cosmos-lab.org'' which is an N310 USRP. So turn this on as well.
     53{{{
     54console> omf tell -a on -t srv1-lg1.sb1.cosmos-lab.org,sdr1-lg1.sb1.cosmos-lab.org
     55}}}
     56
     57 5. Use the ''omf stat'' command again to verify ON/OFF status of the devices.
     58{{{
     59console> omf stat -t srv1-lg1.sb1.cosmos-lab.org,sdr1-lg1.sb1.cosmos-lab.org
     60}}}
     61
     62
     63 7. Configure interface
     64{{{
     65ifconfig enp1s0 10.115.1.1 netmask 255.255.0.0 mtu 8000
     66}}}
     67
     68 6. Next ssh into the experiment server and discover the USRP that we turned on. We'll need the ip address for this USRP; At the command line do a 'host sdr1-lg1.sb1.cosmos-lab.org' to find its ip address. Then run ''uhd_find_devices'' with the --args option to discovery the USRP.
     69{{{
     70native@localhost:~$ host sdr1-lg1.sb1.cosmos-lab.org
     71sdr1-lg1.sb1.cosmos-lab.org has address 10.113.2.1
     72
     73native@localhost:~$ uhd_find_devices --args="addr=10.113.2.1"
     74
     75<<some output here>>>
     76}}}
     77
     78=== Explain ''rx_multi_receive'' application and how to use ===
     79Navigate to the ~/RX_MULTI_RECEIVE directory - this contains the files that build the ''rx_multi_receive'' application.
     80This is a c++ application that can be run on the experiment server to collect a set of continuous samples.
     81
     82Use the --help option to display all the variables ''rx_multi_receive'' accepts.
     83{{{
     84root@node20-1:~/RX_MULTI_RECEIVE# ./rx_multi_receive --help
     85linux; GNU C++ version 4.8.4; Boost_105400; UHD_003.010.001.001-0-unknown
     86
     87UHD RX Multi Receive Allowed options:
     88  --help                        help message
     89  --args arg                    single uhd device address args
     90  --secs arg (=1.5)             number of seconds in the future to receive
     91  --nsamps arg (=10000)         total number of samples to receive
     92  --freq arg (=900000000)       RF center frequency in Hz for all channels
     93  --rate arg (=6250000)         rate of incoming samples for all channels
     94  --gain arg (=0)               gain for the RF chain for all channels
     95  --ant arg                     rx antenna selection for all channels
     96  --prefix arg                  enables file output with filename prefix
     97  --addr arg                    udp address: 10.10.0.10
     98  --port arg (=1337)            udp port: 1337
     99  --sync arg (=now)             synchronization method: now, pps, mimo
     100  --subdev arg                  subdev spec (homogeneous across motherboards)
     101  --dilv                        specify to disable inner-loop verbose
     102  --int-n                       tune USRP with integer-N tuning
     103  --channels arg (=0)           which channel(s) to use (specify "0", "1",
     104                                "0,1", etc)
     105  --oml-id arg                  OML sender ID - pass the hostname here
     106  --oml-domain arg (=omlcli)    file name for OML database
     107  --oml-collect arg (=oml:3003) Storage options:
     108                                 network: <server:port>
     109                                 local text file: <file:my_file_name>
     110}}}
     111
     112To use ''rx_multi_receive'' standalone on an experiment server we can using the following options
     113{{{
     114root@node20-1:~/RX_MULTI_RECEIVE# ~/RX_MULTI_RECEIVE/rx_multi_receive --args="addr0=10.10.23.5" --freq 2440e6 --rate 20e6 --gain 3
     115 --nsamps 1024000 --channels "0" --dilv
     116}}}
     117
     118 --args="addr0=10.10.23.5" specifies the SDR's IP address.
     119 --freq 2440e6             sets the center freq
     120 --rate 20e6               sets sampling rate
     121 --gain 3                  sets receive path gain
     122 --nsamps 1024000          number of samples to collect
     123
     124Executing the application with only the above options will only configure the USRP's radio parameters and read in the specified nu
     125mber of samples. However the samples will be lost once the application exits. You should see output similar to the following.
     126{{{
     127
     128linux; GNU C++ version 4.8.4; Boost_105400; UHD_003.010.001.001-0-unknown
     129
     130
     131Creating the usrp device with: addr0=10.10.23.5...
     132-- X300 initialization sequence...
     133-- Determining maximum frame size... 7972 bytes.
     134-- Setup basic communication...
     135-- Loading values from EEPROM...
     136-- Setup RF frontend clocking...
     137-- Radio 1x clock:200
     138
     139:
     140:
     141:
     142
     143Using Device: Single USRP:
     144  Device: X-Series Device
     145  Mboard 0: X310
     146  RX Channel: 0
     147    RX DSP: 0
     148    RX Dboard: A
     149    RX Subdev: UBX RX
     150  TX Channel: 0
     151    TX DSP: 0
     152    TX Dboard: A
     153    TX Subdev: UBX TX
     154  TX Channel: 1
     155    TX DSP: 0
     156    TX Dboard: B
     157    TX Subdev: UBX TX
     158
     159Number mboards        = 1
     160Number of rx channels = 1
     161Setting RX Rate: 20.000000 Msps...
     162Actual RX Rate: 20.000000 Msps...
     163
     164Setting RX Freq: 2440.000000 MHz...
     165Actual RX Freq: 2440.000000 MHz...
     166
     167Setting RX Gain: 3.000000 dB...
     168Actual RX Gain: 3.000000 dB...
     169
     170Setting device timestamp to 0...
     171channel_nums.size() = 1
     172
     173UHD Warning:
     174    For this connection, UHD recommends a send frame size of at least 8000 for best
     175    performance, but your system's MTU will only allow 7972.
     176    This will negatively impact your maximum achievable sample rate.
     177
     178UHD Warning:
     179    For this connection, UHD recommends a receive frame size of at least 8000 for best
     180    performance, but your system's MTU will only allow 7972.
     181    This will negatively impact your maximum achievable sample rate.
     182
     183Begin streaming 1024000 samples, 1.500000 seconds in the future...
     184samps_per_buff = 1024
     185num_buff_ptrs = 1000
     186mdbp_idx = 1000
     187
     188Done!
     189
     190}}}
     191
     192To save the samples for post processing, specify the following OML arguments
     193 --oml-id `hostname`          this identifies the source of the data being store.
     194 --oml-domain rx_samples     file name for the OML database
     195 --oml-collect oml:3003       network storage located on oml:3003
     196
     197
     198Rerun the application with these and we'll see a few additional lines of output at the end indicating a connection to the OML database server.
     199
     200{{{
     201
     202Writing FFT blocks into rx_samples.sq3 @ oml:3003
     203May 13 21:36:18 INFO    OML Client V2.10.1rc [Protocol V4] Copyright 2007-2013, NICTA
     204INFO    OmlNetOutStream: attempting to connect to server at tcp://oml:3003
     205INFO    tcp:oml:3003: Waiting for buffered queue thread to drain...
     206
     207}}}
     208
     209
     210=== Instrumenting ''rx_multi_receive'' application with OML ===
     211The source file for this application is in ~/RX_MULTI_RECEIVE/main.cpp. Without going into the details off c++ and the enitire contents of the source file, we'll make note of the following blocks of code:
     212
     213 1. Lines xxx creates a handle to the USRP at the specified IP address. This handle is used thoughout the source to make reference to the radio.
     214 2. Lines xxx uses the handle to configure the radio paramters passed in from the command line.
     215 3. The read loop on lines xxx to xxx. This block reads out the complex floating samples into a buffer that is used for post processi
     216ng samples.
     217 4. Lines xxx to xxx are OML additions made to send the FFTed sample data to the OML server for storage.
     218
     219 In side this block, we create an object that performs 1024pt FFTs.
     220{{{
     221   std::vector<std::complex<float> > time_buff( samps_per_buff );
     222   std::vector<std::complex<float> > freq_buff( samps_per_buff );
     223   std::vector<float>                signal_mag_instant( samps_per_buff );
     224
     225   fftwf_plan fft_p = fftwf_plan_dft_1d( samps_per_buff,
     226                                         (fftwf_complex*)&time_buff.front(),
     227                                         (fftwf_complex*)&freq_buff.front(),
     228                                         FFTW_FORWARD,
     229                                         FFTW_ESTIMATE);
     230}}}
     231
     232 We also contruct an object for writing data to an OML server. Initialized the OML object with the OML options described above.
     233{{{
     234      // OML object for sending data
     235      CWriteOml oml;
     236      oml.init(oml_id, oml_domain, oml_collect );
     237}}}
     238
     239 Create keyed-values that will be sent for storage. Here we specify a string label with an OML type. After all the keyed-value pairs have been defined, we start a connection with the OML service.
     240 {{{
     241       std::vector< std::pair<std::string, OmlValueT> > _omlKeys;
     242      //                                 string label        OML type
     243      _omlKeys.push_back( std::make_pair("mboard_id",        OML_STRING_VALUE));
     244      _omlKeys.push_back( std::make_pair("mboard_serial",    OML_STRING_VALUE));
     245      _omlKeys.push_back( std::make_pair("mboard_name",      OML_STRING_VALUE));
     246      _omlKeys.push_back( std::make_pair("rx_id",            OML_STRING_VALUE));
     247      _omlKeys.push_back( std::make_pair("rx_subdev_name",   OML_STRING_VALUE));
     248      _omlKeys.push_back( std::make_pair("rx_subdev_spec",   OML_STRING_VALUE));
     249      _omlKeys.push_back( std::make_pair("rx_ant",           OML_STRING_VALUE));
     250
     251      _omlKeys.push_back( std::make_pair("channel",          OML_UINT32_VALUE));
     252      _omlKeys.push_back( std::make_pair("total_samps",      OML_UINT32_VALUE));
     253      _omlKeys.push_back( std::make_pair("sample_size",      OML_UINT32_VALUE));
     254
     255      _omlKeys.push_back( std::make_pair("rx_freq",          OML_DOUBLE_VALUE));
     256      _omlKeys.push_back( std::make_pair("rx_rate",          OML_DOUBLE_VALUE));
     257      _omlKeys.push_back( std::make_pair("rx_gain",          OML_DOUBLE_VALUE));
     258      _omlKeys.push_back( std::make_pair("SizeFFT",          OML_UINT32_VALUE));
     259      _omlKeys.push_back( std::make_pair("Bins",             OML_BLOB_VALUE));
     260
     261      oml.start( _omlKeys );
     262 }}}
     263
     264 After the OML start has been issued we can set the keyed-value pairs with updated values from sensors. In this section the FFT is
     265 performed on chunk of 1024 comoplex samples and the magnitude is computed. These get stored in the OML as binary data (oml_blob).
     266 Once all the keyed-valued pairs are updated with set_key(), they are sented over to the OML server by issuing the insert command.
     267 This is done repeatedly until the entire buffer has been processed.
     268 {{{
     269        oml.set_key("rx_id",            (void*)usrp_info["rx_id"].c_str() );
     270        oml.set_key("rx_subdev_name",   (void*)usrp_info["rx_subdev_name"].c_str() );
     271        oml.set_key("rx_subdev_spec",   (void*)usrp_info["rx_subdev_spec"].c_str() );
     272        oml.set_key("rx_ant",           (void*)usrp_info["rx_ant"].c_str() );
     273
     274        d64 = (double)(usrp->get_rx_freq() / 1e6);
     275        oml.set_key("rx_freq", (void*)&d64);
     276
     277        unsigned int nfftBlocks = MultiDeviceBuffer.at(ch).size() / samps_per_buff;
     278        for (unsigned int j = 0; j < nfftBlocks; j++)
     279        {
     280          // copy samples into time_buff for FFT
     281          memcpy((void*)time_buff.data(),
     282                 (void*)(MultiDeviceBuffer.at(ch).data() + j*samps_per_buff ),
     283                 samps_per_buff * sizeof(std::complex<float>) );
     284
     285          // Execute FFT. This performs fft on time_buff samples and store results in freq_buff.
     286          fftwf_execute(fft_p); // FWD FFT is NOT normalized so div by N.
     287
     288          // compute magnitude
     289          for(unsigned int z = 0; z < signal_mag_instant.size(); z++)
     290            signal_mag_instant.at(z) = abs(freq_buff.at(z));
     291
     292          // save the magnitude values as an OML blob
     293          oml.set_key_blob("Bins",(void*)&signal_mag_instant.front(),
     294                           (unsigned int)signal_mag_instant.size() * sizeof(float) );
     295
     296          // Send OML measurement to OML server
     297          oml.insert();
     298        }
     299
     300        //oml.stop();  // Don't need this since it is called in the destructor.
     301 }}}
     302
     303 Once this block completes the connection to the OML server is taken down and no more data can be stored into the database.
     304
     305
     306=== View results from OML database ===
     307
     308The database  is store in /var/lib/oml2 of the console. Use the command line front-end tool (sqlite3) to query the database direct
     309ly especially for binary data. For a detailed overview on sqlite3 CLI please refer ​http://www.sqlite.org/cli.html.
     310
     311An application has been made to parse this database. This application is very specific to this tutorial. If the format of the data
     312base table changes, the application may no longer be able to parse the database file.
     313Display all the tables in the database.
     314{{{
     315console> ./db_parse --file /var/lib/oml2/rx_multi_samples.sq3 --showtables
     316
     317name = _senders
     318
     319name = _experiment_metadata
     320
     321name = _mp__rx_multi_samples
     322
     323Use following command to retrieve contents of table.
     324./db_parse --file /var/lib/oml2/rx_multi_samples.sq3 --exec "SELECT * FROM <table>"
     325
     326To retrieve contents of the blob:
     327./db_parse --file /var/lib/oml2/rx_multi_samples.sq3 --blob2bin ch0_data.bin --ch 0 --table  _mp__rx_multi_samples --key Bins
     328
     329}}}
     330
     331
     332We can recover the contents of the FFT data for each channel and save them into a binary file for viewing in octave.
     333{{{
     334console> ./db_parse --file /var/lib/oml2/rx_multi_samples.sq3 --blob2bin ch0_data.bin --ch 0 --table  _mp__rx_multi_samples --key
     335Bins
     336
     337Executing query statement
     338select LENGTH(Bins),Bins from _mp__rx_multi_samples where channel=0
     339}}}
     340
     341In the console we should have a binary file by the name ch0_data.bin. This can be loaded and viewed in ocatve.
     342{{{
     343octave> mag0 = fReadBinaryFile('ch0_data.bin','single');
     344octave> mag0 = reshape(mag0, 1024, length(mag0)/1024);
     345octave> image(mag0*1000)
     346}}}
     347
     348Upload image of mag0...
     349