GNU Radio's SATELLITES Package
time_dependent_delay_impl.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2025 Daniel Estevez <daniel@destevez.net>.
4  *
5  * This file is part of gr-satellites
6  *
7  * SPDX-License-Identifier: GPL-3.0-or-later
8  */
9 
10 #ifndef INCLUDED_SATELLITES_TIME_DEPENDENT_DELAY_IMPL_H
11 #define INCLUDED_SATELLITES_TIME_DEPENDENT_DELAY_IMPL_H
12 
13 #include <gnuradio/filter/fir_filter.h>
15 #include <cstdint>
16 
17 namespace gr {
18 namespace satellites {
19 
21 {
22 private:
23  const double d_samp_rate;
24  size_t d_current_index;
25  double d_t0;
26  uint64_t d_sample_t0;
27  std::vector<double> d_times;
28  std::vector<double> d_delays_samples; // delays in the file in units of samples
29  std::vector<gr::filter::kernel::fir_filter_ccf> d_filters;
30  const double d_fir_delay;
31  const int d_taps_per_filter;
32  std::vector<gr::tag_t> d_future_tags;
33 
34  // Used by UHD
35  const pmt::pmt_t d_rx_time_key;
36 
37  // Used by gr-difi
38  const pmt::pmt_t d_pck_n_key;
39  const pmt::pmt_t d_full_key;
40  const pmt::pmt_t d_frac_key;
41 
42  double d_current_time;
43  double d_current_delay; // current delay in units of samples
44 
45  // Called after a time update. Makes the current index go backwards if
46  // needed because of a time update "to the past".
47  void adjust_current_index()
48  {
49  while ((d_current_index > 0) && (d_times[d_current_index] > d_t0)) {
50  --d_current_index;
51  }
52  }
53 
54  void read_delay_file(const std::string& filename);
55 
56  void update_time_from_tags(int noutput_items)
57  {
58  std::vector<gr::tag_t> tags;
59  get_tags_in_window(tags, 0, 0, noutput_items);
60  for (const auto& tag : tags) {
61  double t0;
62  bool set = false;
63  if (pmt::eqv(tag.key, d_rx_time_key)) {
64  if (pmt::is_tuple(tag.value)) {
65  t0 = static_cast<double>(
66  pmt::to_uint64(pmt::tuple_ref(tag.value, 0))) +
67  pmt::to_double(pmt::tuple_ref(tag.value, 1));
68  set = true;
69  }
70  } else if (pmt::eqv(tag.key, d_pck_n_key)) {
71  if (pmt::is_dict(tag.value)) {
72  const auto full_pmt =
73  pmt::dict_ref(tag.value, d_full_key, pmt::PMT_NIL);
74  const auto frac_pmt =
75  pmt::dict_ref(tag.value, d_frac_key, pmt::PMT_NIL);
76  if (pmt::is_integer(full_pmt) && pmt::is_uint64(frac_pmt)) {
77  const auto full = pmt::to_long(full_pmt);
78  const auto frac = pmt::to_uint64(frac_pmt);
79  // in DIFI, frac gives the number of picoseconds
80  t0 =
81  static_cast<double>(full) + 1e-12 * static_cast<double>(frac);
82  set = true;
83  }
84  }
85  }
86 
87  if (set) {
88  d_sample_t0 = tag.offset;
89  d_t0 = t0;
90  d_logger->info("set time {} at sample {}", d_t0, d_sample_t0);
91  adjust_current_index();
92  }
93  }
94  }
95 
96  // this cannot be const, because nitems_written() is not const
97  double compute_time(uint64_t sample_absolute_idx) const
98  {
99  return d_t0 + static_cast<double>(static_cast<int64_t>(sample_absolute_idx) -
100  static_cast<int64_t>(d_sample_t0)) /
101  d_samp_rate;
102  }
103 
104  double compute_delay(double time)
105  {
106  // Advance d_current_index so that the next time is greater than the
107  // current.
108  while (d_current_index + 1 < d_times.size() &&
109  d_times[d_current_index + 1] <= time) {
110  ++d_current_index;
111  }
112  if ((time < d_times[d_current_index]) ||
113  (d_current_index + 1 == d_times.size())) {
114  // We are before the beginning or past the end of the file, so we
115  // maintain a constant delay.
116  return d_delays_samples[d_current_index];
117  }
118  // Linearly interpolate delay
119  double alpha = (time - d_times[d_current_index]) /
120  (d_times[d_current_index + 1] - d_times[d_current_index]);
121  return (1.0 - alpha) * d_delays_samples[d_current_index] +
122  alpha * d_delays_samples[d_current_index + 1];
123  }
124 
125  // compute delay without touching d_current_index
126  double compute_tag_delay(double time) const
127  {
128  size_t current_index = d_current_index;
129  // Rewind current_index if needed
130  while (current_index >= 1 && d_times[current_index] > time) {
131  --current_index;
132  }
133  // Advance current_index so that the next time is greater than the
134  // current.
135  while (current_index + 1 < d_times.size() && d_times[current_index + 1] <= time) {
136  ++current_index;
137  }
138  if ((time < d_times[current_index]) || (current_index + 1 == d_times.size())) {
139  // We are before the beginning or past the end of the file, so we
140  // maintain a constant delay.
141  return d_delays_samples[current_index];
142  }
143  // Linearly interpolate delay
144  double alpha = (time - d_times[current_index]) /
145  (d_times[current_index + 1] - d_times[current_index]);
146  return (1.0 - alpha) * d_delays_samples[current_index] +
147  alpha * d_delays_samples[current_index + 1];
148  }
149 
150 public:
151  time_dependent_delay_impl(const std::string& filename,
152  double samp_rate,
153  double t0,
154  const std::vector<float>& taps,
155  int num_filters);
157 
158  void set_time(double) override;
159 
160  double time() override
161  {
162  gr::thread::scoped_lock guard(d_setlock);
163  return d_current_time;
164  }
165 
166  double delay() override
167  {
168  gr::thread::scoped_lock guard(d_setlock);
169  return d_current_delay / d_samp_rate;
170  }
171 
172  int work(int noutput_items,
173  gr_vector_const_void_star& input_items,
174  gr_vector_void_star& output_items) override;
175 };
176 
177 } // namespace satellites
178 } // namespace gr
179 
180 #endif /* INCLUDED_SATELLITES_TIME_DEPENDENT_DELAY_IMPL_H */
Definition: time_dependent_delay_impl.h:21
time_dependent_delay_impl(const std::string &filename, double samp_rate, double t0, const std::vector< float > &taps, int num_filters)
double delay() override
Returns the current delay in seconds.
Definition: time_dependent_delay_impl.h:166
double time() override
Returns the current time.
Definition: time_dependent_delay_impl.h:160
void set_time(double) override
Sets the current time.
int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) override
Applies a time-dependent group delay by using a delay vs. time textfile.
Definition: time_dependent_delay.h:40
Definition: ax100_decode.h:17