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
17namespace gr {
18namespace satellites {
19
21{
22private:
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
150public:
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 */
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:18
Definition ax100_decode.h:17