diff --git a/libraries/Filter/HarmonicNotchFilter.cpp b/libraries/Filter/HarmonicNotchFilter.cpp
new file mode 100644
index 0000000000..623061afbe
--- /dev/null
+++ b/libraries/Filter/HarmonicNotchFilter.cpp
@@ -0,0 +1,179 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+
+#include "HarmonicNotchFilter.h"
+
+#define HNF_MAX_FILTERS 3
+#define HNF_MAX_HARMONICS 8
+
+// table of user settable parameters
+const AP_Param::GroupInfo HarmonicNotchFilterParams::var_info[] = {
+
+ // @Param: ENABLE
+ // @DisplayName: Enable
+ // @Description: Enable harmonic notch filter
+ // @Values: 0:Disabled,1:Enabled
+ // @User: Advanced
+ AP_GROUPINFO_FLAGS("ENABLE", 1, HarmonicNotchFilterParams, _enable, 0, AP_PARAM_FLAG_ENABLE),
+
+ // @Param: FREQ
+ // @DisplayName: Base Frequency
+ // @Description: Notch base center frequency in Hz
+ // @Range: 10 400
+ // @Units: Hz
+ // @User: Advanced
+ AP_GROUPINFO("FREQ", 2, HarmonicNotchFilterParams, _center_freq_hz, 80),
+
+ // @Param: BW
+ // @DisplayName: Bandwidth
+ // @Description: Harmonic notch bandwidth in Hz
+ // @Range: 5 100
+ // @Units: Hz
+ // @User: Advanced
+ AP_GROUPINFO("BW", 3, HarmonicNotchFilterParams, _bandwidth_hz, 20),
+
+ // @Param: ATT
+ // @DisplayName: Attenuation
+ // @Description: Harmonic notch attenuation in dB
+ // @Range: 5 30
+ // @Units: dB
+ // @User: Advanced
+ AP_GROUPINFO("ATT", 4, HarmonicNotchFilterParams, _attenuation_dB, 15),
+
+ // @Param: HMNCS
+ // @DisplayName: Harmonics
+ // @Description: Bitmask of harmonic frequencies to apply notches to. This option takes effect on the next reboot. A maximum of 3 harmonics can be used at any one time
+ // @Bitmask: 0:1st harmonic,1:2nd harmonic,2:3rd harmonic,3:4th hamronic,4:5th harmonic,5:6th harmonic,6:7th harmonic,7:8th harmonic
+ // @User: Advanced
+ // @RebootRequired: True
+ AP_GROUPINFO("HMNCS", 5, HarmonicNotchFilterParams, _harmonics, 3),
+
+ // @Param: REF
+ // @DisplayName: Reference value
+ // @Description: Reference value associated with the specified frequency to facilitate frequency scaling
+ // @User: Advanced
+ // @Range: 0.1 0.9
+ // @RebootRequired: True
+ AP_GROUPINFO("REF", 6, HarmonicNotchFilterParams, _reference, 0.1f),
+
+ AP_GROUPEND
+};
+
+
+/*
+ initialise filter
+ */
+template
+void HarmonicNotchFilter::init(float sample_freq_hz, float center_freq_hz, float bandwidth_hz, float attenuation_dB)
+{
+ if (_filters == nullptr) {
+ return;
+ }
+
+ _sample_freq_hz = sample_freq_hz;
+
+ // adjust the center frequency to be in the allowable range
+ center_freq_hz = constrain_float(center_freq_hz, bandwidth_hz * 0.52f, sample_freq_hz * 0.48f);
+
+ NotchFilter::calculate_A_and_Q(center_freq_hz, bandwidth_hz, attenuation_dB, _A, _Q);
+
+ for (uint8_t i = 0, filt = 0; i < HNF_MAX_HARMONICS && filt < _num_filters; i++) {
+ if ((1U<
+void HarmonicNotchFilter::create(uint8_t harmonics)
+{
+ for (uint8_t i = 0; i < HNF_MAX_HARMONICS && _num_filters < HNF_MAX_FILTERS; i++) {
+ if ((1U< 0) {
+ _filters = new NotchFilter[_num_filters];
+ }
+ _harmonics = harmonics;
+}
+
+template
+HarmonicNotchFilter::~HarmonicNotchFilter() {
+ if (_num_filters > 0) {
+ delete[] _filters;
+ }
+}
+
+template
+void HarmonicNotchFilter::update(float center_freq_hz)
+{
+ if (!_initialised) {
+ return;
+ }
+
+ // adjust the center frequency to be in the allowable range
+ center_freq_hz = constrain_float(center_freq_hz, 1.0f, _sample_freq_hz * 0.48f);
+
+ for (uint8_t i = 0, filt = 0; i < HNF_MAX_HARMONICS && filt < _num_filters; i++) {
+ if ((1U<
+T HarmonicNotchFilter::apply(const T &sample)
+{
+ if (!_initialised) {
+ return sample;
+ }
+
+ T output = sample;
+ for (uint8_t i = 0; i < _num_filters; i++) {
+ output = _filters[i].apply(output);
+ }
+ return output;
+}
+
+template
+void HarmonicNotchFilter::reset()
+{
+ if (!_initialised) {
+ return;
+ }
+
+ for (uint8_t i = 0; i < _num_filters; i++) {
+ _filters[i].reset();
+ }
+}
+
+
+/*
+ a notch filter with enable and filter parameters - constructor
+ */
+HarmonicNotchFilterParams::HarmonicNotchFilterParams(void)
+{
+ AP_Param::setup_object_defaults(this, var_info);
+}
+
+/*
+ instantiate template classes
+ */
+template class HarmonicNotchFilter;
diff --git a/libraries/Filter/HarmonicNotchFilter.h b/libraries/Filter/HarmonicNotchFilter.h
new file mode 100644
index 0000000000..e70003d4a0
--- /dev/null
+++ b/libraries/Filter/HarmonicNotchFilter.h
@@ -0,0 +1,61 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "NotchFilter.h"
+
+template
+class HarmonicNotchFilter {
+public:
+ // set parameters
+ void create(uint8_t harmonics);
+ void init(float sample_freq_hz, float center_freq_hz, float bandwidth_hz, float attenuation_dB);
+ T apply(const T &sample);
+ void reset();
+ void update(float center_freq_hz);
+ ~HarmonicNotchFilter();
+
+private:
+ NotchFilter* _filters;
+ float _sample_freq_hz;
+ float _A;
+ float _Q;
+ uint8_t _harmonics;
+ uint8_t _num_filters;
+ bool _initialised;
+};
+
+/*
+ notch filter enable and filter parameters
+ */
+class HarmonicNotchFilterParams : public NotchFilterParams {
+public:
+ HarmonicNotchFilterParams(void);
+ void set_center_freq_hz(float center_freq) { _center_freq_hz.set(center_freq); }
+ uint8_t harmonics(void) const { return _harmonics; }
+ float reference(void) const { return _reference; }
+ static const struct AP_Param::GroupInfo var_info[];
+
+private:
+ AP_Int8 _harmonics;
+ AP_Float _reference;
+};
+
+typedef HarmonicNotchFilter HarmonicNotchFilterVector3f;
+
diff --git a/libraries/Filter/NotchFilter.cpp b/libraries/Filter/NotchFilter.cpp
index 7962cd6815..8b024989fa 100644
--- a/libraries/Filter/NotchFilter.cpp
+++ b/libraries/Filter/NotchFilter.cpp
@@ -15,16 +15,34 @@
#include "NotchFilter.h"
+/*
+ calculate the attenuation and quality factors of the filter
+ */
+template
+void NotchFilter::calculate_A_and_Q(float center_freq_hz, float bandwidth_hz, float attenuation_dB, float& A, float& Q) {
+ const float octaves = log2f(center_freq_hz / (center_freq_hz - bandwidth_hz / 2.0f)) * 2.0f;
+ A = powf(10, -attenuation_dB / 40.0f);
+ Q = sqrtf(powf(2, octaves)) / (powf(2, octaves) - 1.0f);
+}
+
/*
initialise filter
*/
template
void NotchFilter::init(float sample_freq_hz, float center_freq_hz, float bandwidth_hz, float attenuation_dB)
+{
+ // adjust the center frequency to be in the allowable range
+ center_freq_hz = constrain_float(center_freq_hz, bandwidth_hz * 0.52f, sample_freq_hz * 0.48f);
+
+ float A, Q;
+ calculate_A_and_Q(center_freq_hz, bandwidth_hz, attenuation_dB, A, Q);
+ init_with_A_and_Q(sample_freq_hz, center_freq_hz, A, Q);
+}
+
+template
+void NotchFilter::init_with_A_and_Q(float sample_freq_hz, float center_freq_hz, float A, float Q)
{
float omega = 2.0 * M_PI * center_freq_hz / sample_freq_hz;
- float octaves = log2f(center_freq_hz / (center_freq_hz - bandwidth_hz/2)) * 2;
- float A = powf(10, -attenuation_dB/40);
- float Q = sqrtf(powf(2, octaves)) / (powf(2,octaves) - 1);
float alpha = sinf(omega) / (2 * Q/A);
b0 = 1.0 + alpha*A;
b1 = -2.0 * cosf(omega);
@@ -72,13 +90,21 @@ const AP_Param::GroupInfo NotchFilterParams::var_info[] = {
// @User: Advanced
AP_GROUPINFO_FLAGS("ENABLE", 1, NotchFilterParams, _enable, 0, AP_PARAM_FLAG_ENABLE),
+ // @Param: ATT
+ // @DisplayName: Attenuation
+ // @Description: Notch attenuation in dB
+ // @Range: 5 30
+ // @Units: dB
+ // @User: Advanced
+ AP_GROUPINFO("ATT", 4, NotchFilterParams, _attenuation_dB, 15),
+
// @Param: FREQ
// @DisplayName: Frequency
// @Description: Notch center frequency in Hz
// @Range: 10 400
// @Units: Hz
// @User: Advanced
- AP_GROUPINFO("FREQ", 2, NotchFilterParams, _center_freq_hz, 80),
+ AP_GROUPINFO("FREQ", 5, NotchFilterParams, _center_freq_hz, 80),
// @Param: BW
// @DisplayName: Bandwidth
@@ -86,16 +112,8 @@ const AP_Param::GroupInfo NotchFilterParams::var_info[] = {
// @Range: 5 100
// @Units: Hz
// @User: Advanced
- AP_GROUPINFO("BW", 3, NotchFilterParams, _bandwidth_hz, 20),
+ AP_GROUPINFO("BW", 6, NotchFilterParams, _bandwidth_hz, 20),
- // @Param: ATT
- // @DisplayName: Attenuation
- // @Description: Notch attenuation in dB
- // @Range: 5 30
- // @Units: dB
- // @User: Advanced
- AP_GROUPINFO("ATT", 4, NotchFilterParams, _attenuation_dB, 15),
-
AP_GROUPEND
};
diff --git a/libraries/Filter/NotchFilter.h b/libraries/Filter/NotchFilter.h
index 9fd258c2ed..78fea08d92 100644
--- a/libraries/Filter/NotchFilter.h
+++ b/libraries/Filter/NotchFilter.h
@@ -31,10 +31,15 @@ class NotchFilter {
public:
// set parameters
void init(float sample_freq_hz, float center_freq_hz, float bandwidth_hz, float attenuation_dB);
+ void init_with_A_and_Q(float sample_freq_hz, float center_freq_hz, float A, float Q);
T apply(const T &sample);
void reset();
+ // calculate attenuation and quality from provided center frequency and bandwidth
+ static void calculate_A_and_Q(float center_freq_hz, float bandwidth_hz, float attenuation_dB, float& A, float& Q);
+
private:
+
bool initialised;
float b0, b1, b2, a1, a2, a0_inv;
T ntchsig, ntchsig1, ntchsig2, signal2, signal1;
@@ -48,15 +53,15 @@ public:
NotchFilterParams(void);
static const struct AP_Param::GroupInfo var_info[];
- uint16_t center_freq_hz(void) const { return _center_freq_hz; }
- uint16_t bandwidth_hz(void) const { return _bandwidth_hz; }
+ float center_freq_hz(void) const { return _center_freq_hz; }
+ float bandwidth_hz(void) const { return _bandwidth_hz; }
float attenuation_dB(void) const { return _attenuation_dB; }
uint8_t enabled(void) const { return _enable; }
-private:
+protected:
AP_Int8 _enable;
- AP_Int16 _center_freq_hz;
- AP_Int16 _bandwidth_hz;
+ AP_Float _center_freq_hz;
+ AP_Float _bandwidth_hz;
AP_Float _attenuation_dB;
};