123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /*
- 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 <http://www.gnu.org/licenses/>.
- */
- #include "HarmonicNotchFilter.h"
- #include <GCS_MAVLink/GCS.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: Harmonic Notch Filter enable
- // @Description: Harmonic Notch Filter enable
- // @Values: 0:Disabled,1:Enabled
- // @User: Advanced
- AP_GROUPINFO_FLAGS("ENABLE", 1, HarmonicNotchFilterParams, _enable, 0, AP_PARAM_FLAG_ENABLE),
- // @Param: FREQ
- // @DisplayName: Harmonic Notch Filter base frequency
- // @Description: Harmonic Notch Filter base center frequency in Hz
- // @Range: 10 400
- // @Units: Hz
- // @User: Advanced
- AP_GROUPINFO("FREQ", 2, HarmonicNotchFilterParams, _center_freq_hz, 80),
- // @Param: BW
- // @DisplayName: Harmonic Notch Filter bandwidth
- // @Description: Harmonic Notch Filter bandwidth in Hz
- // @Range: 5 100
- // @Units: Hz
- // @User: Advanced
- AP_GROUPINFO("BW", 3, HarmonicNotchFilterParams, _bandwidth_hz, 20),
- // @Param: ATT
- // @DisplayName: Harmonic Notch Filter attenuation
- // @Description: Harmonic Notch Filter attenuation in dB
- // @Range: 5 30
- // @Units: dB
- // @User: Advanced
- AP_GROUPINFO("ATT", 4, HarmonicNotchFilterParams, _attenuation_dB, 15),
- // @Param: HMNCS
- // @DisplayName: Harmonic Notch Filter harmonics
- // @Description: Bitmask of harmonic frequencies to apply Harmonic Notch Filter 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: Harmonic Notch Filter reference value
- // @Description: Reference value associated with the specified frequency to facilitate frequency scaling of the Harmonic Notch Filter
- // @User: Advanced
- // @Range: 0.1 0.9
- // @RebootRequired: True
- AP_GROUPINFO("REF", 6, HarmonicNotchFilterParams, _reference, 0.1f),
- AP_GROUPEND
- };
- /*
- destroy all of the associated notch filters
- */
- template <class T>
- HarmonicNotchFilter<T>::~HarmonicNotchFilter() {
- delete[] _filters;
- _num_filters = 0;
- _num_enabled_filters = 0;
- }
- /*
- initialise the associated filters with the provided shaping constraints
- the constraints are used to determine attenuation (A) and quality (Q) factors for the filter
- */
- template <class T>
- void HarmonicNotchFilter<T>::init(float sample_freq_hz, float center_freq_hz, float bandwidth_hz, float attenuation_dB)
- {
- // sanity check the input
- if (_filters == nullptr || is_zero(sample_freq_hz) || isnan(sample_freq_hz)) {
- return;
- }
- _sample_freq_hz = sample_freq_hz;
- const float nyquist_limit = sample_freq_hz * 0.48f;
- // adjust the fundamental center frequency to be in the allowable range
- center_freq_hz = constrain_float(center_freq_hz, bandwidth_hz * 0.52f, nyquist_limit);
- // calculate attenuation and quality from the shaping constraints
- NotchFilter<T>::calculate_A_and_Q(center_freq_hz, bandwidth_hz, attenuation_dB, _A, _Q);
- _num_enabled_filters = 0;
- // initialize all the configured filters with the same A & Q and multiples of the center frequency
- for (uint8_t i = 0, filt = 0; i < HNF_MAX_HARMONICS && filt < _num_filters; i++) {
- const float notch_center = center_freq_hz * (i+1);
- if ((1U<<i) & _harmonics) {
- // only enable the filter if its center frequency is below the nyquist frequency
- if (notch_center < nyquist_limit) {
- _filters[filt].init_with_A_and_Q(sample_freq_hz, notch_center, _A, _Q);
- _num_enabled_filters++;
- }
- filt++;
- }
- }
- _initialised = true;
- }
- /*
- allocate a collection of, at most HNF_MAX_FILTERS, notch filters to be managed by this harmonic notch filter
- */
- template <class T>
- void HarmonicNotchFilter<T>::allocate_filters(uint8_t harmonics)
- {
- for (uint8_t i = 0; i < HNF_MAX_HARMONICS && _num_filters < HNF_MAX_FILTERS; i++) {
- if ((1U<<i) & harmonics) {
- _num_filters++;
- }
- }
- if (_num_filters > 0) {
- _filters = new NotchFilter<T>[_num_filters];
- if (_filters == nullptr) {
- gcs().send_text(MAV_SEVERITY_WARNING, "Failed to allocate %u bytes for HarmonicNotchFilter", (unsigned int)(_num_filters * sizeof(NotchFilter<T>)));
- _num_filters = 0;
- }
- }
- _harmonics = harmonics;
- }
- /*
- update the underlying filters' center frequency using the current attenuation and quality
- this function is cheaper than init() because A & Q do not need to be recalculated
- */
- template <class T>
- void HarmonicNotchFilter<T>::update(float center_freq_hz)
- {
- if (!_initialised) {
- return;
- }
- // adjust the fundamental center frequency to be in the allowable range
- const float nyquist_limit = _sample_freq_hz * 0.48f;
- center_freq_hz = constrain_float(center_freq_hz, 1.0f, nyquist_limit);
- _num_enabled_filters = 0;
- // update all of the filters using the new center frequency and existing A & Q
- for (uint8_t i = 0, filt = 0; i < HNF_MAX_HARMONICS && filt < _num_filters; i++) {
- const float notch_center = center_freq_hz * (i+1);
- if ((1U<<i) & _harmonics) {
- // only enable the filter if its center frequency is below the nyquist frequency
- if (notch_center < nyquist_limit) {
- _filters[filt].init_with_A_and_Q(_sample_freq_hz, notch_center, _A, _Q);
- _num_enabled_filters++;
- }
- filt++;
- }
- }
- }
- /*
- apply a sample to each of the underlying filters in turn and return the output
- */
- template <class T>
- T HarmonicNotchFilter<T>::apply(const T &sample)
- {
- if (!_initialised) {
- return sample;
- }
- T output = sample;
- for (uint8_t i = 0; i < _num_enabled_filters; i++) {
- output = _filters[i].apply(output);
- }
- return output;
- }
- /*
- reset all of the underlying filters
- */
- template <class T>
- void HarmonicNotchFilter<T>::reset()
- {
- if (!_initialised) {
- return;
- }
- for (uint8_t i = 0; i < _num_filters; i++) {
- _filters[i].reset();
- }
- }
- /*
- create parameters for the harmonic notch filter and initialise defaults
- */
- HarmonicNotchFilterParams::HarmonicNotchFilterParams(void)
- {
- AP_Param::setup_object_defaults(this, var_info);
- }
- /*
- instantiate template classes
- */
- template class HarmonicNotchFilter<Vector3f>;
|