2020-02-18 18:39:53 +00:00
|
|
|
/*!
|
|
|
|
* \file obsdiff.cc
|
2020-02-18 21:46:22 +00:00
|
|
|
* \brief This program implements a single difference and double difference
|
2020-02-18 18:39:53 +00:00
|
|
|
* comparison algorithm to evaluate receiver's performance at observable level
|
|
|
|
* \authors <ul>
|
|
|
|
* <li> Javier Arribas, 2020. jarribas(at)cttc.es
|
|
|
|
* </ul>
|
|
|
|
*
|
|
|
|
*
|
2020-07-28 14:57:15 +00:00
|
|
|
* -----------------------------------------------------------------------------
|
2020-02-18 18:39:53 +00:00
|
|
|
*
|
2020-12-30 12:35:06 +00:00
|
|
|
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
2020-02-18 18:39:53 +00:00
|
|
|
* This file is part of GNSS-SDR.
|
|
|
|
*
|
2020-12-30 12:35:06 +00:00
|
|
|
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
|
2020-02-18 18:39:53 +00:00
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
*
|
2020-07-28 14:57:15 +00:00
|
|
|
* -----------------------------------------------------------------------------
|
2020-02-18 18:39:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gnuplot_i.h"
|
|
|
|
#include "obsdiff_flags.h"
|
|
|
|
#include <armadillo>
|
2020-02-24 12:04:39 +00:00
|
|
|
// Classes for handling observations RINEX files (data)
|
2020-02-18 18:39:53 +00:00
|
|
|
#include <gpstk/Rinex3ObsData.hpp>
|
|
|
|
#include <gpstk/Rinex3ObsHeader.hpp>
|
|
|
|
#include <gpstk/Rinex3ObsStream.hpp>
|
2020-02-24 12:04:39 +00:00
|
|
|
|
|
|
|
// Classes for handling satellite navigation parameters RINEX
|
|
|
|
// files (ephemerides)
|
|
|
|
#include <gpstk/Rinex3NavData.hpp>
|
|
|
|
#include <gpstk/Rinex3NavHeader.hpp>
|
|
|
|
#include <gpstk/Rinex3NavStream.hpp>
|
|
|
|
|
|
|
|
// Classes for handling RINEX files with meteorological parameters
|
|
|
|
#include <gpstk/RinexMetBase.hpp>
|
|
|
|
#include <gpstk/RinexMetData.hpp>
|
|
|
|
#include <gpstk/RinexMetHeader.hpp>
|
|
|
|
#include <gpstk/RinexMetStream.hpp>
|
|
|
|
|
|
|
|
// Class for handling tropospheric model
|
|
|
|
#include <gpstk/GGTropModel.hpp>
|
|
|
|
|
|
|
|
// Class for storing >broadcast-type> ephemerides
|
|
|
|
#include <gpstk/GPSEphemerisStore.hpp>
|
|
|
|
|
|
|
|
// Class for handling RAIM
|
|
|
|
#include <gpstk/PRSolution.hpp>
|
|
|
|
|
|
|
|
// Class defining GPS system constants
|
|
|
|
#include <gpstk/GNSSconstants.hpp>
|
2020-02-18 18:39:53 +00:00
|
|
|
#include <matio.h>
|
2020-03-11 11:01:02 +00:00
|
|
|
#include <algorithm>
|
2020-02-18 18:39:53 +00:00
|
|
|
#include <array>
|
|
|
|
#include <fstream>
|
|
|
|
#include <map>
|
|
|
|
#include <set>
|
2020-02-19 07:29:36 +00:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-08-13 18:54:22 +00:00
|
|
|
#if GFLAGS_OLD_NAMESPACE
|
|
|
|
namespace gflags
|
|
|
|
{
|
|
|
|
using namespace google;
|
|
|
|
}
|
|
|
|
#endif
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
// Create the lists of GNSS satellites
|
|
|
|
std::set<int> available_gps_prn = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
|
|
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
|
|
|
29, 30, 31, 32};
|
|
|
|
|
|
|
|
std::set<int> available_sbas_prn = {123, 131, 135, 136, 138};
|
|
|
|
|
|
|
|
std::set<int> available_galileo_prn = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
|
|
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
|
|
|
29, 30, 31, 32, 33, 34, 35, 36};
|
|
|
|
|
|
|
|
|
|
|
|
bool file_exist(const char* fileName)
|
|
|
|
{
|
|
|
|
std::ifstream infile(fileName);
|
|
|
|
return infile.good();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
std::map<int, arma::mat> ReadRinexObs(const std::string& rinex_file, char system, const std::string& signal)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
std::map<int, arma::mat> obs_map;
|
|
|
|
if (not file_exist(rinex_file.c_str()))
|
|
|
|
{
|
|
|
|
std::cout << "Warning: RINEX Obs file " << rinex_file << " does not exist\n";
|
|
|
|
return obs_map;
|
|
|
|
}
|
2020-03-04 09:48:55 +00:00
|
|
|
// Open and read _baseerence RINEX observables file
|
2020-02-18 18:39:53 +00:00
|
|
|
try
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
gpstk::Rinex3ObsStream r_base(rinex_file);
|
2020-02-28 11:11:21 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
gpstk::Rinex3ObsData r_base_data;
|
|
|
|
gpstk::Rinex3ObsHeader r_base_header;
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
gpstk::RinexDatum dataobj;
|
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
r_base >> r_base_header;
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
std::set<int> PRN_set;
|
|
|
|
gpstk::SatID prn;
|
|
|
|
switch (system)
|
|
|
|
{
|
|
|
|
case 'G':
|
2020-12-02 13:27:59 +00:00
|
|
|
#if OLD_GPSTK
|
2020-02-18 18:39:53 +00:00
|
|
|
prn.system = gpstk::SatID::systemGPS;
|
2020-12-02 13:27:59 +00:00
|
|
|
#else
|
|
|
|
prn.system = gpstk::SatelliteSystem::GPS;
|
|
|
|
#endif
|
2020-02-18 18:39:53 +00:00
|
|
|
PRN_set = available_gps_prn;
|
|
|
|
break;
|
|
|
|
case 'E':
|
2020-12-02 13:27:59 +00:00
|
|
|
#if OLD_GPSTK
|
2020-02-18 18:39:53 +00:00
|
|
|
prn.system = gpstk::SatID::systemGalileo;
|
2020-12-02 13:27:59 +00:00
|
|
|
#else
|
|
|
|
prn.system = gpstk::SatelliteSystem::Galileo;
|
|
|
|
#endif
|
2020-02-18 18:39:53 +00:00
|
|
|
PRN_set = available_galileo_prn;
|
|
|
|
break;
|
|
|
|
default:
|
2020-12-02 13:27:59 +00:00
|
|
|
#if OLD_GPSTK
|
2020-02-18 18:39:53 +00:00
|
|
|
prn.system = gpstk::SatID::systemGPS;
|
2020-12-02 13:27:59 +00:00
|
|
|
#else
|
|
|
|
prn.system = gpstk::SatelliteSystem::GPS;
|
|
|
|
#endif
|
2020-02-18 18:39:53 +00:00
|
|
|
PRN_set = available_gps_prn;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "Reading RINEX OBS file " << rinex_file << " ...\n";
|
2020-03-04 09:48:55 +00:00
|
|
|
while (r_base >> r_base_data)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-12-30 20:49:29 +00:00
|
|
|
for (const auto& prn_it : PRN_set)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-02-25 07:25:19 +00:00
|
|
|
prn.id = prn_it;
|
2020-03-04 09:48:55 +00:00
|
|
|
gpstk::CommonTime time = r_base_data.time;
|
2020-02-18 18:39:53 +00:00
|
|
|
double sow(static_cast<gpstk::GPSWeekSecond>(time).sow);
|
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
auto pointer = r_base_data.obs.find(prn);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
if (pointer != r_base_data.obs.end())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// insert next column
|
|
|
|
try
|
|
|
|
{
|
|
|
|
obs_map.at(prn.id);
|
|
|
|
}
|
|
|
|
catch (const std::out_of_range& oor)
|
|
|
|
{
|
|
|
|
obs_map[prn.id] = arma::mat();
|
|
|
|
}
|
|
|
|
|
|
|
|
arma::mat& obs_mat = obs_map[prn.id];
|
|
|
|
obs_mat.insert_rows(obs_mat.n_rows, arma::zeros<arma::mat>(1, 4));
|
|
|
|
|
|
|
|
if (strcmp("1C\0", signal.c_str()) == 0)
|
|
|
|
{
|
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 0) = sow;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "C1C", r_base_header);
|
2020-02-24 14:06:48 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 1) = dataobj.data; // C1C P1 (psudorange L1)
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "D1C", r_base_header);
|
2020-02-24 14:06:48 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 2) = dataobj.data; // D1C Carrier Doppler
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "L1C", r_base_header);
|
2020-02-24 14:06:48 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 3) = dataobj.data; // L1C Carrier Phase
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
else if (strcmp("1B\0", signal.c_str()) == 0)
|
|
|
|
{
|
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 0) = sow;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "C1B", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 1) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "D1B", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 2) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "L1B", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 3) = dataobj.data;
|
|
|
|
}
|
2020-02-24 14:06:48 +00:00
|
|
|
else if (strcmp("2S\0", signal.c_str()) == 0) // L2M
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 0) = sow;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "C2S", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 1) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "D2S", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 2) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "L2S", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 3) = dataobj.data;
|
|
|
|
}
|
|
|
|
else if (strcmp("L5\0", signal.c_str()) == 0)
|
|
|
|
{
|
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 0) = sow;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "C5I", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 1) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "D5I", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 2) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "L5I", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 3) = dataobj.data;
|
|
|
|
}
|
|
|
|
else if (strcmp("5X\0", signal.c_str()) == 0) // Simulator gives RINEX with E5a+E5b. Doppler and accumulated Carrier phase WILL differ
|
|
|
|
{
|
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 0) = sow;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "C8I", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 1) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "D8I", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 2) = dataobj.data;
|
2020-03-04 09:48:55 +00:00
|
|
|
dataobj = r_base_data.getObs(prn, "L8I", r_base_header);
|
2020-02-18 18:39:53 +00:00
|
|
|
obs_mat.at(obs_mat.n_rows - 1, 3) = dataobj.data;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "ReadRinexObs unknown signal requested: " << signal << '\n';
|
2020-02-18 18:39:53 +00:00
|
|
|
return obs_map;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // end while
|
|
|
|
} // End of 'try' block
|
|
|
|
catch (const gpstk::FFStreamError& e)
|
|
|
|
{
|
|
|
|
std::cout << e;
|
|
|
|
return obs_map;
|
|
|
|
}
|
|
|
|
catch (const gpstk::Exception& e)
|
|
|
|
{
|
|
|
|
std::cout << e;
|
|
|
|
return obs_map;
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
std::cout << "Exception: " << e.what();
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "unknown error. I don't feel so well...\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
return obs_map;
|
|
|
|
}
|
2020-02-28 11:11:21 +00:00
|
|
|
if (obs_map.empty())
|
|
|
|
{
|
|
|
|
std::cout << "Warning: file "
|
|
|
|
<< rinex_file
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " contains no data.\n";
|
2020-02-28 11:11:21 +00:00
|
|
|
}
|
2020-02-18 18:39:53 +00:00
|
|
|
return obs_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool save_mat_xy(std::vector<double>& x, std::vector<double>& y, std::string filename)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// WRITE MAT FILE
|
|
|
|
mat_t* matfp;
|
|
|
|
matvar_t* matvar;
|
|
|
|
filename.append(".mat");
|
2020-07-07 16:53:50 +00:00
|
|
|
// std::cout << "save_mat_xy write " << filename << '\n';
|
2020-02-18 18:39:53 +00:00
|
|
|
matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT5);
|
|
|
|
if (reinterpret_cast<int64_t*>(matfp) != nullptr)
|
|
|
|
{
|
|
|
|
size_t dims[2] = {1, x.size()};
|
|
|
|
matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &x[0], 0);
|
|
|
|
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
|
|
|
|
Mat_VarFree(matvar);
|
|
|
|
|
|
|
|
matvar = Mat_VarCreate("y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &y[0], 0);
|
|
|
|
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
|
|
|
|
Mat_VarFree(matvar);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "save_mat_xy: error creating file\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
Mat_Close(matfp);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (const std::exception& ex)
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "save_mat_xy: " << ex.what() << '\n';
|
2020-02-18 18:39:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool save_mat_x(std::vector<double>* x, std::string filename)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// WRITE MAT FILE
|
|
|
|
mat_t* matfp;
|
|
|
|
matvar_t* matvar;
|
|
|
|
filename.append(".mat");
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "save_mat_x write " << filename << '\n';
|
2020-02-18 18:39:53 +00:00
|
|
|
matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT5);
|
|
|
|
if (reinterpret_cast<int64_t*>(matfp) != nullptr)
|
|
|
|
{
|
|
|
|
std::array<size_t, 2> dims{1, x->size()};
|
|
|
|
matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims.data(), &x[0], 0);
|
|
|
|
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
|
|
|
|
Mat_VarFree(matvar);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "save_mat_x: error creating file\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
Mat_Close(matfp);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (const std::exception& ex)
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "save_mat_x: " << ex.what() << '\n';
|
2020-02-18 18:39:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-24 12:04:39 +00:00
|
|
|
void carrier_phase_double_diff(
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::mat& true_ch0,
|
|
|
|
arma::mat& true_ch1,
|
|
|
|
arma::mat& measured_ch0,
|
|
|
|
arma::mat& measured_ch1,
|
2020-02-24 12:04:39 +00:00
|
|
|
const std::string& data_title, double common_rx_clock_error_s)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// 1. True value interpolation to match the measurement times
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
|
|
|
|
arma::vec true_ch0_carrier_phase_interp;
|
|
|
|
arma::vec true_ch1_carrier_phase_interp;
|
2020-02-24 14:06:48 +00:00
|
|
|
// interpolate measured observables accounting with the receiver clock differences
|
2020-02-24 12:04:39 +00:00
|
|
|
arma::interp1(true_ch0.col(0), true_ch0.col(3), measurement_time - common_rx_clock_error_s, true_ch0_carrier_phase_interp);
|
|
|
|
arma::interp1(true_ch1.col(0), true_ch1.col(3), measurement_time - common_rx_clock_error_s, true_ch1_carrier_phase_interp);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
arma::vec meas_ch1_carrier_phase_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(3), measurement_time, meas_ch1_carrier_phase_interp);
|
|
|
|
// generate double difference accumulated carrier phases
|
2020-02-25 15:56:16 +00:00
|
|
|
|
|
|
|
arma::vec delta_true_carrier_phase_cycles = true_ch0_carrier_phase_interp - true_ch1_carrier_phase_interp;
|
|
|
|
arma::vec delta_measured_carrier_phase_cycles = measured_ch0.col(3) - meas_ch1_carrier_phase_interp;
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_true_data = arma::find_nonfinite(delta_true_carrier_phase_cycles);
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(delta_measured_carrier_phase_cycles);
|
|
|
|
|
|
|
|
arma::mat tmp_mat = arma::conv_to<arma::mat>::from(delta_true_carrier_phase_cycles);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
delta_true_carrier_phase_cycles = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(delta_measured_carrier_phase_cycles);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
delta_measured_carrier_phase_cycles = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(measurement_time);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
measurement_time = tmp_mat.col(0);
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0), measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
if (!measurement_time.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// debug
|
|
|
|
// std::vector<double> tmp_time_vec(measurement_time.colptr(0),
|
|
|
|
// measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
// std::vector<double> tmp_vector_y6(delta_true_carrier_doppler_cycles.colptr(0),
|
|
|
|
// delta_true_carrier_doppler_cycles.colptr(0) + delta_true_carrier_doppler_cycles.n_rows);
|
|
|
|
// save_mat_xy(tmp_time_vec, tmp_vector_y6, std::string("true_delta_doppler"));
|
|
|
|
// std::vector<double> tmp_vector_y7(delta_measured_carrier_doppler_cycles.colptr(0),
|
|
|
|
// delta_measured_carrier_doppler_cycles.colptr(0) + delta_measured_carrier_doppler_cycles.n_rows);
|
|
|
|
// save_mat_xy(tmp_time_vec, tmp_vector_y7, std::string("measured_delta_doppler"));
|
|
|
|
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
err = delta_measured_carrier_phase_cycles - delta_true_carrier_phase_cycles;
|
2020-02-25 15:56:16 +00:00
|
|
|
|
|
|
|
// compute error without the accumulated carrier phase offsets (which depends on the receiver starting time)
|
|
|
|
err = err - arma::mean(err);
|
|
|
|
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << "Double diff Carrier Phase RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [Cycles]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
|
|
|
g3.set_title(data_title + "Double diff Carrier Phase error [Cycles]");
|
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
|
|
|
g3.set_ylabel("Double diff Carrier Phase error [Cycles]");
|
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
|
|
|
"Double diff Carrier Phase error");
|
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "double_diff_carrier_phase_error");
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "No valid data\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-24 12:04:39 +00:00
|
|
|
void carrier_phase_single_diff(
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::mat& measured_ch0,
|
|
|
|
arma::mat& measured_ch1,
|
|
|
|
const std::string& data_title)
|
|
|
|
{
|
|
|
|
// 1. True value interpolation to match the measurement times
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
|
|
|
|
arma::vec meas_ch1_carrier_phase_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(3), measurement_time, meas_ch1_carrier_phase_interp);
|
|
|
|
// generate single difference accumulated carrier phases
|
|
|
|
// compute error without the accumulated carrier phase offsets (which depends on the receiver starting time)
|
2020-02-25 15:56:16 +00:00
|
|
|
arma::vec delta_measured_carrier_phase_cycles = measured_ch0.col(3) - meas_ch1_carrier_phase_interp;
|
|
|
|
delta_measured_carrier_phase_cycles = delta_measured_carrier_phase_cycles - arma::mean(delta_measured_carrier_phase_cycles);
|
2020-02-18 18:39:53 +00:00
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(delta_measured_carrier_phase_cycles);
|
|
|
|
|
|
|
|
arma::mat tmp_mat = arma::conv_to<arma::mat>::from(delta_measured_carrier_phase_cycles);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
delta_measured_carrier_phase_cycles = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(measurement_time);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
measurement_time = tmp_mat.col(0);
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0), measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
if (!measurement_time.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
err = delta_measured_carrier_phase_cycles;
|
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << "Single diff Carrier Phase RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [Cycles]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
|
|
|
g3.set_title(data_title + "Single diff Carrier Phase error [Cycles]");
|
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
|
|
|
g3.set_ylabel("Single diff Carrier Phase error [Cycles]");
|
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
|
|
|
"Single diff Carrier Phase error");
|
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "single_diff_carrier_phase_error");
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "No valid data\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-24 12:04:39 +00:00
|
|
|
void carrier_doppler_double_diff(
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::mat& true_ch0,
|
|
|
|
arma::mat& true_ch1,
|
|
|
|
arma::mat& measured_ch0,
|
|
|
|
arma::mat& measured_ch1,
|
2020-02-24 12:04:39 +00:00
|
|
|
const std::string& data_title, double common_rx_clock_error_s)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// 1. True value interpolation to match the measurement times
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
|
|
|
|
arma::vec true_ch0_carrier_doppler_interp;
|
|
|
|
arma::vec true_ch1_carrier_doppler_interp;
|
2020-02-24 14:06:48 +00:00
|
|
|
// interpolate measured observables accounting with the receiver clock differences
|
2020-02-24 12:04:39 +00:00
|
|
|
arma::interp1(true_ch0.col(0), true_ch0.col(2), measurement_time - common_rx_clock_error_s, true_ch0_carrier_doppler_interp);
|
|
|
|
arma::interp1(true_ch1.col(0), true_ch1.col(2), measurement_time - common_rx_clock_error_s, true_ch1_carrier_doppler_interp);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
arma::vec meas_ch1_carrier_doppler_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(2), measurement_time, meas_ch1_carrier_doppler_interp);
|
|
|
|
// generate double difference carrier Doppler
|
|
|
|
arma::vec delta_true_carrier_doppler_cycles = true_ch0_carrier_doppler_interp - true_ch1_carrier_doppler_interp;
|
|
|
|
arma::vec delta_measured_carrier_doppler_cycles = measured_ch0.col(2) - meas_ch1_carrier_doppler_interp;
|
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_true_data = arma::find_nonfinite(delta_true_carrier_doppler_cycles);
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(delta_measured_carrier_doppler_cycles);
|
|
|
|
|
|
|
|
arma::mat tmp_mat = arma::conv_to<arma::mat>::from(delta_true_carrier_doppler_cycles);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
delta_true_carrier_doppler_cycles = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(delta_measured_carrier_doppler_cycles);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
delta_measured_carrier_doppler_cycles = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(measurement_time);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
measurement_time = tmp_mat.col(0);
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0), measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
if (!measurement_time.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// debug
|
|
|
|
// std::vector<double> tmp_time_vec(measurement_time.colptr(0),
|
|
|
|
// measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
// std::vector<double> tmp_vector_y6(delta_true_carrier_doppler_cycles.colptr(0),
|
|
|
|
// delta_true_carrier_doppler_cycles.colptr(0) + delta_true_carrier_doppler_cycles.n_rows);
|
|
|
|
// save_mat_xy(tmp_time_vec, tmp_vector_y6, std::string("true_delta_doppler"));
|
|
|
|
// std::vector<double> tmp_vector_y7(delta_measured_carrier_doppler_cycles.colptr(0),
|
|
|
|
// delta_measured_carrier_doppler_cycles.colptr(0) + delta_measured_carrier_doppler_cycles.n_rows);
|
|
|
|
// save_mat_xy(tmp_time_vec, tmp_vector_y7, std::string("measured_delta_doppler"));
|
|
|
|
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
err = delta_measured_carrier_doppler_cycles - delta_true_carrier_doppler_cycles;
|
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << "Double diff Carrier Doppler RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [Hz]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
|
|
|
g3.set_title(data_title + "Double diff Carrier Doppler error [Hz]");
|
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
|
|
|
g3.set_ylabel("Double diff Carrier Doppler error [Hz]");
|
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
|
|
|
"Double diff Carrier Doppler error");
|
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "double_diff_carrier_doppler_error");
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "No valid data\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-24 12:04:39 +00:00
|
|
|
void carrier_doppler_single_diff(
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::mat& measured_ch0,
|
|
|
|
arma::mat& measured_ch1,
|
|
|
|
const std::string& data_title)
|
|
|
|
{
|
|
|
|
// 1. True value interpolation to match the measurement times
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
|
|
|
|
arma::vec meas_ch1_carrier_doppler_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(2), measurement_time, meas_ch1_carrier_doppler_interp);
|
|
|
|
// generate single difference carrier Doppler
|
|
|
|
arma::vec delta_measured_carrier_doppler_cycles = measured_ch0.col(2) - meas_ch1_carrier_doppler_interp;
|
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(delta_measured_carrier_doppler_cycles);
|
|
|
|
|
|
|
|
arma::mat tmp_mat = arma::conv_to<arma::mat>::from(delta_measured_carrier_doppler_cycles);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
delta_measured_carrier_doppler_cycles = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(measurement_time);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
measurement_time = tmp_mat.col(0);
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0), measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
if (!measurement_time.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
err = delta_measured_carrier_doppler_cycles;
|
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << "Single diff Carrier Doppler RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [Hz]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
|
|
|
g3.set_title(data_title + "Single diff Carrier Doppler error [Hz]");
|
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
|
|
|
g3.set_ylabel("Single diff Carrier Doppler error [Hz]");
|
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
|
|
|
"Single diff Carrier Doppler error");
|
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "single_diff_carrier_doppler_error");
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "No valid data\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-24 12:04:39 +00:00
|
|
|
void code_pseudorange_double_diff(
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::mat& true_ch0,
|
|
|
|
arma::mat& true_ch1,
|
|
|
|
arma::mat& measured_ch0,
|
|
|
|
arma::mat& measured_ch1,
|
2020-02-24 12:04:39 +00:00
|
|
|
const std::string& data_title, double common_rx_clock_error_s)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// 1. True value interpolation to match the measurement times
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
arma::vec true_ch0_obs_interp;
|
|
|
|
arma::vec true_ch1_obs_interp;
|
2020-02-24 14:06:48 +00:00
|
|
|
// interpolate measured observables accounting with the receiver clock differences
|
2020-02-24 12:04:39 +00:00
|
|
|
arma::interp1(true_ch0.col(0), true_ch0.col(1), measurement_time - common_rx_clock_error_s, true_ch0_obs_interp);
|
|
|
|
arma::interp1(true_ch1.col(0), true_ch1.col(1), measurement_time - common_rx_clock_error_s, true_ch1_obs_interp);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
arma::vec meas_ch1_obs_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(1), measurement_time, meas_ch1_obs_interp);
|
|
|
|
// generate double difference carrier Doppler
|
|
|
|
arma::vec delta_true_obs = true_ch0_obs_interp - true_ch1_obs_interp;
|
|
|
|
arma::vec delta_measured_obs = measured_ch0.col(1) - meas_ch1_obs_interp;
|
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_true_data = arma::find_nonfinite(delta_true_obs);
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(delta_measured_obs);
|
|
|
|
|
|
|
|
arma::mat tmp_mat = arma::conv_to<arma::mat>::from(delta_true_obs);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
delta_true_obs = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(delta_measured_obs);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
delta_measured_obs = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(measurement_time);
|
|
|
|
tmp_mat.shed_rows(arma::join_cols(NaN_in_true_data, NaN_in_measured_data));
|
|
|
|
measurement_time = tmp_mat.col(0);
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0), measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
if (!measurement_time.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// debug
|
|
|
|
// std::vector<double> tmp_time_vec(measurement_time.colptr(0),
|
|
|
|
// measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
// std::vector<double> tmp_vector_y6(delta_true_carrier_doppler_cycles.colptr(0),
|
|
|
|
// delta_true_carrier_doppler_cycles.colptr(0) + delta_true_carrier_doppler_cycles.n_rows);
|
|
|
|
// save_mat_xy(tmp_time_vec, tmp_vector_y6, std::string("true_delta_doppler"));
|
|
|
|
// std::vector<double> tmp_vector_y7(delta_measured_carrier_doppler_cycles.colptr(0),
|
|
|
|
// delta_measured_carrier_doppler_cycles.colptr(0) + delta_measured_carrier_doppler_cycles.n_rows);
|
|
|
|
// save_mat_xy(tmp_time_vec, tmp_vector_y7, std::string("measured_delta_doppler"));
|
|
|
|
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
|
|
|
|
err = delta_measured_obs - delta_true_obs;
|
|
|
|
|
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << "Double diff Pseudorange RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [meters]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
|
|
|
g3.set_title(data_title + "Double diff Pseudorange error [m]");
|
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
|
|
|
g3.set_ylabel("Double diff Pseudorange error [m]");
|
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
2020-03-11 11:01:02 +00:00
|
|
|
"Double diff Pseudorange error");
|
2020-02-18 18:39:53 +00:00
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "double_diff_pseudorange_error");
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "No valid data\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-24 12:04:39 +00:00
|
|
|
void code_pseudorange_single_diff(
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::mat& measured_ch0,
|
|
|
|
arma::mat& measured_ch1,
|
|
|
|
const std::string& data_title)
|
|
|
|
{
|
|
|
|
// 1. True value interpolation to match the measurement times
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
|
|
|
|
arma::vec meas_ch1_obs_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(1), measurement_time, meas_ch1_obs_interp);
|
|
|
|
// generate single difference carrier Doppler
|
|
|
|
arma::vec delta_measured_obs = measured_ch0.col(1) - meas_ch1_obs_interp;
|
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(delta_measured_obs);
|
|
|
|
|
|
|
|
arma::mat tmp_mat = arma::conv_to<arma::mat>::from(delta_measured_obs);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
delta_measured_obs = tmp_mat.col(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(measurement_time);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
measurement_time = tmp_mat.col(0);
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0), measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
if (!measurement_time.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
|
|
|
|
err = delta_measured_obs;
|
|
|
|
|
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << "Single diff Pseudorange RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [meters]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
|
|
|
g3.set_title(data_title + "Single diff Pseudorange error [m]");
|
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
|
|
|
g3.set_ylabel("Single diff Pseudorange error [m]");
|
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
2020-03-11 11:01:02 +00:00
|
|
|
"Single diff Pseudorange error");
|
2020-02-18 18:39:53 +00:00
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "single_diff_pseudorange_error");
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "No valid data\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-25 15:56:16 +00:00
|
|
|
void coderate_phaserate_consistence(
|
|
|
|
arma::mat& measured_ch0,
|
|
|
|
const std::string& data_title)
|
|
|
|
{
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
arma::vec delta_time = measurement_time.subvec(1, measurement_time.n_elem - 1) - measurement_time.subvec(0, measurement_time.n_elem - 2);
|
2020-03-04 09:48:55 +00:00
|
|
|
|
2020-02-25 17:27:04 +00:00
|
|
|
// Test 4 is for the pseudorange phase consistency
|
2020-02-25 15:56:16 +00:00
|
|
|
//
|
2020-02-25 17:27:04 +00:00
|
|
|
// 1) Checks for the value of the pseudoranges to be within a certain threshold.
|
2020-02-25 15:56:16 +00:00
|
|
|
arma::vec prange = measured_ch0.col(1);
|
2020-03-04 09:48:55 +00:00
|
|
|
|
2020-02-25 17:27:04 +00:00
|
|
|
// todo: This code is only valid for L1/E1 carrier frequency.
|
2020-02-25 15:56:16 +00:00
|
|
|
arma::vec phase = measured_ch0.col(3) * (gpstk::C_MPS / gpstk::L1_FREQ_GPS);
|
|
|
|
|
|
|
|
double mincodeval = 5000000.0;
|
|
|
|
double maxcodeval = 40000000.0;
|
|
|
|
arma::uvec idx = arma::find(prange < mincodeval);
|
|
|
|
if (idx.n_elem > 0)
|
|
|
|
{
|
|
|
|
std::cout << "Warning: Pseudorange measurement is less than minimum acceptable value of " << mincodeval << " meters.\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
idx = arma::find(prange > maxcodeval);
|
|
|
|
if (idx.n_elem > 0)
|
|
|
|
{
|
|
|
|
std::cout << "Warning: Pseudorange measurement is above than maximum acceptable value of " << maxcodeval << " meters.\n";
|
|
|
|
}
|
|
|
|
|
2020-02-25 17:27:04 +00:00
|
|
|
// 2) It checks that the pseduorange rate is within a certain threshold
|
|
|
|
// check code rate
|
2020-03-04 09:48:55 +00:00
|
|
|
arma::vec coderate = (prange.subvec(1, prange.n_elem - 1) - prange.subvec(0, prange.n_elem - 2)) / delta_time;
|
2020-02-25 15:56:16 +00:00
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(coderate);
|
|
|
|
|
|
|
|
if (NaN_in_measured_data.n_elem > 0)
|
|
|
|
{
|
|
|
|
std::cout << "Warning: Pseudorange rate have NaN values. \n";
|
|
|
|
}
|
|
|
|
|
|
|
|
double mincoderate = 0.001;
|
|
|
|
double maxcoderate = 5000.0;
|
|
|
|
|
|
|
|
idx = arma::find(coderate > maxcoderate and coderate < mincoderate);
|
|
|
|
if (idx.n_elem > 0)
|
|
|
|
{
|
2020-02-28 11:11:21 +00:00
|
|
|
std::cout << "Warning: bad code rate \n";
|
2020-02-25 15:56:16 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 17:27:04 +00:00
|
|
|
// 3) It checks that the phase rate is within a certain threshold
|
2020-03-04 09:48:55 +00:00
|
|
|
arma::vec phaserate = (phase.subvec(1, prange.n_elem - 1) - phase.subvec(0, prange.n_elem - 2)) / delta_time;
|
2020-02-25 15:56:16 +00:00
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
NaN_in_measured_data = arma::find_nonfinite(phase);
|
|
|
|
|
|
|
|
if (NaN_in_measured_data.n_elem > 0)
|
|
|
|
{
|
|
|
|
std::cout << "Warning: Carrier phase rate have NaN values. \n";
|
|
|
|
}
|
|
|
|
|
|
|
|
double minphaserate = 0.001;
|
|
|
|
double maxphaserate = 5000.0;
|
|
|
|
|
|
|
|
idx = arma::find(phaserate > maxphaserate and phaserate < minphaserate);
|
|
|
|
if (idx.n_elem > 0)
|
|
|
|
{
|
2020-02-28 11:11:21 +00:00
|
|
|
std::cout << "Warning: bad phase rate \n";
|
2020-02-25 15:56:16 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 17:27:04 +00:00
|
|
|
// 4) It checks the difference between code and phase rates
|
|
|
|
// check difference between code and phase rates
|
2020-02-25 15:56:16 +00:00
|
|
|
arma::vec ratediff = phaserate - coderate;
|
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
// debug
|
|
|
|
std::vector<double> tmp_time_vec(measurement_time.colptr(0),
|
|
|
|
measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
std::vector<double> tmp_vector_y6(phaserate.colptr(0),
|
|
|
|
phaserate.colptr(0) + phaserate.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector_y6, std::string("phaserate_" + data_title));
|
|
|
|
std::vector<double> tmp_vector_y7(coderate.colptr(0),
|
|
|
|
coderate.colptr(0) + coderate.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector_y7, std::string("coderate_" + data_title));
|
|
|
|
|
2020-02-25 15:56:16 +00:00
|
|
|
double maxratediff = 5;
|
2020-02-28 11:11:21 +00:00
|
|
|
idx = arma::find(ratediff > maxratediff);
|
2020-02-25 15:56:16 +00:00
|
|
|
if (idx.n_elem > 0)
|
|
|
|
{
|
2020-02-28 11:11:21 +00:00
|
|
|
std::cout << "Warning: bad code and phase rate difference \n";
|
2020-02-25 15:56:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0) + 1, measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
err = ratediff;
|
|
|
|
|
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << " RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [m/s]\n";
|
2020-02-25 15:56:16 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
2020-02-28 11:11:21 +00:00
|
|
|
g3.set_title(data_title + "Code rate - phase rate [m/s]");
|
2020-02-25 15:56:16 +00:00
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
2020-02-28 11:11:21 +00:00
|
|
|
g3.set_ylabel("Code rate - phase rate [m/s]");
|
2020-02-25 15:56:16 +00:00
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
|
|
|
"Code rate - phase rate");
|
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "Code_rate_minus_phase_rate");
|
2020-02-25 15:56:16 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void code_phase_diff(
|
|
|
|
arma::mat& measured_ch0,
|
|
|
|
arma::mat& measured_ch1,
|
|
|
|
const std::string& data_title)
|
|
|
|
{
|
|
|
|
// 1. True value interpolation to match the measurement times
|
|
|
|
arma::vec measurement_time = measured_ch0.col(0);
|
|
|
|
|
|
|
|
arma::vec code_range_ch1_obs_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(1), measurement_time, code_range_ch1_obs_interp);
|
|
|
|
arma::vec carrier_phase_ch1_obs_interp;
|
|
|
|
arma::interp1(measured_ch1.col(0), measured_ch1.col(3), measurement_time, carrier_phase_ch1_obs_interp);
|
|
|
|
|
|
|
|
// generate Code - Phase vector
|
|
|
|
arma::vec code_minus_phase = (measured_ch0.col(1) - code_range_ch1_obs_interp) - (measured_ch0.col(3) - carrier_phase_ch1_obs_interp) * (gpstk::C_MPS / gpstk::L1_FREQ_GPS);
|
|
|
|
|
|
|
|
// remove NaN
|
|
|
|
arma::uvec NaN_in_measured_data = arma::find_nonfinite(code_minus_phase);
|
|
|
|
|
|
|
|
arma::mat tmp_mat = arma::conv_to<arma::mat>::from(code_minus_phase);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
code_minus_phase = tmp_mat.col(0);
|
|
|
|
|
|
|
|
code_minus_phase = code_minus_phase - code_minus_phase(0);
|
|
|
|
|
|
|
|
tmp_mat = arma::conv_to<arma::mat>::from(measurement_time);
|
|
|
|
tmp_mat.shed_rows(NaN_in_measured_data);
|
|
|
|
measurement_time = tmp_mat.col(0);
|
|
|
|
|
|
|
|
std::vector<double>
|
|
|
|
time_vector(measurement_time.colptr(0), measurement_time.colptr(0) + measurement_time.n_rows);
|
|
|
|
|
2020-02-25 17:31:44 +00:00
|
|
|
if (!measurement_time.empty())
|
2020-02-25 15:56:16 +00:00
|
|
|
{
|
|
|
|
// 2. RMSE
|
|
|
|
arma::vec err;
|
|
|
|
err = code_minus_phase;
|
|
|
|
|
|
|
|
arma::vec err2 = arma::square(err);
|
|
|
|
double rmse = sqrt(arma::mean(err2));
|
|
|
|
|
|
|
|
// 3. Mean err and variance
|
|
|
|
double error_mean = arma::mean(err);
|
|
|
|
double error_var = arma::var(err);
|
|
|
|
|
|
|
|
// 4. Peaks
|
|
|
|
double max_error = arma::max(err);
|
|
|
|
double min_error = arma::min(err);
|
|
|
|
|
|
|
|
// 5. report
|
|
|
|
std::streamsize ss = std::cout.precision();
|
|
|
|
std::cout << std::setprecision(10) << data_title << " RMSE = "
|
|
|
|
<< rmse << ", mean = " << error_mean
|
|
|
|
<< ", stdev = " << sqrt(error_var)
|
|
|
|
<< " (max,min) = " << max_error
|
|
|
|
<< "," << min_error
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " [meters]\n";
|
2020-02-25 15:56:16 +00:00
|
|
|
std::cout.precision(ss);
|
|
|
|
|
|
|
|
// plots
|
|
|
|
if (FLAGS_show_plots)
|
|
|
|
{
|
|
|
|
Gnuplot g3("linespoints");
|
|
|
|
g3.set_title(data_title + "Code range - Carrier phase range [m]");
|
|
|
|
g3.set_grid();
|
|
|
|
g3.set_xlabel("Time [s]");
|
|
|
|
g3.set_ylabel("Code range - Carrier phase range [m]");
|
|
|
|
// conversion between arma::vec and std:vector
|
|
|
|
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
|
|
|
|
g3.cmd("set key box opaque");
|
|
|
|
g3.plot_xy(time_vector, range_error_m,
|
|
|
|
"Code range - Carrier phase range");
|
|
|
|
g3.set_legend();
|
2020-03-11 11:01:02 +00:00
|
|
|
std::string data_title_aux = data_title;
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ' ', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), '(', '_');
|
|
|
|
std::replace(data_title_aux.begin(), data_title_aux.end(), ')', '_');
|
|
|
|
g3.savetops(data_title_aux + "Code_range_Carrier_phase_range");
|
2020-02-25 15:56:16 +00:00
|
|
|
|
|
|
|
g3.showonscreen(); // window output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "No valid data\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-25 07:25:19 +00:00
|
|
|
double compute_rx_clock_error(const std::string& rinex_nav_filename, const std::string& rinex_obs_file)
|
2020-02-24 12:04:39 +00:00
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Computing receiver's clock error...\n";
|
2020-02-24 12:04:39 +00:00
|
|
|
if (not file_exist(rinex_nav_filename.c_str()))
|
|
|
|
{
|
|
|
|
std::cout << "Warning: RINEX Nav file " << rinex_nav_filename << " does not exist, receiver's clock error could not be computed!\n";
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
// Declaration of objects for storing ephemerides and handling RAIM
|
|
|
|
gpstk::GPSEphemerisStore bcestore;
|
|
|
|
gpstk::PRSolution raimSolver;
|
|
|
|
|
|
|
|
// Object for void-type tropospheric model (in case no meteorological
|
|
|
|
// RINEX is available)
|
|
|
|
gpstk::ZeroTropModel noTropModel;
|
|
|
|
|
|
|
|
// Object for GG-type tropospheric model (Goad and Goodman, 1974)
|
|
|
|
// Default constructor => default values for model
|
|
|
|
gpstk::GGTropModel ggTropModel;
|
|
|
|
|
|
|
|
// Pointer to one of the two available tropospheric models. It points
|
|
|
|
// to the void model by default
|
|
|
|
gpstk::TropModel* tropModelPtr = &noTropModel;
|
|
|
|
|
|
|
|
double rx_clock_error_s = 0.0;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Read nav file and store unique list of ephemerides
|
|
|
|
gpstk::Rinex3NavStream rnffs(rinex_nav_filename.c_str()); // Open ephemerides data file
|
|
|
|
gpstk::Rinex3NavData rne;
|
|
|
|
gpstk::Rinex3NavHeader hdr;
|
|
|
|
|
|
|
|
// Let's read the header (may be skipped)
|
|
|
|
rnffs >> hdr;
|
|
|
|
|
|
|
|
// Storing the ephemeris in "bcstore"
|
2020-02-25 07:25:19 +00:00
|
|
|
while (rnffs >> rne)
|
|
|
|
{
|
|
|
|
bcestore.addEphemeris(rne);
|
|
|
|
}
|
2020-02-24 12:04:39 +00:00
|
|
|
|
|
|
|
// Setting the criteria for looking up ephemeris
|
|
|
|
bcestore.SearchNear();
|
|
|
|
|
|
|
|
// Open and read the observation file one epoch at a time.
|
|
|
|
// For each epoch, compute and print a position solution
|
|
|
|
gpstk::Rinex3ObsStream roffs(rinex_obs_file.c_str()); // Open observations data file
|
|
|
|
|
|
|
|
gpstk::Rinex3ObsHeader roh;
|
|
|
|
gpstk::Rinex3ObsData rod;
|
|
|
|
|
|
|
|
// Let's read the header
|
|
|
|
roffs >> roh;
|
|
|
|
|
|
|
|
int indexC1;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
indexC1 = roh.getObsIndex("C1");
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cerr << "The observation file doesn't have C1 pseudoranges, RX clock error could not be computed!\n";
|
2020-02-24 12:04:39 +00:00
|
|
|
return (0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let's process all lines of observation data, one by one
|
|
|
|
while (roffs >> rod)
|
|
|
|
{
|
|
|
|
// Apply editing criteria
|
|
|
|
if (rod.epochFlag == 0 || rod.epochFlag == 1) // Begin usable data
|
|
|
|
{
|
|
|
|
std::vector<gpstk::SatID> prnVec;
|
|
|
|
std::vector<double> rangeVec;
|
|
|
|
|
|
|
|
// Define the "it" iterator to visit the observations PRN map.
|
|
|
|
// Rinex3ObsData::DataMap is a map from RinexSatID to
|
|
|
|
// vector<RinexDatum>:
|
|
|
|
// std::map<RinexSatID, vector<RinexDatum> >
|
|
|
|
gpstk::Rinex3ObsData::DataMap::const_iterator it;
|
|
|
|
|
|
|
|
// This part gets the PRN numbers and ionosphere-corrected
|
|
|
|
// pseudoranges for the current epoch. They are correspondly fed
|
|
|
|
// into "prnVec" and "rangeVec"; "obs" is a public attribute of
|
|
|
|
// Rinex3ObsData to get the map of observations
|
|
|
|
for (it = rod.obs.begin(); it != rod.obs.end(); it++)
|
|
|
|
{
|
|
|
|
// The RINEX file may have P1 observations, but the current
|
|
|
|
// satellite may not have them.
|
|
|
|
double C1(0.0);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
C1 = rod.getObs((*it).first, indexC1).data;
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
// Ignore this satellite if P1 is not found
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Now, we include the current PRN number in the first part
|
|
|
|
// of "it" iterator into the vector holding the satellites.
|
|
|
|
// All satellites in view at this epoch that have P1 or P1+P2
|
|
|
|
// observations will be included.
|
|
|
|
prnVec.push_back((*it).first);
|
|
|
|
|
|
|
|
// The same is done for the vector of doubles holding the
|
|
|
|
// corrected ranges
|
|
|
|
rangeVec.push_back(C1);
|
|
|
|
|
|
|
|
// WARNING: Please note that so far no further correction
|
|
|
|
// is done on data: Relativistic effects, tropospheric
|
|
|
|
// correction, instrumental delays, etc.
|
|
|
|
} // End of 'for( it = rod.obs.begin(); it!= rod.obs.end(); ...'
|
|
|
|
|
|
|
|
// The default constructor for PRSolution2 objects (like
|
|
|
|
// "raimSolver") is to set a RMSLimit of 6.5. We change that
|
|
|
|
// here. With this value of 3e6 the solution will have a lot
|
|
|
|
// more dispersion.
|
|
|
|
raimSolver.RMSLimit = 3e6;
|
|
|
|
|
|
|
|
// In order to compute positions we need the current time, the
|
|
|
|
// vector of visible satellites, the vector of corresponding
|
|
|
|
// ranges, the object containing satellite ephemerides, and a
|
|
|
|
// pointer to the tropospheric model to be applied
|
|
|
|
try
|
|
|
|
{
|
2020-12-02 13:27:59 +00:00
|
|
|
#if OLD_GPSTK
|
2020-02-24 12:04:39 +00:00
|
|
|
std::vector<gpstk::SatID::SatelliteSystem> Syss;
|
2020-12-02 13:27:59 +00:00
|
|
|
#endif
|
2020-02-24 12:04:39 +00:00
|
|
|
gpstk::Matrix<double> invMC;
|
|
|
|
int iret;
|
2020-12-02 13:27:59 +00:00
|
|
|
// Call RAIMCompute
|
|
|
|
#if OLD_GPSTK
|
2020-02-24 12:04:39 +00:00
|
|
|
iret = raimSolver.RAIMCompute(rod.time, prnVec, Syss, rangeVec, invMC,
|
|
|
|
&bcestore, tropModelPtr);
|
2020-12-02 13:27:59 +00:00
|
|
|
#else
|
|
|
|
iret = raimSolver.RAIMCompute(rod.time, prnVec, rangeVec, invMC,
|
|
|
|
&bcestore, tropModelPtr);
|
|
|
|
#endif
|
2020-02-24 12:04:39 +00:00
|
|
|
switch (iret)
|
|
|
|
{
|
|
|
|
/// @return Return values:
|
|
|
|
/// 1 solution is ok, but may be degraded; check TropFlag,
|
|
|
|
/// RMSFlag, SlopeFlag 0 ok
|
|
|
|
case -1:
|
|
|
|
|
|
|
|
std::cout << " algorithm failed to converge at time: " << rod.time
|
|
|
|
<< " \n";
|
|
|
|
break;
|
|
|
|
case -2:
|
|
|
|
std::cout
|
|
|
|
<< " singular problem, no solution is possible at time: "
|
|
|
|
<< rod.time << " \n";
|
|
|
|
break;
|
|
|
|
case -3:
|
|
|
|
std::cout << " not enough good data (> 4) to form a (RAIM) "
|
|
|
|
"solution at time: "
|
|
|
|
<< rod.time << " \n";
|
|
|
|
break;
|
|
|
|
case -4:
|
|
|
|
std::cout
|
|
|
|
<< "ephemeris not found for all the satellites at time: "
|
|
|
|
<< rod.time << " \n";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// return iret;
|
|
|
|
}
|
2020-02-28 11:11:21 +00:00
|
|
|
catch (const gpstk::Exception& e)
|
2020-02-24 12:04:39 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we got a valid solution, let's print it
|
|
|
|
if (raimSolver.isValid())
|
|
|
|
{
|
|
|
|
std::cout << "RX POS ECEF [XYZ] " << std::fixed << std::setprecision(3) << " "
|
|
|
|
<< std::setw(12) << raimSolver.Solution(0) << " "
|
|
|
|
<< std::setw(12) << raimSolver.Solution(1) << " "
|
|
|
|
<< std::setw(12) << raimSolver.Solution(2) << "\n";
|
|
|
|
|
|
|
|
std::cout << "RX CLK " << std::fixed << std::setprecision(16)
|
|
|
|
<< raimSolver.Solution(3) / gpstk::C_MPS << " [s] \n";
|
|
|
|
|
|
|
|
std::cout << "NSATS, DOPs " << std::setw(2) << raimSolver.Nsvs << std::fixed
|
|
|
|
<< std::setprecision(2) << " "
|
|
|
|
<< std::setw(4) << raimSolver.PDOP << " " << std::setw(4) << raimSolver.GDOP
|
|
|
|
<< " " << std::setw(8) << raimSolver.RMSResidual << "\n";
|
|
|
|
gpstk::Position rx_pos;
|
|
|
|
rx_pos.setECEF(gpstk::Triple(raimSolver.Solution(0), raimSolver.Solution(1), raimSolver.Solution(2)));
|
|
|
|
|
|
|
|
double lat_deg = rx_pos.geodeticLatitude();
|
|
|
|
double lon_deg = rx_pos.longitude();
|
|
|
|
double Alt_m = rx_pos.getAltitude();
|
|
|
|
std::cout << "RX POS GEO [Lat,Long,H]" << std::fixed << std::setprecision(10) << " "
|
|
|
|
<< std::setw(12) << lat_deg << ","
|
|
|
|
<< std::setw(12) << lon_deg << ","
|
|
|
|
<< std::setw(12) << Alt_m << " [deg],[deg],[m]\n";
|
|
|
|
|
2020-02-24 14:06:48 +00:00
|
|
|
// set computed RX clock error and stop iterating obs epochs
|
2020-02-24 12:04:39 +00:00
|
|
|
rx_clock_error_s = raimSolver.Solution(3) / gpstk::C_MPS;
|
|
|
|
break;
|
|
|
|
} // End of 'if( raimSolver.isValid() )'
|
2020-02-24 14:06:48 +00:00
|
|
|
} // End of 'if( rod.epochFlag == 0 || rod.epochFlag == 1 )'
|
|
|
|
} // End of 'while( roffs >> rod )'
|
2020-02-24 12:04:39 +00:00
|
|
|
}
|
2020-02-28 11:11:21 +00:00
|
|
|
catch (const gpstk::FFStreamError& e)
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "GPSTK exception: " << e << '\n';
|
2020-02-28 11:11:21 +00:00
|
|
|
}
|
|
|
|
catch (const gpstk::Exception& e)
|
2020-02-24 12:04:39 +00:00
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "GPSTK exception: " << e << '\n';
|
2020-02-24 12:04:39 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Caught an unexpected exception.\n";
|
2020-02-24 12:04:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rx_clock_error_s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-18 18:39:53 +00:00
|
|
|
void RINEX_doublediff_dupli_sat()
|
|
|
|
{
|
|
|
|
// special test mode for duplicated satellites
|
|
|
|
// read rinex receiver-under-test observations
|
2020-03-04 09:48:55 +00:00
|
|
|
std::map<int, arma::mat> rover_obs = ReadRinexObs(FLAGS_rover_rinex_obs, 'G', std::string("1C"));
|
|
|
|
if (rover_obs.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Cut measurement initial transitory of the measurements
|
|
|
|
double initial_transitory_s = FLAGS_skip_obs_transitory_s;
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Skipping initial transitory of " << initial_transitory_s << " [s]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::uvec index;
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(rover_ob.second.col(0) >= (rover_ob.second.col(0)(0) + initial_transitory_s), 1, "first");
|
2020-02-18 18:39:53 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
rover_ob.second.shed_rows(0, index(0));
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<unsigned int> prn_pairs;
|
|
|
|
std::stringstream ss(FLAGS_dupli_sat_prns);
|
|
|
|
unsigned int i;
|
|
|
|
while (ss >> i)
|
|
|
|
{
|
|
|
|
prn_pairs.push_back(i);
|
|
|
|
if (ss.peek() == ',')
|
|
|
|
{
|
|
|
|
ss.ignore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prn_pairs.size() % 2 != 0)
|
|
|
|
{
|
|
|
|
std::cout << "Test settings error: duplicated_satellites_prns are even\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (unsigned int n = 0; n < prn_pairs.size(); n = n + 2)
|
|
|
|
{
|
|
|
|
// compute double differences
|
2020-03-04 09:48:55 +00:00
|
|
|
if (rover_obs.find(prn_pairs.at(n)) != rover_obs.end() and rover_obs.find(prn_pairs.at(n + 1)) != rover_obs.end())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Computing single difference observables for duplicated SV pairs...\n";
|
|
|
|
std::cout << "SD = OBS_ROVER(SV" << prn_pairs.at(n) << ") - OBS_ROVER(SV" << prn_pairs.at(n + 1) << ")\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
code_pseudorange_single_diff(rover_obs.at(prn_pairs.at(n)),
|
|
|
|
rover_obs.at(prn_pairs.at(n + 1)),
|
2020-02-18 18:39:53 +00:00
|
|
|
"SD = OBS(SV" + std::to_string(prn_pairs.at(n)) + ") - OBS(SV" + std::to_string(prn_pairs.at(n + 1)) + ") ");
|
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
carrier_phase_single_diff(rover_obs.at(prn_pairs.at(n)),
|
|
|
|
rover_obs.at(prn_pairs.at(n + 1)),
|
2020-02-18 18:39:53 +00:00
|
|
|
"SD = OBS(SV" + std::to_string(prn_pairs.at(n)) + ") - OBS(SV" + std::to_string(prn_pairs.at(n + 1)) + ") ");
|
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
carrier_doppler_single_diff(rover_obs.at(prn_pairs.at(n)),
|
|
|
|
rover_obs.at(prn_pairs.at(n + 1)),
|
2020-02-18 18:39:53 +00:00
|
|
|
"SD = OBS(SV" + std::to_string(prn_pairs.at(n)) + ") - OBS(SV" + std::to_string(prn_pairs.at(n + 1)) + ") ");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "Satellite ID " << prn_pairs.at(n) << " and/or " << prn_pairs.at(n + 1) << " not found in RINEX file\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-24 12:04:39 +00:00
|
|
|
void RINEX_doublediff(bool remove_rx_clock_error)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
// read rinex base observations
|
|
|
|
std::map<int, arma::mat> base_obs = ReadRinexObs(FLAGS_base_rinex_obs, FLAGS_system.c_str()[0], FLAGS_signal);
|
|
|
|
// read rinex receiver-under-test (rover) observations
|
|
|
|
std::map<int, arma::mat> rover_obs = ReadRinexObs(FLAGS_rover_rinex_obs, FLAGS_system.c_str()[0], FLAGS_signal);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
if (base_obs.empty() or rover_obs.empty())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-02-24 12:04:39 +00:00
|
|
|
|
2020-02-24 14:06:48 +00:00
|
|
|
// compute rx clock errors
|
2020-03-04 09:48:55 +00:00
|
|
|
double base_rx_clock_error_s = 0.0;
|
|
|
|
double rover_rx_clock_error_s = 0.0;
|
2020-02-24 12:04:39 +00:00
|
|
|
if (remove_rx_clock_error == true)
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
base_rx_clock_error_s = compute_rx_clock_error(FLAGS_rinex_nav, FLAGS_base_rinex_obs);
|
|
|
|
rover_rx_clock_error_s = compute_rx_clock_error(FLAGS_rinex_nav, FLAGS_rover_rinex_obs);
|
2020-02-24 12:04:39 +00:00
|
|
|
}
|
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
double common_clock_error_s = rover_rx_clock_error_s - base_rx_clock_error_s;
|
2020-02-24 12:04:39 +00:00
|
|
|
|
2020-02-18 18:39:53 +00:00
|
|
|
// Cut measurement initial transitory of the measurements
|
|
|
|
double initial_transitory_s = FLAGS_skip_obs_transitory_s;
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Skipping initial transitory of " << initial_transitory_s << " [s]\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::uvec index;
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(rover_ob.second.col(0) >= (rover_ob.second.col(0)(0) + initial_transitory_s), 1, "first");
|
2020-02-18 18:39:53 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
rover_ob.second.shed_rows(0, index(0));
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cut observation vectors ends to the shortest one (base or rover)
|
2020-03-04 09:48:55 +00:00
|
|
|
arma::colvec base_obs_time = base_obs.begin()->second.col(0);
|
|
|
|
arma::colvec rover_obs_time = rover_obs.begin()->second.col(0);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
if (base_obs_time.back() < rover_obs_time.back())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
|
|
|
// there are more rover observations than base observations
|
|
|
|
// cut rover vector
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Cutting rover observations vector end..\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
arma::uvec index2;
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(rover_ob.second.col(0) >= base_obs_time.back(), 1, "first");
|
2020-02-18 18:39:53 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
rover_ob.second.shed_rows(index(0), rover_ob.second.n_rows - 1);
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// there are more base observations than rover observations
|
|
|
|
// cut base vector
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Cutting base observations vector end..\n";
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& base_ob : base_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(base_ob.second.col(0) >= rover_obs_time.back(), 1, "first");
|
2020-02-18 18:39:53 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
base_ob.second.shed_rows(index(0), base_ob.second.n_rows - 1);
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// also skip last seconds of the observations (some artifacts are present in some RINEX endings)
|
2020-03-04 09:48:55 +00:00
|
|
|
base_obs_time = base_obs.begin()->second.col(0);
|
|
|
|
rover_obs_time = rover_obs.begin()->second.col(0);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
double skip_ends_s = FLAGS_skip_obs_ends_s;
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Skipping last " << skip_ends_s << " [s] of observations\n";
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(rover_ob.second.col(0) >= (rover_obs_time.back() - skip_ends_s), 1, "first");
|
2020-02-18 18:39:53 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
rover_ob.second.shed_rows(index(0), rover_ob.second.n_rows - 1);
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& base_ob : base_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(base_ob.second.col(0) >= (base_obs_time.back() - skip_ends_s), 1, "first");
|
2020-02-18 18:39:53 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
base_ob.second.shed_rows(index(0), base_ob.second.n_rows - 1);
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save observations in .mat files
|
|
|
|
std::cout << "Saving RAW observables inputs to .mat files...\n";
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& base_ob : base_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-05 18:11:52 +00:00
|
|
|
// std::cout << it->first << " => " << it->second.n_rows << '\n';
|
|
|
|
// std::cout << it->first << " has NaN values: " << it->second.has_nan() << '\n';
|
2020-03-04 09:48:55 +00:00
|
|
|
std::vector<double> tmp_time_vec(base_ob.second.col(0).colptr(0),
|
|
|
|
base_ob.second.col(0).colptr(0) + base_ob.second.n_rows);
|
|
|
|
std::vector<double> tmp_vector(base_ob.second.col(2).colptr(0),
|
|
|
|
base_ob.second.col(2).colptr(0) + base_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector, std::string("base_doppler_sat" + std::to_string(base_ob.first)));
|
|
|
|
|
|
|
|
std::vector<double> tmp_vector2(base_ob.second.col(3).colptr(0),
|
|
|
|
base_ob.second.col(3).colptr(0) + base_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector2, std::string("base_carrier_phase_sat" + std::to_string(base_ob.first)));
|
|
|
|
|
|
|
|
std::vector<double> tmp_vector3(base_ob.second.col(1).colptr(0),
|
|
|
|
base_ob.second.col(1).colptr(0) + base_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector3, std::string("base_pseudorange_sat" + std::to_string(base_ob.first)));
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-05 18:11:52 +00:00
|
|
|
// std::cout << it->first << " => " << it->second.n_rows << '\n';
|
|
|
|
// std::cout << it->first << " has NaN values: " << it->second.has_nan() << '\n';
|
2020-03-04 09:48:55 +00:00
|
|
|
std::vector<double> tmp_time_vec(rover_ob.second.col(0).colptr(0),
|
|
|
|
rover_ob.second.col(0).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
std::vector<double> tmp_vector(rover_ob.second.col(2).colptr(0),
|
|
|
|
rover_ob.second.col(2).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector, std::string("measured_doppler_sat" + std::to_string(rover_ob.first)));
|
|
|
|
|
|
|
|
std::vector<double> tmp_vector2(rover_ob.second.col(3).colptr(0),
|
|
|
|
rover_ob.second.col(3).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector2, std::string("measured_carrier_phase_sat" + std::to_string(rover_ob.first)));
|
|
|
|
|
|
|
|
std::vector<double> tmp_vector3(rover_ob.second.col(1).colptr(0),
|
|
|
|
rover_ob.second.col(1).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector3, std::string("measured_pseudorange_sat" + std::to_string(rover_ob.first)));
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// select reference satellite
|
|
|
|
std::set<int> PRN_set = available_gps_prn;
|
2020-02-24 12:04:39 +00:00
|
|
|
double min_range = std::numeric_limits<double>::max();
|
2020-03-04 09:48:55 +00:00
|
|
|
int reference_sat_id = 1;
|
2020-12-30 20:49:29 +00:00
|
|
|
for (const auto& base_prn_it : PRN_set)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
if (base_obs.find(base_prn_it) != base_obs.end() and rover_obs.find(base_prn_it) != rover_obs.end())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
if (rover_obs.at(base_prn_it).at(0, 1) < min_range)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
min_range = rover_obs.at(base_prn_it).at(0, 1);
|
|
|
|
reference_sat_id = base_prn_it;
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute double differences
|
2020-03-04 09:48:55 +00:00
|
|
|
if (base_obs.find(reference_sat_id) != base_obs.end() and rover_obs.find(reference_sat_id) != rover_obs.end())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Using reference satellite SV " << reference_sat_id << " with minimum range of " << min_range << " [meters]\n";
|
2020-12-30 20:49:29 +00:00
|
|
|
for (const auto& current_sat_id : PRN_set)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
if (current_sat_id != reference_sat_id)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
if (base_obs.find(current_sat_id) != base_obs.end() and rover_obs.find(current_sat_id) != rover_obs.end())
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Computing double difference observables for SV " << current_sat_id << '\n';
|
2020-03-04 09:48:55 +00:00
|
|
|
std::cout << "DD = (OBS_ROVER(SV" << current_sat_id << ") - OBS_ROVER(SV" << reference_sat_id << "))"
|
2020-07-07 16:53:50 +00:00
|
|
|
<< " - (OBS_BASE(SV" << current_sat_id << ") - OBS_BASE(SV" << reference_sat_id << "))\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
code_pseudorange_double_diff(base_obs.at(reference_sat_id),
|
|
|
|
base_obs.at(current_sat_id),
|
|
|
|
rover_obs.at(reference_sat_id),
|
|
|
|
rover_obs.at(current_sat_id),
|
2020-02-24 12:04:39 +00:00
|
|
|
"PRN " + std::to_string(current_sat_id) + " ", common_clock_error_s);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
carrier_phase_double_diff(base_obs.at(reference_sat_id),
|
|
|
|
base_obs.at(current_sat_id),
|
|
|
|
rover_obs.at(reference_sat_id),
|
|
|
|
rover_obs.at(current_sat_id),
|
2020-02-24 12:04:39 +00:00
|
|
|
"PRN " + std::to_string(current_sat_id) + " ", common_clock_error_s);
|
2020-02-18 18:39:53 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
carrier_doppler_double_diff(base_obs.at(reference_sat_id),
|
|
|
|
base_obs.at(current_sat_id),
|
|
|
|
rover_obs.at(reference_sat_id),
|
|
|
|
rover_obs.at(current_sat_id),
|
2020-02-24 12:04:39 +00:00
|
|
|
"PRN " + std::to_string(current_sat_id) + " ", common_clock_error_s);
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
std::cout << "Satellite ID " << reference_sat_id << " not found in both RINEX files\n";
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 18:11:52 +00:00
|
|
|
|
2020-02-25 15:56:16 +00:00
|
|
|
void RINEX_singlediff()
|
|
|
|
{
|
|
|
|
// read rinex receiver-under-test observations
|
2020-03-04 09:48:55 +00:00
|
|
|
std::map<int, arma::mat> rover_obs = ReadRinexObs(FLAGS_rover_rinex_obs, FLAGS_system.c_str()[0], FLAGS_signal);
|
2020-02-25 15:56:16 +00:00
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
if (rover_obs.empty())
|
2020-02-25 15:56:16 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cut measurement initial transitory of the measurements
|
|
|
|
double initial_transitory_s = FLAGS_skip_obs_transitory_s;
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Skipping initial transitory of " << initial_transitory_s << " [s]\n";
|
2020-02-25 15:56:16 +00:00
|
|
|
arma::uvec index;
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-25 15:56:16 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(rover_ob.second.col(0) >= (rover_ob.second.col(0)(0) + initial_transitory_s), 1, "first");
|
2020-02-25 15:56:16 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
rover_ob.second.shed_rows(0, index(0));
|
2020-02-25 15:56:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// also skip last seconds of the observations (some artifacts are present in some RINEX endings)
|
2020-03-04 09:48:55 +00:00
|
|
|
arma::colvec rover_obs_time = rover_obs.begin()->second.col(0);
|
2020-02-25 15:56:16 +00:00
|
|
|
|
|
|
|
double skip_ends_s = FLAGS_skip_obs_ends_s;
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Skipping last " << skip_ends_s << " [s] of observations\n";
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-25 15:56:16 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
index = arma::find(rover_ob.second.col(0) >= (rover_obs_time.back() - skip_ends_s), 1, "first");
|
2020-02-25 15:56:16 +00:00
|
|
|
if ((!index.empty()) and (index(0) > 0))
|
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
rover_ob.second.shed_rows(index(0), rover_ob.second.n_rows - 1);
|
2020-02-25 15:56:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save observations in .mat files
|
|
|
|
std::cout << "Saving RAW observables inputs to .mat files...\n";
|
|
|
|
|
2020-03-04 09:48:55 +00:00
|
|
|
for (auto& rover_ob : rover_obs)
|
2020-02-25 15:56:16 +00:00
|
|
|
{
|
2020-03-05 18:11:52 +00:00
|
|
|
// std::cout << it->first << " => " << it->second.n_rows << '\n';
|
|
|
|
// std::cout << it->first << " has NaN values: " << it->second.has_nan() << '\n';
|
2020-03-04 09:48:55 +00:00
|
|
|
std::vector<double> tmp_time_vec(rover_ob.second.col(0).colptr(0),
|
|
|
|
rover_ob.second.col(0).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
std::vector<double> tmp_vector(rover_ob.second.col(2).colptr(0),
|
|
|
|
rover_ob.second.col(2).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector, std::string("measured_doppler_sat" + std::to_string(rover_ob.first)));
|
|
|
|
|
|
|
|
std::vector<double> tmp_vector2(rover_ob.second.col(3).colptr(0),
|
|
|
|
rover_ob.second.col(3).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector2, std::string("measured_carrier_phase_sat" + std::to_string(rover_ob.first)));
|
|
|
|
|
|
|
|
std::vector<double> tmp_vector3(rover_ob.second.col(1).colptr(0),
|
|
|
|
rover_ob.second.col(1).colptr(0) + rover_ob.second.n_rows);
|
|
|
|
save_mat_xy(tmp_time_vec, tmp_vector3, std::string("measured_pseudorange_sat" + std::to_string(rover_ob.first)));
|
2020-02-25 15:56:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// compute single differences
|
|
|
|
std::set<int> PRN_set = available_gps_prn;
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Computing Code Pseudorange rate vs. Carrier phase rate difference...\n";
|
2020-12-30 20:49:29 +00:00
|
|
|
for (const auto& current_sat_id : PRN_set)
|
2020-02-25 15:56:16 +00:00
|
|
|
{
|
2020-03-04 09:48:55 +00:00
|
|
|
if (rover_obs.find(current_sat_id) != rover_obs.end())
|
2020-02-25 15:56:16 +00:00
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "RateError = PR_rate(SV" << current_sat_id << ") - Phase_rate(SV" << current_sat_id << ")\n";
|
2020-03-04 09:48:55 +00:00
|
|
|
coderate_phaserate_consistence(rover_obs.at(current_sat_id), "PRN " + std::to_string(current_sat_id) + " ");
|
2020-02-25 15:56:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-18 18:39:53 +00:00
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
2020-07-07 16:53:50 +00:00
|
|
|
std::cout << "Running RINEX observables difference tool...\n";
|
2020-08-13 18:54:22 +00:00
|
|
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
2020-02-25 15:56:16 +00:00
|
|
|
if (FLAGS_single_diff)
|
2020-02-18 18:39:53 +00:00
|
|
|
{
|
2020-02-25 15:56:16 +00:00
|
|
|
if (FLAGS_dupli_sat)
|
|
|
|
{
|
|
|
|
RINEX_doublediff_dupli_sat();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RINEX_singlediff();
|
|
|
|
}
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-02-24 12:04:39 +00:00
|
|
|
RINEX_doublediff(FLAGS_remove_rx_clock_error);
|
2020-02-18 18:39:53 +00:00
|
|
|
}
|
2020-02-24 12:04:39 +00:00
|
|
|
|
2020-08-13 18:54:22 +00:00
|
|
|
gflags::ShutDownCommandLineFlags();
|
2020-02-18 18:39:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|