//
// Copyright 2010-2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include
#include
#include
#include
#include //gets time
#include
#include
#include
#include
#include
#include "oml2/omlc.h"
//#include "CWindowAverage.h"
#include "CWriteOML_spectrum.h"
//#include "CProfile.h"
namespace po = boost::program_options;
int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::set_thread_priority_safe();
//variables to be set by po
std::string args, ant, subdev, ref, oml_format;
size_t num_bins;
double rate, freq, gain, bw;
unsigned int nMovingAverageWindowSize;
long time_duration;
//setup the program options
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
("args", po::value(&args)->default_value(""), "multi uhd device address args")
// hardware parameters
("rate", po::value(&rate)->default_value(8e6), "rate of incoming samples (sps)")
("freq", po::value(&freq)->default_value(5000e6), "RF center frequency in Hz")
("gain", po::value(&gain), "gain for the RF chain")
("ant", po::value(&ant), "daughterboard antenna selection")
("subdev", po::value(&subdev), "daughterboard subdevice specification")
("bw", po::value(&bw), "daughterboard IF filter bandwidth in Hz")
("num-bins", po::value(&num_bins)->default_value(256), "the number of FFT points")
("ref", po::value(&ref)->default_value("internal"), "waveform type (internal, external, mimo)")
("time", po::value(&time_duration)->default_value(9999999), "time duration to run for in seconds")
("oml", po::value(&oml_format)->default_value("file"), "file - record values to oml text file, oml:3003 - record values to oml server")
("win-size", po::value(&nMovingAverageWindowSize)->default_value(4), "moving average window size for FFT bins");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
//print the help message
if (vm.count("help") or not vm.count("rate")){
std::cout << boost::format("UHD RX ASCII Art DFT %s") % desc << std::endl;
return ~0;
}
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
//Lock mboard clocks
usrp->set_clock_source(ref);
//always select the subdevice first, the channel mapping affects the other settings
if (vm.count("subdev")) usrp->set_rx_subdev_spec(subdev);
std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
//set the sample rate
if (not vm.count("rate")){
std::cerr << "Please specify the sample rate with --rate" << std::endl;
return ~0;
}
std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
usrp->set_rx_rate(rate);
std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;
//set the center frequency
if (not vm.count("freq")){
std::cerr << "Please specify the center frequency with --freq" << std::endl;
return ~0;
}
std::cout << boost::format("Setting RX Freq: %f MHz...") % (freq/1e6) << std::endl;
usrp->set_rx_freq(freq);
std::cout << boost::format("Actual RX Freq: %f MHz...") % (usrp->get_rx_freq()/1e6) << std::endl << std::endl;
//set the rf gain
if (vm.count("gain")){
std::cout << boost::format("Setting RX Gain: %f dB...") % gain << std::endl;
usrp->set_rx_gain(gain);
std::cout << boost::format("Actual RX Gain: %f dB...") % usrp->get_rx_gain() << std::endl << std::endl;
}
//set the IF filter bandwidth
if (vm.count("bw")){
std::cout << boost::format("Setting RX Bandwidth: %f MHz...") % bw << std::endl;
usrp->set_rx_bandwidth(bw);
std::cout << boost::format("Actual RX Bandwidth: %f MHz...") % usrp->get_rx_bandwidth() << std::endl << std::endl;
}
//set the antenna
if (vm.count("ant")) usrp->set_rx_antenna(ant);
boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time
//Check Ref and LO Lock detect
std::vector sensor_names;
sensor_names = usrp->get_rx_sensor_names(0);
if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked") != sensor_names.end()) {
uhd::sensor_value_t lo_locked = usrp->get_rx_sensor("lo_locked",0);
std::cout << boost::format("Checking RX: %s ...") % lo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(lo_locked.to_bool());
}
sensor_names = usrp->get_mboard_sensor_names(0);
if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
}
if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
}
//create a receive streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
unsigned int nCount = 0;
//allocate recv buffer and metatdata
uhd::rx_metadata_t md;
std::vector > buff(num_bins);
std::vector > out_buff(num_bins);
// allocate buffer for averaging vectors
std::vector mag_buff(num_bins);
//std::vector WindowAverage(num_bins);
CWriteOML OML;
//------------------------------------------------------------------
//-- Initialize
//------------------------------------------------------------------
usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
boost::system_time next_refresh = boost::get_system_time();
boost::system_time end_time = boost::get_system_time() + boost::posix_time::seconds(long(time_duration));
std::string db_filename("spectrum_measurement");
OML.init(db_filename, oml_format);
OML.start(num_bins);
// set up FFT engine
fftwf_complex *in = (fftwf_complex*)&buff.front();
fftwf_complex *out = (fftwf_complex*)&out_buff.front();
fftwf_plan p;
p = fftwf_plan_dft_1d(num_bins, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
std::cout << "refresh interval = " << long(1e6*num_bins/rate) << std::endl;
std::cout << "fft bins = " << num_bins << std::endl;
//std::cout << "window size = " << nMovingAverageWindowSize << std::endl;
//------------------------------------------------------------------
//-- Main loop
//------------------------------------------------------------------
while (true){
nCount++;
if (boost::get_system_time() >= end_time) break;
//read a buffer's worth of samples every iteration
size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md);
//std::cerr << nCount << " ";
if (num_rx_samps != buff.size())
{
std::cerr << num_rx_samps << " " << md.error_code << std::endl;
continue ;
}
//check and update the refresh condition - vile indeed... I put it down here and it quiets it down
if (boost::get_system_time() < next_refresh) { continue; }
next_refresh = boost::get_system_time() + boost::posix_time::microseconds(long(1e6*num_bins/rate));
//for (unsigned int i = 0 ; i < num_bins; i++)
// buff.at(i) = std::complex(1.0,0.0);
// take FFT
fftwf_execute(p); /* repeat as needed */
if (nCount % 4 /*nMovingAverageWindowSize*/ != 0) continue;
// find magnitude value
for (unsigned int i = 0 ; i < num_bins ; ++i)
mag_buff.at(i) = abs( out_buff.at(i) );
// dump out FD to file
OML.insert((uint32_t)rate, (float)freq, (uint32_t)gain, (char*)"---", (float*)&mag_buff.front());
}
#if 0
{
std::fstream ofs( "fd.dat", std::ios::out | std::ios::binary );
ofs.write( (const char*)&out_buff.front(), sizeof(std::complex)*out_buff.size() );
ofs.close();
}
#endif
//------------------------------------------------------------------
//-- Cleanup
//------------------------------------------------------------------
fftwf_destroy_plan(p);
usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
OML.stop();
//finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
return 0;
}