1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-06-25 22:43:14 +00:00

Adding code rate vs. carrier phase rate single difference test to obsdiff utility

This commit is contained in:
Javier 2020-02-25 16:56:16 +01:00
parent 86a1dc5ca3
commit 38a0777946
2 changed files with 310 additions and 7 deletions

View File

@ -311,9 +311,9 @@ void carrier_phase_double_diff(
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
// compute error without the accumulated carrier phase offsets (which depends on the receiver starting time)
arma::vec delta_true_carrier_phase_cycles = (true_ch0_carrier_phase_interp - true_ch0_carrier_phase_interp(0)) - (true_ch1_carrier_phase_interp - true_ch1_carrier_phase_interp(0));
arma::vec delta_measured_carrier_phase_cycles = (measured_ch0.col(3) - measured_ch0.col(3)(0)) - (meas_ch1_carrier_phase_interp - meas_ch1_carrier_phase_interp(0));
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;
// remove NaN
arma::uvec NaN_in_true_data = arma::find_nonfinite(delta_true_carrier_phase_cycles);
@ -349,6 +349,10 @@ void carrier_phase_double_diff(
// 2. RMSE
arma::vec err;
err = delta_measured_carrier_phase_cycles - delta_true_carrier_phase_cycles;
// compute error without the accumulated carrier phase offsets (which depends on the receiver starting time)
err = err - arma::mean(err);
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
@ -408,8 +412,8 @@ void carrier_phase_single_diff(
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)
arma::vec delta_measured_carrier_phase_cycles = (measured_ch0.col(3) - measured_ch0.col(3)(0)) - (meas_ch1_carrier_phase_interp - meas_ch1_carrier_phase_interp(0));
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);
// remove NaN
arma::uvec NaN_in_measured_data = arma::find_nonfinite(delta_measured_carrier_phase_cycles);
@ -843,6 +847,225 @@ void code_pseudorange_single_diff(
}
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);
//Test 4 is for the pseudorange phase consistency
//
//1) Checks for the value of the pseudoranges to be within a certain threshold.
arma::vec prange = measured_ch0.col(1);
//todo: This code is only valid for L1/E1 carrier frequency.
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";
}
//2) It checks that the pseduorange rate is within a certain threshold
// % check code rate
arma::vec coderate = prange.subvec(1, prange.n_elem - 1) - prange.subvec(0, prange.n_elem - 2) / delta_time;
// 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)
{
std::cout << "Warning: bad code reate \n";
}
//3) It checks that the phase rate is within a certain threshold
arma::vec phaserate = phase.subvec(1, prange.n_elem - 1) - phase.subvec(0, prange.n_elem - 2) / delta_time;
// 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)
{
std::cout << "Warning: bad phase reate \n";
}
//4) It checks the difference between code and phase rates
// % check difference between code and phase rates
arma::vec ratediff = phaserate - coderate;
double maxratediff = 5;
idx = arma::find(phaserate > maxratediff);
if (idx.n_elem > 0)
{
std::cout << "Warning: bad code and phase reate difference \n";
}
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
<< " [meters]" << std::endl;
std::cout.precision(ss);
// plots
if (FLAGS_show_plots)
{
Gnuplot g3("linespoints");
g3.set_title(data_title + "Code rate - phase rate [m]");
g3.set_grid();
g3.set_xlabel("Time [s]");
g3.set_ylabel("Code rate - phase rate [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 rate - phase rate");
g3.set_legend();
g3.savetops(data_title + "Code_rate_minus_phase_rate");
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);
if (measurement_time.size() > 0)
{
// 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
<< " [meters]" << std::endl;
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();
g3.savetops(data_title + "Code_range_Carrier_phase_range");
g3.showonscreen(); // window output
}
}
else
{
std::cout << "No valid data\n";
}
}
double compute_rx_clock_error(const std::string& rinex_nav_filename, const std::string& rinex_obs_file)
{
std::cout << "Computing receiver's clock error..." << std::endl;
@ -1320,14 +1543,93 @@ void RINEX_doublediff(bool remove_rx_clock_error)
}
}
void RINEX_singlediff()
{
// read rinex receiver-under-test observations
std::map<int, arma::mat> test_obs = ReadRinexObs(FLAGS_test_rinex_obs, 'G', std::string("1C\0"));
if (test_obs.empty())
{
return;
}
// Cut measurement initial transitory of the measurements
double initial_transitory_s = FLAGS_skip_obs_transitory_s;
std::cout << "Skipping initial transitory of " << initial_transitory_s << " [s]" << std::endl;
arma::uvec index;
for (auto& test_ob : test_obs)
{
index = arma::find(test_ob.second.col(0) >= (test_ob.second.col(0)(0) + initial_transitory_s), 1, "first");
if ((!index.empty()) and (index(0) > 0))
{
test_ob.second.shed_rows(0, index(0));
}
}
// also skip last seconds of the observations (some artifacts are present in some RINEX endings)
arma::colvec test_obs_time = test_obs.begin()->second.col(0);
double skip_ends_s = FLAGS_skip_obs_ends_s;
std::cout << "Skipping last " << skip_ends_s << " [s] of observations" << std::endl;
for (auto& test_ob : test_obs)
{
index = arma::find(test_ob.second.col(0) >= (test_obs_time.back() - skip_ends_s), 1, "first");
if ((!index.empty()) and (index(0) > 0))
{
test_ob.second.shed_rows(index(0), test_ob.second.n_rows - 1);
}
}
// Save observations in .mat files
std::cout << "Saving RAW observables inputs to .mat files...\n";
for (auto& test_ob : test_obs)
{
// std::cout << it->first << " => " << it->second.n_rows << '\n';
// std::cout << it->first << " has NaN values: " << it->second.has_nan() << '\n';
std::vector<double> tmp_time_vec(test_ob.second.col(0).colptr(0),
test_ob.second.col(0).colptr(0) + test_ob.second.n_rows);
std::vector<double> tmp_vector(test_ob.second.col(2).colptr(0),
test_ob.second.col(2).colptr(0) + test_ob.second.n_rows);
save_mat_xy(tmp_time_vec, tmp_vector, std::string("measured_doppler_sat" + std::to_string(test_ob.first)));
std::vector<double> tmp_vector2(test_ob.second.col(3).colptr(0),
test_ob.second.col(3).colptr(0) + test_ob.second.n_rows);
save_mat_xy(tmp_time_vec, tmp_vector2, std::string("measured_carrier_phase_sat" + std::to_string(test_ob.first)));
std::vector<double> tmp_vector3(test_ob.second.col(1).colptr(0),
test_ob.second.col(1).colptr(0) + test_ob.second.n_rows);
save_mat_xy(tmp_time_vec, tmp_vector3, std::string("measured_pseudorange_sat" + std::to_string(test_ob.first)));
}
// compute single differences
std::set<int> PRN_set = available_gps_prn;
std::cout << "Computing Code Pseudorange rate vs. Carrier phase rate difference..." << std::endl;
for (auto& current_sat_id : PRN_set)
{
if (test_obs.find(current_sat_id) != test_obs.end())
{
std::cout << "RateError = PR_rate(SV" << current_sat_id << ") - Phase_rate(SV" << current_sat_id << ")" << std::endl;
coderate_phaserate_consistence(test_obs.at(current_sat_id), "PRN " + std::to_string(current_sat_id) + " ");
}
}
}
int main(int argc, char** argv)
{
std::cout << "Running RINEX observables difference tool..." << std::endl;
google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_dupli_sat)
if (FLAGS_single_diff)
{
RINEX_doublediff_dupli_sat();
if (FLAGS_dupli_sat)
{
RINEX_doublediff_dupli_sat();
}
else
{
RINEX_singlediff();
}
}
else
{

View File

@ -28,6 +28,7 @@ DEFINE_double(skip_obs_ends_s, 5.0, "Skip the lasts observable outputs to avoid
DEFINE_bool(single_diffs, false, "Compute also the single difference errors for Accumulated Carrier Phase and Carrier Doppler (requires LO synchronization between receivers)");
DEFINE_bool(compare_with_5X, false, "Compare the E5a Doppler and Carrier Phases with the E5 full bw in RINEX (expect discrepancy due to the center frequencies difference)");
DEFINE_bool(dupli_sat, false, "Enable special observable test mode where the scenario contains duplicated satellite orbits");
DEFINE_bool(single_diff, false, "Enable special observable test mode using only rover observables");
DEFINE_string(dupli_sat_prns, "1,2,3,4", "List of duplicated satellites PRN pairs (i.e. 1,2,3,4 indicates that the PRNs 1,2 share the same orbit. The same applies for PRNs 3,4)");
DEFINE_string(ref_rinex_obs, "reference.obs", "Filename of reference RINEX observation file");
DEFINE_string(rinex_nav, "reference.nav", "Filename of reference RINEX navigation file");