4 #ifndef DP3_DDECAL_PIECE_WISE_PHASE_FITTER_H_
5 #define DP3_DDECAL_PIECE_WISE_PHASE_FITTER_H_
30 template <
typename Iter>
31 static void Unwrap(Iter first, Iter last) {
32 for (Iter iter = first + 1; iter != last; ++iter) {
33 while (*iter - (*(iter - 1)) > M_PI) *iter -= 2.0 * M_PI;
34 while ((*(iter - 1) - *iter) > M_PI) *iter += 2.0 * M_PI;
40 const double nOctaves =
41 (log(frequencies.back()) - log(frequencies.front())) / M_LN2;
43 return std::min<size_t>(frequencies.size(), std::ceil(frequencies.size() /
46 return frequencies.size();
61 const std::vector<double>& data,
62 std::vector<double>& fittedData) {
63 size_t chunkSize = std::min(data.size(), _chunkSize);
67 for (
size_t ch = 0; ch < data.size(); ch += chunkSize) {
69 if (pos > data.size() - chunkSize) pos = data.size() - chunkSize;
70 fitChunk(chunkSize, pos, nu, data, fittedData);
76 const std::vector<double>& data,
const double* weights,
77 std::vector<double>& fittedData) {
78 size_t chunkSize = std::min(data.size(), _chunkSize);
82 for (
size_t ch = 0; ch < data.size(); ch += chunkSize) {
84 if (pos > data.size() - chunkSize) pos = data.size() - chunkSize;
85 fitChunk(chunkSize, pos, nu, data, weights, fittedData);
94 void SlidingFit(
const double* nu,
const double* data,
double* fittedData,
96 const size_t chunkSize = std::min(_chunkSize, n);
98 std::copy(data, data + n, fittedData);
100 const size_t leftEdge = chunkSize / 2,
101 rightEdge = n - chunkSize + chunkSize / 2;
104 PieceWisePhaseFitter::fitSlope(&data[0], &nu[0], chunkSize, a, b);
105 for (
size_t ch = 0; ch != leftEdge; ++ch) fittedData[ch] = a + b * nu[ch];
107 for (
size_t ch = 0; ch != n - chunkSize; ++ch) {
108 PieceWisePhaseFitter::fitSlope(&data[ch], &nu[ch], chunkSize, a, b);
109 fittedData[ch + chunkSize / 2] = a + b * nu[ch + chunkSize / 2];
112 PieceWisePhaseFitter::fitSlope(&data[n - chunkSize], &nu[n - chunkSize],
114 for (
size_t ch = rightEdge; ch != n; ++ch)
115 fittedData[ch] = a + b * nu[ch];
136 void SlidingFit(
const double* nu,
const double* data,
const double* weights,
137 double* fittedData,
size_t n) {
138 const size_t chunkSize = std::min(_chunkSize, n);
140 std::copy(data, data + n, fittedData);
142 const size_t leftEdge = chunkSize / 2,
143 rightEdge = n - chunkSize + chunkSize / 2;
146 PieceWisePhaseFitter::fitSlope(&data[0], &nu[0], &weights[0], chunkSize,
148 for (
size_t ch = 0; ch != leftEdge; ++ch) fittedData[ch] = a + b * nu[ch];
150 for (
size_t ch = 0; ch != n - chunkSize; ++ch) {
151 PieceWisePhaseFitter::fitSlope(&data[ch], &nu[ch], &weights[ch],
153 fittedData[ch + chunkSize / 2] = a + b * nu[ch + chunkSize / 2];
156 PieceWisePhaseFitter::fitSlope(&data[n - chunkSize], &nu[n - chunkSize],
157 &weights[n - chunkSize], chunkSize, a, b);
158 for (
size_t ch = rightEdge; ch != n; ++ch)
159 fittedData[ch] = a + b * nu[ch];
164 const double* weights,
double* fittedData,
166 if (std::min(_chunkSize, n) <= 1) {
167 std::copy(data, data + n, fittedData);
171 size_t bp =
BreakPoint(data, weights, fittedData, n);
172 SlidingFit(nu, data, weights, fittedData, bp);
173 SlidingFit(nu + bp, data + bp, weights + bp, fittedData + bp, n - bp);
190 if (values.empty())
return 0.0;
191 std::sort(values.begin(), values.end());
194 for (std::pair<double, double>& v : values) sum += v.second;
198 double prefixSum = sum - values[0].second;
199 while (prefixSum > sum / 2) {
201 prefixSum -= values[index].second;
203 return values[index].first;
207 const double* fittedData,
size_t n) {
208 double largest = 0.0;
210 size_t ni = std::min(n, _chunkSize);
211 for (
size_t i = 0; i != n - ni; ++i) {
213 for (
size_t j = 0; j != ni; ++j) {
214 double dist = data[i + j] - fittedData[i + j];
215 curSum += std::abs(dist) * weights[i + j];
217 if (curSum > largest) {
219 index = i + _chunkSize / 2;
230 std::vector<double> _tempArray;
231 std::vector<std::pair<double, double>> _tempWeightedArray;
236 void fitSlope(
const double* data,
const double* frequencies,
size_t n,
237 double& a,
double& b) {
238 double sum_x = 0.0, sum_xSq = 0.0, mean_y = 0.0, ss_xy = 0.0;
239 std::vector<double>& d = _tempArray;
240 d.assign(data, data + n);
241 size_t qCounts[4] = {0, 0, 0, 0};
242 for (
double& v : d) {
245 else if (v > M_PI * 1.0)
247 else if (v > M_PI * 0.5)
253 for (
size_t i = 1; i != 4; ++i) {
254 if (qCounts[i] > qCounts[maxQ]) maxQ = i;
256 double wrapTo = (maxQ * 0.5 + 0.25) * M_PI;
257 for (
double& v : d) {
258 if (v - wrapTo > M_PI)
260 else if (v - wrapTo < -M_PI)
263 std::nth_element(d.data(), d.data() + n / 2, d.data() + n);
265 for (
size_t i = 0; i != n; ++i) {
267 if (x - wrapTo > M_PI)
269 else if (x - wrapTo < -M_PI)
271 sum_x += frequencies[i];
272 sum_xSq += frequencies[i] * frequencies[i];
274 ss_xy += frequencies[i] * x;
277 double mean_x = sum_x / n;
278 double ss_xx = sum_xSq - mean_x * sum_x;
279 ss_xy -= sum_x * mean_y;
281 a = mean_y - b * mean_x;
284 template <
typename Iter1,
typename Iter2>
285 double weightedMedian(Iter1 valBegin, Iter1 valEnd, Iter2 weightBegin) {
286 _tempWeightedArray.resize(std::distance(valBegin, valEnd));
287 auto wIter = _tempWeightedArray.begin();
288 while (valBegin != valEnd) {
289 *wIter = std::make_pair(*valBegin, *weightBegin);
300 void fitSlope(
const double* data,
const double* frequencies,
301 const double* weights,
size_t n,
double& a,
double& b) {
302 size_t qCounts[4] = {0, 0, 0, 0};
303 for (
size_t i = 0; i != n; ++i) {
304 if (data[i] > M_PI * 1.5)
305 qCounts[3] += weights[i];
306 else if (data[i] > M_PI * 1.0)
307 qCounts[2] += weights[i];
308 else if (data[i] > M_PI * 0.5)
309 qCounts[1] += weights[i];
311 qCounts[0] += weights[i];
314 for (
size_t i = 1; i != 4; ++i) {
315 if (qCounts[i] > qCounts[maxQ]) maxQ = i;
317 double wrapTo = (maxQ * 0.5 + 0.25) * M_PI;
318 std::vector<double>& d = _tempArray;
320 for (
size_t i = n / 4; i != n * 3 / 4; ++i) {
322 if (v - wrapTo > M_PI)
324 else if (v - wrapTo < -M_PI)
329 weightedMedian(d.data() + n / 4, d.data() + n * 3 / 4, weights + n / 4);
331 double sum_x = 0.0, sum_xSq = 0.0, mean_y = 0.0, ss_xy = 0.0,
334 for (
size_t i = 0; i != n; ++i) {
336 if (x - wrapTo > M_PI)
338 else if (x - wrapTo < -M_PI)
340 sum_x += frequencies[i] * weights[i];
341 sum_xSq += frequencies[i] * frequencies[i] * weights[i];
342 mean_y += x * weights[i];
343 ss_xy += frequencies[i] * x * weights[i];
344 sum_weight += weights[i];
346 if (sum_weight == 0.0) {
350 mean_y /= sum_weight;
351 double mean_x = sum_x / sum_weight;
352 double ss_xx = sum_xSq - mean_x * sum_x;
353 ss_xy -= sum_x * mean_y;
355 a = mean_y - b * mean_x;
359 void fitChunk(
size_t chunkSize,
size_t pos,
const std::vector<double>& nu,
360 const std::vector<double>& data,
361 std::vector<double>& fittedData) {
363 PieceWisePhaseFitter::fitSlope(&data[pos], &nu[pos], chunkSize, a, b);
364 for (
size_t ch = 0; ch != chunkSize; ++ch)
365 fittedData[ch + pos] = a + b * nu[ch + pos];
368 void fitChunk(
size_t chunkSize,
size_t pos,
const std::vector<double>& nu,
369 const std::vector<double>& data,
const double* weights,
370 std::vector<double>& fittedData) {
372 PieceWisePhaseFitter::fitSlope(&data[pos], &nu[pos], &weights[pos],
374 for (
size_t ch = 0; ch != chunkSize; ++ch)
375 fittedData[ch + pos] = a + b * nu[ch + pos];
382 static bool removeDeviations(std::vector<double>& data,
383 std::vector<double>& frequencies,
double a,
384 double b,
double phaseThreshold) {
385 if (data.empty())
return false;
388 for (
size_t i = 0; i != data.size(); ++i) {
389 double deviation = std::abs(data[i] - (a + b * frequencies[i]));
390 if (deviation >= maxDev) {
395 if (maxDev > phaseThreshold) {
396 data.erase(data.begin() + index);
397 frequencies.erase(frequencies.begin() + index);
Definition: PieceWisePhaseFitter.h:14
void PieceWiseFit(const std::vector< double > &nu, const std::vector< double > &data, const double *weights, std::vector< double > &fittedData)
Definition: PieceWisePhaseFitter.h:75
void PieceWiseFit(const std::vector< double > &nu, const std::vector< double > &data, std::vector< double > &fittedData)
Definition: PieceWisePhaseFitter.h:60
void SlidingFit(const double *nu, const double *data, const double *weights, double *fittedData, size_t n)
Definition: PieceWisePhaseFitter.h:136
static double WeightedMedian(std::vector< std::pair< double, double >> &values)
Definition: PieceWisePhaseFitter.h:189
PieceWisePhaseFitter()
Definition: PieceWisePhaseFitter.h:16
void SetChunkSize(size_t chunkSize)
Definition: PieceWisePhaseFitter.h:25
static void Unwrap(Iter first, Iter last)
Definition: PieceWisePhaseFitter.h:31
size_t SlidingFitWithBreak(const double *nu, const double *data, const double *weights, double *fittedData, size_t n)
Definition: PieceWisePhaseFitter.h:163
void SlidingFit(const double *nu, const double *data, double *fittedData, size_t n)
Definition: PieceWisePhaseFitter.h:94
static size_t CalculateChunkSize(const std::vector< double > &frequencies)
Definition: PieceWisePhaseFitter.h:38
size_t ChunkSize() const
Definition: PieceWisePhaseFitter.h:24
size_t BreakPoint(const double *data, const double *weights, const double *fittedData, size_t n)
Definition: PieceWisePhaseFitter.h:206
PieceWisePhaseFitter(size_t chunkSize)
Definition: PieceWisePhaseFitter.h:22
This file has generic helper routines for testing steps.
Definition: AntennaConfig.h:53