sablib
Loading...
Searching...
No Matches
moving_median.cpp
Go to the documentation of this file.
1
6
7#include <algorithm>
8#include <set>
9
10#include "moving_median.h"
11
12namespace sablib {
13
14namespace {
15
16//
17// Implementation of SlidingMedian class
18//
19class SlidingMedian
20{
21public:
22 SlidingMedian(const unsigned int n) : window_size(2 * n + 1) {};
23
24 void Add(const double value)
25 {
26 if(low.empty() || value <= *low.rbegin()) {
27 low.insert(value);
28 }
29 else {
30 high.insert(value);
31 }
32
33 Rebalance();
34 }
35
36 void Remove(const double value)
37 {
38 auto it = low.find(value);
39
40 if(it != low.end()) {
41 low.erase(it);
42 }
43 else {
44 it = high.find(value);
45
46 if(it != high.end()) {
47 high.erase(it);
48 }
49 }
50
51 Rebalance();
52 }
53
54 double Median() const
55 {
56 if(window_size % 2 == 1) {
57 return *low.rbegin();
58 }
59 else {
60 return (*low.rbegin() + *high.begin()) / 2;
61 }
62 }
63
64private:
65 unsigned int window_size;
66 // low : lower value group
67 // high: higher value group
68 std::multiset<double> high, low;
69
70 void Rebalance()
71 {
72 if(low.size() > high.size() + 1) {
73 high.insert(*low.rbegin());
74 low.erase(low.find(*low.rbegin()));
75 }
76 else if(high.size() > low.size()) {
77 low.insert(*high.begin());
78 high.erase(high.begin());
79 }
80 }
81};
82
83}; // unnamed namespace
84
85//
86// Implementation of MovingMedian() function
87//
88const std::vector<double> MovingMedian(const std::vector<double> & y, const unsigned int n)
89{
90 if(y.size() == 0) {
91 throw std::invalid_argument("MovingMedian(): the length of y is zero.");
92 }
93
94 if(n == 0) {
95 throw std::invalid_argument("MovingMedian(): n is zero.");
96 }
97
98 unsigned int points = 2 * n + 1;
99 SlidingMedian smed(n);
100 std::vector<double> yy(y.size() + 2 * n), result;
101
102 std::fill_n(yy.begin(), n, y.front());
103 std::copy(y.begin(), y.end(), yy.begin() + n);
104 std::fill_n(yy.begin() + n + y.size(), n, y.back());
105
106 result.reserve(y.size());
107
108 for(unsigned int i = 0; i < yy.size(); i++) {
109 smed.Add(yy[i]);
110
111 if(i >= points) {
112 smed.Remove(yy[i - points]);
113 }
114
115 if(i > points) {
116 result.emplace_back(smed.Median());
117 }
118 }
119
120 return result;
121}
122
123}; // namespace sablib
const std::vector< double > MovingMedian(const std::vector< double > &y, const unsigned int n)
Performs moving median smoothing.
Smoothing using moving median.