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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
use hifitime::Unit;
use horrorshow::box_html;
use rinex::prelude::{Duration, Epoch, EpochFlag, Rinex};
use crate::QcOpts;
#[derive(Debug, Clone)]
pub struct QcSamplingAnalysis {
/// First [`Epoch`] identified in time
pub first_epoch: Option<Epoch>,
/// Last [`Epoch`] identified in time
pub last_epoch: Option<Epoch>,
/// Time span of this RINEX context
pub duration: Option<Duration>,
/// File [`Header`] sample rate
pub sample_rate: Option<Duration>,
/// Dominant sample rate
pub dominant_sample_rate: Option<Duration>,
/// Unusual data gaps
pub gaps: Vec<(Epoch, Duration)>,
/// Epoch anomalies such as
/// possible receiver loss of lock, bad conditions..
pub anomalies: Vec<(Epoch, EpochFlag)>,
}
impl QcSamplingAnalysis {
pub fn new(rnx: &Rinex, opts: &QcOpts) -> Self {
Self {
first_epoch: rnx.first_epoch(),
last_epoch: rnx.last_epoch(),
duration: rnx.duration(),
sample_rate: rnx.sample_rate(),
dominant_sample_rate: rnx.dominant_sample_rate(),
gaps: rnx.data_gaps(opts.gap_tolerance).collect(),
anomalies: rnx.epoch_anomalies().collect(),
}
}
}
use horrorshow::RenderBox;
use rinex_qc_traits::HtmlReport;
impl HtmlReport for QcSamplingAnalysis {
fn to_html(&self) -> String {
todo!()
}
fn to_inline_html(&self) -> Box<dyn RenderBox + '_> {
box_html! {
tr {
th {
: "Start"
}
th {
: "End"
}
th {
: "Span"
}
}
tr {
@ if let Some(epoch) = self.first_epoch {
td {
: epoch.to_string()
}
} else {
td {
: "Unknown"
}
}
@ if let Some(epoch) = self.last_epoch {
td {
: epoch.to_string()
}
} else {
td {
: "Unknown"
}
}
@ if let Some(duration) = self.duration {
td {
: duration.to_string()
}
} else {
td {
: "Unknown"
}
}
}
tr {
th {
: "Sample rate (Header)"
}
@ if let Some(rate) = self.sample_rate {
td {
: format!("{} ({:.3} Hz)", rate, 1.0 / rate.to_unit(Unit::Second))
}
} else {
th {
: "Unspecified"
}
}
}
tr {
th {
: "Dominant Sample rate"
}
@ if let Some(rate) = self.dominant_sample_rate {
td {
: format!("{} ({:.3} Hz)", rate, 1.0 / rate.to_unit(Unit::Second))
}
} else {
th {
: "Undetermined"
}
}
}
tr {
th {
: "Gap analysis"
}
@ if self.gaps.is_empty() {
th {
: "No gaps detected"
}
} else {
tr {
td {
@ for (epoch, dt) in &self.gaps {
p {
: format!("Start : {}, Duration: {}", epoch, dt)
}
}
}
}
}
}
}
}
}