Tutorials/k0SDR/Tutorial04a: spectrum.cpp

File spectrum.cpp, 9.9 KB (added by nilanjan, 10 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}