Merge branch 'next' of https://github.com/gnss-sdr/gnss-sdr into fix_dynamic_bit_selection

This commit is contained in:
Marc Majoral 2023-08-05 19:25:41 +02:00
commit ae526bcb14
52 changed files with 3914 additions and 350 deletions

View File

@ -40,6 +40,8 @@ option(ENABLE_FMCOMMS2 "Enable the use of FMCOMMS4-EBZ + ZedBoard hardware, requ
option(ENABLE_PLUTOSDR "Enable the use of ADALM-PLUTO Evaluation Boards (Analog Devices Inc.), requires gr-iio" OFF)
option(ENABLE_AD936X_SDR "Enable the use of AD936X front-ends using libiio, requires libiio" OFF)
option(ENABLE_AD9361 "Enable the use of AD9361 direct to FPGA hardware, requires libiio" OFF)
option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF)
@ -342,7 +344,7 @@ set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.13")
set(GNSSSDR_GTEST_LOCAL_VERSION "1.13.0")
set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "master")
set(GNSSSDR_GNSSTK_LOCAL_VERSION "14.0.0")
set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.8.0")
set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.8.2")
set(GNSSSDR_MATHJAX_EXTERNAL_VERSION "2.7.7")
# Downgrade versions if requirements are not met
@ -3152,6 +3154,7 @@ set_package_properties(LIBAD9361 PROPERTIES
)
if(NOT LIBAD9361_FOUND)
set(ENABLE_AD9361 OFF)
set(ENABLE_AD936X_SDR OFF)
set(ENABLE_FMCOMMS2 OFF)
endif()
if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2)
@ -3191,6 +3194,7 @@ if(ENABLE_AD9361 OR ENABLE_FMCOMMS2)
message(STATUS " * gnuradio-iio from https://github.com/analogdevicesinc/gr-iio")
if(ENABLE_PACKAGING)
set(ENABLE_AD9361 OFF)
set(ENABLE_AD936X_SDR OFF)
set(ENABLE_FMCOMMS2 OFF)
else()
message(FATAL_ERROR "libiio is required for building gnss-sdr with -DENABLE_AD9361=ON.")
@ -3404,6 +3408,7 @@ add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. R
add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.")
add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.")
add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.")
add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.")
add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.")
add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.")
add_feature_info(ENABLE_ARRAY ENABLE_ARRAY "Enables Raw_Array_Signal_Source and Array_Signal_Conditioner for using CTTC's antenna array. Requires gr-dbfcttc.")

View File

