Tutorials/k0SDR/Tutorial04a: spectrum.cpp

File spectrum.cpp, 9.9 KB (added by nilanjan, 5 years ago)
Line 
1//
2// Copyright 2010-2011 Ettus Research LLC
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16//
17
18#include <uhd/utils/thread_priority.hpp>
19#include <uhd/utils/safe_main.hpp>
20#include <uhd/usrp/multi_usrp.hpp>
21#include <boost/program_options.hpp>
22#include <boost/thread/thread.hpp> //gets time
23#include <boost/format.hpp>
24#include <iostream>
25#include <complex>
26#include <fstream>
27#include <fftw3.h>
28#include "oml2/omlc.h"
29//#include "CWindowAverage.h"
30#include "CWriteOML_spectrum.h"
31//#include "CProfile.h"
32
33namespace po = boost::program_options;
34
35int UHD_SAFE_MAIN(int argc, char *argv[]){
36    uhd::set_thread_priority_safe();
37
38    //variables to be set by po
39    std::string args, ant, subdev, ref, oml_format;
40    size_t num_bins;
41    double rate, freq, gain, bw;
42    unsigned int nMovingAverageWindowSize;
43    long time_duration;
44
45    //setup the program options
46    po::options_description desc("Allowed options");
47    desc.add_options()
48        ("help", "help message")
49        ("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
50        // hardware parameters
51        ("rate", po::value<double>(&rate)->default_value(8e6), "rate of incoming samples (sps)")
52        ("freq", po::value<double>(&freq)->default_value(5000e6), "RF center frequency in Hz")
53        ("gain", po::value<double>(&gain), "gain for the RF chain")
54        ("ant", po::value<std::string>(&ant), "daughterboard antenna selection")
55        ("subdev", po::value<std::string>(&subdev), "daughterboard subdevice specification")
56        ("bw", po::value<double>(&bw), "daughterboard IF filter bandwidth in Hz")
57
58        ("num-bins", po::value<size_t>(&num_bins)->default_value(256), "the number of FFT points")
59        ("ref", po::value<std::string>(&ref)->default_value("internal"), "waveform type (internal, external, mimo)")
60
61        ("time", po::value<long>(&time_duration)->default_value(9999999), "time duration to run for in seconds")
62        ("oml", po::value<std::string>(&oml_format)->default_value("file"), "file - record values to oml text file, oml:3003 - record values to oml server")
63        ("win-size", po::value<size_t>(&nMovingAverageWindowSize)->default_value(4), "moving average window size for FFT bins");
64
65    po::variables_map vm;
66    po::store(po::parse_command_line(argc, argv, desc), vm);
67    po::notify(vm);
68
69    //print the help message
70    if (vm.count("help") or not vm.count("rate")){
71        std::cout << boost::format("UHD RX ASCII Art DFT %s") % desc << std::endl;
72        return ~0;
73    }
74
75    //create a usrp device
76    std::cout << std::endl;
77    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
78    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
79
80    //Lock mboard clocks
81    usrp->set_clock_source(ref);
82
83     //always select the subdevice first, the channel mapping affects the other settings
84    if (vm.count("subdev")) usrp->set_rx_subdev_spec(subdev);
85
86    std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
87
88    //set the sample rate
89    if (not vm.count("rate")){
90        std::cerr << "Please specify the sample rate with --rate" << std::endl;
91        return ~0;
92    }
93    std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
94    usrp->set_rx_rate(rate);
95    std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;
96
97    //set the center frequency
98    if (not vm.count("freq")){
99        std::cerr << "Please specify the center frequency with --freq" << std::endl;
100        return ~0;
101    }
102    std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl;
103    usrp->set_rx_freq(freq);
104    std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl;
105
106    //set the rf gain
107    if (vm.count("gain")){
108        std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
109        usrp->set_rx_gain(gain);
110        std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;
111    }
112
113    //set the IF filter bandwidth
114    if (vm.count("bw")){
115        std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % bw << std::endl;
116        usrp->set_rx_bandwidth(bw);
117        std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % usrp->get_rx_bandwidth() << std::endl << std::endl;
118    }
119
120    //set the antenna
121    if (vm.count("ant")) usrp->set_rx_antenna(ant);
122
123    boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time
124
125    //Check Ref and LO Lock detect
126    std::vector<std::string> sensor_names;
127    sensor_names = usrp->get_rx_sensor_names(0);
128    if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked") != sensor_names.end()) {
129        uhd::sensor_value_t lo_locked = usrp->get_rx_sensor("lo_locked",0);
130        std::cout << boost::format("Checking RX: %s ...") % lo_locked.to_pp_string() << std::endl;
131        UHD_ASSERT_THROW(lo_locked.to_bool());
132    }
133    sensor_names = usrp->get_mboard_sensor_names(0);
134    if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
135        uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
136        std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl;
137        UHD_ASSERT_THROW(mimo_locked.to_bool());
138    }
139    if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
140        uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
141        std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl;
142        UHD_ASSERT_THROW(ref_locked.to_bool());
143    }
144
145    //create a receive streamer
146    uhd::stream_args_t stream_args("fc32"); //complex floats
147    uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
148
149    unsigned int nCount = 0;
150
151    //allocate recv buffer and metatdata
152    uhd::rx_metadata_t md;
153    std::vector<std::complex<float> > buff(num_bins);
154    std::vector<std::complex<float> > out_buff(num_bins);
155
156    // allocate buffer for averaging vectors
157    std::vector<float> mag_buff(num_bins);
158
159    //std::vector<CWindowAverage > WindowAverage(num_bins);
160    CWriteOML OML;
161
162    //------------------------------------------------------------------
163    //-- Initialize
164    //------------------------------------------------------------------
165    usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
166    boost::system_time next_refresh = boost::get_system_time();
167
168    boost::system_time end_time = boost::get_system_time() + boost::posix_time::seconds(long(time_duration));
169
170    std::string db_filename("spectrum_measurement");
171    OML.init(db_filename, oml_format);
172    OML.start(num_bins);
173
174    // set up FFT engine
175    fftwf_complex *in = (fftwf_complex*)&buff.front();
176    fftwf_complex *out = (fftwf_complex*)&out_buff.front();
177    fftwf_plan p;
178
179    p = fftwf_plan_dft_1d(num_bins, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
180
181
182    std::cout << "refresh interval = " << long(1e6*num_bins/rate)  << std::endl;
183    std::cout << "fft bins = " << num_bins << std::endl;
184    //std::cout << "window size = " << nMovingAverageWindowSize << std::endl;
185
186    //------------------------------------------------------------------
187    //-- Main loop
188    //------------------------------------------------------------------
189    while (true){
190      nCount++;
191
192      if (boost::get_system_time() >= end_time) break;
193
194      //read a buffer's worth of samples every iteration
195      size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md);
196      //std::cerr << nCount << "  ";
197      if (num_rx_samps != buff.size())
198      {
199        std::cerr << num_rx_samps << " " << md.error_code << std::endl;
200        continue ;
201      }
202
203      //check and update the refresh condition - vile indeed... I put it down here and it quiets it down
204      if (boost::get_system_time() < next_refresh) { continue; }
205      next_refresh = boost::get_system_time() + boost::posix_time::microseconds(long(1e6*num_bins/rate));
206
207      //for (unsigned int i = 0 ; i < num_bins; i++)
208      //  buff.at(i) = std::complex<float>(1.0,0.0);
209
210      // take FFT
211      fftwf_execute(p); /* repeat as needed */
212
213      if (nCount % 4 /*nMovingAverageWindowSize*/ != 0) continue;
214
215      // find magnitude value
216      for (unsigned int i = 0 ; i < num_bins ; ++i)
217        mag_buff.at(i) = abs( out_buff.at(i) );
218
219      // dump out FD to file
220      OML.insert((uint32_t)rate, (float)freq, (uint32_t)gain, (char*)"---", (float*)&mag_buff.front());
221    }
222
223#if 0
224    {
225      std::fstream ofs( "fd.dat", std::ios::out | std::ios::binary );
226      ofs.write( (const char*)&out_buff.front(), sizeof(std::complex<float>)*out_buff.size() );
227      ofs.close();
228    }
229#endif
230
231    //------------------------------------------------------------------
232    //-- Cleanup
233    //------------------------------------------------------------------
234    fftwf_destroy_plan(p);
235
236    usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
237
238    OML.stop();
239
240    //finished
241    std::cout << std::endl << "Done!" << std::endl << std::endl;
242
243    return 0;
244}