Skip to content

Commit b9a07b9

Browse files
committed
Template the input type of median filter.
This allows specifying the input type.
1 parent 2bace1c commit b9a07b9

File tree

7 files changed

+102
-71
lines changed

7 files changed

+102
-71
lines changed

examples/median-filter/median-filter.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
const uint8_t kInputPin = 0;
44
const uint8_t kLedPin = 13;
5-
MedianFilter<uint32_t, 5> *filter;
5+
MedianFilter<uint32_t, uint32_t, 5> *filter;
66

77
void setup() {
88
pinMode(kInputPin, INPUT_PULLUP);
9-
filter = new MedianFilter<uint32_t, 5>(filter_functions::ForAnalogRead<kInputPin>());
9+
filter = new MedianFilter<uint32_t, uint32_t, 5>(filter_functions::ForAnalogRead<kInputPin>());
1010
filter->SetLogToSerial(true);
1111

1212
pinMode(kLedPin, OUTPUT);

src/median-filter.h

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
#include "filter.h"
1515

1616
namespace median_filter {
17+
template <typename ValueType>
1718
struct ValuePoint {
18-
uint32_t value;
19+
ValueType value;
1920
uint8_t index;
2021
};
2122
} // namespace median_filter
@@ -28,21 +29,21 @@ struct ValuePoint {
2829
// iterate through the buffer at most once.
2930
//
3031
// For even sizes, this returns the lower median.
31-
template <typename OutputType, uint8_t size>
32-
class MedianFilter : public Filter<uint32_t, OutputType> {
33-
using Filter<uint32_t, OutputType>::sensor_value_;
32+
template <typename InputType, typename OutputType, uint8_t size>
33+
class MedianFilter : public Filter<InputType, OutputType> {
34+
using Filter<InputType, OutputType>::sensor_value_;
3435

3536
public:
36-
MedianFilter(uint32_t (*const ReadFromSensor)());
37-
MedianFilter(uint32_t (*const ReadFromSensor)(),
38-
OutputType (*Convert)(uint32_t input));
37+
MedianFilter(InputType (*const ReadFromSensor)());
38+
MedianFilter(InputType (*const ReadFromSensor)(),
39+
OutputType (*Convert)(InputType input));
3940

4041
protected:
41-
uint32_t DoRun() override;
42+
InputType DoRun() override;
4243

4344
private:
4445
// Sorted list of recent values
45-
std::list<median_filter::ValuePoint> history_;
46+
std::list<median_filter::ValuePoint<InputType>> history_;
4647

4748
// The index of the next value to insert. Used to keep <size> elements in the
4849
// list.
@@ -53,17 +54,18 @@ class MedianFilter : public Filter<uint32_t, OutputType> {
5354
bool history_full_ = false;
5455
};
5556

56-
template <typename OutputType, uint8_t size>
57-
MedianFilter<OutputType, size>::MedianFilter(uint32_t (*const ReadFromSensor)())
58-
: Filter<uint32_t, OutputType>(ReadFromSensor) {}
57+
template <typename InputType, typename OutputType, uint8_t size>
58+
MedianFilter<InputType, OutputType, size>::MedianFilter(
59+
InputType (*const ReadFromSensor)())
60+
: Filter<InputType, OutputType>(ReadFromSensor) {}
5961

60-
template <typename OutputType, uint8_t size>
61-
MedianFilter<OutputType, size>::MedianFilter(
62-
uint32_t (*const ReadFromSensor)(), OutputType (*Convert)(uint32_t input))
63-
: Filter<uint32_t, OutputType>(ReadFromSensor, Convert) {}
62+
template <typename InputType, typename OutputType, uint8_t size>
63+
MedianFilter<InputType, OutputType, size>::MedianFilter(
64+
InputType (*const ReadFromSensor)(), OutputType (*Convert)(InputType input))
65+
: Filter<InputType, OutputType>(ReadFromSensor, Convert) {}
6466

65-
template <typename OutputType, uint8_t size>
66-
uint32_t MedianFilter<OutputType, size>::DoRun() {
67+
template <typename InputType, typename OutputType, uint8_t size>
68+
InputType MedianFilter<InputType, OutputType, size>::DoRun() {
6769
// Initial case: history has 0 or 1 elements
6870
if (history_.empty()) {
6971
history_.push_back({sensor_value_, ring_buffer_index_});
@@ -86,7 +88,7 @@ uint32_t MedianFilter<OutputType, size>::DoRun() {
8688
history_full_ = true;
8789
}
8890

89-
std::list<median_filter::ValuePoint>::iterator it = history_.begin();
91+
auto it = history_.begin();
9092
uint8_t i = 0;
9193
bool inserted = false;
9294
while (it != history_.end()) {
@@ -121,7 +123,7 @@ uint32_t MedianFilter<OutputType, size>::DoRun() {
121123

122124
// typical case: history is full
123125
uint8_t element_index_to_remove = ring_buffer_index_;
124-
std::list<median_filter::ValuePoint>::iterator it = history_.begin();
126+
auto it = history_.begin();
125127
uint8_t i = 0;
126128
bool inserted = false;
127129
bool removed = false;

test/exponential-moving-average-filter-test.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,29 @@ namespace exponential_moving_average_filter_test {
88

99
TEST(ExponentialMovingAverageFilter, alpha_half) {
1010
ExponentialMovingAverageFilter<uint32_t> *filter = new ExponentialMovingAverageFilter<uint32_t>(analogRead, 128);
11-
std::vector<InputOutput<uint32_t>> data = {
11+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
1212
{0, 10, 0},
1313
{1024, 100, 4, 1024},
1414
{1024, 100, 1024},
1515
{0, 100, 0, 1020},
1616
{0, 100, 0},
1717
};
18-
RunDataTest(filter, data);
18+
RunDataTest(filter, data, setAnalogRead);
1919
}
2020

2121
TEST(ExponentialMovingAverageFilter, alpha_full) {
2222
ExponentialMovingAverageFilter<uint32_t> *filter = new ExponentialMovingAverageFilter<uint32_t>(analogRead, 255);
23-
std::vector<InputOutput<uint32_t>> data = {
23+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
2424
{0, 10, 0},
2525
{1024, 100, 1024},
2626
{0, 100, 0},
2727
};
28-
RunDataTest(filter, data);
28+
RunDataTest(filter, data, setAnalogRead);
2929
}
3030

3131
TEST(ExponentialMovingAverageFilter, alpha_low) {
3232
ExponentialMovingAverageFilter<uint32_t> *filter = new ExponentialMovingAverageFilter<uint32_t>(analogRead, 0);
33-
std::vector<InputOutput<uint32_t>> data = {
33+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
3434
{0, 10, 0},
3535
{1024, 10, 4, 50},
3636
{1024, 990, 4, 1024},
@@ -39,12 +39,12 @@ TEST(ExponentialMovingAverageFilter, alpha_low) {
3939
{0, 1000, 0, 1020},
4040
{0, 100, 0},
4141
};
42-
RunDataTest(filter, data);
42+
RunDataTest(filter, data, setAnalogRead);
4343
}
4444

4545
TEST(ExponentialMovingAverageFilter, impulse) {
4646
ExponentialMovingAverageFilter<uint32_t> *filter = new ExponentialMovingAverageFilter<uint32_t>(analogRead, 127);
47-
std::vector<InputOutput<uint32_t>> data = {
47+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
4848
{0, 10, 0},
4949
{1024, 1, 512},
5050
{0, 1, 256},
@@ -69,7 +69,7 @@ TEST(ExponentialMovingAverageFilter, impulse) {
6969
{1024, 1, 1023},
7070
{1024, 1, 1024},
7171
};
72-
RunDataTest(filter, data);
72+
RunDataTest(filter, data, setAnalogRead);
7373
}
7474

7575
float analogInToVoltage(uint32_t analogIn) {
@@ -78,24 +78,24 @@ float analogInToVoltage(uint32_t analogIn) {
7878

7979
TEST(ExponentialMovingAverageFilter, convert) {
8080
ExponentialMovingAverageFilter<float> *filter = new ExponentialMovingAverageFilter<float>(analogRead, 127, analogInToVoltage);
81-
std::vector<InputOutput<float>> data = {
81+
std::vector<InputOutput<uint32_t, float>> data = {
8282
{0, 10, 0.0},
8383
{1023, 100, 0.0, 3.3},
8484
{1023, 10, 3.3},
8585
};
86-
RunDataTest(filter, data);
86+
RunDataTest(filter, data, setAnalogRead);
8787
}
8888

8989
TEST(ExponentialMovingAverageFilter, filter_range) {
9090
// Tests that the filter supports 24-bit filters without overflow.
9191
// Note: 2 ^ 24 = 16777216
9292

9393
ExponentialMovingAverageFilter<uint32_t> *filter = new ExponentialMovingAverageFilter<uint32_t>(analogRead, 127);
94-
std::vector<InputOutput<uint32_t>> data = {
94+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
9595
{16777215, 500, 0, 16777215},
9696
{16777215, 100, 16777215},
9797
};
98-
RunDataTest(filter, data);
98+
RunDataTest(filter, data, setAnalogRead);
9999
}
100100

101101
}

test/filter-test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ namespace filter_test {
99
TEST(Filter, SetMinRunInterval_default) {
1010
// Filter that returns the sensor value immediately
1111
ExponentialMovingAverageFilter<uint32_t> *input = new ExponentialMovingAverageFilter<uint32_t>(analogRead, 255);
12-
std::vector<InputOutput<uint32_t>> data = {
12+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
1313
{1, 1, 1},
1414
{2, 1, 2},
1515
{3, 1, 3},
1616
{4, 1, 4},
1717
{5, 1, 5},
1818
};
19-
RunDataTest(input, data);
19+
RunDataTest(input, data, setAnalogRead);
2020
}
2121

2222
TEST(Filter, SetMinRunInterval_10) {
2323
// Filter that returns the sensor value immediately
2424
ExponentialMovingAverageFilter<uint32_t> *input = new ExponentialMovingAverageFilter<uint32_t>(analogRead, 255);
2525
input->SetMinRunInterval(10);
26-
std::vector<InputOutput<uint32_t>> data = {
26+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
2727
{1, 1, 1},
2828
{2, 9, 1},
2929

@@ -32,7 +32,7 @@ TEST(Filter, SetMinRunInterval_10) {
3232

3333
{3, 10, 3},
3434
};
35-
RunDataTest(input, data);
35+
RunDataTest(input, data, setAnalogRead);
3636
}
3737

3838
TEST(Filter, SetMinRunInterval_updates) {

test/median-filter-test.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,54 @@
77
namespace median_filter_input_test {
88

99
TEST(MedianFilter, loading_in_order) {
10-
MedianFilter<uint32_t, 5> *input = new MedianFilter<uint32_t, 5>(analogRead);
11-
std::vector<InputOutput<uint32_t>> data = {
10+
MedianFilter<uint32_t, uint32_t, 5> *input = new MedianFilter<uint32_t, uint32_t, 5>(analogRead);
11+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
1212
{100, 1, 100},
1313
{200, 1, 100},
1414
{300, 1, 200},
1515
{400, 1, 200},
1616
{500, 1, 300},
1717
};
18-
RunDataTest(input, data);
18+
RunDataTest(input, data, setAnalogRead);
1919
}
2020

2121
TEST(MedianFilter, loading_reverse_order) {
22-
MedianFilter<uint32_t, 5> *input = new MedianFilter<uint32_t, 5>(analogRead);
23-
std::vector<InputOutput<uint32_t>> data = {
22+
MedianFilter<uint32_t, uint32_t, 5> *input = new MedianFilter<uint32_t, uint32_t, 5>(analogRead);
23+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
2424
{500, 1, 500},
2525
{400, 1, 400},
2626
{300, 1, 400},
2727
{200, 1, 300},
2828
{100, 1, 300},
2929
};
30-
RunDataTest(input, data);
30+
RunDataTest(input, data, setAnalogRead);
3131
}
3232

3333
TEST(MedianFilter, loading_random_order) {
34-
MedianFilter<uint32_t, 5> *input = new MedianFilter<uint32_t, 5>(analogRead);
35-
std::vector<InputOutput<uint32_t>> data = {
34+
MedianFilter<uint32_t, uint32_t, 5> *input = new MedianFilter<uint32_t, uint32_t, 5>(analogRead);
35+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
3636
{500, 1, 500},
3737
{100, 1, 100},
3838
{400, 1, 400},
3939
{300, 1, 300},
4040
{200, 1, 300},
4141
};
42-
RunDataTest(input, data);
42+
RunDataTest(input, data, setAnalogRead);
4343
}
4444

4545
TEST(MedianFilter, steady_state_step_function) {
46-
MedianFilter<uint32_t, 5> *input = new MedianFilter<uint32_t, 5>(analogRead);
47-
std::vector<InputOutput<uint32_t>> data = {
46+
MedianFilter<uint32_t, uint32_t, 5> *input = new MedianFilter<uint32_t, uint32_t, 5>(analogRead);
47+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
4848
{100, 5, 100},
4949
{200, 2, 100},
5050
{200, 10, 200},
5151
};
52-
RunDataTest(input, data);
52+
RunDataTest(input, data, setAnalogRead);
5353
}
5454

5555
TEST(MedianFilter, steady_state_impulse) {
56-
MedianFilter<uint32_t, 5> *input = new MedianFilter<uint32_t, 5>(analogRead);
57-
std::vector<InputOutput<uint32_t>> data = {
56+
MedianFilter<uint32_t, uint32_t, 5> *input = new MedianFilter<uint32_t, uint32_t, 5>(analogRead);
57+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
5858
{100, 10, 100},
5959
{200, 2, 100},
6060
{100, 10, 100},
@@ -63,43 +63,55 @@ TEST(MedianFilter, steady_state_impulse) {
6363
{100, 2, 200},
6464
{100, 10, 100},
6565
};
66-
RunDataTest(input, data);
66+
RunDataTest(input, data, setAnalogRead);
6767
}
6868

6969
// Not a reasonable size, but behavior should be consistent
7070
TEST(MedianFilter, size_2) {
71-
MedianFilter<uint32_t, 2> *input = new MedianFilter<uint32_t, 2>(analogRead);
72-
std::vector<InputOutput<uint32_t>> data = {
71+
MedianFilter<uint32_t, uint32_t, 2> *input = new MedianFilter<uint32_t, uint32_t, 2>(analogRead);
72+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
7373
{100, 1, 100},
7474
{200, 1, 100},
7575
{200, 2, 200},
7676
{100, 5, 100},
7777
};
78-
RunDataTest(input, data);
78+
RunDataTest(input, data, setAnalogRead);
7979
}
8080

8181
TEST(MedianFilter, size_3) {
82-
MedianFilter<uint32_t, 3> *input = new MedianFilter<uint32_t, 3>(analogRead);
83-
std::vector<InputOutput<uint32_t>> data = {
82+
MedianFilter<uint32_t, uint32_t, 3> *input = new MedianFilter<uint32_t, uint32_t, 3>(analogRead);
83+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
8484
{100, 2, 100},
8585
{200, 1, 100},
8686
{200, 2, 200},
8787
{100, 1, 200},
8888
{100, 5, 100},
8989
};
90-
RunDataTest(input, data);
90+
RunDataTest(input, data, setAnalogRead);
9191
}
9292

9393
TEST(MedianFilter, size_255) {
94-
MedianFilter<uint32_t, 255> *input = new MedianFilter<uint32_t, 255>(analogRead);
95-
std::vector<InputOutput<uint32_t>> data = {
94+
MedianFilter<uint32_t, uint32_t, 255> *input = new MedianFilter<uint32_t, uint32_t, 255>(analogRead);
95+
std::vector<InputOutput<uint32_t, uint32_t>> data = {
9696
{100, 255, 100},
9797
{200, 127, 100},
9898
{200, 1, 200},
9999
{100, 127, 200},
100100
{100, 1, 100},
101101
};
102-
RunDataTest(input, data);
102+
RunDataTest(input, data, setAnalogRead);
103+
}
104+
105+
TEST(MedianFilter, float) {
106+
MedianFilter<float, float, 255> *input = new MedianFilter<float, float, 255>(floatRead);
107+
std::vector<InputOutput<float, float>> data = {
108+
{1.0, 255, 1.0},
109+
{2.0, 127, 1.0},
110+
{2.0, 1, 2.0},
111+
{1.0, 127, 2.0},
112+
{1.0, 1, 1.0},
113+
};
114+
RunDataTest(input, data, setFloatRead);
103115
}
104116

105117
}

test/run-data-test.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,16 @@ uint32_t analogReadValue = 0;
44
uint32_t analogRead() {
55
return analogReadValue;
66
}
7+
8+
void setAnalogRead(uint32_t value) {
9+
analogReadValue = value;
10+
}
11+
12+
float floatReadValue = 0.0;
13+
float floatRead() {
14+
return floatReadValue;
15+
}
16+
17+
void setFloatRead(float value) {
18+
floatReadValue = value;
19+
}

0 commit comments

Comments
 (0)