mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2025-11-02 16:23:06 +00:00
Remove build and data folders, move tests and utils to the base of the source tree
This commit is contained in:
155
utils/front-end-cal/CMakeLists.txt
Normal file
155
utils/front-end-cal/CMakeLists.txt
Normal file
@@ -0,0 +1,155 @@
|
||||
# GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
# This file is part of GNSS-SDR.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2010-2020 C. Fernandez-Prades cfernandez(at)cttc.es
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
|
||||
if(USE_CMAKE_TARGET_SOURCES)
|
||||
add_library(front_end_cal_lib STATIC)
|
||||
target_sources(front_end_cal_lib
|
||||
PRIVATE
|
||||
front_end_cal.cc
|
||||
PUBLIC
|
||||
front_end_cal.h
|
||||
)
|
||||
else()
|
||||
source_group(Headers FILES front_end_cal.h)
|
||||
add_library(front_end_cal_lib front_end_cal.cc front_end_cal.h)
|
||||
endif()
|
||||
|
||||
target_link_libraries(front_end_cal_lib
|
||||
PUBLIC
|
||||
Armadillo::armadillo
|
||||
Threads::Threads
|
||||
acquisition_adapters
|
||||
gnss_sdr_flags
|
||||
channel_libs
|
||||
algorithms_libs
|
||||
core_receiver
|
||||
core_libs
|
||||
PRIVATE
|
||||
Boost::headers
|
||||
Gnuradio::blocks
|
||||
Gnuradio::runtime
|
||||
)
|
||||
|
||||
if(ENABLE_GLOG_AND_GFLAGS)
|
||||
target_link_libraries(front_end_cal_lib PRIVATE Gflags::gflags Glog::glog)
|
||||
target_compile_definitions(front_end_cal_lib PRIVATE -DUSE_GLOG_AND_GFLAGS=1)
|
||||
else()
|
||||
target_link_libraries(front_end_cal_lib PRIVATE absl::flags absl::log)
|
||||
endif()
|
||||
|
||||
if(ENABLE_CLANG_TIDY)
|
||||
if(CLANG_TIDY_EXE)
|
||||
set_target_properties(front_end_cal_lib
|
||||
PROPERTIES
|
||||
CXX_CLANG_TIDY "${DO_CLANG_TIDY}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_CMAKE_TARGET_SOURCES)
|
||||
add_executable(front-end-cal)
|
||||
target_sources(front-end-cal PRIVATE main.cc)
|
||||
else()
|
||||
add_executable(front-end-cal main.cc)
|
||||
endif()
|
||||
|
||||
target_link_libraries(front-end-cal
|
||||
PRIVATE
|
||||
core_receiver
|
||||
algorithms_libs
|
||||
front_end_cal_lib
|
||||
gnss_sdr_flags
|
||||
Boost::headers
|
||||
)
|
||||
|
||||
if(ENABLE_GLOG_AND_GFLAGS)
|
||||
target_link_libraries(front-end-cal PRIVATE Glog::glog)
|
||||
target_compile_definitions(front-end-cal PRIVATE -DUSE_GLOG_AND_GFLAGS=1)
|
||||
else()
|
||||
target_link_libraries(front-end-cal PRIVATE absl::flags absl::flags_parse absl::log absl::log_initialize absl::log_sink absl::log_sink_registry)
|
||||
endif()
|
||||
|
||||
if(GNURADIO_USES_STD_POINTERS)
|
||||
target_compile_definitions(front-end-cal
|
||||
PRIVATE -DGNURADIO_USES_STD_POINTERS=1
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(front-end-cal
|
||||
PRIVATE -DGNSS_SDR_VERSION="${VERSION}"
|
||||
PRIVATE -DGNSSSDR_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}"
|
||||
)
|
||||
|
||||
if(USE_GENERIC_LAMBDAS)
|
||||
set(has_generic_lambdas HAS_GENERIC_LAMBDA=1)
|
||||
set(no_has_generic_lambdas HAS_GENERIC_LAMBDA=0)
|
||||
target_compile_definitions(front-end-cal
|
||||
PRIVATE
|
||||
"$<$<COMPILE_FEATURES:cxx_generic_lambdas>:${has_generic_lambdas}>"
|
||||
"$<$<NOT:$<COMPILE_FEATURES:cxx_generic_lambdas>>:${no_has_generic_lambdas}>"
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(front-end-cal
|
||||
PRIVATE
|
||||
-DHAS_GENERIC_LAMBDA=0
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USE_BOOST_BIND_PLACEHOLDERS)
|
||||
target_compile_definitions(front-end-cal
|
||||
PRIVATE
|
||||
-DUSE_BOOST_BIND_PLACEHOLDERS=1
|
||||
)
|
||||
endif()
|
||||
|
||||
if(PMT_USES_BOOST_ANY)
|
||||
target_compile_definitions(front-end-cal
|
||||
PRIVATE
|
||||
-DPMT_USES_BOOST_ANY=1
|
||||
)
|
||||
endif()
|
||||
|
||||
include(XcodeRemoveWarningDuplicates)
|
||||
xcode_remove_warning_duplicates(front-end-cal)
|
||||
|
||||
if(ENABLE_STRIP)
|
||||
set_target_properties(front-end-cal PROPERTIES LINK_FLAGS "-s")
|
||||
endif()
|
||||
|
||||
if(ENABLE_CLANG_TIDY)
|
||||
if(CLANG_TIDY_EXE)
|
||||
set_target_properties(front-end-cal
|
||||
PROPERTIES
|
||||
CXX_CLANG_TIDY "${DO_CLANG_TIDY}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET front-end-cal POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:front-end-cal>
|
||||
${LOCAL_INSTALL_BASE_DIR}/install/$<TARGET_FILE_NAME:front-end-cal>
|
||||
)
|
||||
|
||||
install(TARGETS front-end-cal
|
||||
RUNTIME DESTINATION bin
|
||||
COMPONENT "front-end-cal"
|
||||
)
|
||||
|
||||
find_program(GZIP gzip
|
||||
/bin
|
||||
/usr/bin
|
||||
/usr/local/bin
|
||||
/opt/local/bin
|
||||
/sbin
|
||||
)
|
||||
|
||||
if(NOT GZIP_NOTFOUND)
|
||||
execute_process(COMMAND gzip -9 -c ${GNSSSDR_SOURCE_DIR}/docs/manpage/front-end-cal-manpage
|
||||
WORKING_DIRECTORY ${GNSSSDR_BINARY_DIR} OUTPUT_FILE "${GNSSSDR_BINARY_DIR}/front-end-cal.1.gz"
|
||||
)
|
||||
install(FILES ${GNSSSDR_BINARY_DIR}/front-end-cal.1.gz DESTINATION share/man/man1)
|
||||
endif()
|
||||
384
utils/front-end-cal/front_end_cal.cc
Normal file
384
utils/front-end-cal/front_end_cal.cc
Normal file
@@ -0,0 +1,384 @@
|
||||
/*!
|
||||
* \file front_end_cal.cc
|
||||
* \brief Implementation of the Front-end calibration program.
|
||||
* \author Javier Arribas, 2013. 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-2020 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "front_end_cal.h"
|
||||
#include "GPS_L1_CA.h" // for GPS_L1_FREQ_HZ
|
||||
#include "concurrent_map.h"
|
||||
#include "configuration_interface.h"
|
||||
#include "gnss_sdr_supl_client.h"
|
||||
#include "gps_acq_assist.h" // for Gps_Acq_Assist
|
||||
#include "gps_almanac.h"
|
||||
#include "gps_ephemeris.h"
|
||||
#include "gps_iono.h"
|
||||
#include "gps_utc_model.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <algorithm> // for min
|
||||
#include <cmath>
|
||||
#include <iostream> // for operator<<
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include <glog/logging.h>
|
||||
#else
|
||||
#include <absl/log/log.h>
|
||||
#endif
|
||||
|
||||
extern Concurrent_Map<Gps_Ephemeris> global_gps_ephemeris_map;
|
||||
extern Concurrent_Map<Gps_Iono> global_gps_iono_map;
|
||||
extern Concurrent_Map<Gps_Utc_Model> global_gps_utc_model_map;
|
||||
extern Concurrent_Map<Gps_Almanac> global_gps_almanac_map;
|
||||
extern Concurrent_Map<Gps_Acq_Assist> global_gps_acq_assist_map;
|
||||
|
||||
|
||||
bool FrontEndCal::read_assistance_from_XML()
|
||||
{
|
||||
Gnss_Sdr_Supl_Client supl_client_ephemeris_;
|
||||
std::string eph_xml_filename = "gps_ephemeris.xml";
|
||||
std::cout << "SUPL: Trying to read GPS ephemeris from XML file " << eph_xml_filename << '\n';
|
||||
LOG(INFO) << "SUPL: Trying to read GPS ephemeris from XML file " << eph_xml_filename;
|
||||
if (supl_client_ephemeris_.load_ephemeris_xml(eph_xml_filename) == true)
|
||||
{
|
||||
std::map<int, Gps_Ephemeris>::iterator gps_eph_iter;
|
||||
for (gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin();
|
||||
gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end();
|
||||
gps_eph_iter++)
|
||||
{
|
||||
std::cout << "SUPL: Read XML Ephemeris for GPS SV " << gps_eph_iter->first << '\n';
|
||||
LOG(INFO) << "SUPL: Read XML Ephemeris for GPS SV " << gps_eph_iter->first;
|
||||
LOG(INFO) << "New Ephemeris record inserted with Toe=" << gps_eph_iter->second.toe << " and GPS Week=" << gps_eph_iter->second.WN;
|
||||
global_gps_ephemeris_map.write(gps_eph_iter->second.PRN, gps_eph_iter->second);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
std::cout << "ERROR: SUPL client error reading XML\n";
|
||||
LOG(WARNING) << "ERROR: SUPL client error reading XML";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int FrontEndCal::Get_SUPL_Assist()
|
||||
{
|
||||
// ######### GNSS Assistance #################################
|
||||
Gnss_Sdr_Supl_Client supl_client_acquisition_;
|
||||
Gnss_Sdr_Supl_Client supl_client_ephemeris_;
|
||||
int supl_mcc; // Current network MCC (Mobile country code), 3 digits.
|
||||
int supl_mns; // Current network MNC (Mobile Network code), 2 or 3 digits.
|
||||
int supl_lac; // Current network LAC (Location area code),16 bits, 1-65520 are valid values.
|
||||
int supl_ci; // Cell Identity (16 bits, 0-65535 are valid values).
|
||||
|
||||
// GNSS Assistance configuration
|
||||
int error = 0;
|
||||
bool enable_gps_supl_assistance = configuration_->property("GNSS-SDR.SUPL_gps_enabled", false);
|
||||
if (enable_gps_supl_assistance == true)
|
||||
// SUPL SERVER TEST. Not operational yet!
|
||||
{
|
||||
LOG(INFO) << "SUPL RRLP GPS assistance enabled!";
|
||||
std::string default_acq_server = "supl.nokia.com";
|
||||
std::string default_eph_server = "supl.google.com";
|
||||
supl_client_ephemeris_.server_name = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_server", std::move(default_acq_server));
|
||||
supl_client_acquisition_.server_name = configuration_->property("GNSS-SDR.SUPL_gps_acquisition_server", std::move(default_eph_server));
|
||||
supl_client_ephemeris_.server_port = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_port", 7275);
|
||||
supl_client_acquisition_.server_port = configuration_->property("GNSS-SDR.SUPL_gps_acquisition_port", 7275);
|
||||
supl_mcc = configuration_->property("GNSS-SDR.SUPL_MCC", 244);
|
||||
supl_mns = configuration_->property("GNSS-SDR.SUPL_MNC", 5);
|
||||
|
||||
std::string default_lac = "0x59e2";
|
||||
std::string default_ci = "0x31b0";
|
||||
try
|
||||
{
|
||||
supl_lac = boost::lexical_cast<int>(configuration_->property("GNSS-SDR.SUPL_LAC", std::move(default_lac)));
|
||||
}
|
||||
catch (boost::bad_lexical_cast &)
|
||||
{
|
||||
supl_lac = 0x59e2;
|
||||
}
|
||||
try
|
||||
{
|
||||
supl_ci = boost::lexical_cast<int>(configuration_->property("GNSS-SDR.SUPL_CI", std::move(default_ci)));
|
||||
}
|
||||
catch (boost::bad_lexical_cast &)
|
||||
{
|
||||
supl_ci = 0x31b0;
|
||||
}
|
||||
|
||||
bool SUPL_read_gps_assistance_xml = configuration_->property("GNSS-SDR.SUPL_read_gps_assistance_xml", false);
|
||||
if (SUPL_read_gps_assistance_xml == true)
|
||||
{
|
||||
// read assistance from file
|
||||
read_assistance_from_XML();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Request ephemeris from SUPL server
|
||||
supl_client_ephemeris_.request = 1;
|
||||
LOG(INFO) << "SUPL: Trying to read GPS ephemeris from SUPL server...";
|
||||
std::cout << "SUPL: Trying to read GPS ephemeris from SUPL server...\n";
|
||||
error = supl_client_ephemeris_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci);
|
||||
if (error == 0)
|
||||
{
|
||||
std::map<int, Gps_Ephemeris>::iterator gps_eph_iter;
|
||||
for (gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin();
|
||||
gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end();
|
||||
gps_eph_iter++)
|
||||
{
|
||||
LOG(INFO) << "SUPL: Received Ephemeris for GPS SV " << gps_eph_iter->first;
|
||||
std::cout << "SUPL: Received Ephemeris for GPS SV " << gps_eph_iter->first << '\n';
|
||||
LOG(INFO) << "New Ephemeris record inserted with Toe=" << gps_eph_iter->second.toe << " and GPS Week=" << gps_eph_iter->second.WN;
|
||||
global_gps_ephemeris_map.write(gps_eph_iter->second.PRN, gps_eph_iter->second);
|
||||
}
|
||||
// Save ephemeris to XML file
|
||||
std::string eph_xml_filename = configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_xml", eph_default_xml_filename);
|
||||
if (supl_client_ephemeris_.save_ephemeris_map_xml(eph_xml_filename, supl_client_ephemeris_.gps_ephemeris_map) == true)
|
||||
{
|
||||
LOG(INFO) << "SUPL: XML Ephemeris file created.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(WARNING) << "ERROR: SUPL client for Ephemeris returned " << error;
|
||||
std::cout << "ERROR in SUPL client. Please check your Internet connection and SUPL server configuration\n";
|
||||
}
|
||||
|
||||
// Request almanac , IONO and UTC Model
|
||||
supl_client_ephemeris_.request = 0;
|
||||
LOG(INFO) << "SUPL: Try read Almanac, Iono, Utc Model, Ref Time and Ref Location from SUPL server...";
|
||||
error = supl_client_ephemeris_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci);
|
||||
if (error == 0)
|
||||
{
|
||||
std::map<int, Gps_Almanac>::iterator gps_alm_iter;
|
||||
for (gps_alm_iter = supl_client_ephemeris_.gps_almanac_map.begin();
|
||||
gps_alm_iter != supl_client_ephemeris_.gps_almanac_map.end();
|
||||
gps_alm_iter++)
|
||||
{
|
||||
LOG(INFO) << "SUPL: Received Almanac for GPS SV " << gps_alm_iter->first;
|
||||
std::cout << "SUPL: Received Almanac for GPS SV " << gps_alm_iter->first << '\n';
|
||||
global_gps_almanac_map.write(gps_alm_iter->first, gps_alm_iter->second);
|
||||
}
|
||||
if (supl_client_ephemeris_.gps_iono.valid == true)
|
||||
{
|
||||
LOG(INFO) << "SUPL: Received GPS Iono";
|
||||
std::cout << "SUPL: Received GPS Iono\n";
|
||||
global_gps_iono_map.write(0, supl_client_ephemeris_.gps_iono);
|
||||
}
|
||||
if (supl_client_ephemeris_.gps_utc.valid == true)
|
||||
{
|
||||
LOG(INFO) << "SUPL: Received GPS UTC Model";
|
||||
std::cout << "SUPL: Received GPS UTC Model\n";
|
||||
global_gps_utc_model_map.write(0, supl_client_ephemeris_.gps_utc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(WARNING) << "ERROR: SUPL client for Almanac returned " << error;
|
||||
std::cout << "ERROR in SUPL client. Please check your Internet connection and SUPL server configuration\n";
|
||||
}
|
||||
|
||||
// Request acquisition assistance
|
||||
supl_client_acquisition_.request = 2;
|
||||
LOG(INFO) << "SUPL: Trying to read Acquisition assistance from SUPL server...";
|
||||
std::cout << "SUPL: Trying to read Acquisition assistance from SUPL server...\n";
|
||||
|
||||
error = supl_client_acquisition_.get_assistance(supl_mcc, supl_mns, supl_lac, supl_ci);
|
||||
if (error == 0)
|
||||
{
|
||||
std::map<int, Gps_Acq_Assist>::iterator gps_acq_iter;
|
||||
for (gps_acq_iter = supl_client_acquisition_.gps_acq_map.begin();
|
||||
gps_acq_iter != supl_client_acquisition_.gps_acq_map.end();
|
||||
gps_acq_iter++)
|
||||
{
|
||||
LOG(INFO) << "SUPL: Received Acquisition assistance for GPS SV " << gps_acq_iter->first;
|
||||
std::cout << "SUPL: Received Acquisition assistance for GPS SV " << gps_acq_iter->first << '\n';
|
||||
LOG(INFO) << "New acq assist record inserted";
|
||||
global_gps_acq_assist_map.write(gps_acq_iter->second.PRN, gps_acq_iter->second);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(WARNING) << "ERROR: SUPL client for Acquisition assistance returned " << error;
|
||||
std::cout << "ERROR in SUPL client. Please check your Internet connection and SUPL server configuration\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void FrontEndCal::set_configuration(std::shared_ptr<ConfigurationInterface> configuration)
|
||||
{
|
||||
configuration_ = std::move(configuration);
|
||||
}
|
||||
|
||||
|
||||
bool FrontEndCal::get_ephemeris()
|
||||
{
|
||||
bool read_ephemeris_from_xml = configuration_->property("GNSS-SDR.read_eph_from_xml", false);
|
||||
|
||||
if (read_ephemeris_from_xml == true)
|
||||
{
|
||||
std::cout << "Trying to read ephemeris from XML file...\n";
|
||||
LOG(INFO) << "Trying to read ephemeris from XML file...";
|
||||
if (read_assistance_from_XML() == false)
|
||||
{
|
||||
std::cout << "ERROR: Could not read Ephemeris file: Trying to get ephemeris from SUPL server...\n";
|
||||
LOG(INFO) << "ERROR: Could not read Ephemeris file: Trying to get ephemeris from SUPL server...";
|
||||
if (Get_SUPL_Assist() == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cout << "Trying to read ephemeris from SUPL server...\n";
|
||||
LOG(INFO) << "Trying to read ephemeris from SUPL server...";
|
||||
if (Get_SUPL_Assist() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
arma::vec FrontEndCal::lla2ecef(const arma::vec &lla)
|
||||
{
|
||||
// WGS84 flattening
|
||||
double f = 1.0 / 298.257223563;
|
||||
|
||||
// WGS84 equatorial radius
|
||||
double R = 6378137.0;
|
||||
|
||||
arma::vec ellipsoid = "0.0 0.0";
|
||||
double phi = (lla(0) / 360.0) * TWO_PI;
|
||||
double lambda = (lla(1) / 360.0) * TWO_PI;
|
||||
|
||||
ellipsoid(0) = R;
|
||||
ellipsoid(1) = sqrt(1.0 - (1.0 - f) * (1.0 - f));
|
||||
|
||||
arma::vec ecef = "0.0 0.0 0.0 0.0";
|
||||
ecef = geodetic2ecef(phi, lambda, lla(3), ellipsoid);
|
||||
|
||||
return ecef;
|
||||
}
|
||||
|
||||
|
||||
arma::vec FrontEndCal::geodetic2ecef(double phi, double lambda, double h, const arma::vec &ellipsoid)
|
||||
{
|
||||
double a = ellipsoid(0);
|
||||
double e2 = ellipsoid(1) * ellipsoid(1);
|
||||
double sinphi = sin(phi);
|
||||
double cosphi = cos(phi);
|
||||
double N = a / sqrt(1.0 - e2 * sinphi * sinphi);
|
||||
arma::vec ecef = "0.0 0.0 0.0 0.0";
|
||||
|
||||
ecef(0) = (N + h) * cosphi * cos(lambda);
|
||||
ecef(1) = (N + h) * cosphi * sin(lambda);
|
||||
ecef(2) = (N * (1.0 - e2) + h) * sinphi;
|
||||
|
||||
return ecef;
|
||||
}
|
||||
|
||||
|
||||
double FrontEndCal::estimate_doppler_from_eph(unsigned int PRN, double tow, double lat, double lon, double height) noexcept(false)
|
||||
{
|
||||
int num_secs = 10;
|
||||
double step_secs = 0.5;
|
||||
|
||||
// Observer position ECEF
|
||||
arma::vec obs_ecef = "0.0 0.0 0.0 0.0";
|
||||
arma::vec lla = "0.0 0.0 0.0 0.0";
|
||||
lla(0) = lat;
|
||||
lla(1) = lon;
|
||||
lla(2) = height;
|
||||
obs_ecef = lla2ecef(lla);
|
||||
|
||||
// Satellite positions ECEF
|
||||
std::map<int, Gps_Ephemeris> eph_map;
|
||||
eph_map = global_gps_ephemeris_map.get_map_copy();
|
||||
|
||||
std::map<int, Gps_Ephemeris>::iterator eph_it;
|
||||
eph_it = eph_map.find(PRN);
|
||||
|
||||
if (eph_it != eph_map.end())
|
||||
{
|
||||
arma::vec SV_pos_ecef = "0.0 0.0 0.0 0.0";
|
||||
double obs_time_start;
|
||||
double obs_time_stop;
|
||||
obs_time_start = tow - static_cast<double>(num_secs) / 2.0;
|
||||
obs_time_stop = tow + static_cast<double>(num_secs) / 2.0;
|
||||
int n_points = round((obs_time_stop - obs_time_start) / step_secs);
|
||||
arma::vec ranges = arma::zeros(n_points, 1);
|
||||
double obs_time = obs_time_start;
|
||||
for (int i = 0; i < n_points; i++)
|
||||
{
|
||||
eph_it->second.satellitePosition(obs_time);
|
||||
SV_pos_ecef(0) = eph_it->second.satpos_X;
|
||||
SV_pos_ecef(1) = eph_it->second.satpos_Y;
|
||||
SV_pos_ecef(2) = eph_it->second.satpos_Z;
|
||||
// SV distances to observer (true range)
|
||||
ranges(i) = arma::norm(SV_pos_ecef - obs_ecef, 2);
|
||||
obs_time += step_secs;
|
||||
}
|
||||
// Observer to satellite radial velocity
|
||||
// Numeric derivative: Positive slope means that the distance from obs to
|
||||
// satellite is increasing
|
||||
arma::vec obs_to_sat_velocity;
|
||||
obs_to_sat_velocity = (ranges.subvec(1, (n_points - 1)) - ranges.subvec(0, (n_points - 2))) / step_secs;
|
||||
// Doppler equations are formulated accounting for positive velocities if the
|
||||
// tx and rx are approaching to each other. So, the satellite velocity must
|
||||
// be redefined as:
|
||||
obs_to_sat_velocity = -obs_to_sat_velocity;
|
||||
|
||||
// Doppler estimation
|
||||
arma::vec Doppler_Hz;
|
||||
Doppler_Hz = (obs_to_sat_velocity / SPEED_OF_LIGHT_M_S) * GPS_L1_FREQ_HZ;
|
||||
double mean_Doppler_Hz;
|
||||
mean_Doppler_Hz = arma::mean(Doppler_Hz);
|
||||
return mean_Doppler_Hz;
|
||||
}
|
||||
throw std::runtime_error("1");
|
||||
}
|
||||
|
||||
|
||||
void FrontEndCal::GPS_L1_front_end_model_E4000(double f_bb_true_Hz, double f_bb_meas_Hz, double fs_nominal_hz, double *estimated_fs_Hz, double *estimated_f_if_Hz, double *f_osc_err_ppm)
|
||||
{
|
||||
const double f_osc_n = 28.8e6;
|
||||
// PLL registers settings (according to E4000 datasheet)
|
||||
const double N = 109.0;
|
||||
const double Y = 65536.0;
|
||||
const double X = 26487.0;
|
||||
const double R = 2.0;
|
||||
|
||||
// Obtained RF center frequency
|
||||
double f_rf_pll = (f_osc_n * (N + X / Y)) / R;
|
||||
|
||||
// RF frequency error caused by fractional PLL roundings
|
||||
double f_bb_err_pll = GPS_L1_FREQ_HZ - f_rf_pll;
|
||||
|
||||
// Measured F_rf error
|
||||
double f_rf_err = (f_bb_meas_Hz - f_bb_true_Hz) - f_bb_err_pll;
|
||||
double f_osc_err_hz = (f_rf_err * R) / (N + X / Y);
|
||||
|
||||
f_osc_err_hz = -f_osc_err_hz;
|
||||
*f_osc_err_ppm = f_osc_err_hz / (f_osc_n / 1e6);
|
||||
|
||||
double frac = fs_nominal_hz / f_osc_n;
|
||||
*estimated_fs_Hz = frac * (f_osc_n + f_osc_err_hz);
|
||||
*estimated_f_if_Hz = f_rf_err;
|
||||
}
|
||||
129
utils/front-end-cal/front_end_cal.h
Normal file
129
utils/front-end-cal/front_end_cal.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*!
|
||||
* \file front_end_cal.h
|
||||
* \brief Interface of the Front-end calibration program.
|
||||
* \author Javier Arribas, 2013. 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-2020 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_FRONT_END_CAL_H
|
||||
#define GNSS_SDR_FRONT_END_CAL_H
|
||||
|
||||
#include <armadillo>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class ConfigurationInterface;
|
||||
|
||||
class FrontEndCal
|
||||
{
|
||||
public:
|
||||
FrontEndCal() = default;
|
||||
~FrontEndCal() = default;
|
||||
|
||||
/*!
|
||||
* \brief Sets the configuration data required by get_ephemeris function
|
||||
*
|
||||
*/
|
||||
void set_configuration(std::shared_ptr<ConfigurationInterface> configuration);
|
||||
|
||||
/*!
|
||||
* \brief This function connects to a Secure User Location Protocol (SUPL) server to obtain
|
||||
* the current GPS ephemeris and GPS assistance data. It requires the configuration parameters set by
|
||||
* set_configuration function.
|
||||
*
|
||||
*/
|
||||
bool get_ephemeris();
|
||||
|
||||
/*!
|
||||
* \brief This function estimates the GPS L1 satellite Doppler frequency [Hz] using the following data:
|
||||
* 1- Orbital model from the ephemeris
|
||||
* 2- Approximate GPS Time of Week (TOW)
|
||||
* 3- Approximate receiver Latitude and Longitude (WGS-84)
|
||||
*
|
||||
*/
|
||||
double estimate_doppler_from_eph(unsigned int PRN, double tow, double lat, double lon, double height) noexcept(false);
|
||||
|
||||
/*!
|
||||
* \brief This function models the Elonics E4000 + RTL2832 front-end
|
||||
* Inputs:
|
||||
* f_bb_true_Hz - Ideal output frequency in baseband [Hz]
|
||||
* f_in_bb_meas_Hz - measured output frequency in baseband [Hz]
|
||||
* Outputs:
|
||||
* estimated_fs_Hz - Sampling frequency estimation based on the
|
||||
* measurements and the front-end model
|
||||
* estimated_f_if_bb_Hz - Equivalent bb if frequency estimation based on the
|
||||
* measurements and the front-end model
|
||||
* Front-end TUNER Elonics E4000 + RTL2832 sampler For GPS L1 1575.42 MHz
|
||||
*
|
||||
*/
|
||||
void GPS_L1_front_end_model_E4000(double f_bb_true_Hz, double f_bb_meas_Hz, double fs_nominal_hz, double *estimated_fs_Hz, double *estimated_f_if_Hz, double *f_osc_err_ppm);
|
||||
|
||||
private:
|
||||
std::shared_ptr<ConfigurationInterface> configuration_;
|
||||
|
||||
/*
|
||||
* LLA2ECEF Convert geodetic coordinates to Earth-centered Earth-fixed
|
||||
* (ECEF) coordinates. P = LLA2ECEF( LLA ) converts an M-by-3 array of geodetic coordinates
|
||||
* (latitude, longitude and altitude), LLA, to an M-by-3 array of ECEF
|
||||
* coordinates, P. LLA is in [degrees degrees meters]. P is in meters.
|
||||
* The default ellipsoid planet is WGS84. Original copyright (c) by Kai Borre.
|
||||
*/
|
||||
arma::vec lla2ecef(const arma::vec &lla);
|
||||
|
||||
/*
|
||||
* GEODETIC2ECEF Convert geodetic to geocentric (ECEF) coordinates
|
||||
* [X, Y, Z] = GEODETIC2ECEF(PHI, LAMBDA, H, ELLIPSOID) converts geodetic
|
||||
* point locations specified by the coordinate arrays PHI (geodetic
|
||||
* latitude in radians), LAMBDA (longitude in radians), and H (ellipsoidal
|
||||
* height) to geocentric Cartesian coordinates X, Y, and Z. The geodetic
|
||||
* coordinates refer to the reference ellipsoid specified by ELLIPSOID (a
|
||||
* row vector with the form [semimajor axis, eccentricity]). H must use
|
||||
* the same units as the semimajor axis; X, Y, and Z will be expressed in
|
||||
* these units also.
|
||||
*
|
||||
* The geocentric Cartesian coordinate system is fixed with respect to the
|
||||
* Earth, with its origin at the center of the ellipsoid and its X-, Y-,
|
||||
* and Z-axes intersecting the surface at the following points:
|
||||
* PHI LAMBDA
|
||||
* X-axis: 0 0 (Equator at the Prime Meridian)
|
||||
* Y-axis: 0 pi/2 (Equator at 90-degrees East
|
||||
* Z-axis: pi/2 0 (North Pole)
|
||||
*
|
||||
* A common synonym is Earth-Centered, Earth-Fixed coordinates, or ECEF.
|
||||
*
|
||||
* See also ECEF2GEODETIC, ECEF2LV, GEODETIC2GEOCENTRICLAT, LV2ECEF.
|
||||
*
|
||||
* Copyright 2004-2009 The MathWorks, Inc.
|
||||
* $Revision: 1.1.6.4 $ $Date: 2009/04/15 23:34:46 $
|
||||
* Reference
|
||||
* ---------
|
||||
* Paul R. Wolf and Bon A. Dewitt, "Elements of Photogrammetry with
|
||||
* Applications in GIS," 3rd Ed., McGraw-Hill, 2000 (Appendix F-3).
|
||||
*/
|
||||
arma::vec geodetic2ecef(double phi, double lambda, double h, const arma::vec &ellipsoid);
|
||||
|
||||
/*
|
||||
* Reads the ephemeris data from an external XML file
|
||||
*/
|
||||
bool read_assistance_from_XML();
|
||||
|
||||
/*
|
||||
* Connects to Secure User Location Protocol (SUPL) server to obtain
|
||||
* the current GPS ephemeris and GPS assistance data.
|
||||
*/
|
||||
int Get_SUPL_Assist();
|
||||
|
||||
const std::string eph_default_xml_filename = "./gps_ephemeris.xml";
|
||||
};
|
||||
|
||||
#endif
|
||||
779
utils/front-end-cal/main.cc
Normal file
779
utils/front-end-cal/main.cc
Normal file
@@ -0,0 +1,779 @@
|
||||
/*!
|
||||
* \file main.cc
|
||||
* \brief Main file of the Front-end calibration program.
|
||||
* \author Javier Arribas, 2013. 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-2020 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef FRONT_END_CAL_VERSION
|
||||
#define FRONT_END_CAL_VERSION "0.0.1"
|
||||
#endif
|
||||
|
||||
#include "GPS_L1_CA.h" // for GPS_L1_CA_COD...
|
||||
#include "concurrent_map.h"
|
||||
#include "concurrent_queue.h"
|
||||
#include "configuration_interface.h" // for Configuration...
|
||||
#include "file_configuration.h"
|
||||
#include "front_end_cal.h"
|
||||
#include "gnss_block_factory.h"
|
||||
#include "gnss_block_interface.h" // for GNSSBlockInte...
|
||||
#include "gnss_sdr_filesystem.h"
|
||||
#include "gnss_sdr_flags.h"
|
||||
#include "gnss_synchro.h"
|
||||
#include "gps_acq_assist.h" // for Gps_Acq_Assist
|
||||
#include "gps_almanac.h"
|
||||
#include "gps_ephemeris.h"
|
||||
#include "gps_iono.h"
|
||||
#include "gps_l1_ca_pcps_acquisition_fine_doppler.h"
|
||||
#include "gps_utc_model.h"
|
||||
#include "signal_source_interface.h" // for SignalSourceInterface
|
||||
#include <boost/any.hpp> // for bad_any_cast
|
||||
#include <boost/exception/exception.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <gnuradio/block.h> // for block
|
||||
#include <gnuradio/blocks/file_sink.h>
|
||||
#include <gnuradio/blocks/file_source.h>
|
||||
#include <gnuradio/blocks/head.h>
|
||||
#include <gnuradio/blocks/null_sink.h>
|
||||
#include <gnuradio/blocks/skiphead.h>
|
||||
#include <gnuradio/gr_complex.h> // for gr_complex
|
||||
#include <gnuradio/io_signature.h> // for io_signature
|
||||
#include <gnuradio/runtime_types.h> // for block_sptr
|
||||
#include <gnuradio/top_block.h>
|
||||
#include <pmt/pmt.h> // for pmt_t, to_long
|
||||
#include <pmt/pmt_sugar.h> // for mp
|
||||
#include <chrono>
|
||||
#include <cmath> // for round
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <ctime> // for ctime
|
||||
#include <exception>
|
||||
#include <iomanip> // for std::setiosflags, std::setprecision
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept> // for logic_error
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#else
|
||||
#include <absl/flags/flag.h>
|
||||
#include <absl/flags/parse.h>
|
||||
#include <absl/flags/usage.h>
|
||||
#include <absl/flags/usage_config.h>
|
||||
#include <absl/log/globals.h>
|
||||
#include <absl/log/initialize.h>
|
||||
#include <absl/log/log.h>
|
||||
#include <absl/log/log_sink.h>
|
||||
#include <absl/log/log_sink_registry.h>
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#if HAS_GENERIC_LAMBDA
|
||||
#else
|
||||
#include <boost/bind/bind.hpp>
|
||||
#endif
|
||||
|
||||
#if PMT_USES_BOOST_ANY
|
||||
namespace wht = boost;
|
||||
#else
|
||||
namespace wht = std;
|
||||
#endif
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#if GFLAGS_OLD_NAMESPACE
|
||||
namespace gflags
|
||||
{
|
||||
using namespace google;
|
||||
}
|
||||
#endif
|
||||
DECLARE_string(log_dir);
|
||||
#else
|
||||
class FrontEndCalLogSink : public absl::LogSink
|
||||
{
|
||||
public:
|
||||
FrontEndCalLogSink()
|
||||
{
|
||||
if (!absl::GetFlag(FLAGS_log_dir).empty())
|
||||
{
|
||||
logfile.open(absl::GetFlag(FLAGS_log_dir) + "/front_end_cal.log");
|
||||
}
|
||||
else
|
||||
{
|
||||
logfile.open(GetTempDir() + "/front_end_cal.log");
|
||||
}
|
||||
}
|
||||
void Send(const absl::LogEntry& entry) override
|
||||
{
|
||||
logfile << entry.text_message_with_prefix_and_newline() << std::flush;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ofstream logfile;
|
||||
};
|
||||
std::string FrontEndCalVersionString() { return std::string(FRONT_END_CAL_VERSION) + "\n"; }
|
||||
#endif
|
||||
|
||||
Concurrent_Map<Gps_Ephemeris> global_gps_ephemeris_map;
|
||||
Concurrent_Map<Gps_Iono> global_gps_iono_map;
|
||||
Concurrent_Map<Gps_Utc_Model> global_gps_utc_model_map;
|
||||
Concurrent_Map<Gps_Almanac> global_gps_almanac_map;
|
||||
Concurrent_Map<Gps_Acq_Assist> global_gps_acq_assist_map;
|
||||
Concurrent_Queue<Gps_Acq_Assist> global_gps_acq_assist_queue;
|
||||
|
||||
bool stop;
|
||||
Concurrent_Queue<int> channel_internal_queue;
|
||||
std::vector<Gnss_Synchro> gnss_sync_vector;
|
||||
Gnss_Synchro gnss_synchro;
|
||||
|
||||
// ######## GNURADIO BLOCK MESSAGE RECEVER #########
|
||||
class FrontEndCal_msg_rx;
|
||||
|
||||
using FrontEndCal_msg_rx_sptr = gnss_shared_ptr<FrontEndCal_msg_rx>;
|
||||
|
||||
FrontEndCal_msg_rx_sptr FrontEndCal_msg_rx_make();
|
||||
|
||||
|
||||
class FrontEndCal_msg_rx : public gr::block
|
||||
{
|
||||
private:
|
||||
friend FrontEndCal_msg_rx_sptr FrontEndCal_msg_rx_make();
|
||||
void msg_handler_channel_events(const pmt::pmt_t& msg);
|
||||
FrontEndCal_msg_rx();
|
||||
|
||||
public:
|
||||
int rx_message{0};
|
||||
};
|
||||
|
||||
|
||||
FrontEndCal_msg_rx_sptr FrontEndCal_msg_rx_make()
|
||||
{
|
||||
return FrontEndCal_msg_rx_sptr(new FrontEndCal_msg_rx());
|
||||
}
|
||||
|
||||
|
||||
void FrontEndCal_msg_rx::msg_handler_channel_events(const pmt::pmt_t& msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
int64_t message = pmt::to_long(msg);
|
||||
rx_message = message;
|
||||
channel_internal_queue.push(rx_message);
|
||||
}
|
||||
catch (const wht::bad_any_cast& e)
|
||||
{
|
||||
LOG(WARNING) << "msg_handler_telemetry Bad any cast!\n";
|
||||
rx_message = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FrontEndCal_msg_rx::FrontEndCal_msg_rx()
|
||||
: gr::block("FrontEndCal_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0))
|
||||
{
|
||||
this->message_port_register_in(pmt::mp("events"));
|
||||
this->set_msg_handler(pmt::mp("events"),
|
||||
#if HAS_GENERIC_LAMBDA
|
||||
[this](auto&& PH1) { msg_handler_channel_events(PH1); });
|
||||
#else
|
||||
#if USE_BOOST_BIND_PLACEHOLDERS
|
||||
boost::bind(&FrontEndCal_msg_rx::msg_handler_channel_events, this, boost::placeholders::_1));
|
||||
#else
|
||||
boost::bind(&FrontEndCal_msg_rx::msg_handler_channel_events, this, _1));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void wait_message()
|
||||
{
|
||||
while (!stop)
|
||||
{
|
||||
int message;
|
||||
channel_internal_queue.wait_and_pop(message);
|
||||
// std::cout<<"Acq message rx="<<message<< '\n';
|
||||
switch (message)
|
||||
{
|
||||
case 1: // Positive acq
|
||||
gnss_sync_vector.push_back(gnss_synchro);
|
||||
// acquisition->reset();
|
||||
break;
|
||||
case 2: // negative acq
|
||||
// acquisition->reset();
|
||||
break;
|
||||
case 3:
|
||||
stop = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool front_end_capture(const std::shared_ptr<ConfigurationInterface>& configuration)
|
||||
{
|
||||
auto success = false;
|
||||
|
||||
std::string trace_step;
|
||||
|
||||
gr::top_block_sptr top_block;
|
||||
GNSSBlockFactory block_factory;
|
||||
std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue;
|
||||
|
||||
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
|
||||
top_block = gr::make_top_block("Acquisition test");
|
||||
|
||||
try
|
||||
{
|
||||
// Note: the block_factory returns a unique_ptr (what you would get with an "auto"
|
||||
// declaration), but the flowgraph uses shared_ptr. Without further understanding of why
|
||||
// it should matter in this context, used shared_ptr throughout
|
||||
std::shared_ptr<SignalSourceInterface> source;
|
||||
std::shared_ptr<GNSSBlockInterface> conditioner;
|
||||
|
||||
trace_step = "creating source";
|
||||
source = block_factory.GetSignalSource(configuration.get(), queue.get());
|
||||
|
||||
trace_step = "creating signal conditioner";
|
||||
conditioner = block_factory.GetSignalConditioner(configuration.get());
|
||||
|
||||
trace_step = "unexpected in setup code";
|
||||
|
||||
gr::block_sptr sink;
|
||||
sink = gr::blocks::file_sink::make(sizeof(gr_complex), "tmp_capture.dat");
|
||||
|
||||
// -- Find number of samples per spreading code ---
|
||||
int64_t fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000);
|
||||
int samples_per_code = round(fs_in_ / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS));
|
||||
int nsamples = samples_per_code * 50;
|
||||
|
||||
int skip_samples = fs_in_ * 5; // skip 5 seconds
|
||||
|
||||
gr::block_sptr head = gr::blocks::head::make(sizeof(gr_complex), nsamples);
|
||||
|
||||
gr::block_sptr skiphead = gr::blocks::skiphead::make(sizeof(gr_complex), skip_samples);
|
||||
|
||||
trace_step = "connecting the GNU Radio blocks";
|
||||
source->connect(top_block);
|
||||
conditioner->connect(top_block);
|
||||
top_block->connect(source->get_right_block(), 0, conditioner->get_left_block(), 0);
|
||||
top_block->connect(conditioner->get_right_block(), 0, skiphead, 0);
|
||||
top_block->connect(skiphead, 0, head, 0);
|
||||
top_block->connect(head, 0, sink, 0);
|
||||
top_block->run();
|
||||
|
||||
success = true;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
std::cout << "Exception caught " << trace_step << ": " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
static time_t utc_time(int week, int64_t tow)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
/* Jan 5/6 midnight 1980 - beginning of GPS time as Unix time */
|
||||
t = 315964801;
|
||||
|
||||
/* soon week will wrap again, uh oh... */
|
||||
/* TS 44.031: GPSTOW, range 0-604799.92, resolution 0.08 sec, 23-bit presentation */
|
||||
/* The factor 0.08 was applied in the ephemeris SUPL class */
|
||||
/* here the tow is in [s] */
|
||||
t += (1024 + week) * 604800 + tow;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
const std::string intro_help(
|
||||
std::string("\n RTL-SDR E4000 RF front-end center frequency and sampling rate calibration tool that uses GPS signals\n") +
|
||||
"Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors)\n" +
|
||||
"This program comes with ABSOLUTELY NO WARRANTY;\n" +
|
||||
"See COPYING file to see a copy of the General Public License\n \n");
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::SetUsageMessage(intro_help);
|
||||
google::SetVersionString(FRONT_END_CAL_VERSION);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
#else
|
||||
absl::FlagsUsageConfig empty_config;
|
||||
empty_config.version_string = &FrontEndCalVersionString;
|
||||
absl::SetFlagsUsageConfig(empty_config);
|
||||
absl::SetProgramUsageMessage(intro_help);
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
#endif
|
||||
std::cout << "Initializing... Please wait.\n";
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
std::cout << "front-end-cal program ended.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
if (FLAGS_log_dir.empty())
|
||||
#else
|
||||
absl::LogSink* fecLogSink = new FrontEndCalLogSink;
|
||||
absl::AddLogSink(fecLogSink);
|
||||
absl::InitializeLog();
|
||||
if (absl::GetFlag(FLAGS_log_dir).empty())
|
||||
#endif
|
||||
{
|
||||
std::cout << "Logging will be done at "
|
||||
<< "/tmp"
|
||||
<< '\n'
|
||||
<< "Use front-end-cal --log_dir=/path/to/log to change that."
|
||||
<< '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
const fs::path p(FLAGS_log_dir);
|
||||
#else
|
||||
const fs::path p(absl::GetFlag(FLAGS_log_dir));
|
||||
#endif
|
||||
if (!fs::exists(p))
|
||||
{
|
||||
std::cout << "The path "
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
<< FLAGS_log_dir
|
||||
#else
|
||||
<< absl::GetFlag(FLAGS_log_dir)
|
||||
#endif
|
||||
<< " does not exist, attempting to create it"
|
||||
<< '\n';
|
||||
errorlib::error_code ec;
|
||||
if (!fs::create_directory(p, ec))
|
||||
{
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
std::cerr << "Could not create the " << FLAGS_log_dir << " folder. Front-end-cal program ended.\n";
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#else
|
||||
std::cerr << "Could not create the " << absl::GetFlag(FLAGS_log_dir) << " folder. Front-end-cal program ended.\n";
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::cout << "Logging with be done at "
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
<< FLAGS_log_dir << '\n';
|
||||
#else
|
||||
<< absl::GetFlag(FLAGS_log_dir) << '\n';
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
std::cerr << "Could not create the " << FLAGS_log_dir << " folder. Front-end-cal program ended.\n";
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#else
|
||||
std::cerr << "Could not create the " << absl::GetFlag(FLAGS_log_dir) << " folder. Front-end-cal program ended.\n";
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 0. Instantiate the FrontEnd Calibration class
|
||||
try
|
||||
{
|
||||
FrontEndCal front_end_cal;
|
||||
|
||||
// 1. Load configuration parameters from config file
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
std::shared_ptr<ConfigurationInterface> configuration = std::make_shared<FileConfiguration>(FLAGS_config_file);
|
||||
#else
|
||||
std::shared_ptr<ConfigurationInterface> configuration = std::make_shared<FileConfiguration>(absl::GetFlag(FLAGS_config_file));
|
||||
#endif
|
||||
front_end_cal.set_configuration(configuration);
|
||||
|
||||
// 2. Get SUPL information from server: Ephemeris record, assistance info and TOW
|
||||
try
|
||||
{
|
||||
if (front_end_cal.get_ephemeris() == true)
|
||||
{
|
||||
std::cout << "SUPL data received OK!\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failure connecting to SUPL server\n";
|
||||
}
|
||||
}
|
||||
catch (const boost::exception& e)
|
||||
{
|
||||
std::cout << "Failure connecting to SUPL server\n";
|
||||
}
|
||||
|
||||
// 3. Capture some front-end samples to hard disk
|
||||
try
|
||||
{
|
||||
if (front_end_capture(configuration))
|
||||
{
|
||||
std::cout << "Front-end RAW samples captured\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failure capturing front-end samples\n";
|
||||
}
|
||||
}
|
||||
catch (const boost::bad_lexical_cast& e)
|
||||
{
|
||||
std::cout << "Exception caught while capturing samples (bad lexical cast)\n";
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << "Exception caught while capturing samples: " << e.what() << '\n';
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "Unexpected exception\n";
|
||||
}
|
||||
|
||||
// 4. Setup GNU Radio flowgraph (file_source -> Acquisition_10m)
|
||||
gr::top_block_sptr top_block;
|
||||
top_block = gr::make_top_block("Acquisition test");
|
||||
|
||||
// Satellite signal definition
|
||||
gnss_synchro = Gnss_Synchro();
|
||||
gnss_synchro.Channel_ID = 0;
|
||||
gnss_synchro.System = 'G';
|
||||
std::string signal = "1C";
|
||||
signal.copy(gnss_synchro.Signal, 2, 0);
|
||||
gnss_synchro.PRN = 1;
|
||||
|
||||
int64_t fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000);
|
||||
configuration->set_property("Acquisition.max_dwells", "10");
|
||||
|
||||
auto acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFineDoppler>(configuration.get(), "Acquisition", 1, 1);
|
||||
|
||||
acquisition->set_channel(1);
|
||||
acquisition->set_gnss_synchro(&gnss_synchro);
|
||||
acquisition->set_threshold(configuration->property("Acquisition.threshold", 2.0));
|
||||
acquisition->set_doppler_max(configuration->property("Acquisition.doppler_max", 10000));
|
||||
acquisition->set_doppler_step(configuration->property("Acquisition.doppler_step", 250));
|
||||
|
||||
gr::block_sptr source;
|
||||
source = gr::blocks::file_source::make(sizeof(gr_complex), "tmp_capture.dat");
|
||||
#if GNURADIO_USES_STD_POINTERS
|
||||
std::shared_ptr<FrontEndCal_msg_rx> msg_rx;
|
||||
#else
|
||||
boost::shared_ptr<FrontEndCal_msg_rx> msg_rx;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
msg_rx = FrontEndCal_msg_rx_make();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << "Failure connecting the message port system: " << e.what() << '\n';
|
||||
exit(0);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
acquisition->connect(top_block);
|
||||
top_block->connect(source, 0, acquisition->get_left_block(), 0);
|
||||
top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << "Failure connecting the GNU Radio blocks: " << e.what() << '\n';
|
||||
}
|
||||
|
||||
// 5. Run the flowgraph
|
||||
// Get visible GPS satellites (positive acquisitions with Doppler measurements)
|
||||
// Compute Doppler estimations
|
||||
|
||||
// todo: Fix the front-end cal to support new channel internal message system (no more external queues)
|
||||
std::map<int, double> doppler_measurements_map;
|
||||
std::map<int, double> cn0_measurements_map;
|
||||
|
||||
std::thread ch_thread;
|
||||
|
||||
// record startup time
|
||||
std::chrono::time_point<std::chrono::system_clock> start;
|
||||
std::chrono::time_point<std::chrono::system_clock> end;
|
||||
std::chrono::duration<double> elapsed_seconds{};
|
||||
start = std::chrono::system_clock::now();
|
||||
|
||||
bool start_msg = true;
|
||||
|
||||
for (unsigned int PRN = 1; PRN < 33; PRN++)
|
||||
{
|
||||
gnss_synchro.PRN = PRN;
|
||||
acquisition->set_gnss_synchro(&gnss_synchro);
|
||||
acquisition->init();
|
||||
acquisition->set_local_code();
|
||||
acquisition->reset();
|
||||
stop = false;
|
||||
try
|
||||
{
|
||||
ch_thread = std::thread(wait_message);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG(INFO) << "Exception caught (thread resource error)";
|
||||
}
|
||||
top_block->run();
|
||||
if (start_msg == true)
|
||||
{
|
||||
std::cout << "Searching for GPS Satellites in L1 band...\n";
|
||||
std::cout << "[";
|
||||
start_msg = false;
|
||||
}
|
||||
if (!gnss_sync_vector.empty())
|
||||
{
|
||||
std::cout << " " << PRN << " ";
|
||||
double doppler_measurement_hz = 0;
|
||||
for (auto& it : gnss_sync_vector)
|
||||
{
|
||||
doppler_measurement_hz += it.Acq_doppler_hz;
|
||||
}
|
||||
doppler_measurement_hz = doppler_measurement_hz / gnss_sync_vector.size();
|
||||
doppler_measurements_map.insert(std::pair<int, double>(PRN, doppler_measurement_hz));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " . ";
|
||||
}
|
||||
try
|
||||
{
|
||||
channel_internal_queue.push(3);
|
||||
}
|
||||
catch (const boost::exception& e)
|
||||
{
|
||||
LOG(INFO) << "Exception caught while pushing to the internal queue.";
|
||||
}
|
||||
try
|
||||
{
|
||||
ch_thread.join();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG(INFO) << "Exception caught while joining threads.";
|
||||
}
|
||||
gnss_sync_vector.clear();
|
||||
#if GNURADIO_USES_STD_POINTERS
|
||||
std::dynamic_pointer_cast<gr::blocks::file_source>(source)->seek(0, 0);
|
||||
#else
|
||||
boost::dynamic_pointer_cast<gr::blocks::file_source>(source)->seek(0, 0);
|
||||
#endif
|
||||
std::cout.flush();
|
||||
}
|
||||
std::cout << "]\n";
|
||||
|
||||
// report the elapsed time
|
||||
end = std::chrono::system_clock::now();
|
||||
elapsed_seconds = end - start;
|
||||
std::cout << "Total signal acquisition run time "
|
||||
<< elapsed_seconds.count()
|
||||
<< " [seconds]\n";
|
||||
|
||||
// 6. find TOW from SUPL assistance
|
||||
double current_TOW = 0;
|
||||
try
|
||||
{
|
||||
if (global_gps_ephemeris_map.size() > 0)
|
||||
{
|
||||
std::map<int, Gps_Ephemeris> Eph_map;
|
||||
Eph_map = global_gps_ephemeris_map.get_map_copy();
|
||||
current_TOW = Eph_map.begin()->second.tow;
|
||||
|
||||
time_t t = utc_time(Eph_map.begin()->second.WN, static_cast<int64_t>(current_TOW));
|
||||
|
||||
std::cout << "Reference Time:\n";
|
||||
std::cout << " GPS Week: " << Eph_map.begin()->second.WN << '\n';
|
||||
std::cout << " GPS TOW: " << static_cast<int64_t>(current_TOW) << " " << static_cast<int64_t>(current_TOW) * 0.08 << '\n';
|
||||
std::cout << " ~ UTC: " << ctime(&t) << '\n';
|
||||
std::cout << "Current TOW obtained from SUPL assistance = " << current_TOW << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unable to get Ephemeris SUPL assistance. TOW is unknown!\n";
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#endif
|
||||
std::cout << "GNSS-SDR Front-end calibration program ended.\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (const boost::exception& e)
|
||||
{
|
||||
std::cout << "Exception in getting Global ephemeris map\n";
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#endif
|
||||
std::cout << "GNSS-SDR Front-end calibration program ended.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get user position from config file (or from SUPL using GSM Cell ID)
|
||||
double lat_deg = configuration->property("GNSS-SDR.init_latitude_deg", 41.0);
|
||||
double lon_deg = configuration->property("GNSS-SDR.init_longitude_deg", 2.0);
|
||||
double altitude_m = configuration->property("GNSS-SDR.init_altitude_m", 100);
|
||||
|
||||
std::cout << "Reference location (defined in config file):\n";
|
||||
|
||||
std::cout << "Latitude=" << lat_deg << " [º]\n";
|
||||
std::cout << "Longitude=" << lon_deg << " [º]\n";
|
||||
std::cout << "Altitude=" << altitude_m << " [m]\n";
|
||||
|
||||
if (doppler_measurements_map.empty())
|
||||
{
|
||||
std::cout << "Sorry, no GPS satellites detected in the front-end capture, please check the antenna setup...\n";
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#endif
|
||||
std::cout << "GNSS-SDR Front-end calibration program ended.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::map<int, double> f_if_estimation_Hz_map;
|
||||
std::map<int, double> f_fs_estimation_Hz_map;
|
||||
std::map<int, double> f_ppm_estimation_Hz_map;
|
||||
|
||||
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2) << "Doppler analysis results:\n";
|
||||
|
||||
std::cout << "SV ID Measured [Hz] Predicted [Hz]\n";
|
||||
|
||||
for (auto& it : doppler_measurements_map)
|
||||
{
|
||||
try
|
||||
{
|
||||
double doppler_estimated_hz;
|
||||
doppler_estimated_hz = front_end_cal.estimate_doppler_from_eph(it.first, current_TOW, lat_deg, lon_deg, altitude_m);
|
||||
std::cout << " " << it.first << " " << it.second << " " << doppler_estimated_hz << '\n';
|
||||
// 7. Compute front-end IF and sampling frequency estimation
|
||||
// Compare with the measurements and compute clock drift using FE model
|
||||
double estimated_fs_Hz;
|
||||
double estimated_f_if_Hz;
|
||||
double f_osc_err_ppm;
|
||||
front_end_cal.GPS_L1_front_end_model_E4000(doppler_estimated_hz, it.second, fs_in_, &estimated_fs_Hz, &estimated_f_if_Hz, &f_osc_err_ppm);
|
||||
|
||||
f_if_estimation_Hz_map.insert(std::pair<int, double>(it.first, estimated_f_if_Hz));
|
||||
f_fs_estimation_Hz_map.insert(std::pair<int, double>(it.first, estimated_fs_Hz));
|
||||
f_ppm_estimation_Hz_map.insert(std::pair<int, double>(it.first, f_osc_err_ppm));
|
||||
}
|
||||
catch (const std::logic_error& e)
|
||||
{
|
||||
std::cout << "Logic error caught: " << e.what() << '\n';
|
||||
}
|
||||
catch (const boost::lock_error& e)
|
||||
{
|
||||
std::cout << "Exception caught while reading ephemeris\n";
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
std::cout << " " << it.first << " " << it.second << " (Eph not found)\n";
|
||||
}
|
||||
}
|
||||
|
||||
// FINAL FE estimations
|
||||
double mean_f_if_Hz = 0;
|
||||
double mean_fs_Hz = 0;
|
||||
double mean_osc_err_ppm = 0;
|
||||
int n_elements = f_if_estimation_Hz_map.size();
|
||||
|
||||
for (auto& it : f_if_estimation_Hz_map)
|
||||
{
|
||||
mean_f_if_Hz += it.second;
|
||||
const auto est_fs = f_fs_estimation_Hz_map.find(it.first);
|
||||
if (est_fs != f_fs_estimation_Hz_map.cend())
|
||||
{
|
||||
mean_fs_Hz += est_fs->second;
|
||||
}
|
||||
const auto est_ppm = f_ppm_estimation_Hz_map.find(it.first);
|
||||
if (est_ppm != f_ppm_estimation_Hz_map.cend())
|
||||
{
|
||||
mean_osc_err_ppm += est_ppm->second;
|
||||
}
|
||||
}
|
||||
|
||||
mean_f_if_Hz /= n_elements;
|
||||
mean_fs_Hz /= n_elements;
|
||||
mean_osc_err_ppm /= n_elements;
|
||||
|
||||
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2) << "Parameters estimation for Elonics E4000 Front-End:\n";
|
||||
|
||||
std::cout << "Sampling frequency =" << mean_fs_Hz << " [Hz]\n";
|
||||
std::cout << "IF bias present in baseband=" << mean_f_if_Hz << " [Hz]\n";
|
||||
std::cout << "Reference oscillator error =" << mean_osc_err_ppm << " [ppm]\n";
|
||||
|
||||
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2)
|
||||
<< "Corrected Doppler vs. Predicted\n";
|
||||
std::cout << "SV ID Corrected [Hz] Predicted [Hz]\n";
|
||||
|
||||
for (auto& it : doppler_measurements_map)
|
||||
{
|
||||
try
|
||||
{
|
||||
double doppler_estimated_hz;
|
||||
doppler_estimated_hz = front_end_cal.estimate_doppler_from_eph(it.first, current_TOW, lat_deg, lon_deg, altitude_m);
|
||||
std::cout << " " << it.first << " " << it.second - mean_f_if_Hz << " " << doppler_estimated_hz << '\n';
|
||||
}
|
||||
catch (const std::logic_error& e)
|
||||
{
|
||||
std::cout << "Logic error caught: " << e.what() << '\n';
|
||||
}
|
||||
catch (const boost::lock_error& e)
|
||||
{
|
||||
std::cout << "Exception caught while reading ephemeris\n";
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
std::cout << " " << it.first << " " << it.second - mean_f_if_Hz << " (Eph not found)\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Exception: " << e.what();
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unknown error\n";
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
#endif
|
||||
std::cout << "GNSS-SDR Front-end calibration program ended.\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user