Move External TimeTag propagation to the time counter channel. PVT OBS timestamp comarison completed

This commit is contained in:
Javier Arribas 2021-04-19 12:27:02 +02:00
parent 26bc9c9b5a
commit 5c3134dbde
8 changed files with 266 additions and 56 deletions

View File

@ -1816,6 +1816,35 @@ void rtklib_pvt_gs::initialize_and_apply_carrier_phase_offset()
int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items __attribute__((unused)))
{
//**************** time tags ****************
if (d_enable_rx_clock_correction == false) //todo: currently only works if clock correction is disabled
{
std::vector<gr::tag_t> tags_vec;
//time tag from obs to pvt is always propagated in channel 0
this->get_tags_in_range(tags_vec, 0, this->nitems_read(0), this->nitems_read(0) + noutput_items);
for (std::vector<gr::tag_t>::iterator it = tags_vec.begin(); it != tags_vec.end(); ++it)
{
try
{
if (pmt::any_ref(it->value).type().hash_code() == typeid(const std::shared_ptr<GnssTime>).hash_code())
{
const std::shared_ptr<GnssTime> timetag = boost::any_cast<const std::shared_ptr<GnssTime>>(pmt::any_ref(it->value));
//std::cout << "PVT timetag: " << timetag->rx_time << "\n";
d_TimeChannelTagTimestamps.push(*timetag);
}
else
{
std::cout << "hash code not match\n";
}
}
catch (const boost::bad_any_cast& e)
{
std::cout << "msg Bad any_cast: " << e.what();
}
}
}
//************* end time tags **************
for (int32_t epoch = 0; epoch < noutput_items; epoch++)
{
bool flag_display_pvt = false;
@ -1999,7 +2028,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
{
flag_compute_pvt_output = true;
// std::cout.precision(17);
// std::cout << "current_RX_time: " << current_RX_time << " map time: " << d_gnss_observables_map.begin()->second.RX_time << '\n';
//std::cout << "current_RX_time: " << current_RX_time_ms << " map time: " << d_gnss_observables_map.begin()->second.RX_time << '\n';
}
flag_pvt_valid = true;
}
@ -2017,20 +2046,52 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
flag_pvt_valid = d_user_pvt_solver->get_PVT(d_gnss_observables_map, false);
}
if (flag_pvt_valid == true)
{
//experimental VTL tests
// send tracking command
const std::shared_ptr<TrackingCmd> trk_cmd_test = std::make_shared<TrackingCmd>(TrackingCmd());
trk_cmd_test->carrier_freq_hz = 12345.4;
trk_cmd_test->sample_counter = d_gnss_observables_map.begin()->second.Tracking_sample_counter;
this->message_port_pub(pmt::mp("pvt_to_trk"), pmt::make_any(trk_cmd_test));
// const std::shared_ptr<TrackingCmd> trk_cmd_test = std::make_shared<TrackingCmd>(TrackingCmd());
// trk_cmd_test->carrier_freq_hz = 12345.4;
// trk_cmd_test->sample_counter = d_gnss_observables_map.begin()->second.Tracking_sample_counter;
// this->message_port_pub(pmt::mp("pvt_to_trk"), pmt::make_any(trk_cmd_test));
// initialize (if needed) the accumulated phase offset and apply it to the active channels
// required to report accumulated phase cycles comparable to pseudoranges
initialize_and_apply_carrier_phase_offset();
const double Rx_clock_offset_s = d_user_pvt_solver->get_time_offset_s();
//**************** time tags ****************
if (d_enable_rx_clock_correction == false) //todo: currently only works if clock correction is disabled
{
//************ Source TimeTag comparison with GNSS computed TOW *************
if (!d_TimeChannelTagTimestamps.empty())
{
double delta_rxtime_to_tag;
GnssTime current_tag;
do
{
current_tag = d_TimeChannelTagTimestamps.front();
delta_rxtime_to_tag = d_rx_time * 1000.0 - current_tag.rx_time;
d_TimeChannelTagTimestamps.pop();
}
while (fabs(delta_rxtime_to_tag) >= 100 and !d_TimeChannelTagTimestamps.empty());
if (fabs(delta_rxtime_to_tag) <= 100) //[ms]
{
double timestamp_tow_error_ns = 1000000.0 * (Rx_clock_offset_s * 1000.0 + delta_rxtime_to_tag + static_cast<double>(current_tag.tow_ms) - d_rx_time * 1000.0 + current_tag.tow_ms_fraction);
std::cout << "[Time ch] RX TimeTag Week: " << current_tag.week
<< ", TOW: " << current_tag.tow_ms
<< " [ms], TOW fraction: " << current_tag.tow_ms_fraction
<< " [ms], GNSS-SDR OBS CORRECTED TOW - EXTERNAL TIMETAG TOW: " << timestamp_tow_error_ns << " [ns] \n";
}
}
}
//**********************************************
if (d_enable_rx_clock_correction == true and fabs(Rx_clock_offset_s) > 0.000001) // 1us !!
{
LOG(INFO) << "Warning: Rx clock offset at interpolated RX time: " << Rx_clock_offset_s * 1000.0 << "[ms]"

View File

@ -19,6 +19,7 @@
#include "gnss_block_interface.h"
#include "gnss_synchro.h"
#include "gnss_time.h"
#include "rtklib.h"
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
@ -31,9 +32,10 @@
#include <ctime> // for time_t
#include <map> // for map
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <sys/types.h> // for key_t
#include <vector> // for vector
#include <queue>
#include <string> // for string
#include <sys/types.h> // for key_t
#include <vector> // for vector
/** \addtogroup PVT
* \{ */
@ -202,6 +204,8 @@ private:
std::map<int, Gnss_Synchro> d_gnss_observables_map_t0;
std::map<int, Gnss_Synchro> d_gnss_observables_map_t1;
std::queue<GnssTime> d_TimeChannelTagTimestamps;
boost::posix_time::time_duration d_utc_diff_time;
size_t d_gps_ephemeris_sptr_type_hash_code;

View File

@ -143,6 +143,8 @@ hybrid_observables_gs::hybrid_observables_gs(const Obs_Conf &conf_) : gr::block(
d_mapStringValues["B1"] = evBDS_B1;
d_mapStringValues["B2"] = evBDS_B2;
d_mapStringValues["B3"] = evBDS_B3;
last_rx_clock_round20ms_error = 0;
set_tag_propagation_policy(TPP_DONT); //no tag propagation, the time tag will be adjusted and regenerated in work()
}
@ -192,12 +194,16 @@ void hybrid_observables_gs::msg_handler_pvt_to_observables(const pmt::pmt_t &msg
if (pmt::any_ref(msg).type().hash_code() == d_double_type_hash_code)
{
const auto new_rx_clock_offset_s = boost::any_cast<double>(pmt::any_ref(msg));
double old_tow_corrected = static_cast<double>(d_T_rx_TOW_ms) - new_rx_clock_offset_s * 1000.0;
d_T_rx_TOW_ms = d_T_rx_TOW_ms - static_cast<int>(round(new_rx_clock_offset_s * 1000.0));
// align the receiver clock to integer multiple of 20 ms
if (d_T_rx_TOW_ms % 20)
{
d_T_rx_TOW_ms += 20 - d_T_rx_TOW_ms % 20;
}
last_rx_clock_round20ms_error = static_cast<double>(d_T_rx_TOW_ms) - old_tow_corrected;
// d_Rx_clock_buffer.clear(); // Clear all the elements in the buffer
for (uint32_t n = 0; n < d_nchannels_out; n++)
{
@ -605,32 +611,93 @@ void hybrid_observables_gs::smooth_pseudoranges(std::vector<Gnss_Synchro> &data)
void hybrid_observables_gs::check_tag_timestamp(const std::vector<Gnss_Synchro> &data, uint64_t rx_clock)
{
std::vector<Gnss_Synchro>::const_iterator it;
for (it = data.begin(); it != data.end(); it++)
{
if (!d_SourceTagTimestamps[it->Channel_ID].empty() and it->Flag_valid_pseudorange == true)
{
//std::cout << "RX Time: " << (static_cast<double>(rx_clock) / static_cast<double>(it->fs)) << "s\n";
double delta_rxtime_to_tag;
GnssTime current_tag;
do
{
current_tag = d_SourceTagTimestamps[it->Channel_ID].front();
delta_rxtime_to_tag = (static_cast<double>(rx_clock) / static_cast<double>(it->fs)) - current_tag.rx_time;
// std::cout << "[ch:" << it->Channel_ID << "][" << delta_rxtime_to_tag << "]\n";
d_SourceTagTimestamps[it->Channel_ID].pop();
}
while (fabs(delta_rxtime_to_tag) >= 0.05 and !d_SourceTagTimestamps[it->Channel_ID].empty());
// std::vector<Gnss_Synchro>::const_iterator it;
// for (it = data.begin(); it != data.end(); it++)
// {
// if (!d_SourceTagTimestamps[it->Channel_ID].empty() and it->Flag_valid_pseudorange == true)
// {
// //std::cout << "RX Time: " << (static_cast<double>(rx_clock) / static_cast<double>(it->fs)) << "s\n";
// double delta_rxtime_to_tag;
// GnssTime current_tag;
// do
// {
// current_tag = d_SourceTagTimestamps[it->Channel_ID].front();
// delta_rxtime_to_tag = (static_cast<double>(rx_clock) / static_cast<double>(it->fs)) - current_tag.rx_time;
// // std::cout << "[ch:" << it->Channel_ID << "][" << delta_rxtime_to_tag << "]\n";
// d_SourceTagTimestamps[it->Channel_ID].pop();
// }
// while (fabs(delta_rxtime_to_tag) >= 0.2 and !d_SourceTagTimestamps[it->Channel_ID].empty());
//
// if (fabs(delta_rxtime_to_tag) <= 0.2)
// {
// std::cout << "[ch:" << it->Channel_ID << "][" << delta_rxtime_to_tag
// << "] OBS RX TimeTag Week: " << current_tag.week
// << ", TOW: " << current_tag.tow_ms
// << " [ms], TOW fraction: " << current_tag.tow_ms_fraction
// << " [ms], DELTA TLM TOW: " << last_rx_clock_round20ms_error + delta_rxtime_to_tag * 1000.0 + static_cast<double>(current_tag.tow_ms) - static_cast<double>(d_T_rx_TOW_ms) + current_tag.tow_ms_fraction << " [ms] \n";
//
// const std::shared_ptr<GnssTime> tmp_obj = std::make_shared<GnssTime>(GnssTime());
// *tmp_obj = current_tag;
// tmp_obj->week = current_tag.week;
// double intpart;
// tmp_obj->tow_ms_fraction = modf(delta_rxtime_to_tag * 1000.0, &intpart);
// tmp_obj->tow_ms = current_tag.tow_ms + static_cast<int>(intpart);
// tmp_obj->rx_time = static_cast<double>(rx_clock) / static_cast<double>(it->fs);
// add_item_tag(it->Channel_ID, this->nitems_written(it->Channel_ID) + 1, pmt::mp("timetag"), pmt::make_any(tmp_obj));
// }
// }
// }
if (fabs(delta_rxtime_to_tag) <= 0.05)
//std::cout << "RX Time: " << (static_cast<double>(rx_clock) / static_cast<double>(it->fs)) << "s\n";
if (!d_TimeChannelTagTimestamps.empty())
{
double fs = 0;
std::vector<Gnss_Synchro>::const_iterator it;
for (it = data.begin(); it != data.end(); it++)
{
if (it->Flag_valid_pseudorange == true)
{
std::cout << "[ch:" << it->Channel_ID << "][" << delta_rxtime_to_tag
<< "] OBS RX TimeTag Week: " << current_tag.week
<< ", TOW: " << current_tag.tow_ms
<< " [ms], TOW fraction: " << current_tag.tow_ms_fraction
<< " [ms], DELTA TLM TOW: " << delta_rxtime_to_tag * 1000.0 + static_cast<double>(current_tag.tow_ms) - it->RX_time * 1000.0 + current_tag.tow_ms_fraction << " [ms] \n";
fs = static_cast<double>(it->fs);
break;
}
}
double delta_rxtime_to_tag = 100;
GnssTime current_tag;
do
{
current_tag = d_TimeChannelTagTimestamps.front();
delta_rxtime_to_tag = (static_cast<double>(rx_clock) / fs) - current_tag.rx_time;
if (delta_rxtime_to_tag >= 0)
{
d_TimeChannelTagTimestamps.pop();
}
}
while (delta_rxtime_to_tag >= 0.1 and !d_TimeChannelTagTimestamps.empty());
if (delta_rxtime_to_tag >= 0 and delta_rxtime_to_tag <= 0.1)
{
// std::cout << "[Time ch][" << delta_rxtime_to_tag
// << "] OBS RX TimeTag Week: " << current_tag.week
// << ", TOW: " << current_tag.tow_ms
// << " [ms], TOW fraction: " << current_tag.tow_ms_fraction
// << " [ms], DELTA TLM TOW: " << last_rx_clock_round20ms_error + delta_rxtime_to_tag * 1000.0 + static_cast<double>(current_tag.tow_ms) - static_cast<double>(d_T_rx_TOW_ms) + current_tag.tow_ms_fraction << " [ms] \n";
const std::shared_ptr<GnssTime> tmp_obj = std::make_shared<GnssTime>(GnssTime());
*tmp_obj = current_tag;
double intpart;
tmp_obj->tow_ms_fraction = tmp_obj->tow_ms_fraction + modf(delta_rxtime_to_tag * 1000.0, &intpart);
tmp_obj->tow_ms = current_tag.tow_ms + static_cast<int>(intpart);
tmp_obj->rx_time = static_cast<double>(d_T_rx_TOW_ms); //static_cast<double>(rx_clock) / static_cast<double>(data.begin()->fs);
add_item_tag(0, this->nitems_written(0) + 1, pmt::mp("timetag"), pmt::make_any(tmp_obj));
delta_rxtime_to_tag = 100;
}
// else
// {
// std::cout << "Delta: " << delta_rxtime_to_tag << "\n";
// }
}
}
@ -647,16 +714,10 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused)
if (ninput_items[d_nchannels_in - 1] > 0)
{
d_Rx_clock_buffer.push_back(in[d_nchannels_in - 1][0].Tracking_sample_counter);
// Consume one item from the clock channel (last of the input channels)
consume(static_cast<int32_t>(d_nchannels_in) - 1, 1);
}
// Push the tracking observables into buffers to allow the observable interpolation at the desired Rx clock
for (uint32_t n = 0; n < d_nchannels_out; n++)
{
//**************** time tags ****************
std::vector<gr::tag_t> tags_vec;
this->get_tags_in_range(tags_vec, n, this->nitems_read(n), this->nitems_read(n) + ninput_items[n]);
this->get_tags_in_range(tags_vec, d_nchannels_in - 1, this->nitems_read(d_nchannels_in - 1), this->nitems_read(d_nchannels_in - 1) + 1);
for (std::vector<gr::tag_t>::iterator it = tags_vec.begin(); it != tags_vec.end(); ++it)
{
try
@ -664,8 +725,8 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused)
if (pmt::any_ref(it->value).type().hash_code() == typeid(const std::shared_ptr<GnssTime>).hash_code())
{
const std::shared_ptr<GnssTime> timetag = boost::any_cast<const std::shared_ptr<GnssTime>>(pmt::any_ref(it->value));
//std::cout << "[ch " << n << "] timetag: " << timetag->rx_time << "\n";
d_SourceTagTimestamps.at(n).push(*timetag);
//std::cout << "[Time ch ] timetag: " << timetag->rx_time << "\n";
d_TimeChannelTagTimestamps.push(*timetag);
}
else
{
@ -679,6 +740,40 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused)
}
//************* end time tags **************
// Consume one item from the clock channel (last of the input channels)
consume(static_cast<int32_t>(d_nchannels_in) - 1, 1);
}
// Push the tracking observables into buffers to allow the observable interpolation at the desired Rx clock
for (uint32_t n = 0; n < d_nchannels_out; n++)
{
//**************** time tags ****************
// std::vector<gr::tag_t> tags_vec;
// this->get_tags_in_range(tags_vec, n, this->nitems_read(n), this->nitems_read(n) + ninput_items[n]);
// for (std::vector<gr::tag_t>::iterator it = tags_vec.begin(); it != tags_vec.end(); ++it)
// {
// try
// {
// if (pmt::any_ref(it->value).type().hash_code() == typeid(const std::shared_ptr<GnssTime>).hash_code())
// {
// const std::shared_ptr<GnssTime> timetag = boost::any_cast<const std::shared_ptr<GnssTime>>(pmt::any_ref(it->value));
// //std::cout << "[ch " << n << "] timetag: " << timetag->rx_time << "\n";
// d_SourceTagTimestamps.at(n).push(*timetag);
// }
// else
// {
// std::cout << "hash code not match\n";
// }
// }
// catch (const boost::bad_any_cast &e)
// {
// std::cout << "msg Bad any_cast: " << e.what();
// }
// }
//************* end time tags **************
for (int32_t m = 0; m < ninput_items[n]; m++)
{
// Push the valid tracking Gnss_Synchros to their corresponding deque

View File

@ -106,6 +106,7 @@ private:
boost::circular_buffer<uint64_t> d_Rx_clock_buffer; // time history
std::vector<std::queue<GnssTime>> d_SourceTagTimestamps;
std::queue<GnssTime> d_TimeChannelTagTimestamps;
std::vector<bool> d_channel_last_pll_lock;
std::vector<double> d_channel_last_pseudorange_smooth;
@ -118,6 +119,7 @@ private:
double d_smooth_filter_M;
uint32_t d_T_rx_TOW_ms;
double last_rx_clock_round20ms_error;
uint32_t d_T_rx_step_ms;
uint32_t d_T_status_report_timer_ms;
uint32_t d_nchannels_in;

View File

@ -2036,23 +2036,23 @@ int dll_pll_veml_tracking::general_work(int noutput_items __attribute__((unused)
//generate new tag associated with gnss-synchro object
if (d_timetag_waiting == true)
{
int64_t diff_samplecount = uint64diff(current_synchro_data.Tracking_sample_counter, d_last_timetag_samplecounter);
double intpart;
d_last_timetag.tow_ms_fraction = modf(1000.0 * static_cast<double>(diff_samplecount) / d_trk_parameters.fs_in, &intpart);
const std::shared_ptr<GnssTime> tmp_obj = std::make_shared<GnssTime>(GnssTime());
tmp_obj->week = d_last_timetag.week;
tmp_obj->tow_ms = d_last_timetag.tow_ms + static_cast<int>(intpart);
tmp_obj->tow_ms_fraction = d_last_timetag.tow_ms_fraction;
tmp_obj->rx_time = static_cast<double>(current_synchro_data.Tracking_sample_counter) / d_trk_parameters.fs_in;
add_item_tag(0, this->nitems_written(0) + 1, pmt::mp("timetag"), pmt::make_any(tmp_obj));
//std::cout << "[" << this->nitems_written(0) + 1 << "] Sent TimeTag Week: " << d_last_timetag.week << ", TOW: " << d_last_timetag.tow_ms << " [ms], TOW fraction: " << d_last_timetag.tow_ms_fraction << " [ms] \n";
d_timetag_waiting = false;
}
// if (d_timetag_waiting == true)
// {
// int64_t diff_samplecount = uint64diff(current_synchro_data.Tracking_sample_counter, d_last_timetag_samplecounter);
//
// double intpart;
// d_last_timetag.tow_ms_fraction = modf(1000.0 * static_cast<double>(diff_samplecount) / d_trk_parameters.fs_in, &intpart);
//
// const std::shared_ptr<GnssTime> tmp_obj = std::make_shared<GnssTime>(GnssTime());
// tmp_obj->week = d_last_timetag.week;
// tmp_obj->tow_ms = d_last_timetag.tow_ms + static_cast<int>(intpart);
// tmp_obj->tow_ms_fraction = d_last_timetag.tow_ms_fraction;
// tmp_obj->rx_time = static_cast<double>(current_synchro_data.Tracking_sample_counter) / d_trk_parameters.fs_in;
// add_item_tag(0, this->nitems_written(0) + 1, pmt::mp("timetag"), pmt::make_any(tmp_obj));
//
// //std::cout << "[" << this->nitems_written(0) + 1 << "][diff_time: " << 1000.0 * static_cast<double>(diff_samplecount) / d_trk_parameters.fs_in << "] Sent TimeTag Week: " << d_last_timetag.week << ", TOW: " << d_last_timetag.tow_ms << " [ms], TOW fraction: " << d_last_timetag.tow_ms_fraction << " [ms] \n";
// d_timetag_waiting = false;
// }
return 1;
}

View File

@ -76,6 +76,7 @@ target_link_libraries(core_libs
core_libs_supl
core_system_parameters
pvt_libs
algorithms_libs
PRIVATE
Boost::serialization
Gflags::gflags

View File

@ -17,6 +17,7 @@
#include "gnss_sdr_sample_counter.h"
#include "gnss_synchro.h"
#include "gnss_time.h"
#include <gnuradio/io_signature.h>
#include <pmt/pmt.h> // for from_double
#include <pmt/pmt_sugar.h> // for mp
@ -48,6 +49,7 @@ gnss_sdr_sample_counter::gnss_sdr_sample_counter(
flag_m = false;
flag_h = false;
flag_days = false;
set_tag_propagation_policy(TPP_DONT); //no tag propagation, the time tag will be adjusted and regenerated in work()
}
@ -57,6 +59,12 @@ gnss_sdr_sample_counter_sptr gnss_sdr_make_sample_counter(double _fs, int32_t _i
return sample_counter_;
}
int64_t gnss_sdr_sample_counter::uint64diff(uint64_t first, uint64_t second)
{
uint64_t abs_diff = (first > second) ? (first - second) : (second - first);
assert(abs_diff <= INT64_MAX);
return (first > second) ? (int64_t)abs_diff : -(int64_t)abs_diff;
}
int gnss_sdr_sample_counter::work(int noutput_items __attribute__((unused)),
gr_vector_const_void_star &input_items __attribute__((unused)),
@ -129,5 +137,42 @@ int gnss_sdr_sample_counter::work(int noutput_items __attribute__((unused)),
sample_counter += samples_per_output;
out[0].Tracking_sample_counter = sample_counter;
current_T_rx_ms += interval_ms;
//**************** time tags ****************
std::vector<gr::tag_t> tags_vec;
//notice that nitems_read is updated in decimation blocks after leaving work() with return 1, equivalent to call consume_each
this->get_tags_in_range(tags_vec, 0, this->nitems_read(0), this->nitems_read(0) + samples_per_output);
for (std::vector<gr::tag_t>::iterator it = tags_vec.begin(); it != tags_vec.end(); ++it)
{
try
{
if (pmt::any_ref(it->value).type().hash_code() == typeid(const std::shared_ptr<GnssTime>).hash_code())
{
//recompute timestamp to match the last sample in the consumed samples in this batch
int64_t diff_samplecount = uint64diff(out[0].Tracking_sample_counter, it->offset);
const std::shared_ptr<GnssTime> last_timetag = boost::any_cast<const std::shared_ptr<GnssTime>>(pmt::any_ref(it->value));
double intpart;
last_timetag->tow_ms_fraction = modf(1000.0 * static_cast<double>(diff_samplecount) / fs, &intpart);
last_timetag->tow_ms = last_timetag->tow_ms + static_cast<int>(intpart);
last_timetag->rx_time = static_cast<double>(out[0].Tracking_sample_counter) / fs;
add_item_tag(0, this->nitems_written(0) + 1, pmt::mp("timetag"), pmt::make_any(last_timetag));
//std::cout << "COUNTER TAG: this->nitems_read(0):" << this->nitems_read(0) << " sample_counter:" << sample_counter
// << " it->offset:" << it->offset << " diff:" << diff_samplecount << "\n";
//getchar();
}
else
{
std::cout << "hash code not match\n";
}
}
catch (const boost::bad_any_cast &e)
{
std::cout << "msg Bad any_cast: " << e.what();
}
}
//************* end time tags **************
return 1;
}

View File

@ -58,6 +58,8 @@ private:
int32_t _interval_ms,
size_t _size);
int64_t uint64diff(uint64_t first, uint64_t second);
double fs;
int64_t current_T_rx_ms; // Receiver time in ms since the beginning of the run
uint64_t sample_counter;