JayBeams  0.1
Another project to have fun coding.
time_delay_estimator_many.hpp
Go to the documentation of this file.
1 #ifndef jb_fftw_time_delay_estimator_many_hpp
2 #define jb_fftw_time_delay_estimator_many_hpp
3 
5 #include <jb/fftw/plan.hpp>
6 #include <jb/fftw/tde_result.hpp>
7 #include <jb/complex_traits.hpp>
8 
9 /*
10 #include <jb/testing/check_close_enough.hpp>
11 */
12 
13 namespace jb {
14 namespace fftw {
15 
16 /**
17  * A time delay estimator based on cross-correlation.
18  *
19  * Timeseries are implemented as standard containers (e.g. vector<>), as well as
20  * boost multi arrays of N dimensions
21  *
22  * @tparam array_t timeseries array type
23  */
24 template <typename array_t>
26 public:
27  //@{
28 
29  /**
30  * @name Type traits
31  */
32  /// The input timeseries type
33  using array_type = array_t;
34 
35  /// The values stored in the input timeseries
36  using element_type =
38 
39  /// Extract T out of std::complex<T>, otherwise simply T.
40  using precision_type =
42 
43  /// complex_type use by FFT plans frequency array type
44  using complex_type = std::complex<precision_type>;
45 
46  /// The type used to store the DFT of the input timeseries
49 
50  /// The type used to store the inverse of the DFT
53 
54  /// The execution plan to apply the (forward) DFT
56 
57  /// The execution plan to apply the inverse (aka backward) DFT
59 
60  /// The type used to store the TDE confidence between two timeseries
62 
63  /// The type used to store the estimated_delay between two timeseries
65 
66  /// The sqr sum of a timeseries
68 
69  //@}
70 
71  /**
72  * Constructs a time delay estimator using @a a and @a b as prototypes
73  * for the arguments.
74  *
75  * The optimal algorithm to compute the FFTs used in the cross correlation
76  * depends on the size of the input parameters and their memory alignment.
77  *
78  * The FFTW library modifies the arguments to compute the optimal
79  * execution plan, do not assume the values are unmodified.
80  *
81  * @param a multi array timeseries
82  * @param b multi array timeseries
83  */
85  : tmpa_(jb::detail::array_shape(a))
86  , tmpb_(jb::detail::array_shape(b))
89  , out_(jb::detail::array_shape(a))
91  , nsamples_(jb::detail::nsamples(a))
92  , num_timeseries_(jb::detail::element_count(a) / nsamples_) {
94  throw std::invalid_argument("size mismatch in time_delay_estimator ctor");
95  }
96  }
97 
98  /**
99  * Compute the time-delay estimate between two timeseries a and b.
100  *
101  * @param confidence to return the TDE(a,b) confidence
102  * @param estimated_delay to return the result of TDE(a,b)
103  * @param a input timeseries, FFTW library might modify their values
104  * @param b input timeseries, FFTW library might modify their values
105  * @param sum2 contains sqr sum of one of the timeseries (a or b)
106  */
108  confidence_type& confidence, estimated_delay_type& estimated_delay,
109  array_type& a, array_type& b, sum2_type const& sum2) {
110  // Validate the input sizes. For some types of timeseries the
111  // alignment may be different too, but we only use the alignment
112  // when the type of timeseries guarantees to always be aligned.
115  throw std::invalid_argument(
116  "shape mismatch in time_delay_estimator<>::estimate_delay()");
117  }
118  // First we apply the Fourier transform to both inputs ...
119  a2tmpa_.execute(a, tmpa_);
120  b2tmpb_.execute(b, tmpb_);
121  // ... then we compute Conj(A) * B for the transformed inputs ...
122  // @todo issue #86: investigate use of SSE instructions
123  complex_type* it_tmpa = tmpa_.data();
124  complex_type* it_tmpb = tmpb_.data();
125  for (std::size_t i = 0; i != jb::detail::element_count(tmpa_);
126  ++i, ++it_tmpa, ++it_tmpb) {
127  *it_tmpa = std::conj(*it_tmpa) * (*it_tmpb);
128  }
129  // ... then we compute the inverse Fourier transform to the result ...
131 
132  // ... finally we compute the estimated delay and its confidence
133  // @todo issue #86: investigate use of SSE instructions
134  precision_type* it_out = out_.data();
135  for (std::size_t i = 0; i != num_timeseries_; ++i) {
136  precision_type max_val = std::numeric_limits<precision_type>::min();
137  std::size_t tde_val = 0;
138  for (std::size_t j = 0; j != nsamples_; ++j, ++it_out) {
139  if (max_val < *it_out) {
140  max_val = *it_out;
141  tde_val = j;
142  }
143  }
144  if (sum2[i] < std::numeric_limits<precision_type>::epsilon()) {
145  confidence[i] = precision_type(0);
146  } else {
147  confidence[i] = max_val / sum2[i];
148  }
149  estimated_delay[i] = tde_val;
150  }
151  }
152 
153 private:
154  /**
155  * Determine the correct FFTW planning flags given the inputs.
156  */
157  static int planning_flags() {
159  return FFTW_MEASURE | FFTW_PRESERVE_INPUT;
160  }
161  return FFTW_MEASURE | FFTW_PRESERVE_INPUT | FFTW_UNALIGNED;
162  }
163 
164 private:
165  /// tmpa_ : timeseries to store the result of FFT(a)
167  /// tmpb_ : timeseries to store the result of FFT(b)
169  /// a2tmpa_ : fftw plan to execute FFT(a)
171  /// b2tmpb_ : fftw plan to execute FFT(b)
173  /// out_ : timeseries to store the result of inverse FFT
175  /// tmpa2out : fftw plan to execute inverse FFT of a timeseries
177  /// nsamples : num samples of timeseries
178  std::size_t nsamples_;
179  /// num_timeseries : num of timeseries contained in a and b
180  std::size_t num_timeseries_;
181 };
182 
183 } // namespace fftw
184 } // namespace jb
185 
186 #endif // jb_fftw_time_delay_estimator_many_hpp
typename container_type::value_type element_type
Define the type of the elements in the container.
typename jb::extract_value_type< element_type >::precision precision_type
Extract T out of std::complex<T>, otherwise simply T.
output_array_type out_
out_ : timeseries to store the result of inverse FFT
plan< in_array_type, out_array_type > create_forward_plan(in_array_type const &in, out_array_type &out, int flags=default_plan_flags)
Create a plan to compute many DFTs given the input and output arrays.
Definition: plan.hpp:231
A time-delay estimator (TDE) is an algorithm to compare two families of timeseries and return the est...
Definition: tde_result.hpp:37
void execute(in_timeseries_type const &in, out_timeseries_type &out) const
Execute the plan for vectors.
Definition: plan.hpp:106
std::size_t nsamples_
nsamples : num samples of timeseries
std::size_t array_shape(container_type const &a)
Return the shape of the container in a form suitable for construction of a vector-like container...
time_delay_estimator_many(array_type &a, array_type &b)
Constructs a time delay estimator using a and b as prototypes for the arguments.
typename jb::detail::array_traits< array_type >::element_type element_type
The values stored in the input timeseries.
frequency_array_type tmpa_
tmpa_ : timeseries to store the result of FFT(a)
A time delay estimator based on cross-correlation.
void estimate_delay(confidence_type &confidence, estimated_delay_type &estimated_delay, array_type &a, array_type &b, sum2_type const &sum2)
Compute the time-delay estimate between two timeseries a and b.
Alias array_type based on the container_type shape to store value_type.
iplan tmpa2out_
tmpa2out : fftw plan to execute inverse FFT of a timeseries
typename jb::detail::aligned_container< precision_type, array_type >::array_type output_array_type
The type used to store the inverse of the DFT.
frequency_array_type tmpb_
tmpb_ : timeseries to store the result of FFT(b)
std::complex< precision_type > complex_type
complex_type use by FFT plans frequency array type
plan< in_array_type, out_array_type > create_backward_plan(in_array_type const &in, out_array_type &out, int flags=default_plan_flags)
Create a plan to compute many inverse DFT given the input and output arrays.
Definition: plan.hpp:261
typename jb::detail::aligned_container< complex_type, array_type >::array_type frequency_array_type
The type used to store the DFT of the input timeseries.
array_t array_type
The input timeseries type.
static int planning_flags()
Determine the correct FFTW planning flags given the inputs.
std::size_t nsamples(container_type const &a)
Count the elements in the last dimension of a vector-like container.
Determine if a timeseries type guarantees alignment suitable for SIMD optimizations.
std::size_t num_timeseries_
num_timeseries : num of timeseries contained in a and b
dplan b2tmpb_
b2tmpb_ : fftw plan to execute FFT(b)
dplan a2tmpa_
a2tmpa_ : fftw plan to execute FFT(a)
std::size_t element_count(container_type const &a)
Count the number of elements for a vector-like container.
The top-level namespace for the JayBeams library.
Definition: as_hhmmss.hpp:7