@ -12,6 +12,20 @@ SPDX-FileCopyrightText: 2011-2023 Carles Fernandez-Prades <carles.fernandez@cttc
All notable changes to GNSS-SDR will be documented in this file.
## [Unreleased](https://github.com/gnss-sdr/gnss-sdr/tree/next)
### Improvements in Repeatability
- A Kalman filter is now available in the PVT block, smoothing the outputs of a
simple Least Squares solution and improving the precision of delivered fixes.
It can be enabled by setting `PVT.enable_pvt_kf=true` in the configuration
file. The user can set values for the measurement and process noise
covariances with the following optional parameters (here with their default
values): `PVT.kf_measures_ecef_pos_sd_m=1.0`, in [m];
`PVT.kf_measures_ecef_vel_sd_ms=0.1`, in [m/s];
`PVT.kf_system_ecef_pos_sd_m=0.01`, in [m]; and
`PVT.kf_system_ecef_vel_sd_ms=0.001`, in [m/s].
## [GNSS-SDR v0.0.18](https://github.com/gnss-sdr/gnss-sdr/releases/tag/v0.0.18) - 2023-04-06
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7805514.svg)](https://doi.org/10.5281/zenodo.7805514)

View File

@ -74,6 +74,13 @@ Rtklib_Pvt::Rtklib_Pvt(const ConfigurationInterface* configuration,
// display rate
pvt_output_parameters.display_rate_ms = bc::lcm(pvt_output_parameters.output_rate_ms, configuration->property(role + ".display_rate_ms", 500));
// PVT KF settings
pvt_output_parameters.enable_pvt_kf = configuration->property(role + ".enable_pvt_kf", false);
pvt_output_parameters.measures_ecef_pos_sd_m = configuration->property(role + ".kf_measures_ecef_pos_sd_m", 1.0);
pvt_output_parameters.measures_ecef_vel_sd_ms = configuration->property(role + ".kf_measures_ecef_vel_sd_ms", 0.1);
pvt_output_parameters.system_ecef_pos_sd_m = configuration->property(role + ".kf_system_ecef_pos_sd_m", 0.01);
pvt_output_parameters.system_ecef_vel_sd_ms = configuration->property(role + ".kf_system_ecef_vel_sd_ms", 0.001);
// NMEA Printer settings
pvt_output_parameters.flag_nmea_tty_port = configuration->property(role + ".flag_nmea_tty_port", false);
pvt_output_parameters.nmea_dump_filename = configuration->property(role + ".nmea_dump_filename", default_nmea_dump_filename);

View File

@ -178,7 +178,6 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels,
d_enable_rx_clock_correction(conf_.enable_rx_clock_correction),
d_an_printer_enabled(conf_.an_output_enabled),
d_log_timetag(conf_.log_source_timetag),
d_use_e6_for_pvt(conf_.use_e6_for_pvt),
d_use_has_corrections(conf_.use_has_corrections),
d_use_unhealthy_sats(conf_.use_unhealthy_sats)
{
@ -535,22 +534,19 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels,
{
// setup two PVT solvers: internal solver for rx clock and user solver
// user PVT solver
d_user_pvt_solver = std::make_shared<Rtklib_Solver>(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, d_use_e6_for_pvt);
d_user_pvt_solver->set_averaging_depth(1);
d_user_pvt_solver = std::make_shared<Rtklib_Solver>(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, conf_);
d_user_pvt_solver->set_pre_2009_file(conf_.pre_2009_file);
// internal PVT solver, mainly used to estimate the receiver clock
rtk_t internal_rtk = rtk;
internal_rtk.opt.mode = PMODE_SINGLE; // use single positioning mode in internal PVT solver
d_internal_pvt_solver = std::make_shared<Rtklib_Solver>(internal_rtk, dump_ls_pvt_filename, d_type_of_rx, false, false, d_use_e6_for_pvt);
d_internal_pvt_solver->set_averaging_depth(1);
d_internal_pvt_solver = std::make_shared<Rtklib_Solver>(internal_rtk, dump_ls_pvt_filename, d_type_of_rx, false, false, conf_);
d_internal_pvt_solver->set_pre_2009_file(conf_.pre_2009_file);
}
else
{
// only one solver, customized by the user options
d_internal_pvt_solver = std::make_shared<Rtklib_Solver>(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, d_use_e6_for_pvt);
d_internal_pvt_solver->set_averaging_depth(1);
d_internal_pvt_solver = std::make_shared<Rtklib_Solver>(rtk, dump_ls_pvt_filename, d_type_of_rx, d_dump, d_dump_mat, conf_);
d_internal_pvt_solver->set_pre_2009_file(conf_.pre_2009_file);
d_user_pvt_solver = d_internal_pvt_solver;
}
@ -2110,7 +2106,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
// old_time_debug = d_gnss_observables_map.cbegin()->second.RX_time * 1000.0;
uint32_t current_RX_time_ms = 0;
// #### solve PVT and store the corrected observable set
if (d_internal_pvt_solver->get_PVT(d_gnss_observables_map, false))
if (d_internal_pvt_solver->get_PVT(d_gnss_observables_map, d_observable_interval_ms / 1000.0))
{
d_pvt_errors_counter = 0; // Reset consecutive PVT error counter
const double Rx_clock_offset_s = d_internal_pvt_solver->get_time_offset_s();
@ -2224,7 +2220,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
// compute on the fly PVT solution
if (flag_compute_pvt_output == true)
{
flag_pvt_valid = d_user_pvt_solver->get_PVT(d_gnss_observables_map, false);
flag_pvt_valid = d_user_pvt_solver->get_PVT(d_gnss_observables_map, d_output_rate_ms / 1000.0);
}
if (flag_pvt_valid == true)
@ -2336,28 +2332,28 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
{
if (current_RX_time_ms % d_kml_rate_ms == 0)
{
d_kml_dump->print_position(d_user_pvt_solver.get(), false);
d_kml_dump->print_position(d_user_pvt_solver.get());
}
}
if (d_gpx_output_enabled)
{
if (current_RX_time_ms % d_gpx_rate_ms == 0)
{
d_gpx_dump->print_position(d_user_pvt_solver.get(), false);
d_gpx_dump->print_position(d_user_pvt_solver.get());
}
}
if (d_geojson_output_enabled)
{
if (current_RX_time_ms % d_geojson_rate_ms == 0)
{
d_geojson_printer->print_position(d_user_pvt_solver.get(), false);
d_geojson_printer->print_position(d_user_pvt_solver.get());
}
}
if (d_nmea_output_file_enabled)
{
if (current_RX_time_ms % d_nmea_rate_ms == 0)
{
d_nmea_printer->Print_Nmea_Line(d_user_pvt_solver.get(), false);
d_nmea_printer->Print_Nmea_Line(d_user_pvt_solver.get());
}
}
if (d_rinex_output_enabled)

View File

@ -276,7 +276,6 @@ private:
bool d_enable_has_messages;
bool d_an_printer_enabled;
bool d_log_timetag;
bool d_use_e6_for_pvt;
bool d_use_has_corrections;
bool d_use_unhealthy_sats;
};

View File

@ -23,6 +23,7 @@ set(PVT_LIB_SOURCES
monitor_ephemeris_udp_sink.cc
has_simple_printer.cc
geohash.cc
pvt_kf.cc
)
set(PVT_LIB_HEADERS
@ -45,6 +46,7 @@ set(PVT_LIB_HEADERS
monitor_ephemeris_udp_sink.h
has_simple_printer.h
geohash.h
pvt_kf.h
)
list(SORT PVT_LIB_HEADERS)

View File

@ -156,24 +156,11 @@ bool GeoJSON_Printer::set_headers(const std::string& filename, bool time_tag_nam
}
bool GeoJSON_Printer::print_position(const Pvt_Solution* const position, bool print_average_values)
bool GeoJSON_Printer::print_position(const Pvt_Solution* const position)
{
double latitude;
double longitude;
double height;
if (print_average_values == false)
{
latitude = position->get_latitude();
longitude = position->get_longitude();
height = position->get_height();
}
else
{
latitude = position->get_avg_latitude();
longitude = position->get_avg_longitude();
height = position->get_avg_height();
}
const double latitude = position->get_latitude();
const double longitude = position->get_longitude();
const double height = position->get_height();
if (geojson_file.is_open())
{

View File

@ -42,7 +42,7 @@ public:
explicit GeoJSON_Printer(const std::string& base_path = ".");
~GeoJSON_Printer();
bool set_headers(const std::string& filename, bool time_tag_name = true);
bool print_position(const Pvt_Solution* const position, bool print_average_values);
bool print_position(const Pvt_Solution* const position);
bool close_file();
private:

View File

@ -140,12 +140,8 @@ bool Gpx_Printer::set_headers(const std::string& filename, bool time_tag_name)
}
bool Gpx_Printer::print_position(const Pvt_Solution* const position, bool print_average_values)
bool Gpx_Printer::print_position(const Pvt_Solution* const position)
{
double latitude;
double longitude;
double height;
positions_printed = true;
const double speed_over_ground = position->get_speed_over_ground(); // expressed in m/s
@ -162,18 +158,9 @@ bool Gpx_Printer::print_position(const Pvt_Solution* const position, bool print_
utc_time.resize(23, '0'); // time up to ms
utc_time.append("Z"); // UTC time zone
if (print_average_values == false)
{
latitude = position->get_latitude();
longitude = position->get_longitude();
height = position->get_height();
}
else
{
latitude = position->get_avg_latitude();
longitude = position->get_avg_longitude();
height = position->get_avg_height();
}
const double latitude = position->get_latitude();
const double longitude = position->get_longitude();
const double height = position->get_height();
if (gpx_file.is_open())
{

View File

@ -42,7 +42,7 @@ public:
explicit Gpx_Printer(const std::string& base_path = ".");
~Gpx_Printer();
bool set_headers(const std::string& filename, bool time_tag_name = true);
bool print_position(const Pvt_Solution* const position, bool print_average_values);
bool print_position(const Pvt_Solution* const position);
bool close_file();
private:

View File

@ -210,12 +210,8 @@ bool Kml_Printer::set_headers(const std::string& filename, bool time_tag_name)
}
bool Kml_Printer::print_position(const Pvt_Solution* const position, bool print_average_values)
bool Kml_Printer::print_position(const Pvt_Solution* const position)
{
double latitude;
double longitude;
double height;
positions_printed = true;
const double speed_over_ground = position->get_speed_over_ground(); // expressed in m/s
@ -232,18 +228,9 @@ bool Kml_Printer::print_position(const Pvt_Solution* const position, bool print_
utc_time.resize(23, '0'); // time up to ms
utc_time.append("Z"); // UTC time zone
if (print_average_values == false)
{
latitude = position->get_latitude();
longitude = position->get_longitude();
height = position->get_height();
}
else
{
latitude = position->get_avg_latitude();
longitude = position->get_avg_longitude();
height = position->get_avg_height();
}
const double latitude = position->get_latitude();
const double longitude = position->get_longitude();
const double height = position->get_height();
if (kml_file.is_open() && tmp_file.is_open())
{

View File

@ -41,7 +41,7 @@ public:
explicit Kml_Printer(const std::string& base_path = std::string("."));
~Kml_Printer();
bool set_headers(const std::string& filename, bool time_tag_name = true);
bool print_position(const Pvt_Solution* const position, bool print_average_values);
bool print_position(const Pvt_Solution* const position);
bool close_file();
private:

View File

@ -100,7 +100,7 @@ Nmea_Printer::Nmea_Printer(const std::string& filename,
{
nmea_dev_descriptor = -1;
}
print_avg_pos = false;
d_PVT_data = nullptr;
}
@ -190,11 +190,10 @@ void Nmea_Printer::close_serial() const
}
bool Nmea_Printer::Print_Nmea_Line(const Rtklib_Solver* const pvt_data, bool print_average_values)
bool Nmea_Printer::Print_Nmea_Line(const Rtklib_Solver* const pvt_data)
{
// set the new PVT data
d_PVT_data = pvt_data;
print_avg_pos = print_average_values;
// generate the NMEA sentences

View File

@ -57,7 +57,7 @@ public:
/*!
* \brief Print NMEA PVT and satellite info to the initialized device
*/
bool Print_Nmea_Line(const Rtklib_Solver* const pvt_data, bool print_average_values);
bool Print_Nmea_Line(const Rtklib_Solver* const pvt_data);
private:
int init_serial(const std::string& serial_device); // serial port control
@ -80,8 +80,6 @@ private:
std::string nmea_devname;
int nmea_dev_descriptor; // NMEA serial device descriptor (i.e. COM port)
bool print_avg_pos;
bool d_flag_nmea_output_file;
};

View File

@ -94,6 +94,13 @@ public:
bool use_e6_for_pvt = true;
bool use_has_corrections = true;
bool use_unhealthy_sats = false;
// PVT KF parameters
bool enable_pvt_kf = false;
double measures_ecef_pos_sd_m = 1.0;
double measures_ecef_vel_sd_ms = 0.1;
double system_ecef_pos_sd_m = 0.01;
double system_ecef_vel_sd_ms = 0.001;
};

View File

@ -0,0 +1,133 @@
/*!
* \file pvt_kf.cc
* \brief Kalman Filter for Position and Velocity
* \author Javier Arribas, 2023. jarribas(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "pvt_kf.h"
#include <glog/logging.h>
void Pvt_Kf::init_Kf(const arma::vec& p,
const arma::vec& v,
double update_interval_s,
double measures_ecef_pos_sd_m,
double measures_ecef_vel_sd_ms,
double system_ecef_pos_sd_m,
double system_ecef_vel_sd_ms)
{
// Kalman Filter class variables
const double Ti = update_interval_s;
d_F = {{1.0, 0.0, 0.0, Ti, 0.0, 0.0},
{0.0, 1.0, 0.0, 0.0, Ti, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0, Ti},
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 1.0}};
d_H = arma::eye(6, 6);
// measurement matrix static covariances
d_R = {{pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, pow(measures_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0), 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0), 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, pow(measures_ecef_vel_sd_ms, 2.0)}};
// system covariance matrix (static)
d_Q = {{pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0)}};
// initial Kalman covariance matrix
d_P_old_old = {{pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, pow(system_ecef_pos_sd_m, 2.0), 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0), 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, pow(system_ecef_vel_sd_ms, 2.0)}};
// states: position ecef [m], velocity ecef [m/s]
d_x_old_old = arma::zeros(6);
d_x_old_old.subvec(0, 2) = p;
d_x_old_old.subvec(3, 5) = v;
d_initialized = true;
DLOG(INFO) << "Ti: " << Ti;
DLOG(INFO) << "F: " << d_F;
DLOG(INFO) << "H: " << d_H;
DLOG(INFO) << "R: " << d_R;
DLOG(INFO) << "Q: " << d_Q;
DLOG(INFO) << "P: " << d_P_old_old;
DLOG(INFO) << "x: " << d_x_old_old;
}
bool Pvt_Kf::is_initialized() const
{
return d_initialized;
}
void Pvt_Kf::reset_Kf()
{
d_initialized = false;
}
void Pvt_Kf::run_Kf(const arma::vec& p, const arma::vec& v)
{
if (d_initialized)
{
// Kalman loop
// Prediction
d_x_new_old = d_F * d_x_old_old;
d_P_new_old = d_F * d_P_old_old * d_F.t() + d_Q;
// Measurement update
try
{
arma::vec z = arma::join_cols(p, v);
arma::mat K = d_P_new_old * d_H.t() * arma::inv(d_H * d_P_new_old * d_H.t() + d_R); // Kalman gain
d_x_new_new = d_x_new_old + K * (z - d_H * d_x_new_old);
d_P_new_new = (arma::eye(6, 6) - K * d_H) * d_P_new_old;
// prepare data for next KF epoch
d_x_old_old = d_x_new_new;
d_P_old_old = d_P_new_new;
}
catch (...)
{
d_x_new_new = d_x_new_old;
this->reset_Kf();
}
}
}
void Pvt_Kf::get_pv_Kf(arma::vec& p, arma::vec& v) const
{
if (d_initialized)
{
p = d_x_new_new.subvec(0, 2);
v = d_x_new_new.subvec(3, 5);
}
}

View File

@ -0,0 +1,68 @@
/*!
* \file pvt_kf.h
* \brief Kalman Filter for Position and Velocity
* \author Javier Arribas, 2023. jarribas(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_PVT_KF_H
#define GNSS_SDR_PVT_KF_H
#include <armadillo>
/** \addtogroup PVT
* \{ */
/** \addtogroup PVT_libs
* \{ */
/*!
* \brief Kalman Filter for Position and Velocity
*
*/
class Pvt_Kf
{
public:
Pvt_Kf() = default;
virtual ~Pvt_Kf() = default;
void init_Kf(const arma::vec& p,
const arma::vec& v,
double update_interval_s,
double measures_ecef_pos_sd_m,
double measures_ecef_vel_sd_ms,
double system_ecef_pos_sd_m,
double system_ecef_vel_sd_ms);
bool is_initialized() const;
void run_Kf(const arma::vec& p, const arma::vec& v);
void get_pv_Kf(arma::vec& p, arma::vec& v) const;
void reset_Kf();
private:
// Kalman Filter class variables
arma::mat d_F;
arma::mat d_H;
arma::mat d_R;
arma::mat d_Q;
arma::mat d_P_old_old;
arma::mat d_P_new_old;
arma::mat d_P_new_new;
arma::vec d_x_old_old;
arma::vec d_x_new_old;
arma::vec d_x_new_new;
bool d_initialized{false};
};
/** \} */
/** \} */
#endif // GNSS_SDR_Pvt_Kf_H

View File

@ -69,70 +69,6 @@ int Pvt_Solution::cart2geo(double X, double Y, double Z, int elipsoid_selection)
}
void Pvt_Solution::set_averaging_depth(int depth)
{
d_averaging_depth = depth;
}
void Pvt_Solution::set_averaging_flag(bool flag)
{
d_flag_averaging = flag;
}
void Pvt_Solution::perform_pos_averaging()
{
// MOVING AVERAGE PVT
bool avg = d_flag_averaging;
if (avg == true)
{
if (d_hist_longitude_d.size() == static_cast<unsigned int>(d_averaging_depth))
{
// Pop oldest value
d_hist_longitude_d.pop_back();
d_hist_latitude_d.pop_back();
d_hist_height_m.pop_back();
// Push new values
d_hist_longitude_d.push_front(d_longitude_d);
d_hist_latitude_d.push_front(d_latitude_d);
d_hist_height_m.push_front(d_height_m);
d_avg_latitude_d = 0.0;
d_avg_longitude_d = 0.0;
d_avg_height_m = 0.0;
for (size_t i = 0; i < d_hist_longitude_d.size(); i++)
{
d_avg_latitude_d = d_avg_latitude_d + d_hist_latitude_d.at(i);
d_avg_longitude_d = d_avg_longitude_d + d_hist_longitude_d.at(i);
d_avg_height_m = d_avg_height_m + d_hist_height_m.at(i);
}
d_avg_latitude_d = d_avg_latitude_d / static_cast<double>(d_averaging_depth);
d_avg_longitude_d = d_avg_longitude_d / static_cast<double>(d_averaging_depth);
d_avg_height_m = d_avg_height_m / static_cast<double>(d_averaging_depth);
d_valid_position = true;
}
else
{
// int current_depth=d_hist_longitude_d.size();
// Push new values
d_hist_longitude_d.push_front(d_longitude_d);
d_hist_latitude_d.push_front(d_latitude_d);
d_hist_height_m.push_front(d_height_m);
d_avg_latitude_d = d_latitude_d;
d_avg_longitude_d = d_longitude_d;
d_avg_height_m = d_height_m;
d_valid_position = false;
}
}
else
{
d_valid_position = true;
}
}
double Pvt_Solution::get_time_offset_s() const
{
return d_rx_dt_s;
@ -199,30 +135,6 @@ double Pvt_Solution::get_course_over_ground() const
}
double Pvt_Solution::get_avg_latitude() const
{
return d_avg_latitude_d;
}
double Pvt_Solution::get_avg_longitude() const
{
return d_avg_longitude_d;
}
double Pvt_Solution::get_avg_height() const
{
return d_avg_height_m;
}
bool Pvt_Solution::is_averaging() const
{
return d_flag_averaging;
}
bool Pvt_Solution::is_valid_position() const
{
return d_valid_position;

View File

@ -20,7 +20,6 @@
#include <boost/date_time/posix_time/posix_time.hpp>
#include <array>
#include <deque>
/** \addtogroup PVT
* \{ */
@ -38,20 +37,10 @@ public:
Pvt_Solution() = default;
virtual ~Pvt_Solution() = default;
void set_rx_pos(const std::array<double, 3> &pos); //!< Set position: X, Y, Z in Cartesian ECEF coordinates [m]
void set_rx_vel(const std::array<double, 3> &vel); //!< Set velocity: East [m/s], North [m/s], Up [m/s]
void set_position_UTC_time(const boost::posix_time::ptime &pt);
void set_time_offset_s(double offset); //!< Set RX time offset [s]
void set_clock_drift_ppm(double clock_drift_ppm); //!< Set the Rx clock drift [ppm]
void set_speed_over_ground(double speed_m_s); //!< Set RX speed over ground [m/s]
void set_course_over_ground(double cog_deg); //!< Set RX course over ground [deg]
void set_valid_position(bool is_valid);
void set_num_valid_observations(int num); //!< Set the number of valid pseudorange observations (valid satellites)
void set_pre_2009_file(bool pre_2009_file); //!< Flag for the week rollover computation in post processing mode for signals older than 2009
// averaging
void set_averaging_depth(int depth); //!< Set length of averaging window
void set_averaging_flag(bool flag);
void perform_pos_averaging();
virtual double get_hdop() const = 0;
virtual double get_vdop() const = 0;
virtual double get_pdop() const = 0;
virtual double get_gdop() const = 0;
std::array<double, 3> get_rx_pos() const;
std::array<double, 3> get_rx_vel() const;
@ -63,18 +52,20 @@ public:
double get_clock_drift_ppm() const; //!< Get the Rx clock drift [ppm]
double get_speed_over_ground() const; //!< Get RX speed over ground [m/s]
double get_course_over_ground() const; //!< Get RX course over ground [deg]
double get_avg_latitude() const; //!< Get RX position averaged Latitude WGS84 [deg]
double get_avg_longitude() const; //!< Get RX position averaged Longitude WGS84 [deg]
double get_avg_height() const; //!< Get RX position averaged height WGS84 [m]
int get_num_valid_observations() const; //!< Get the number of valid pseudorange observations (valid satellites)
bool is_pre_2009() const;
bool is_valid_position() const;
bool is_averaging() const;
virtual double get_hdop() const = 0;
virtual double get_vdop() const = 0;
virtual double get_pdop() const = 0;
virtual double get_gdop() const = 0;
void set_rx_pos(const std::array<double, 3> &pos); //!< Set position: X, Y, Z in Cartesian ECEF coordinates [m]
void set_rx_vel(const std::array<double, 3> &vel); //!< Set velocity: East [m/s], North [m/s], Up [m/s]
void set_position_UTC_time(const boost::posix_time::ptime &pt);
void set_time_offset_s(double offset); //!< Set RX time offset [s]
void set_clock_drift_ppm(double clock_drift_ppm); //!< Set the Rx clock drift [ppm]
void set_speed_over_ground(double speed_m_s); //!< Set RX speed over ground [m/s]
void set_course_over_ground(double cog_deg); //!< Set RX course over ground [deg]
void set_valid_position(bool is_valid);
void set_num_valid_observations(int num); //!< Set the number of valid pseudorange observations (valid satellites)
void set_pre_2009_file(bool pre_2009_file); //!< Flag for the week rollover computation in post processing mode for signals older than 2009
private:
/*
@ -98,10 +89,6 @@ private:
std::array<double, 3> d_rx_vel{};
boost::posix_time::ptime d_position_UTC_time;
std::deque<double> d_hist_latitude_d;
std::deque<double> d_hist_longitude_d;
std::deque<double> d_hist_height_m;
double d_latitude_d{0.0}; // RX position Latitude WGS84 [deg]
double d_longitude_d{0.0}; // RX position Longitude WGS84 [deg]
double d_height_m{0.0}; // RX position height WGS84 [m]
@ -110,16 +97,10 @@ private:
double d_speed_over_ground_m_s{0.0}; // RX speed over ground [m/s]
double d_course_over_ground_d{0.0}; // RX course over ground [deg]
double d_avg_latitude_d{0.0}; // Averaged latitude in degrees
double d_avg_longitude_d{0.0}; // Averaged longitude in degrees
double d_avg_height_m{0.0}; // Averaged height [m]
int d_averaging_depth{0}; // Length of averaging window
int d_valid_observations{0}; // Number of valid observations in this epoch
bool d_pre_2009_file{false}; // Flag to correct week rollover in post processing mode for signals older than 2009
bool d_valid_position{false};
bool d_flag_averaging{false};
};

View File

@ -49,15 +49,13 @@ Rtklib_Solver::Rtklib_Solver(const rtk_t &rtk,
uint32_t type_of_rx,
bool flag_dump_to_file,
bool flag_dump_to_mat,
bool use_e6_for_pvt) : d_dump_filename(dump_filename),
d_rtk(rtk),
d_type_of_rx(type_of_rx),
d_flag_dump_enabled(flag_dump_to_file),
d_flag_dump_mat_enabled(flag_dump_to_mat),
d_use_e6_for_pvt(use_e6_for_pvt)
Pvt_Conf conf) : d_dump_filename(dump_filename),
d_rtk(rtk),
d_conf(std::move(conf)),
d_type_of_rx(type_of_rx),
d_flag_dump_enabled(flag_dump_to_file),
d_flag_dump_mat_enabled(flag_dump_to_mat)
{
this->set_averaging_flag(false);
// see freq index at src/algorithms/libs/rtklib/rtklib_rtkcmn.cc
// function: satwavelen
d_rtklib_freq_index[0] = 0;
@ -900,7 +898,7 @@ void Rtklib_Solver::get_current_has_obs_correction(const std::string &signal, ui
}
bool Rtklib_Solver::get_PVT(const std::map<int, Gnss_Synchro> &gnss_observables_map, bool flag_averaging)
bool Rtklib_Solver::get_PVT(const std::map<int, Gnss_Synchro> &gnss_observables_map, double kf_update_interval_s)
{
std::map<int, Gnss_Synchro>::const_iterator gnss_observables_iter;
std::map<int, Galileo_Ephemeris>::const_iterator galileo_ephemeris_iter;
@ -911,8 +909,6 @@ bool Rtklib_Solver::get_PVT(const std::map<int, Gnss_Synchro> &gnss_observables_
const Glonass_Gnav_Utc_Model &gnav_utc = this->glonass_gnav_utc_model;
this->set_averaging_flag(flag_averaging);
// ********************************************************************************
// ****** PREPARE THE DATA (SV EPHEMERIS AND OBSERVATIONS) ************************
// ********************************************************************************
@ -1039,7 +1035,7 @@ bool Rtklib_Solver::get_PVT(const std::map<int, Gnss_Synchro> &gnss_observables_
DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN;
}
}
if (sig_ == "E6" && d_use_e6_for_pvt)
if (sig_ == "E6" && d_conf.use_e6_for_pvt)
{
galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN);
if (galileo_ephemeris_iter != galileo_ephemeris_map.cend())
@ -1083,6 +1079,47 @@ bool Rtklib_Solver::get_PVT(const std::map<int, Gnss_Synchro> &gnss_observables_
DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN;
}
}
if (sig_ == "E6")
{
galileo_ephemeris_iter = galileo_ephemeris_map.find(gnss_observables_iter->second.PRN);
if (galileo_ephemeris_iter != galileo_ephemeris_map.cend())
{
bool found_E1_obs = false;
for (int i = 0; i < valid_obs; i++)
{
if (eph_data[i].sat == (static_cast<int>(gnss_observables_iter->second.PRN + NSATGPS + NSATGLO)))
{
d_obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(d_obs_data[i + glo_valid_obs],
gnss_observables_iter->second,
galileo_ephemeris_iter->second.WN,
2); // Band E6
found_E1_obs = true;
break;
}
}
if (!found_E1_obs)
{
// insert Galileo E6 obs as new obs and also insert its ephemeris
// convert ephemeris from GNSS-SDR class to RTKLIB structure
eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second);
// convert observation from GNSS-SDR class to RTKLIB structure
const auto default_code_ = static_cast<unsigned char>(CODE_NONE);
obsd_t newobs = {{0, 0}, '0', '0', {}, {},
{default_code_, default_code_, default_code_},
{}, {0.0, 0.0, 0.0}, {}};
d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs,
gnss_observables_iter->second,
galileo_ephemeris_iter->second.WN,
2); // Band E6
// std::cout << "Week " << galileo_ephemeris_iter->second.WN << '\n';
valid_obs++;
}
}
else // the ephemeris are not available for this SV
{
DLOG(INFO) << "No ephemeris data for SV " << gnss_observables_iter->second.PRN;
}
}
break;
}
case 'G':
@ -1466,6 +1503,10 @@ bool Rtklib_Solver::get_PVT(const std::map<int, Gnss_Synchro> &gnss_observables_
d_rtk.neb = 0; // clear error buffer to avoid repeating the error message
this->set_time_offset_s(0.0); // reset rx time estimation
this->set_num_valid_observations(0);
if (d_conf.enable_pvt_kf == true)
{
d_pvt_kf.reset_Kf();
}
}
else
{
@ -1500,9 +1541,41 @@ bool Rtklib_Solver::get_PVT(const std::map<int, Gnss_Synchro> &gnss_observables_
}
this->set_valid_position(true);
std::array<double, 4> rx_position_and_time{};
if (d_conf.enable_pvt_kf == true)
{
if (d_pvt_kf.is_initialized() == false)
{
arma::vec p = {pvt_sol.rr[0], pvt_sol.rr[1], pvt_sol.rr[2]};
arma::vec v = {pvt_sol.rr[3], pvt_sol.rr[4], pvt_sol.rr[5]};
d_pvt_kf.init_Kf(p,
v,
kf_update_interval_s,
d_conf.measures_ecef_pos_sd_m,
d_conf.measures_ecef_vel_sd_ms,
d_conf.system_ecef_pos_sd_m,
d_conf.system_ecef_vel_sd_ms);
}
else
{
arma::vec p = {pvt_sol.rr[0], pvt_sol.rr[1], pvt_sol.rr[2]};
arma::vec v = {pvt_sol.rr[3], pvt_sol.rr[4], pvt_sol.rr[5]};
d_pvt_kf.run_Kf(p, v);
d_pvt_kf.get_pv_Kf(p, v);
pvt_sol.rr[0] = p[0]; // [m]
pvt_sol.rr[1] = p[1]; // [m]
pvt_sol.rr[2] = p[2]; // [m]
pvt_sol.rr[3] = v[0]; // [ms]
pvt_sol.rr[4] = v[1]; // [ms]
pvt_sol.rr[5] = v[2]; // [ms]
}
}
rx_position_and_time[0] = pvt_sol.rr[0]; // [m]
rx_position_and_time[1] = pvt_sol.rr[1]; // [m]
rx_position_and_time[2] = pvt_sol.rr[2]; // [m]
// todo: fix this ambiguity in the RTKLIB units in receiver clock offset!
if (d_rtk.opt.mode == PMODE_SINGLE)
{

View File

@ -56,6 +56,8 @@
#include "gps_iono.h"
#include "gps_utc_model.h"
#include "monitor_pvt.h"
#include "pvt_conf.h"
#include "pvt_kf.h"
#include "pvt_solution.h"
#include "rtklib.h"
#include "rtklib_conversions.h"
@ -84,10 +86,10 @@ public:
uint32_t type_of_rx,
bool flag_dump_to_file,
bool flag_dump_to_mat,
bool use_e6_for_pvt = true);
Pvt_Conf conf);
~Rtklib_Solver();
bool get_PVT(const std::map<int, Gnss_Synchro>& gnss_observables_map, bool flag_averaging);
bool get_PVT(const std::map<int, Gnss_Synchro>& gnss_observables_map, double kf_update_interval_s);
double get_hdop() const override;
double get_vdop() const override;
@ -149,10 +151,11 @@ private:
rtk_t d_rtk{};
nav_t d_nav_data{};
Monitor_Pvt d_monitor_pvt{};
Pvt_Conf d_conf;
Pvt_Kf d_pvt_kf;
uint32_t d_type_of_rx;
bool d_flag_dump_enabled;
bool d_flag_dump_mat_enabled;
bool d_use_e6_for_pvt;
};

View File

@ -16,8 +16,13 @@ if(ENABLE_PLUTOSDR)
##############################################
# ADALM-PLUTO (Analog Devices Inc.)
##############################################
list(APPEND OPT_DRIVER_SOURCES plutosdr_signal_source.cc)
list(APPEND OPT_DRIVER_HEADERS plutosdr_signal_source.h)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} plutosdr_signal_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} plutosdr_signal_source.h)
##############################################
# CUSTOM AD936X IIO SOURCE
##############################################
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_custom_signal_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_custom_signal_source.h)
endif()
if(ENABLE_FMCOMMS2)
@ -94,6 +99,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES
labsat_signal_source.cc
two_bit_cpx_file_signal_source.cc
two_bit_packed_file_signal_source.cc
four_bit_cpx_file_signal_source.cc
file_timestamp_signal_source.cc
${OPT_DRIVER_SOURCES}
)
@ -112,6 +118,7 @@ set(SIGNAL_SOURCE_ADAPTER_HEADERS
labsat_signal_source.h
two_bit_cpx_file_signal_source.h
two_bit_packed_file_signal_source.h
four_bit_cpx_file_signal_source.h
file_timestamp_signal_source.h
${OPT_DRIVER_HEADERS}
)

View File

@ -0,0 +1,541 @@
/*!
* \file ad936x_custom_signal_source.cc
* \brief A direct IIO custom front-end gnss-sdr signal source for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ad936x_custom_signal_source.h"
#include "configuration_interface.h"
#include "gnss_frequencies.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <boost/exception/diagnostic_information.hpp>
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <iostream>
using namespace std::string_literals;
Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_stream,
unsigned int out_stream,
Concurrent_Queue<pmt::pmt_t>* queue __attribute__((unused)))
: SignalSourceBase(configuration, role, "Ad936x_Custom_Signal_Source"s),
in_stream_(in_stream),
out_stream_(out_stream),
item_type_(configuration->property(role + ".item_type", std::string("gr_complex"))),
samples_(configuration->property(role + ".samples", int64_t(0))),
dump_(configuration->property(role + ".dump", false)),
dump_filename_(configuration->property(role + ".dump_filename", std::string("./data/signal_source.dat"))),
pluto_uri_(configuration->property(role + ".pluto_uri", std::string("local"))),
board_type_(configuration->property(role + ".board_type", std::string("single_ad9361"))),
sample_rate_(configuration->property(role + ".sampling_frequency", 4.0e6)),
bandwidth_(configuration->property(role + ".bandwidth", configuration->property(role + ".sampling_frequency", 4.0e6) / 1.1)),
freq_(configuration->property(role + ".freq", FREQ1)),
freq_2ch(configuration->property(role + ".freq_2ch", FREQ1)),
rf_port_select_(configuration->property(role + ".rf_port_select", std::string("A_BALANCED"))),
rf_filter(configuration->property(role + ".rf_filter", std::string("none"))),
gain_mode_rx0_(configuration->property(role + ".gain_mode_rx0", std::string("slow_attack"))),
gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", std::string("slow_attack"))),
rf_gain_rx0_(configuration->property(role + ".gain_rx0", 40.0)),
rf_gain_rx1_(configuration->property(role + ".gain_rx1", 40.0)),
enable_ch0(configuration->property(role + ".enable_ch0", true)),
enable_ch1(configuration->property(role + ".enable_ch1", false)),
PPS_mode_(configuration->property(role + ".PPS_mode", false)),
fe_ip_(configuration->property(role + ".fe_ip", std::string("192.168.2.1"))),
fe_ctlport_(configuration->property(role + ".fe_ctlport", int32_t(10000))),
ssize_(configuration->property(role + ".ssize", int32_t(12))),
bshift_(configuration->property(role + ".bshift", int64_t(0))),
spattern_(configuration->property(role + ".spattern", false)),
inverted_spectrum_ch0_(configuration->property(role + ".inverted_spectrum_ch0", false)),
inverted_spectrum_ch1_(configuration->property(role + ".inverted_spectrum_ch1", false)),
lo_attenuation_db_(configuration->property(role + ".lo_attenuation_db", 6.0)),
high_side_lo_(configuration->property(role + ".high_side_lo", false)),
tx_lo_channel_(configuration->property(role + ".tx_lo_channel", 1)),
rx0_to_rx1_delay_ns_(configuration->property(role + ".rx0_to_rx1_delay_ns", 0.0))
{
if (item_type_ == "gr_complex")
{
item_size_ = sizeof(gr_complex);
// 1. Make the driver instance
bool customsamplesize = false;
if (ssize_ != 12 or spattern_ == true) customsamplesize = true; // custom FPGA DMA firmware
if (ssize_ == 12) // default original FPGA DMA firmware
{
ssize_ = 16; // set to 16 bits and do not try to change sample size
}
ad936x_iio_source = ad936x_iio_make_source_sptr(
pluto_uri_,
board_type_,
bandwidth_,
sample_rate_,
freq_,
rf_port_select_,
rf_filter,
gain_mode_rx0_,
gain_mode_rx1_,
rf_gain_rx0_,
rf_gain_rx1_,
enable_ch0,
enable_ch1,
freq_2ch,
PPS_mode_,
customsamplesize,
fe_ip_,
fe_ctlport_,
ssize_,
bshift_,
spattern_,
lo_attenuation_db_,
high_side_lo_,
tx_lo_channel_);
n_channels = 1;
if (enable_ch0 == true and enable_ch1 == true)
{
n_channels = 2;
}
int delay_samples = 0;
if (n_channels == 2 and rx0_to_rx1_delay_ns_ != 0.0)
{
double ts = 1.0 / static_cast<double>(sample_rate_);
delay_samples = std::round(ts * rx0_to_rx1_delay_ns_ * 1e-9);
if (delay_samples != 0)
{
delay_enabled = true;
if (delay_samples > 0)
{
apply_delay_on_rx0 = true;
LOG(INFO) << " Instantiating delay of rx0 equal to " << delay_samples << " samples.";
}
else
{
// delay applied to rx1 instead.
apply_delay_on_rx0 = false;
delay_samples = -delay_samples;
LOG(INFO) << " Instantiating delay of rx1 equal to " << delay_samples << " samples.";
}
}
else
{
LOG(INFO) << " Specified rx0_to_rx1 delay is smaller than the front-end sample period.";
}
}
else
{
apply_delay_on_rx0 = false;
delay_enabled = false;
}
if (delay_enabled == true)
{
gr_delay = gr::blocks::delay::make(sizeof(gr_complex), delay_samples);
}
for (int n = 0; n < n_channels; n++)
{
if (n == 0) inverted_spectrum_vec.push_back(inverted_spectrum_ch0_);
if (n == 1) inverted_spectrum_vec.push_back(inverted_spectrum_ch1_);
}
for (int n = 0; n < n_channels; n++)
{
if (ssize_ == 16)
{
gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n)));
}
else if (ssize_ == 8)
{
unpack_short_byte.push_back(make_unpack_short_byte_samples());
gr_char_to_short_.push_back(gr::blocks::char_to_short::make());
gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n)));
}
else if (ssize_ == 4)
{
gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n)));
unpack_byte_fourbits.push_back(make_unpack_byte_4bit_samples());
unpack_short_byte.push_back(make_unpack_short_byte_samples());
}
else if (ssize_ == 2)
{
gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, inverted_spectrum_vec.at(n)));
unpack_byte_twobits.push_back(make_unpack_byte_2bit_cpx_samples());
unpack_short_byte.push_back(make_unpack_short_byte_samples());
}
}
}
else
{
LOG(ERROR) << item_type_ << " unrecognized item type";
exit(1);
}
if (dump_)
{
for (int n = 0; n < n_channels; n++)
{
DLOG(INFO) << "Dumping output into file " << (dump_filename_ + "c_h" + std::to_string(n) + ".bin");
sink_.emplace_back(gr::blocks::file_sink::make(item_size_, (dump_filename_ + "_ch" + std::to_string(n) + ".bin").c_str()));
}
}
if (in_stream_ > 0)
{
LOG(ERROR) << "A signal source does not have an input stream";
}
if (out_stream_ > 1)
{
LOG(ERROR) << "This implementation only supports one output stream";
}
}
void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block)
{
for (int n = 0; n < n_channels; n++)
{
if (ssize_ == 16)
{
top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (delay_enabled == true)
{
if (n == 0 and apply_delay_on_rx0 == true)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else if (n == 1 and apply_delay_on_rx0 == false)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else if (ssize_ == 8)
{
top_block->connect(ad936x_iio_source, n, unpack_short_byte.at(n), 0);
top_block->connect(unpack_short_byte.at(n), 0, gr_char_to_short_.at(n), 0);
top_block->connect(gr_char_to_short_.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
if (delay_enabled == true)
{
if (n == 0 and apply_delay_on_rx0 == true)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else if (n == 1 and apply_delay_on_rx0 == false)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else if (ssize_ == 4)
{
top_block->connect(ad936x_iio_source, n, unpack_short_byte.at(n), 0);
top_block->connect(unpack_short_byte.at(n), 0, unpack_byte_fourbits.at(n), 0);
top_block->connect(unpack_byte_fourbits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (delay_enabled == true)
{
if (n == 0 and apply_delay_on_rx0 == true)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else if (n == 1 and apply_delay_on_rx0 == false)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else if (ssize_ == 2)
{
top_block->connect(ad936x_iio_source, n, unpack_short_byte.at(n), 0);
top_block->connect(unpack_short_byte.at(n), 0, unpack_byte_twobits.at(n), 0);
top_block->connect(unpack_byte_twobits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (delay_enabled == true)
{
if (n == 0 and apply_delay_on_rx0 == true)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else if (n == 1 and apply_delay_on_rx0 == false)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else
{
top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (delay_enabled == true)
{
if (n == 0 and apply_delay_on_rx0 == true)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else if (n == 1 and apply_delay_on_rx0 == false)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, gr_delay, 0);
DLOG(INFO) << "connected gr_interleaved_short_to_complex to gr_delay for channel " << n;
if (dump_)
{
top_block->connect(gr_delay, 0, sink_.at(n), 0);
DLOG(INFO) << "connected delayed source to file sink";
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
else
{
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
}
}
void Ad936xCustomSignalSource::disconnect(gr::top_block_sptr top_block)
{
for (int n = 0; n < n_channels; n++)
{
if (ssize_ == 16)
{
top_block->disconnect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "disconnect ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "disconnect source to file sink";
}
}
else if (ssize_ == 8)
{
top_block->disconnect(ad936x_iio_source, n, unpack_short_byte.at(n), 0);
top_block->disconnect(unpack_short_byte.at(n), 0, gr_char_to_short_.at(n), 0);
top_block->disconnect(gr_char_to_short_.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "disconnect ad936x_iio_source source to gr_interleaved_short_to_complex_ for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else if (ssize_ == 4)
{
top_block->disconnect(ad936x_iio_source, n, unpack_short_byte.at(n), 0);
top_block->disconnect(unpack_short_byte.at(n), 0, unpack_byte_fourbits.at(n), 0);
top_block->disconnect(unpack_byte_fourbits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "disconnect ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "disconnect source to file sink";
}
}
else if (ssize_ == 2)
{
top_block->disconnect(ad936x_iio_source, n, unpack_short_byte.at(n), 0);
top_block->disconnect(unpack_short_byte.at(n), 0, unpack_byte_twobits.at(n), 0);
top_block->disconnect(unpack_byte_twobits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "disconnect ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "disconnect source to file sink";
}
}
else
{
top_block->disconnect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "disconnect ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "disconnect source to file sink";
}
}
}
}
gr::basic_block_sptr Ad936xCustomSignalSource::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block()
{
return gr_interleaved_short_to_complex_.at(0);
}
gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block(int RF_channel)
{
if (delay_enabled == true)
{
if (RF_channel == 0 and apply_delay_on_rx0 == true)
{
return gr_delay;
}
else if (RF_channel == 1 and apply_delay_on_rx0 == false)
{
return gr_delay;
}
else
{
return gr_interleaved_short_to_complex_.at(RF_channel);
}
}
else
{
return gr_interleaved_short_to_complex_.at(RF_channel);
}
}

View File

@ -0,0 +1,129 @@
/*!
* \file ad936x_custom_signal_source.h
* \brief A direct IIO custom front-end gnss-sdr signal source for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H
#define GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H
#include "ad936x_iio_source.h"
#include "concurrent_queue.h"
#include "conjugate_cc.h"
#include "signal_source_base.h"
#include "unpack_byte_2bit_cpx_samples.h"
#include "unpack_byte_4bit_samples.h"
#include "unpack_short_byte_samples.h"
#include <gnuradio/blocks/char_to_short.h>
#include <gnuradio/blocks/file_sink.h>
// #include <gnuradio/blocks/interleaved_char_to_complex.h>
#include <gnuradio/blocks/delay.h>
#include <gnuradio/blocks/interleaved_short_to_complex.h>
#include <pmt/pmt.h>
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
class ConfigurationInterface;
/*!
* \brief This class instantiates the Ad936xCustom gnuradio signal source.
* It has support also for a customized Ad936xCustom firmware and signal source to support PPS samplestamp reading.
*/
class Ad936xCustomSignalSource : public SignalSourceBase
{
public:
Ad936xCustomSignalSource(const ConfigurationInterface* configuration,
const std::string& role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t>* queue);
~Ad936xCustomSignalSource() = default;
inline size_t item_size() override
{
return item_size_;
}
void connect(gr::top_block_sptr top_block) override;
void disconnect(gr::top_block_sptr top_block) override;
gr::basic_block_sptr get_left_block() override;
gr::basic_block_sptr get_right_block() override;
gr::basic_block_sptr get_right_block(int RF_channel) override;
private:
unsigned int in_stream_;
unsigned int out_stream_;
gr::block_sptr ad936x_iio_source;
std::vector<gr::blocks::file_sink::sptr> sink_;
std::vector<std::string> filename_vec_;
gr::blocks::delay::sptr gr_delay;
std::vector<gr::blocks::char_to_short::sptr> gr_char_to_short_;
std::vector<gr::blocks::interleaved_short_to_complex::sptr> gr_interleaved_short_to_complex_;
// std::vector<gr::blocks::interleaved_char_to_complex::sptr> gr_interleaved_char_to_complex_;
std::vector<unpack_short_byte_samples_sptr> unpack_short_byte;
std::vector<unpack_byte_4bit_samples_sptr> unpack_byte_fourbits;
std::vector<unpack_byte_2bit_cpx_samples_sptr> unpack_byte_twobits;
std::string item_type_;
size_t item_size_;
int64_t samples_;
bool dump_;
std::string dump_filename_;
// Front-end settings
std::string pluto_uri_;
std::string board_type_;
long long sample_rate_;
long long bandwidth_;
long long freq_;
long long freq_2ch;
std::string rf_port_select_;
std::string rf_filter;
std::string gain_mode_rx0_;
std::string gain_mode_rx1_;
double rf_gain_rx0_;
double rf_gain_rx1_;
bool enable_ch0;
bool enable_ch1;
bool PPS_mode_;
std::string fe_ip_;
int fe_ctlport_;
int ssize_;
int bshift_;
bool spattern_;
bool inverted_spectrum_ch0_;
bool inverted_spectrum_ch1_;
double lo_attenuation_db_;
bool high_side_lo_;
int tx_lo_channel_;
double rx0_to_rx1_delay_ns_;
bool delay_enabled;
bool apply_delay_on_rx0;
std::vector<bool> inverted_spectrum_vec;
int n_channels;
};
/** \} */
/** \} */
#endif // GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H

View File

@ -1,6 +1,7 @@
/*!
* \file file_timestamp_signal_source.h
* \brief This class reads samples stored in a file and generate stream tags with its timestamp information stored in separated file
* \file file_timestamp_signal_source.cc
* \brief This class reads samples stored in a file and generate stream tags
* with its timestamp information stored in separated file
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
@ -13,17 +14,19 @@
*
* -----------------------------------------------------------------------------
*/
#include "file_timestamp_signal_source.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_timestamp.h"
#include <glog/logging.h>
#include <string>
using namespace std::string_literals;
FileTimestampSignalSource::FileTimestampSignalSource(const ConfigurationInterface* configuration,
const std::string& role, unsigned int in_streams, unsigned int out_streams,
const std::string& role,
unsigned int in_streams,
unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue)
: FileSourceBase(configuration, role, "File_Timestamp_Signal_Source"s, queue, "byte"s),
timestamp_file_(configuration->property(role + ".timestamp_filename"s, "../data/example_capture_timestamp.dat"s)),
@ -51,19 +54,60 @@ gnss_shared_ptr<gr::block> FileTimestampSignalSource::source() const { return ti
void FileTimestampSignalSource::create_file_source_hook()
{
timestamp_block_ = gnss_sdr_make_Timestamp(
std::get<0>(itemTypeToSize()),
timestamp_file_,
timestamp_clock_offset_ms_);
int source_items_to_samples = 1;
bool is_complex = false;
if (item_type() == "ibyte")
{
source_items_to_samples = 1;
}
else if (item_type() == "byte")
{
source_items_to_samples = 1;
}
else if (item_type() == "short")
{
source_items_to_samples = 1;
}
else if (item_type() == "ishort")
{
source_items_to_samples = 1;
}
else if (item_type() == "gr_complex")
{
source_items_to_samples = 1;
is_complex = true;
}
if (is_complex == false)
{
std::cout << "A : " << std::get<0>(itemTypeToSize()) << "\n";
timestamp_block_ = gnss_sdr_make_Timestamp(
std::get<0>(itemTypeToSize()),
timestamp_file_,
timestamp_clock_offset_ms_,
source_items_to_samples * 2);
}
else
{
std::cout << "B : " << std::get<0>(itemTypeToSize()) << "\n";
timestamp_block_ = gnss_sdr_make_Timestamp(
std::get<0>(itemTypeToSize()),
timestamp_file_,
timestamp_clock_offset_ms_,
source_items_to_samples);
}
DLOG(INFO) << "timestamp_block_(" << timestamp_block_->unique_id() << ")";
}
void FileTimestampSignalSource::pre_connect_hook(gr::top_block_sptr top_block)
{
top_block->connect(file_source(), 0, timestamp_block_, 0);
DLOG(INFO) << "connected file_source to timestamp_block_";
}
void FileTimestampSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block)
{
top_block->disconnect(file_source(), 0, timestamp_block_, 0);

View File

@ -1,6 +1,7 @@
/*!
* \file file_timestamp_signal_source.h
* \brief This class reads samples stored in a file and generate stream tags with its timestamp information stored in separated file
* \brief This class reads samples stored in a file and generate stream tags
* with its timestamp information stored in separated file
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------

View File

@ -0,0 +1,143 @@
/*!
* \file four_bit_cpx_file_signal_source.cc
* \brief Implementation of a class that reads signals samples from a 2 bit complex sampler front-end file
* and adapts it to a SignalSourceInterface.
* \author Javier Arribas, 2015 jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "four_bit_cpx_file_signal_source.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <glog/logging.h>
using namespace std::string_literals;
FourBitCpxFileSignalSource::FourBitCpxFileSignalSource(
const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_streams, unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue)
: FileSourceBase(configuration, role, "Four_Bit_Cpx_File_Signal_Source"s, queue, "byte"s),
sample_type_(configuration->property(role + ".sample_type", "iq"s)),
timestamp_file_(configuration->property(role + ".timestamp_filename"s, ""s)),
timestamp_clock_offset_ms_(configuration->property(role + ".timestamp_clock_offset_ms"s, 0.0))
{
// the complex-ness of the input is inferred from the output type
if (sample_type_ == "iq")
{
reverse_interleaving_ = false;
}
else if (sample_type_ == "qi")
{
reverse_interleaving_ = true;
}
else
{
LOG(WARNING) << sample_type_ << " unrecognized sample type. Assuming: ";
}
if (in_streams > 0)
{
LOG(ERROR) << "A signal source does not have an input stream";
}
if (out_streams > 1)
{
LOG(ERROR) << "This implementation only supports one output stream";
}
// override value with commandline flag, if present
if (FLAGS_timestamp_source != "-")
{
timestamp_file_ = FLAGS_timestamp_source;
}
}
std::tuple<size_t, bool> FourBitCpxFileSignalSource::itemTypeToSize()
{
auto is_complex = false;
auto item_size = size_t(sizeof(char)); // default
if (item_type() == "byte")
{
item_size = sizeof(char);
}
else
{
LOG(WARNING) << item_type() << " unrecognized item type. Using byte.";
}
return std::make_tuple(item_size, is_complex);
}
// 1 byte -> 1 complex samples
double FourBitCpxFileSignalSource::packetsPerSample() const { return 1.0; }
gnss_shared_ptr<gr::block> FourBitCpxFileSignalSource::source() const
{
if (timestamp_file_.size() > 1)
{
return timestamp_block_;
}
else
{
return inter_shorts_to_cpx_;
}
}
void FourBitCpxFileSignalSource::create_file_source_hook()
{
unpack_byte_ = make_unpack_byte_4bit_samples();
DLOG(INFO) << "unpack_byte_2bit_cpx_samples(" << unpack_byte_->unique_id() << ")";
inter_shorts_to_cpx_ = gr::blocks::interleaved_short_to_complex::make(false, reverse_interleaving_); // I/Q swap enabled
DLOG(INFO) << "interleaved_short_to_complex(" << inter_shorts_to_cpx_->unique_id() << ")";
if (timestamp_file_.size() > 1)
{
timestamp_block_ = gnss_sdr_make_Timestamp(sizeof(gr_complex),
timestamp_file_,
timestamp_clock_offset_ms_,
1);
DLOG(INFO) << "timestamp_block_(" << timestamp_block_->unique_id() << ")";
}
}
void FourBitCpxFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block)
{
top_block->connect(file_source(), 0, unpack_byte_, 0);
top_block->connect(unpack_byte_, 0, inter_shorts_to_cpx_, 0);
DLOG(INFO) << "connected file_source to unpacker";
if (timestamp_file_.size() > 1)
{
top_block->connect(inter_shorts_to_cpx_, 0, timestamp_block_, 0);
DLOG(INFO) << "connected file_source to timestamp_block_";
}
}
void FourBitCpxFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block)
{
if (timestamp_file_.size() > 1)
{
top_block->disconnect(inter_shorts_to_cpx_, 0, timestamp_block_, 0);
DLOG(INFO) << "disconnected file_source from timestamp_block_";
}
top_block->disconnect(file_source(), 0, unpack_byte_, 0);
top_block->disconnect(unpack_byte_, 0, inter_shorts_to_cpx_, 0);
DLOG(INFO) << "disconnected file_source from unpacker";
}

View File

@ -0,0 +1,75 @@
/*!
* \file four_bit_cpx_file_signal_source.h
* \brief Interface of a class that reads signals samples from a 2 bit complex sampler front-end file
* and adapts it to a SignalSourceInterface.
* \author Javier Arribas, 2015 jarribas(at)cttc.es
*
* This class represents a file signal source.
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_FOUR_BIT_CPX_FILE_SIGNAL_SOURCE_H
#define GNSS_SDR_FOUR_BIT_CPX_FILE_SIGNAL_SOURCE_H
#include "file_source_base.h"
#include "gnss_sdr_timestamp.h"
#include "unpack_byte_4bit_samples.h"
#include <gnuradio/blocks/interleaved_short_to_complex.h>
#include <cstddef>
#include <string>
#include <tuple>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
class ConfigurationInterface;
/*!
* \brief Class that reads signals samples from a file
* and adapts it to a SignalSourceInterface
*/
class FourBitCpxFileSignalSource : public FileSourceBase
{
public:
FourBitCpxFileSignalSource(const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_streams,
unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue);
~FourBitCpxFileSignalSource() = default;
protected:
std::tuple<size_t, bool> itemTypeToSize() override;
double packetsPerSample() const override;
gnss_shared_ptr<gr::block> source() const override;
void create_file_source_hook() override;
void pre_connect_hook(gr::top_block_sptr top_block) override;
void pre_disconnect_hook(gr::top_block_sptr top_block) override;
private:
unpack_byte_4bit_samples_sptr unpack_byte_;
gr::blocks::interleaved_short_to_complex::sptr inter_shorts_to_cpx_;
gnss_shared_ptr<Gnss_Sdr_Timestamp> timestamp_block_;
std::string sample_type_;
std::string timestamp_file_;
double timestamp_clock_offset_ms_;
bool reverse_interleaving_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_FOUR_BIT_CPX_FILE_SIGNAL_SOURCE_H

View File

@ -10,12 +10,24 @@ if(ENABLE_RAW_UDP AND PCAP_FOUND)
list(APPEND OPT_DRIVER_HEADERS gr_complex_ip_packet_source.h)
endif()
if(ENABLE_AD936X_SDR)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} gr_complex_ip_packet_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gr_complex_ip_packet_source.h)
endif()
if(ENABLE_PLUTOSDR)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_iio_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_iio_source.h)
endif()
set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
fifo_reader.cc
unpack_byte_2bit_samples.cc
unpack_byte_2bit_cpx_samples.cc
unpack_byte_4bit_samples.cc
unpack_intspir_1bit_samples.cc
unpack_short_byte_samples.cc
rtl_tcp_signal_source_c.cc
unpack_2bit_samples.cc
unpack_spir_gss6450_samples.cc
@ -29,6 +41,7 @@ set(SIGNAL_SOURCE_GR_BLOCKS_HEADERS
unpack_byte_2bit_cpx_samples.h
unpack_byte_4bit_samples.h
unpack_intspir_1bit_samples.h
unpack_short_byte_samples.h
rtl_tcp_signal_source_c.h
unpack_2bit_samples.h
unpack_spir_gss6450_samples.h

View File

@ -0,0 +1,348 @@
/*!
* \file ad936x_iio_source.cc
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ad936x_iio_source.h"
#include "INIReader.h"
#include "ad936x_iio_samples.h"
#include "command_event.h"
#include "gnss_sdr_make_unique.h"
#include "pps_samplestamp.h"
#include <gnuradio/io_signature.h>
#include <algorithm>
#include <array>
#include <exception>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <utility>
ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_,
double lo_attenuation_db_,
bool high_side_lo_,
int tx_lo_channel_)
{
return ad936x_iio_source_sptr(new ad936x_iio_source(
pluto_uri_,
board_type_,
bandwidth_,
sample_rate_,
freq_,
rf_port_select_,
rf_filter,
gain_mode_rx0_,
gain_mode_rx1_,
rf_gain_rx0_,
rf_gain_rx1_,
enable_ch0,
enable_ch1,
freq_2ch,
ppsmode_,
customsamplesize_,
fe_ip_,
fe_ctlport_,
ssize_,
bshift_,
spattern_,
lo_attenuation_db_,
high_side_lo_,
tx_lo_channel_));
}
void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector<std::fstream> *files_out)
{
int32_t current_byte = 0;
int16_t ch = 0;
// std::cout << "nbytes: " << samples_in->n_bytes << " nsamples: " << samples_in->n_samples << " nch: " << nchannels << "\n";
while (current_byte < samples_in->n_bytes)
{
for (ch = 0; ch < nchannels; ch++)
{
// std::cout << current_byte << " of " << samples_in->n_bytes << " test: " << (int)samples_in->buffer[current_byte] << "\n";
(*files_out).at(ch).write(&samples_in->buffer[current_byte], 4); // two bytes I + two bytes Q per channel
current_byte += 4;
}
}
}
ad936x_iio_source::ad936x_iio_source(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_,
double lo_attenuation_db_,
bool high_side_lo_,
int tx_lo_channel_) : gr::block("ad936x_iio_source",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(1, 4, sizeof(int16_t)))
{
ad936x_custom = std::make_unique<ad936x_iio_custom>(0, 0);
try
{
if (ad936x_custom->initialize_device(pluto_uri_, board_type_) == true)
{
// configure channels
if (ad936x_custom->init_config_ad9361_rx(bandwidth_,
sample_rate_,
freq_,
rf_port_select_,
rf_filter,
gain_mode_rx0_,
gain_mode_rx1_,
rf_gain_rx0_,
rf_gain_rx1_,
enable_ch0,
enable_ch1,
freq_2ch,
lo_attenuation_db_,
high_side_lo_,
tx_lo_channel_) == true)
{
std::cout << "ad936x_iio_source HW configured OK!\n";
// PPS FPGA Samplestamp information from TCP server
pps_rx = std::make_shared<pps_tcp_rx>();
ppsqueue = std::shared_ptr<Concurrent_Queue<PpsSamplestamp>>(new Concurrent_Queue<PpsSamplestamp>());
pps_rx->set_pps_samplestamp_queue(ppsqueue);
ad936x_custom->set_pps_samplestamp_queue(ppsqueue);
// start PPS RX thread
if (ppsmode_ == true or customsamplesize_ == true)
{
pps_rx_thread = std::thread(&pps_tcp_rx::receive_pps, pps_rx, fe_ip_, fe_ctlport_);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// configure custom FPGA options
switch (ssize_)
{
case 16:
{
std::cout << "FPGA sample size set to 16 bits per sample.\n";
if (pps_rx->send_cmd("ssize=16\n") == false) std::cout << "cmd send error!\n";
break;
}
case 8:
{
std::cout << "FPGA sample size set to 8 bits per sample.\n";
if (pps_rx->send_cmd("ssize=8\n") == false) std::cout << "cmd send error!\n";
break;
}
case 4:
{
std::cout << "FPGA sample size set to 4 bits per sample.\n";
if (pps_rx->send_cmd("ssize=4\n") == false) std::cout << "cmd send error!\n";
break;
}
case 2:
{
std::cout << "FPGA sample size set to 2 bits per sample.\n";
if (pps_rx->send_cmd("ssize=2\n") == false) std::cout << "cmd send error!\n";
break;
}
default:
{
std::cout << "WARNING: Unsupported ssize. FPGA sample size set to 16 bits per sample.\n";
if (pps_rx->send_cmd("ssize=16") == false) std::cout << "cmd send error!\n";
}
}
if (bshift_ >= 0 and bshift_ <= 14)
{
std::cout << "FPGA sample bits shift left set to " + std::to_string(bshift_) + " positions.\n";
if (pps_rx->send_cmd("bshift=" + std::to_string(bshift_) + "\n") == false) std::cout << "cmd send error!\n";
}
else
{
std::cout << "WARNING: Unsupported bshift. FPGA sample bits shift left set to 0.\n";
if (pps_rx->send_cmd("bshift=0\n") == false) std::cout << "cmd send error!\n";
}
if (spattern_ == true)
{
std::cout << "FPGA debug sample pattern is active!.\n";
if (pps_rx->send_cmd("spattern=1\n") == false) std::cout << "cmd send error!\n";
}
else
{
std::cout << "FPGA debug sample pattern disabled.\n";
if (pps_rx->send_cmd("spattern=0\n") == false) std::cout << "cmd send error!\n";
}
}
else
{
std::cout << "PPS mode NOT enabled, not configuring PlutoSDR custom timestamping FPGA IP.\n";
}
}
else
{
std::cerr << "ad936x_iio_source IIO initialization error." << std::endl;
exit(1);
}
}
else
{
std::cerr << "ad936x_iio_source IIO initialization error." << std::endl;
exit(1);
}
}
catch (std::exception const &ex)
{
std::cerr << "STD exception: " << ex.what() << std::endl;
exit(1);
}
catch (...)
{
std::cerr << "Unexpected catch" << std::endl;
exit(1);
}
set_min_noutput_items(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2); // multiplexed I,Q, so, two samples per complex sample
set_min_output_buffer(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * sizeof(int16_t) * 2);
// std::cout << "max_output_buffer " << min_output_buffer(0) << " min_noutput_items: " << min_noutput_items() << "\n";
// for (int n = 0; n < ad936x_custom->n_channels; n++)
// {
// std::string cap_file_root_name = "./debug_cap_ch";
// samplesfile.push_back(std::fstream(cap_file_root_name + std::to_string(n) + ".dat", std::ios::out | std::ios::binary));
// // samplesfile.back().exceptions(std::ios_base::badbit | std::ios_base::failbit); //this will enable exceptions for debug
//
// if (samplesfile.back().is_open() == false)
// {
// std::cout << "ERROR: Could not open " << cap_file_root_name + "_ch" + std::to_string(n) + ".dat"
// << " for record samples!\n";
// }
// }
}
ad936x_iio_source::~ad936x_iio_source()
{
// Terminate PPS thread
if (pps_rx_thread.joinable())
{
pthread_t id = pps_rx_thread.native_handle();
pps_rx_thread.detach();
pthread_cancel(id);
}
}
bool ad936x_iio_source::start()
{
return ad936x_custom->start_sample_rx(false);
}
bool ad936x_iio_source::stop()
{
std::cout << "stopping ad936x_iio_source...\n";
ad936x_custom->stop_record();
return true;
}
int ad936x_iio_source::general_work(int noutput_items,
__attribute__((unused)) gr_vector_int &ninput_items,
__attribute__((unused)) gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
std::shared_ptr<ad936x_iio_samples> current_buffer;
ad936x_iio_samples *current_samples;
ad936x_custom->pop_sample_buffer(current_buffer);
current_samples = current_buffer.get();
// I and Q samples are interleaved in buffer: IQIQIQ...
int32_t n_interleaved_iq_samples_per_channel = current_samples->n_bytes / (ad936x_custom->n_channels * 2);
if (noutput_items < n_interleaved_iq_samples_per_channel)
{
std::cout << "ad936x_iio_source output buffer overflow! noutput_items: " << noutput_items << " vs. " << n_interleaved_iq_samples_per_channel << "\n";
return 0;
}
else
{
// ad9361_channel_demux_and_record(current_samples, ad936x_custom->n_channels, &samplesfile);
auto **out = reinterpret_cast<int8_t **>(&output_items[0]);
uint32_t current_byte = 0;
uint32_t current_byte_in_gr = 0;
int16_t ch = 0;
// std::cout << "nbytes: " << samples_in->n_bytes << " nsamples: " << samples_in->n_samples << " nch: " << nchannels << "\n";
if (ad936x_custom->n_channels == 1)
{
memcpy(out[0], &current_samples->buffer[current_byte], current_samples->n_bytes);
}
else
{
while (current_byte < current_samples->n_bytes)
{
for (ch = 0; ch < ad936x_custom->n_channels; ch++)
{
memcpy(&out[ch][current_byte_in_gr], &current_samples->buffer[current_byte], 4); // two bytes I + two bytes Q per channel: 4 bytes
current_byte += 4;
}
current_byte_in_gr += 4;
}
}
ad936x_custom->push_sample_buffer(current_buffer);
return n_interleaved_iq_samples_per_channel; // always int16_t samples interleaved (I,Q,I,Q)
// for (size_t n = 0; n < ad936x_custom->n_channels; n++)
// {
// produce(n, current_samples->n_samples[n]);
// }
//
//
// return this->WORK_CALLED_PRODUCE;
}
}

View File

@ -0,0 +1,159 @@
/*!
* \file ad936x_iio_source.h
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_AD936X_IIO_SOURCE_H
#define GNSS_SDR_AD936X_IIO_SOURCE_H
#include "ad936x_iio_custom.h"
#include "concurrent_queue.h"
#include "gnss_block_interface.h"
#include "ppstcprx.h"
#include <gnuradio/block.h>
#include <pmt/pmt.h>
#include <cstddef>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_gnuradio_blocks
* \{ */
class ad936x_iio_source;
using ad936x_iio_source_sptr = gnss_shared_ptr<ad936x_iio_source>;
ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_,
double lo_attenuation_db_,
bool high_side_lo_,
int tx_lo_channel_);
/*!
* \brief This class implements conversion between Labsat 2, 3 and 3 Wideband
* formats to gr_complex
*/
class ad936x_iio_source : public gr::block
{
public:
~ad936x_iio_source();
//! start the sample transmission
bool start();
//! stop the sample transmission
bool stop();
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
private:
friend ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_,
double lo_attenuation_db_,
bool high_side_lo_,
int tx_lo_channel_);
ad936x_iio_source(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_,
double lo_attenuation_db_,
bool high_side_lo_,
int tx_lo_channel_);
void ad9361_channel_demux_to_buffer(ad936x_iio_samples *samples_in, int nchannels, gr_vector_void_star &output_items);
void ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector<std::fstream> *files_out);
std::thread pps_rx_thread;
std::unique_ptr<ad936x_iio_custom> ad936x_custom;
std::shared_ptr<pps_tcp_rx> pps_rx;
std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> ppsqueue;
std::vector<std::fstream> samplesfile;
};
/** \} */
/** \} */
#endif // GNSS_SDR_AD936X_IIO_SOURCE_H

View File

@ -19,6 +19,7 @@
#include "gr_complex_ip_packet_source.h"
#include <gnuradio/io_signature.h>
#include <volk/volk.h>
#include <array>
#include <cstdint>
#include <utility>
@ -30,6 +31,11 @@
const int FIFO_SIZE = 1472000;
struct byte_2bit_struct
{
signed two_bit_sample : 2; // <- 2 bits wide only
};
/* 4 bytes IP address */
typedef struct gr_ip_address
{
@ -105,7 +111,7 @@ Gr_Complex_Ip_Packet_Source::Gr_Complex_Ip_Packet_Source(std::string src_device,
d_pcap_thread(nullptr),
d_src_device(std::move(src_device)),
descr(nullptr),
fifo_buff(new char[FIFO_SIZE]),
fifo_buff(static_cast<char *>(volk_malloc(static_cast<int32_t>(FIFO_SIZE * sizeof(char)), volk_get_alignment()))),
fifo_read_ptr(0),
fifo_write_ptr(0),
fifo_items(0),
@ -120,6 +126,11 @@ Gr_Complex_Ip_Packet_Source::Gr_Complex_Ip_Packet_Source(std::string src_device,
d_wire_sample_type = 1;
d_bytes_per_sample = d_n_baseband_channels * 2;
}
else if (wire_sample_type == "c2bits")
{
d_wire_sample_type = 5;
d_bytes_per_sample = d_n_baseband_channels;
}
else if (wire_sample_type == "c4bits")
{
d_wire_sample_type = 2;
@ -183,7 +194,8 @@ bool Gr_Complex_Ip_Packet_Source::stop()
bool Gr_Complex_Ip_Packet_Source::open()
{
std::array<char, PCAP_ERRBUF_SIZE> errbuf{};
boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function
// boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function
gr::thread::scoped_lock guard(d_setlock);
// open device for reading
descr = pcap_open_live(d_src_device.c_str(), 1500, 1, 1000, errbuf.data());
if (descr == nullptr)
@ -239,7 +251,7 @@ void Gr_Complex_Ip_Packet_Source::static_pcap_callback(u_char *args, const struc
void Gr_Complex_Ip_Packet_Source::pcap_callback(__attribute__((unused)) u_char *args, __attribute__((unused)) const struct pcap_pkthdr *pkthdr,
const u_char *packet)
{
boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function
// boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function
const gr_ip_header *ih;
const gr_udp_header *uh;
@ -286,6 +298,7 @@ void Gr_Complex_Ip_Packet_Source::pcap_callback(__attribute__((unused)) u_char *
if (aligned_write_items >= payload_length_bytes)
{
// write all in a single memcpy
gr::thread::scoped_lock guard(d_setlock);
memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], payload_length_bytes); // size in bytes
fifo_write_ptr += payload_length_bytes;
if (fifo_write_ptr == FIFO_SIZE)
@ -297,6 +310,7 @@ void Gr_Complex_Ip_Packet_Source::pcap_callback(__attribute__((unused)) u_char *
else
{
// two step wrap write
gr::thread::scoped_lock guard(d_setlock);
memcpy(&fifo_buff[fifo_write_ptr], &udp_payload[0], aligned_write_items); // size in bytes
fifo_write_ptr = payload_length_bytes - aligned_write_items;
memcpy(&fifo_buff[0], &udp_payload[aligned_write_items], fifo_write_ptr); // size in bytes
@ -321,107 +335,164 @@ void Gr_Complex_Ip_Packet_Source::my_pcap_loop_thread(pcap_t *pcap_handle)
void Gr_Complex_Ip_Packet_Source::demux_samples(const gr_vector_void_star &output_items, int num_samples_readed)
{
for (int n = 0; n < num_samples_readed; n++)
if (d_wire_sample_type == 5)
{
switch (d_wire_sample_type)
// interleaved 2-bit I 2-bit Q samples packed in bytes: 1 byte -> 2 complex samples
int nsample = 0;
byte_2bit_struct sample{}; // <- 2 bits wide only
int real;
int imag;
for (int nbyte = 0; nbyte < num_samples_readed / 2; nbyte++)
{
case 1: // interleaved byte samples
for (const auto &output_item : output_items)
{
int8_t real;
int8_t imag;
real = fifo_buff[fifo_read_ptr++];
imag = fifo_buff[fifo_read_ptr++];
// Read packed input sample (1 byte = 2 complex samples)
// * Packing Order
// * Most Significant Nibble - Sample n
// * Least Significant Nibble - Sample n+1
// * Bit Packing order in Nibble Q1 Q0 I1 I0
// normal
int8_t c = fifo_buff[fifo_read_ptr++];
// Q[n]
sample.two_bit_sample = (c >> 6) & 3;
imag = (2 * static_cast<int8_t>(sample.two_bit_sample) + 1);
// I[n]
sample.two_bit_sample = (c >> 4) & 3;
real = (2 * static_cast<int8_t>(sample.two_bit_sample) + 1);
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
static_cast<gr_complex *>(output_item)[nsample] = gr_complex(real, imag);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
}
}
break;
case 2: // 4-bit samples
for (const auto &output_item : output_items)
{
int8_t real;
int8_t imag;
uint8_t tmp_char2;
tmp_char2 = fifo_buff[fifo_read_ptr] & 0x0F;
if (tmp_char2 >= 8)
{
real = 2 * (tmp_char2 - 16) + 1;
}
else
{
real = 2 * tmp_char2 + 1;
}
tmp_char2 = fifo_buff[fifo_read_ptr++] >> 4;
tmp_char2 = tmp_char2 & 0x0F;
if (tmp_char2 >= 8)
{
imag = 2 * (tmp_char2 - 16) + 1;
}
else
{
imag = 2 * tmp_char2 + 1;
static_cast<gr_complex *>(output_item)[nsample] = gr_complex(imag, real);
}
// Q[n+1]
sample.two_bit_sample = (c >> 2) & 3;
imag = (2 * static_cast<int8_t>(sample.two_bit_sample) + 1);
// I[n+1]
sample.two_bit_sample = c & 3;
real = (2 * static_cast<int8_t>(sample.two_bit_sample) + 1);
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
static_cast<gr_complex *>(output_item)[nsample + 1] = gr_complex(real, imag);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
static_cast<gr_complex *>(output_item)[nsample + 1] = gr_complex(imag, real);
}
}
break;
case 3: // interleaved float samples
for (const auto &output_item : output_items)
{
float real;
float imag;
memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real));
fifo_read_ptr += 4; // Four bytes in float
memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag));
fifo_read_ptr += 4; // Four bytes in float
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
}
}
break;
case 4: // interleaved short samples
for (const auto &output_item : output_items)
{
int16_t real;
int16_t imag;
memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real));
fifo_read_ptr += 2; // two bytes in short
memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag));
fifo_read_ptr += 2; // two bytes in short
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
}
}
break;
default:
std::cout << "Unknown wire sample type\n";
exit(0);
}
if (fifo_read_ptr == FIFO_SIZE)
}
else
{
for (int n = 0; n < num_samples_readed; n++)
{
fifo_read_ptr = 0;
switch (d_wire_sample_type)
{
case 1: // interleaved byte samples
for (const auto &output_item : output_items)
{
int8_t real;
int8_t imag;
real = fifo_buff[fifo_read_ptr++];
imag = fifo_buff[fifo_read_ptr++];
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
}
}
break;
case 2: // 4-bit samples
for (const auto &output_item : output_items)
{
int8_t real;
int8_t imag;
uint8_t tmp_char2;
tmp_char2 = fifo_buff[fifo_read_ptr] & 0x0F;
if (tmp_char2 >= 8)
{
real = 2 * (tmp_char2 - 16) + 1;
}
else
{
real = 2 * tmp_char2 + 1;
}
tmp_char2 = fifo_buff[fifo_read_ptr++] >> 4;
tmp_char2 = tmp_char2 & 0x0F;
if (tmp_char2 >= 8)
{
imag = 2 * (tmp_char2 - 16) + 1;
}
else
{
imag = 2 * tmp_char2 + 1;
}
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
}
}
break;
case 3: // interleaved float samples
for (const auto &output_item : output_items)
{
float real;
float imag;
memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real));
fifo_read_ptr += 4; // Four bytes in float
memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag));
fifo_read_ptr += 4; // Four bytes in float
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
}
}
break;
case 4: // interleaved short samples
for (const auto &output_item : output_items)
{
int16_t real;
int16_t imag;
memcpy(&real, &fifo_buff[fifo_read_ptr], sizeof(real));
fifo_read_ptr += 2; // two bytes in short
memcpy(&imag, &fifo_buff[fifo_read_ptr], sizeof(imag));
fifo_read_ptr += 2; // two bytes in short
if (d_IQ_swap)
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(real, imag);
}
else
{
static_cast<gr_complex *>(output_item)[n] = gr_complex(imag, real);
}
}
break;
default:
std::cout << "Unknown wire sample type\n";
exit(0);
}
if (fifo_read_ptr == FIFO_SIZE)
{
fifo_read_ptr = 0;
}
}
}
}
@ -432,7 +503,7 @@ int Gr_Complex_Ip_Packet_Source::work(int noutput_items,
gr_vector_void_star &output_items)
{
// send samples to next GNU Radio block
boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function
// boost::mutex::scoped_lock lock(d_mutex); // hold mutex for duration of this function
if (fifo_items == 0)
{
return 0;
@ -446,21 +517,24 @@ int Gr_Complex_Ip_Packet_Source::work(int noutput_items,
int num_samples_readed;
int bytes_requested;
bytes_requested = noutput_items * d_bytes_per_sample;
bytes_requested = static_cast<int>(static_cast<float>(noutput_items) * d_bytes_per_sample);
if (bytes_requested < fifo_items)
{
num_samples_readed = noutput_items; // read all
// update fifo items
fifo_items = fifo_items - bytes_requested;
}
else
{
num_samples_readed = fifo_items / d_bytes_per_sample; // read what we have
num_samples_readed = static_cast<int>(static_cast<float>(fifo_items) / d_bytes_per_sample); // read what we have
bytes_requested = fifo_items;
// update fifo items
fifo_items = 0;
}
bytes_requested = num_samples_readed * d_bytes_per_sample;
// read all in a single loop
demux_samples(output_items, num_samples_readed); // it also increases the fifo read pointer
// update fifo items
fifo_items = fifo_items - bytes_requested;
for (uint64_t n = 0; n < output_items.size(); n++)
{

View File

@ -83,7 +83,7 @@ private:
bool open();
boost::thread *d_pcap_thread;
boost::mutex d_mutex;
// boost::mutex d_mutex;
struct sockaddr_in si_me
{
};
@ -98,7 +98,7 @@ private:
int d_udp_port;
int d_n_baseband_channels;
int d_wire_sample_type;
int d_bytes_per_sample;
float d_bytes_per_sample;
bool d_IQ_swap;
};

View File

@ -26,8 +26,8 @@ unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples()
unpack_byte_4bit_samples::unpack_byte_4bit_samples() : sync_interpolator("unpack_byte_4bit_samples",
gr::io_signature::make(1, 1, sizeof(signed char)),
gr::io_signature::make(1, 1, sizeof(signed char)),
gr::io_signature::make(1, 1, sizeof(int8_t)),
gr::io_signature::make(1, 1, sizeof(int16_t)),
2)
{
}
@ -37,8 +37,8 @@ int unpack_byte_4bit_samples::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const auto *in = reinterpret_cast<const signed char *>(input_items[0]);
auto *out = reinterpret_cast<signed char *>(output_items[0]);
const auto *in = reinterpret_cast<const int8_t *>(input_items[0]);
auto *out = reinterpret_cast<int16_t *>(output_items[0]);
int n = 0;
unsigned char tmp_char2;
for (int i = 0; i < noutput_items / 2; i++)
@ -46,21 +46,21 @@ int unpack_byte_4bit_samples::work(int noutput_items,
tmp_char2 = in[i] & 0x0F;
if (tmp_char2 >= 8)
{
out[n++] = 2 * (tmp_char2 - 16) + 1;
out[n++] = static_cast<int16_t>(2 * (tmp_char2 - 16) + 1);
}
else
{
out[n++] = 2 * tmp_char2 + 1;
out[n++] = static_cast<int16_t>(2 * tmp_char2 + 1);
}
tmp_char2 = in[i] >> 4;
tmp_char2 = tmp_char2 & 0x0F;
if (tmp_char2 >= 8)
{
out[n++] = 2 * (tmp_char2 - 16) + 1;
out[n++] = static_cast<int16_t>(2 * (tmp_char2 - 16) + 1);
}
else
{
out[n++] = 2 * tmp_char2 + 1;
out[n++] = static_cast<int16_t>(2 * tmp_char2 + 1);
}
}
return noutput_items;

View File

@ -20,8 +20,8 @@
#ifndef GNSS_SDR_UNPACK_BYTE_4BIT_SAMPLES_H
#define GNSS_SDR_UNPACK_BYTE_4BIT_SAMPLES_H
#include "gnss_block_interface.h"
#include <gnuradio/sync_interpolator.h>
#include <memory>
/** \addtogroup Signal_Source
* \{ */
@ -31,7 +31,7 @@
class unpack_byte_4bit_samples;
using unpack_byte_4bit_samples_sptr = std::shared_ptr<unpack_byte_4bit_samples>;
using unpack_byte_4bit_samples_sptr = gnss_shared_ptr<unpack_byte_4bit_samples>;
unpack_byte_4bit_samples_sptr make_unpack_byte_4bit_samples();

View File

@ -0,0 +1,55 @@
/*!
* \file unpack_short_byte_samples.cc
*
* \brief Unpacks shorts samples to byte samples (1 short = 2 byte samples).
* Packing Order
* Packing order in Nibble I0 I1
* \author Javier Arribas jarribas (at) cttc.es
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "unpack_short_byte_samples.h"
#include <gnuradio/io_signature.h>
unpack_short_byte_samples_sptr make_unpack_short_byte_samples()
{
return unpack_short_byte_samples_sptr(new unpack_short_byte_samples());
}
unpack_short_byte_samples::unpack_short_byte_samples() : sync_interpolator("unpack_short_byte_samples",
gr::io_signature::make(1, 1, sizeof(int16_t)),
gr::io_signature::make(1, 1, sizeof(int8_t)),
2)
{
}
void unpack_short_byte_samples::forecast(int noutput_items,
gr_vector_int &ninput_items_required)
{
if (noutput_items != 0)
{
ninput_items_required[0] = static_cast<int32_t>(noutput_items) / 2;
}
}
int unpack_short_byte_samples::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
// const auto *in = reinterpret_cast<const int16_t *>(input_items[0]);
// auto *out = reinterpret_cast<int8_t *>(output_items[0]);
memcpy(reinterpret_cast<int8_t *>(output_items[0]), reinterpret_cast<const int8_t *>(input_items[0]), noutput_items);
return noutput_items;
}

View File

@ -0,0 +1,58 @@
/*!
* \file unpack_short_byte_samples.cc
*
* \brief Unpacks shorts samples to byte samples (1 short = 2 byte samples).
* Packing Order
* Packing order in Nibble I0 I1
* \author Javier Arribas jarribas (at) cttc.es
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_UNPACK_SHORT_BYTE_SAMPLES_H
#define GNSS_SDR_UNPACK_SHORT_BYTE_SAMPLES_H
#include "gnss_block_interface.h"
#include <gnuradio/sync_interpolator.h>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_gnuradio_blocks
* \{ */
class unpack_short_byte_samples;
using unpack_short_byte_samples_sptr = gnss_shared_ptr<unpack_short_byte_samples>;
unpack_short_byte_samples_sptr make_unpack_short_byte_samples();
/*!
* \brief This class implements conversion between short packet samples to byte samples
* 1 short = 2 byte samples
*/
class unpack_short_byte_samples : public gr::sync_interpolator
{
public:
unpack_short_byte_samples();
void forecast(int noutput_items, gr_vector_int &ninput_items_required);
~unpack_short_byte_samples() = default;
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
private:
friend unpack_short_byte_samples_sptr make_unpack_short_byte_samples_sptr();
};
/** \} */
/** \} */
#endif // GNSS_SDR_UNPACK_SHORT_BYTE_SAMPLES_H

View File

@ -8,8 +8,8 @@
set(OPT_SIGNAL_SOURCE_LIB_SOURCES "")
set(OPT_SIGNAL_SOURCE_LIB_HEADERS "")
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ad9361_manager.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ad9361_manager.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h)
endif()
if(ENABLE_FPGA OR ENABLE_AD9361)
@ -28,6 +28,18 @@ if(ENABLE_FPGA OR ENABLE_AD9361)
endif()
endif()
if(ENABLE_PLUTOSDR)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} pps_samplestamp.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.h)
endif()
set(SIGNAL_SOURCE_LIB_SOURCES
rtl_tcp_commands.cc
rtl_tcp_dongle_info.cc
@ -85,7 +97,7 @@ if(GNURADIO_USES_STD_POINTERS)
)
endif()
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361 OR ENABLE_PLUTOSDR)
target_link_libraries(signal_source_libs
PUBLIC
Iio::iio

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
/*!
* \file ad936x_iio_custom.h
* \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef SRC_LIBS_ad936x_iio_custom_H_
#define SRC_LIBS_ad936x_iio_custom_H_
#include "concurrent_queue.h"
#include "gnss_time.h"
#include "pps_samplestamp.h"
#include <boost/atomic.hpp>
#include <memory>
#include <string>
#ifdef __APPLE__
#include <iio/iio.h>
#else
#include <iio.h>
#endif
#include "ad936x_iio_samples.h"
#include <ad9361.h> // multichip sync and high level functions
#include <thread>
#include <vector>
class ad936x_iio_custom
{
public:
ad936x_iio_custom(int debug_level_, int log_level_);
virtual ~ad936x_iio_custom();
bool initialize_device(std::string pluto_device_uri, std::string board_type);
bool init_config_ad9361_rx(long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
double lo_attenuation_db_,
bool high_side_lo_,
int tx_lo_channel_);
bool calibrate(int ch, double bw_hz);
double get_rx_gain(int ch_num);
bool setRXGain(int ch_num, std::string gain_mode, double gain_dB);
bool set_antenna_port(int ch, int antenna_idx);
double get_frequency(int ch);
bool set_frequency(int ch, double freq_hz);
bool start_sample_rx(bool ppsmode);
void stop_record();
void set_gnsstime_queue(std::shared_ptr<Concurrent_Queue<GnssTime>> queue);
void set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue);
bool get_rx_frequency(long long &freq_hz);
bool set_rx_frequency(long long freq_hz);
bool read_die_temp(double &temp_c);
void pop_sample_buffer(std::shared_ptr<ad936x_iio_samples> &current_buffer);
void push_sample_buffer(std::shared_ptr<ad936x_iio_samples> &current_buffer);
int n_channels;
private:
std::shared_ptr<Concurrent_Queue<GnssTime>> GnssTime_queue;
std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> Pps_queue;
bool check_device();
bool get_iio_param(iio_device *dev, const std::string &param, std::string &value);
void configure_params(struct iio_device *phy,
const std::vector<std::string> &params);
void set_params_rx(struct iio_device *phy_device,
unsigned long long frequency,
unsigned long samplerate, unsigned long bandwidth,
bool quadrature, bool rfdc, bool bbdc,
std::string gain1, double gain1_value,
std::string gain2, double gain2_value,
std::string port_select);
bool config_ad9361_dds(uint64_t freq_rf_tx_hz_,
double tx_attenuation_db_,
int64_t freq_dds_tx_hz_,
double scale_dds_,
double phase_dds_deg_,
int channel);
void get_PPS_timestamp();
void capture(const std::vector<std::string> &channels);
bool select_rf_filter(std::string rf_filter);
void monitor_thread_fn();
void PlutoTxEnable(bool txon);
void setPlutoGpo(int p);
// Device structure
struct iio_context *ctx;
struct iio_device *phy;
struct iio_device *stream_dev;
struct iio_device *dds_dev;
// stream
uint64_t sample_rate_sps;
int debug_level;
int log_level;
bool PPS_mode;
std::mutex mtx;
std::condition_variable cv;
boost::atomic<bool> receive_samples;
boost::atomic<bool> fpga_overflow;
// using queues of smart pointers to preallocated buffers
Concurrent_Queue<std::shared_ptr<ad936x_iio_samples>> free_buffers;
Concurrent_Queue<std::shared_ptr<ad936x_iio_samples>> used_buffers;
std::thread capture_samples_thread;
std::thread overflow_monitor_thread;
std::thread capture_time_thread;
};
#endif /* SRC_LIBS_ad936x_iio_custom_H_ */

View File

@ -0,0 +1,25 @@
/*!
* \file ad936x_iio_samples.cc
* \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ad936x_iio_samples.h"
ad936x_iio_samples::ad936x_iio_samples()
{
n_bytes = 0;
n_interleaved_iq_samples = 0;
step_bytes = 0;
n_channels = 0;
}

View File

@ -0,0 +1,40 @@
/*!
* \file ad936x_iio_samples.h
* \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef SRC_LIBS_ad936x_iio_samples_H_
#define SRC_LIBS_ad936x_iio_samples_H_
#define IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES 32768
#define IIO_INPUTRAMFIFOSIZE 256
#include <memory>
#include <stdint.h>
#include <vector>
class ad936x_iio_samples
{
public:
ad936x_iio_samples();
uint32_t n_bytes;
uint32_t n_interleaved_iq_samples;
uint16_t n_channels;
uint16_t step_bytes;
char buffer[IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 4 * 4]; // max 16 bits samples per buffer (4 channels, 2-bytes per I + 2-bytes per Q)
};
#endif

View File

@ -28,22 +28,23 @@
Gnss_Sdr_Timestamp::Gnss_Sdr_Timestamp(size_t sizeof_stream_item,
std::string timestamp_file, double clock_offset_ms)
std::string timestamp_file, double clock_offset_ms, int items_to_samples)
: gr::sync_block("Timestamp",
gr::io_signature::make(1, 20, sizeof_stream_item),
gr::io_signature::make(1, 20, sizeof_stream_item)),
d_timefile(std::move(timestamp_file)),
d_clock_offset_ms(clock_offset_ms),
d_fraction_ms_offset(modf(d_clock_offset_ms, &d_integer_ms_offset)), // optional clockoffset parameter to convert UTC timestamps to GPS time in some receiver's configuration
d_items_to_samples(items_to_samples),
d_next_timetag_samplecount(0),
d_get_next_timetag(true)
{
}
gnss_shared_ptr<Gnss_Sdr_Timestamp> gnss_sdr_make_Timestamp(size_t sizeof_stream_item, std::string timestamp_file, double clock_offset_ms)
gnss_shared_ptr<Gnss_Sdr_Timestamp> gnss_sdr_make_Timestamp(size_t sizeof_stream_item, std::string timestamp_file, double clock_offset_ms, int items_to_samples)
{
gnss_shared_ptr<Gnss_Sdr_Timestamp> Timestamp_(new Gnss_Sdr_Timestamp(sizeof_stream_item, std::move(timestamp_file), clock_offset_ms));
gnss_shared_ptr<Gnss_Sdr_Timestamp> Timestamp_(new Gnss_Sdr_Timestamp(sizeof_stream_item, std::move(timestamp_file), clock_offset_ms, items_to_samples));
return Timestamp_;
}
@ -110,8 +111,7 @@ int Gnss_Sdr_Timestamp::work(int noutput_items,
for (size_t ch = 0; ch < output_items.size(); ch++)
{
std::memcpy(output_items[ch], input_items[ch], noutput_items * input_signature()->sizeof_stream_item(ch));
uint64_t bytes_to_samples = 2; // todo: improve this.. hardcoded 2 bytes -> 1 complex sample!
int64_t diff_samplecount = uint64diff(this->nitems_written(ch), d_next_timetag_samplecount * bytes_to_samples);
int64_t diff_samplecount = uint64diff(this->nitems_written(ch), d_next_timetag_samplecount * d_items_to_samples);
// std::cout << "diff_samplecount: " << diff_samplecount << ", noutput_items: " << noutput_items << "\n";
if (diff_samplecount <= noutput_items and std::labs(diff_samplecount) <= noutput_items)
{

View File

@ -39,7 +39,8 @@ class Gnss_Sdr_Timestamp;
gnss_shared_ptr<Gnss_Sdr_Timestamp> gnss_sdr_make_Timestamp(
size_t sizeof_stream_item,
std::string timestamp_file,
double clock_offset_ms);
double clock_offset_ms,
int items_to_samples);
class Gnss_Sdr_Timestamp : public gr::sync_block
@ -54,11 +55,13 @@ private:
friend gnss_shared_ptr<Gnss_Sdr_Timestamp> gnss_sdr_make_Timestamp(
size_t sizeof_stream_item,
std::string timestamp_file,
double clock_offset_ms);
double clock_offset_ms,
int items_to_samples);
Gnss_Sdr_Timestamp(size_t sizeof_stream_item,
std::string timestamp_file,
double clock_offset_ms);
double clock_offset_ms,
int items_to_samples);
int64_t uint64diff(uint64_t first, uint64_t second);
bool read_next_timetag();
@ -68,6 +71,7 @@ private:
double d_clock_offset_ms;
double d_fraction_ms_offset;
double d_integer_ms_offset;
int d_items_to_samples;
uint64_t d_next_timetag_samplecount;
bool d_get_next_timetag;
};

View File

@ -0,0 +1,28 @@
/*!
* \file pps_samplestamp.h
* \brief A simple container for the sample count associated to PPS rising edge
* \author Javier Arribas, jarribas(at)cttc.es
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef IIOPPS_PPS_SAMPLESTAMP_H
#define IIOPPS_PPS_SAMPLESTAMP_H
#include <cstdint>
class PpsSamplestamp
{
public:
uint64_t samplestamp = 0; // PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side
uint32_t overflow_reg = 0; // >0 indicates overflow situation in the FPGA RX buffer
};
#endif

View File

@ -0,0 +1,163 @@
/*!
* \file ppstcprx.cc
* \brief TCP client class for front-end PPS samplestamp information reception
* \author Javier Arribas, jarribas(at)cttc.es
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ppstcprx.h"
#include <cstring>
#include <iostream>
#include <sstream>
#include <utility>
#include <vector>
pps_tcp_rx::pps_tcp_rx()
{
// TODO Auto-generated constructor stub
is_connected = false;
clientSd = -1;
}
pps_tcp_rx::~pps_tcp_rx()
{
// TODO Auto-generated destructor stub
}
void pps_tcp_rx::set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue)
{
Pps_queue = std::move(queue);
}
bool pps_tcp_rx::send_cmd(std::string cmd)
{
if (is_connected == true)
{
// send call sends the data you specify as second param and it's length as 3rd param, also returns how many bytes were actually sent
auto bytes_sent = send(clientSd, cmd.data(), cmd.length(), 0);
if (bytes_sent <= 0)
{
std::cerr << "Connection terminated...\n";
return false;
}
else
{
std::cout << "sent bytes..\n";
}
}
else
{
return false;
}
return true;
}
void pps_tcp_rx::receive_pps(std::string ip_address, int port)
{
// create a message buffer
char buf[1500];
// setup a socket and connection tools
sockaddr_in sendSockAddr;
sendSockAddr.sin_family = AF_INET;
sendSockAddr.sin_addr.s_addr =
inet_addr(ip_address.c_str());
sendSockAddr.sin_port = htons(port);
clientSd = socket(AF_INET, SOCK_STREAM, 0);
// try to connect...
int status = connect(clientSd,
(sockaddr *)&sendSockAddr, sizeof(sendSockAddr));
if (status < 0)
{
std::cout << "pps_tcp_rx: Error connecting to PPS TCP server IP " << ip_address << " at port " << port << std::endl;
return;
}
std::string new_pps_line;
is_connected = true;
while (true)
{
int numBytesRead = recv(clientSd, buf, sizeof(buf), 0);
if (numBytesRead > 0)
{
for (int i = 0; i < numBytesRead; i++)
{
char c = buf[i];
if (c == '\n')
{
if (new_pps_line.length() > 0)
{
// std::cout << "pps_tcp_rx debug: " << new_pps_line << "\n";
// parse string and push PPS data to the PPS queue
std::stringstream ss(new_pps_line);
std::vector<std::string> data;
while (ss.good())
{
std::string substr;
std::getline(ss, substr, ',');
data.push_back(substr);
}
if (data.size() >= 2)
{
PpsSamplestamp new_pps;
// sample counter
std::size_t found = data.at(0).find("sc=");
if (found != std::string::npos)
{
try
{
new_pps.samplestamp = std::strtoul(data.at(0).substr(found + 3).c_str(), NULL, 0);
}
catch (const std::exception &ex)
{
std::cout << "pps_tcp_rx debug: sc parse error str " << data.at(0) << "\n";
}
}
else
{
std::cout << "pps_tcp_rx debug: sc parse error str " << data.at(0) << "\n";
}
found = data.at(1).find("o=");
if (found != std::string::npos)
{
try
{
new_pps.overflow_reg = std::stoi(data.at(1).substr(found + 2).c_str(), NULL, 0);
}
catch (const std::exception &ex)
{
std::cout << "pps_tcp_rx debug: o parse error str " << data.at(0) << "\n";
}
}
else
{
std::cout << "pps_tcp_rx debug: o parse error str " << data.at(1) << "\n";
}
Pps_queue->push(new_pps);
// std::cout << "pps_tcp_rx debug: pps pushed!\n";
}
else
{
std::cout << "pps_tcp_rx debug: protocol error!\n";
}
new_pps_line = "";
}
}
else
new_pps_line += c;
}
}
else
{
std::cout << "pps_tcp_rx: Socket disconnected!\n!";
break;
}
}
is_connected = false;
}

View File

@ -0,0 +1,44 @@
/*!
* \file ppstcprx.h
* \brief TCP client class for front-end PPS samplestamp information reception
* \author Javier Arribas, jarribas(at)cttc.es
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef SRC_LIBS_PPSTCPRX_H_
#define SRC_LIBS_PPSTCPRX_H_
#include "concurrent_queue.h"
#include "pps_samplestamp.h"
#include <arpa/inet.h>
#include <memory>
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
class pps_tcp_rx
{
private:
std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> Pps_queue;
int clientSd;
public:
volatile bool is_connected;
pps_tcp_rx();
virtual ~pps_tcp_rx();
void receive_pps(std::string ip_address, int port);
bool send_cmd(std::string cmd);
void set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue);
};
#endif /* SRC_LIBS_PPSTCPRX_H_ */

View File

@ -55,6 +55,18 @@ public:
return the_queue.empty();
}
size_t size() const
{
std::unique_lock<std::mutex> lock(the_mutex);
return the_queue.size();
}
void clear()
{
std::unique_lock<std::mutex> lock(the_mutex);
the_queue = std::queue<Data>();
}
bool try_pop(Data& popped_value)
{
std::unique_lock<std::mutex> lock(the_mutex);

View File

@ -41,6 +41,7 @@
#include "file_signal_source.h"
#include "file_timestamp_signal_source.h"
#include "fir_filter.h"
#include "four_bit_cpx_file_signal_source.h"
#include "freq_xlating_fir_filter.h"
#include "galileo_e1_dll_pll_veml_tracking.h"
#include "galileo_e1_pcps_8ms_ambiguous_acquisition.h"
@ -152,6 +153,7 @@
#endif
#if PLUTOSDR_DRIVER
#include "ad936x_custom_signal_source.h"
#include "plutosdr_signal_source.h"
#endif
@ -698,6 +700,12 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
out_streams, queue);
block = std::move(block_);
}
else if (implementation == "Four_Bit_Cpx_File_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<FourBitCpxFileSignalSource>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
else if (implementation == "Two_Bit_Packed_File_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<TwoBitPackedFileSignalSource>(configuration, role, in_streams,
@ -772,6 +780,12 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
out_streams, queue);
block = std::move(block_);
}
else if (implementation == "Ad936x_Custom_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Ad936xCustomSignalSource>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
#endif
#if FMCOMMS2_DRIVER

View File

@ -17,6 +17,7 @@
#include "gnss_sdr_filesystem.h"
#include "nmea_printer.h"
#include "pvt_conf.h"
#include "rtklib_rtkpos.h"
#include "rtklib_solver.h"
#include <fstream>
@ -144,7 +145,9 @@ void NmeaPrinterTest::conf()
TEST_F(NmeaPrinterTest, PrintLine)
{
std::string filename("nmea_test.nmea");
std::shared_ptr<Rtklib_Solver> pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 1, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
std::shared_ptr<Rtklib_Solver> pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 1, false, false, conf);
boost::posix_time::ptime pt(boost::gregorian::date(1994, boost::date_time::Nov, 19),
boost::posix_time::hours(22) + boost::posix_time::minutes(54) + boost::posix_time::seconds(46));
@ -165,7 +168,7 @@ TEST_F(NmeaPrinterTest, PrintLine)
bool flag_nmea_output_file = true;
ASSERT_NO_THROW({
std::shared_ptr<Nmea_Printer> nmea_printer = std::make_shared<Nmea_Printer>(filename, flag_nmea_output_file, false, "");
nmea_printer->Print_Nmea_Line(pvt_solution.get(), false);
nmea_printer->Print_Nmea_Line(pvt_solution.get());
}) << "Failure printing NMEA messages.";
std::ifstream test_file(filename);

View File

@ -15,6 +15,7 @@
*/
#include "gnss_sdr_filesystem.h"
#include "pvt_conf.h"
#include "rinex_printer.h"
#include "rtklib_rtkpos.h"
#include "rtklib_solver.h"
@ -142,7 +143,9 @@ void RinexPrinterTest::conf()
TEST_F(RinexPrinterTest, GalileoObsHeader)
{
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 4, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 4, false, false, conf);
auto eph = Galileo_Ephemeris();
eph.PRN = 1;
pvt_solution->galileo_ephemeris_map[1] = eph;
@ -228,7 +231,9 @@ TEST_F(RinexPrinterTest, GalileoObsHeader)
TEST_F(RinexPrinterTest, GlonassObsHeader)
{
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 28, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 28, false, false, conf);
auto eph = Glonass_Gnav_Ephemeris();
eph.PRN = 1;
pvt_solution->glonass_gnav_ephemeris_map[1] = eph;
@ -288,7 +293,9 @@ TEST_F(RinexPrinterTest, MixedObsHeader)
auto eph_gps = Gps_Ephemeris();
eph_gal.PRN = 1;
eph_gps.PRN = 1;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 106, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 106, false, false, conf);
pvt_solution->galileo_ephemeris_map[1] = eph_gal;
pvt_solution->gps_ephemeris_map[1] = eph_gps;
@ -358,7 +365,9 @@ TEST_F(RinexPrinterTest, MixedObsHeaderGpsGlo)
auto eph_gps = Gps_Ephemeris();
eph_glo.PRN = 1;
eph_gps.PRN = 1;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 26, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 26, false, false, conf);
pvt_solution->glonass_gnav_ephemeris_map[1] = eph_glo;
pvt_solution->gps_ephemeris_map[1] = eph_gps;
@ -425,7 +434,9 @@ TEST_F(RinexPrinterTest, GalileoObsLog)
bool no_more_finds = false;
auto eph = Galileo_Ephemeris();
eph.PRN = 1;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 4, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 4, false, false, conf);
pvt_solution->galileo_ephemeris_map[1] = eph;
std::map<int, Gnss_Synchro> gnss_observables_map;
@ -505,7 +516,9 @@ TEST_F(RinexPrinterTest, GlonassObsLog)
bool no_more_finds = false;
auto eph = Glonass_Gnav_Ephemeris();
eph.PRN = 22;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 23, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 23, false, false, conf);
pvt_solution->glonass_gnav_ephemeris_map[1] = eph;
std::map<int, Gnss_Synchro> gnss_observables_map;
@ -587,7 +600,9 @@ TEST_F(RinexPrinterTest, GpsObsLogDualBand)
auto eph_cnav = Gps_CNAV_Ephemeris();
eph.PRN = 1;
eph_cnav.PRN = 1;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 7, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 7, false, false, conf);
pvt_solution->gps_ephemeris_map[1] = eph;
pvt_solution->gps_cnav_ephemeris_map[1] = eph_cnav;
std::map<int, Gnss_Synchro> gnss_observables_map;
@ -675,7 +690,9 @@ TEST_F(RinexPrinterTest, GpsObsLogDualBand)
TEST_F(RinexPrinterTest, GalileoObsLogDualBand)
{
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 14, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 14, false, false, conf);
auto eph = Galileo_Ephemeris();
eph.PRN = 1;
pvt_solution->galileo_ephemeris_map[1] = eph;
@ -775,7 +792,9 @@ TEST_F(RinexPrinterTest, MixedObsLog)
auto eph_gal = Galileo_Ephemeris();
eph_gps.PRN = 1;
eph_gal.PRN = 1;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 9, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 9, false, false, conf);
pvt_solution->gps_ephemeris_map[1] = eph_gps;
pvt_solution->galileo_ephemeris_map[1] = eph_gal;
std::map<int, Gnss_Synchro> gnss_observables_map;
@ -899,7 +918,9 @@ TEST_F(RinexPrinterTest, MixedObsLogGpsGlo)
auto eph_glo = Glonass_Gnav_Ephemeris();
eph_gps.PRN = 1;
eph_glo.PRN = 1;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 26, false, false);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto pvt_solution = std::make_shared<Rtklib_Solver>(rtk, "filename", 26, false, false, conf);
pvt_solution->gps_ephemeris_map[1] = eph_gps;
pvt_solution->glonass_gnav_ephemeris_map[1] = eph_glo;
std::map<int, Gnss_Synchro> gnss_observables_map;

View File

@ -18,6 +18,7 @@
#include "gnss_sdr_make_unique.h"
#include "gnss_sdr_supl_client.h"
#include "in_memory_configuration.h"
#include "pvt_conf.h"
#include "rtklib_solver.h"
#include <armadillo>
#include <boost/archive/xml_iarchive.hpp>
@ -28,7 +29,6 @@
#include <iostream>
#include <string>
rtk_t configure_rtklib_options()
{
std::shared_ptr<InMemoryConfiguration> configuration;
@ -384,7 +384,9 @@ TEST(RTKLibSolverTest, test1)
bool save_to_mat = false;
rtk_t rtk = configure_rtklib_options();
auto d_ls_pvt = std::make_unique<Rtklib_Solver>(rtk, nchannels, dump_filename, 1, flag_dump_to_file, save_to_mat);
Pvt_Conf conf;
conf.use_e6_for_pvt = false;
auto d_ls_pvt = std::make_unique<Rtklib_Solver>(rtk, nchannels, dump_filename, 1, flag_dump_to_file, save_to_mat, conf);
d_ls_pvt->set_averaging_depth(1);
// load ephemeris