Skip to content

Commit 4bcbb13

Browse files
committed
feat: template order variable for static allocation
1 parent 09d3644 commit 4bcbb13

File tree

4 files changed

+58
-61
lines changed

4 files changed

+58
-61
lines changed

common_libraries/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ set(BUILD_DIR ${CMAKE_CURRENT_LIST_DIR}/build)
1313

1414
set(COMMON_LIB_SOURCES
1515
${CMAKE_CURRENT_LIST_DIR}/example/some_lib.cpp
16-
${CMAKE_CURRENT_LIST_DIR}/low_pass_fir_filter/low_pass_fir_filter.cpp
16+
${CMAKE_CURRENT_LIST_DIR}/low_pass_fir_filter/low_pass_fir_filter.h
1717
# Autogenerated files:
1818
# ${BUILD_DIR}/autogen/*.cpp
1919
# ${BUILD_DIR}/autogen/*.c

common_libraries/low_pass_fir_filter/low_pass_fir_filter.cpp

Lines changed: 0 additions & 34 deletions
This file was deleted.

common_libraries/low_pass_fir_filter/low_pass_fir_filter.h

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,47 @@ The buffer is initially filled with the first input to simplfy the algorithm (th
1010
The buffer is of size "order" + 1 since we need to store the current input, and also remember the oldest input (to remove from the total output in a subsequent update).
1111
*/
1212

13+
template <int order=1>
1314
class LowPassFIRFilter {
1415
private:
15-
bool buffer_is_empty;
16-
unsigned int buffer[MAX_LP_FIR_ORDER];
17-
unsigned int buffer_index;
18-
float coefficient;
19-
float output;
16+
bool buffer_is_empty = true;
17+
unsigned int buffer[order+1];
18+
unsigned int buffer_index = 0;
19+
float coefficient = 1.0f / (order + 1);
20+
float output = 0;
2021

2122
public:
22-
unsigned int order;
23-
// Default constructor (order 1, equal weights)
24-
LowPassFIRFilter();
23+
LowPassFIRFilter() {
24+
// Valid input check
25+
if (order < 1 || order > MAX_LP_FIR_ORDER) {
26+
throw std::invalid_argument("order must be at least 1 and less than the max order");
27+
}
28+
};
2529

26-
// Constructor with filter order (uses equal weights)
27-
// order = number of previous inputs to use
28-
LowPassFIRFilter(unsigned int order);
30+
unsigned int getOrder() const {
31+
return order;
32+
}
2933

3034
// Update filter with new input and return filtered output
31-
unsigned int update(unsigned int input);
35+
unsigned int update(unsigned int input) {
36+
if (this->buffer_is_empty) {
37+
// fill entire buffer with the first input
38+
for (int i = 0; i < order + 1; i++) {
39+
this->buffer[i] = input;
40+
}
41+
this->buffer_is_empty = false;
42+
return this->output = input;
43+
}
44+
45+
// `input` is the new data point that is begin added. `buffer[buffer_index]` is the old data point that must be removed.
46+
this->output = this->output + input * this->coefficient - this->buffer[this->buffer_index] * this->coefficient;
47+
this->buffer[this->buffer_index] = input;
48+
49+
// the index must wrap around once it reaches the right most side of the buffer. Note that buffer size is order + 1.
50+
this->buffer_index = (this->buffer_index + 1) % (order + 1);
51+
52+
return this->output;
53+
};
3254
};
3355

3456
#endif

common_libraries/low_pass_fir_filter/test/test_low_pass_fir_filter.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,51 @@
33
#include <low_pass_fir_filter.h>
44

55

6+
TEST_CASE("test_getOrder")
7+
{
8+
LowPassFIRFilter<2> filter_instance_1;
9+
REQUIRE(filter_instance_1.getOrder() == 2);
10+
11+
LowPassFIRFilter<5> filter_instance_5;
12+
REQUIRE(filter_instance_5.getOrder() == 5);
13+
}
14+
615
TEST_CASE("test_constructor")
716
{
817

918
SECTION("test_no_order")
1019
{
1120
LowPassFIRFilter filter_instance;
12-
REQUIRE(filter_instance.order == 1);
21+
REQUIRE(filter_instance.getOrder() == 1);
1322
}
1423

15-
SECTION("valid_orders")
24+
SECTION("test_valid_orders")
1625
{
17-
LowPassFIRFilter filter_instance_1(1);
18-
REQUIRE(filter_instance_1.order == 1);
26+
LowPassFIRFilter<1> filter_instance_1;
27+
REQUIRE(filter_instance_1.getOrder() == 1);
1928

20-
LowPassFIRFilter filter_instance_5(5);
21-
REQUIRE(filter_instance_5.order == 5);
29+
LowPassFIRFilter<5> filter_instance_5;
30+
REQUIRE(filter_instance_5.getOrder() == 5);
2231

23-
LowPassFIRFilter filter_instance_10(MAX_LP_FIR_ORDER);
24-
REQUIRE(filter_instance_10.order == MAX_LP_FIR_ORDER);
32+
LowPassFIRFilter<MAX_LP_FIR_ORDER> filter_instance_10;
33+
REQUIRE(filter_instance_10.getOrder() == MAX_LP_FIR_ORDER);
2534
}
2635

2736
SECTION("test_order_too_low_or_too_high")
2837
{
29-
REQUIRE_THROWS_AS(LowPassFIRFilter(0), std::invalid_argument);
30-
REQUIRE_THROWS_AS(LowPassFIRFilter(MAX_LP_FIR_ORDER + 1), std::invalid_argument);
38+
REQUIRE_THROWS_AS(LowPassFIRFilter<0>(), std::invalid_argument);
39+
REQUIRE_THROWS_AS(LowPassFIRFilter<MAX_LP_FIR_ORDER + 1>(), std::invalid_argument);
3140
}
3241

3342
}
3443

3544
TEST_CASE("test_update")
3645
{
3746
SECTION("test_empty_buffer_same_input") {
38-
LowPassFIRFilter filter_instance(5);
47+
LowPassFIRFilter<5> filter_instance;
3948
unsigned int val = 50;
4049
for (unsigned int i = 0; i < 7; i++) {
41-
REQUIRE(filter_instance.update(val) == 50);
50+
REQUIRE(filter_instance.update(val) == val);
4251
}
4352
}
4453

@@ -48,7 +57,7 @@ TEST_CASE("test_update")
4857
buffer = [100, 20, 50, 50, 50] -> output = 54
4958
*/
5059
SECTION("test_empty_buffer_different_inputs") {
51-
LowPassFIRFilter filter_instance(4);
60+
LowPassFIRFilter<4> filter_instance;
5261
unsigned int inputs[] = {50, 50, 50, 100, 20};
5362
unsigned int expected[] = {50, 50, 50, 60, 54};
5463
unsigned int n = 5;
@@ -59,7 +68,7 @@ TEST_CASE("test_update")
5968

6069

6170
SECTION("test_input_spikes") {
62-
LowPassFIRFilter filter_instance(1);
71+
LowPassFIRFilter filter_instance;
6372
unsigned int inputs[] = {50, 60, 70, 500, 100, 60, 50, 40, 50, 40, 50};
6473
unsigned int expected[] = {50, 55, 65, 285, 300, 80, 55, 45, 45, 45, 45};
6574

0 commit comments

Comments
 (0)