DP3
KernelSmoother.h
Go to the documentation of this file.
1 // Copyright (C) 2020 ASTRON (Netherlands Institute for Radio Astronomy)
2 // SPDX-License-Identifier: GPL-3.0-or-later
3 
4 #ifndef DP3_DDECAL_KERNEL_SMOOTHER_H_
5 #define DP3_DDECAL_KERNEL_SMOOTHER_H_
6 
7 #include <cmath>
8 #include <complex>
9 #include <stdexcept>
10 #include <vector>
11 #include <limits>
12 
13 namespace dp3 {
14 namespace ddecal {
15 
28 template <typename DataType, typename NumType>
30  public:
31  enum KernelType {
38  };
39 
57  KernelSmoother(const std::vector<NumType>& frequencies, KernelType kernelType,
58  NumType kernelBandwidth, NumType bandwidthRefFrequency,
59  NumType spectralExponent, bool kernel_truncation)
60  : _frequencies(frequencies),
61  _scratch(frequencies.size()),
62  _kernelType(kernelType),
63  _bandwidth(kernelBandwidth),
64  _bandwidthRefFrequency(bandwidthRefFrequency),
65  _spectralExponent(spectralExponent),
66  _truncate(kernel_truncation) {}
67 
75  NumType Kernel(NumType distance) const {
76  NumType x = distance / _bandwidth;
77  switch (_kernelType) {
78  case RectangularKernel:
79  default:
80  if (x < NumType(-1.0) || x > NumType(1.0))
81  return NumType(0.0);
82  else
83  return NumType(0.5);
84  case TriangularKernel:
85  if (x < NumType(-1.0) || x > NumType(1.0))
86  return NumType(0.0);
87  else
88  return x >= NumType(0.0) ? (NumType(1.0) - x) : (NumType(1.0) + x);
89  case GaussianKernel:
91  if (_truncate && (x < NumType(-1.0) || x > NumType(1.0)))
92  return 0.0;
93  else
94  return std::exp(-x * x * NumType(9.0));
95  case EpanechnikovKernel:
97  if (_truncate && (x < NumType(-1.0) || x > NumType(1.0))) {
98  return 0.0;
99  } else {
100  x = NumType(1.0) - x;
101  return (NumType(3.0) / NumType(4.0)) * x * x;
102  }
103  }
104  }
105 
114  void Smooth(DataType* data, const NumType* weight, NumType kernelSizeFactor) {
115  size_t n = _frequencies.size();
116 
117  size_t bandLeft = 0;
119  const size_t lbound =
120  std::lower_bound(_frequencies.begin(), _frequencies.end(),
121  _frequencies[0] + _bandwidth * 0.5) -
122  _frequencies.begin();
123  size_t bandRight = std::min(lbound + 1u, n);
124  for (size_t i = 0; i != n; ++i) {
125  size_t start = 0;
126  size_t end = n;
127  const NumType localBandwidth =
128  _bandwidthRefFrequency == 0.0
129  ? _bandwidth
130  : _bandwidth * _frequencies[i] / _bandwidthRefFrequency;
131  if (_truncate) {
133  while (_frequencies[bandLeft] < _frequencies[i] - localBandwidth * 0.5)
134  ++bandLeft;
135  while (bandRight != n &&
136  _frequencies[bandRight] < _frequencies[i] + localBandwidth * 0.5)
137  ++bandRight;
138 
142  start = bandLeft > 0 ? bandLeft - 1 : 0;
143  end = bandRight < n ? bandRight + 1 : n;
144  }
145 
146  DataType sum(0.0);
147  NumType weightSum(0.0);
148  const NumType frequencyCorrection =
149  std::pow(localBandwidth / _bandwidth, _spectralExponent);
150  const NumType kernelCorrection = frequencyCorrection * kernelSizeFactor;
151  for (size_t j = start; j != end; ++j) {
152  NumType distance = _frequencies[i] - _frequencies[j];
153  double w = Kernel(distance * kernelCorrection) * weight[j];
154  sum += data[j] * w;
155  weightSum += w;
156  }
157  if (weightSum == 0.0)
158  _scratch[i] = quiet_NaN(_scratch[i]);
159  else
160  _scratch[i] = sum / weightSum;
161  }
162  std::copy(_scratch.begin(), _scratch.end(), data);
163  }
164 
165  private:
166  double quiet_NaN(double) { return std::numeric_limits<double>::quiet_NaN(); }
167 
168  std::complex<double> quiet_NaN(std::complex<double>) {
169  return std::complex<double>(std::numeric_limits<double>::quiet_NaN(),
170  std::numeric_limits<double>::quiet_NaN());
171  }
172 
173  std::vector<NumType> _frequencies;
174  std::vector<DataType> _scratch;
175  enum KernelType _kernelType;
176  NumType _bandwidth;
177  NumType _bandwidthRefFrequency;
178  NumType _spectralExponent;
179  bool _truncate = true;
180 };
181 
182 } // namespace ddecal
183 } // namespace dp3
184 
185 #endif
Smooths a series of possibly irregularly gridded values by a given kernel.
Definition: KernelSmoother.h:29
KernelType
Definition: KernelSmoother.h:31
@ EpanechnikovKernel
Definition: KernelSmoother.h:37
@ RectangularKernel
Definition: KernelSmoother.h:32
@ TriangularKernel
Definition: KernelSmoother.h:33
@ GaussianKernel
Definition: KernelSmoother.h:35
void Smooth(DataType *data, const NumType *weight, NumType kernelSizeFactor)
Definition: KernelSmoother.h:114
KernelSmoother(const std::vector< NumType > &frequencies, KernelType kernelType, NumType kernelBandwidth, NumType bandwidthRefFrequency, NumType spectralExponent, bool kernel_truncation)
Definition: KernelSmoother.h:57
NumType Kernel(NumType distance) const
Definition: KernelSmoother.h:75
This file has generic helper routines for testing steps.
Definition: AntennaConfig.h:53