File: time_dependent_delay_impl.h

package info (click to toggle)
gr-satellites 5.8.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,836 kB
  • sloc: python: 29,546; cpp: 5,448; ansic: 1,247; sh: 118; makefile: 24
file content (180 lines) | stat: -rw-r--r-- 6,378 bytes parent folder | download
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* -*- c++ -*- */
/*
 * Copyright 2025 Daniel Estevez <daniel@destevez.net>.
 *
 * This file is part of gr-satellites
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#ifndef INCLUDED_SATELLITES_TIME_DEPENDENT_DELAY_IMPL_H
#define INCLUDED_SATELLITES_TIME_DEPENDENT_DELAY_IMPL_H

#include <gnuradio/filter/fir_filter.h>
#include <satellites/time_dependent_delay.h>
#include <cstdint>

namespace gr {
namespace satellites {

class time_dependent_delay_impl : public time_dependent_delay
{
private:
    const double d_samp_rate;
    size_t d_current_index;
    double d_t0;
    uint64_t d_sample_t0;
    std::vector<double> d_times;
    std::vector<double> d_delays_samples; // delays in the file in units of samples
    std::vector<gr::filter::kernel::fir_filter_ccf> d_filters;
    const double d_fir_delay;
    const int d_taps_per_filter;
    std::vector<gr::tag_t> d_future_tags;

    // Used by UHD
    const pmt::pmt_t d_rx_time_key;

    // Used by gr-difi
    const pmt::pmt_t d_pck_n_key;
    const pmt::pmt_t d_full_key;
    const pmt::pmt_t d_frac_key;

    double d_current_time;
    double d_current_delay; // current delay in units of samples

    // Called after a time update. Makes the current index go backwards if
    // needed because of a time update "to the past".
    void adjust_current_index()
    {
        while ((d_current_index > 0) && (d_times[d_current_index] > d_t0)) {
            --d_current_index;
        }
    }

    void read_delay_file(const std::string& filename);

    void update_time_from_tags(int noutput_items)
    {
        std::vector<gr::tag_t> tags;
        get_tags_in_window(tags, 0, 0, noutput_items);
        for (const auto& tag : tags) {
            double t0;
            bool set = false;
            if (pmt::eqv(tag.key, d_rx_time_key)) {
                if (pmt::is_tuple(tag.value)) {
                    t0 = static_cast<double>(
                             pmt::to_uint64(pmt::tuple_ref(tag.value, 0))) +
                         pmt::to_double(pmt::tuple_ref(tag.value, 1));
                    set = true;
                }
            } else if (pmt::eqv(tag.key, d_pck_n_key)) {
                if (pmt::is_dict(tag.value)) {
                    const auto full_pmt =
                        pmt::dict_ref(tag.value, d_full_key, pmt::PMT_NIL);
                    const auto frac_pmt =
                        pmt::dict_ref(tag.value, d_frac_key, pmt::PMT_NIL);
                    if (pmt::is_integer(full_pmt) && pmt::is_uint64(frac_pmt)) {
                        const auto full = pmt::to_long(full_pmt);
                        const auto frac = pmt::to_uint64(frac_pmt);
                        // in DIFI, frac gives the number of picoseconds
                        t0 =
                            static_cast<double>(full) + 1e-12 * static_cast<double>(frac);
                        set = true;
                    }
                }
            }

            if (set) {
                d_sample_t0 = tag.offset;
                d_t0 = t0;
                d_logger->info("set time {} at sample {}", d_t0, d_sample_t0);
                adjust_current_index();
            }
        }
    }

    // this cannot be const, because nitems_written() is not const
    double compute_time(uint64_t sample_absolute_idx) const
    {
        return d_t0 + static_cast<double>(static_cast<int64_t>(sample_absolute_idx) -
                                          static_cast<int64_t>(d_sample_t0)) /
                          d_samp_rate;
    }

    double compute_delay(double time)
    {
        // Advance d_current_index so that the next time is greater than the
        // current.
        while (d_current_index + 1 < d_times.size() &&
               d_times[d_current_index + 1] <= time) {
            ++d_current_index;
        }
        if ((time < d_times[d_current_index]) ||
            (d_current_index + 1 == d_times.size())) {
            // We are before the beginning or past the end of the file, so we
            // maintain a constant delay.
            return d_delays_samples[d_current_index];
        }
        // Linearly interpolate delay
        double alpha = (time - d_times[d_current_index]) /
                       (d_times[d_current_index + 1] - d_times[d_current_index]);
        return (1.0 - alpha) * d_delays_samples[d_current_index] +
               alpha * d_delays_samples[d_current_index + 1];
    }

    // compute delay without touching d_current_index
    double compute_tag_delay(double time) const
    {
        size_t current_index = d_current_index;
        // Rewind current_index if needed
        while (current_index >= 1 && d_times[current_index] > time) {
            --current_index;
        }
        // Advance current_index so that the next time is greater than the
        // current.
        while (current_index + 1 < d_times.size() && d_times[current_index + 1] <= time) {
            ++current_index;
        }
        if ((time < d_times[current_index]) || (current_index + 1 == d_times.size())) {
            // We are before the beginning or past the end of the file, so we
            // maintain a constant delay.
            return d_delays_samples[current_index];
        }
        // Linearly interpolate delay
        double alpha = (time - d_times[current_index]) /
                       (d_times[current_index + 1] - d_times[current_index]);
        return (1.0 - alpha) * d_delays_samples[current_index] +
               alpha * d_delays_samples[current_index + 1];
    }

public:
    time_dependent_delay_impl(const std::string& filename,
                              double samp_rate,
                              double t0,
                              const std::vector<float>& taps,
                              int num_filters);
    ~time_dependent_delay_impl() override;

    void set_time(double) override;

    double time() override
    {
        gr::thread::scoped_lock guard(d_setlock);
        return d_current_time;
    }

    double delay() override
    {
        gr::thread::scoped_lock guard(d_setlock);
        return d_current_delay / d_samp_rate;
    }

    int work(int noutput_items,
             gr_vector_const_void_star& input_items,
             gr_vector_void_star& output_items) override;
};

} // namespace satellites
} // namespace gr

#endif /* INCLUDED_SATELLITES_TIME_DEPENDENT_DELAY_IMPL_H */