mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-25 17:25:20 +03:00
Lead-Lag Compensator (#12730)
* Implement Lead-Lag-Compensator * Refactoring / Clean up * Remove trailing whitespaces
This commit is contained in:
parent
405627dec2
commit
460e4d00fe
7 changed files with 151 additions and 92 deletions
|
@ -1142,7 +1142,7 @@ const clivalue_t valueTable[] = {
|
||||||
{ PARAM_NAME_HORIZON_LIMIT_STICKS, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 10, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_LEVEL].D) },
|
{ PARAM_NAME_HORIZON_LIMIT_STICKS, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 10, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_LEVEL].D) },
|
||||||
{ PARAM_NAME_HORIZON_LIMIT_DEGREES, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 10, 250 }, PG_PID_PROFILE, offsetof(pidProfile_t, horizon_limit_degrees) },
|
{ PARAM_NAME_HORIZON_LIMIT_DEGREES, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 10, 250 }, PG_PID_PROFILE, offsetof(pidProfile_t, horizon_limit_degrees) },
|
||||||
{ PARAM_NAME_HORIZON_IGNORE_STICKS, VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_PID_PROFILE, offsetof(pidProfile_t, horizon_ignore_sticks) },
|
{ PARAM_NAME_HORIZON_IGNORE_STICKS, VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_PID_PROFILE, offsetof(pidProfile_t, horizon_ignore_sticks) },
|
||||||
{ PARAM_NAME_HORIZON_DELAY_MS, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 10, 5000 }, PG_PID_PROFILE, offsetof(pidProfile_t, horizon_delay_ms) },
|
{ PARAM_NAME_HORIZON_DELAY_MS, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 10, 5000 }, PG_PID_PROFILE, offsetof(pidProfile_t, horizon_delay_ms) },
|
||||||
|
|
||||||
#if defined(USE_ABSOLUTE_CONTROL)
|
#if defined(USE_ABSOLUTE_CONTROL)
|
||||||
{ PARAM_NAME_ABS_CONTROL_GAIN, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, abs_control_gain) },
|
{ PARAM_NAME_ABS_CONTROL_GAIN, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, abs_control_gain) },
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
@ -131,30 +130,7 @@ FAST_CODE float pt3FilterApply(pt3Filter_t *filter, float input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Slew filter with limit
|
// Biquad filter
|
||||||
|
|
||||||
void slewFilterInit(slewFilter_t *filter, float slewLimit, float threshold)
|
|
||||||
{
|
|
||||||
filter->state = 0.0f;
|
|
||||||
filter->slewLimit = slewLimit;
|
|
||||||
filter->threshold = threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
FAST_CODE float slewFilterApply(slewFilter_t *filter, float input)
|
|
||||||
{
|
|
||||||
if (filter->state >= filter->threshold) {
|
|
||||||
if (input >= filter->state - filter->slewLimit) {
|
|
||||||
filter->state = input;
|
|
||||||
}
|
|
||||||
} else if (filter->state <= -filter->threshold) {
|
|
||||||
if (input <= filter->state + filter->slewLimit) {
|
|
||||||
filter->state = input;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
filter->state = input;
|
|
||||||
}
|
|
||||||
return filter->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get notch filter Q given center frequency (f0) and lower cutoff frequency (f1)
|
// get notch filter Q given center frequency (f0) and lower cutoff frequency (f1)
|
||||||
// Q = f0 / (f2 - f1) ; f2 = f0^2 / f1
|
// Q = f0 / (f2 - f1) ; f2 = f0^2 / f1
|
||||||
|
@ -268,6 +244,76 @@ FAST_CODE float biquadFilterApply(biquadFilter_t *filter, float input)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Phase Compensator (Lead-Lag-Compensator)
|
||||||
|
|
||||||
|
void phaseCompInit(phaseComp_t *filter, const float centerFreqHz, const float centerPhaseDeg, const uint32_t looptimeUs)
|
||||||
|
{
|
||||||
|
phaseCompUpdate(filter, centerFreqHz, centerPhaseDeg, looptimeUs);
|
||||||
|
|
||||||
|
filter->x1 = 0.0f;
|
||||||
|
filter->y1 = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
FAST_CODE void phaseCompUpdate(phaseComp_t *filter, const float centerFreqHz, const float centerPhaseDeg, const uint32_t looptimeUs)
|
||||||
|
{
|
||||||
|
const float omega = 2.0f * M_PIf * centerFreqHz * looptimeUs * 1e-6f;
|
||||||
|
const float sn = sin_approx(centerPhaseDeg * RAD);
|
||||||
|
const float gain = (1 + sn) / (1 - sn);
|
||||||
|
const float alpha = (12 - sq(omega)) / (6 * omega * sqrtf(gain)); // approximate prewarping (series expansion)
|
||||||
|
|
||||||
|
filter->b0 = 1 + alpha * gain;
|
||||||
|
filter->b1 = 2 - filter->b0;
|
||||||
|
filter->a1 = 1 - alpha;
|
||||||
|
|
||||||
|
const float a0 = 1 / (1 + alpha);
|
||||||
|
|
||||||
|
filter->b0 *= a0;
|
||||||
|
filter->b1 *= a0;
|
||||||
|
filter->a1 *= a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FAST_CODE float phaseCompApply(phaseComp_t *filter, const float input)
|
||||||
|
{
|
||||||
|
// compute result
|
||||||
|
const float result = filter->b0 * input + filter->b1 * filter->x1 - filter->a1 * filter->y1;
|
||||||
|
|
||||||
|
// shift input to x1 and result to y1
|
||||||
|
filter->x1 = input;
|
||||||
|
filter->y1 = result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Slew filter with limit
|
||||||
|
|
||||||
|
void slewFilterInit(slewFilter_t *filter, float slewLimit, float threshold)
|
||||||
|
{
|
||||||
|
filter->state = 0.0f;
|
||||||
|
filter->slewLimit = slewLimit;
|
||||||
|
filter->threshold = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
FAST_CODE float slewFilterApply(slewFilter_t *filter, float input)
|
||||||
|
{
|
||||||
|
if (filter->state >= filter->threshold) {
|
||||||
|
if (input >= filter->state - filter->slewLimit) {
|
||||||
|
filter->state = input;
|
||||||
|
}
|
||||||
|
} else if (filter->state <= -filter->threshold) {
|
||||||
|
if (input <= filter->state + filter->slewLimit) {
|
||||||
|
filter->state = input;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filter->state = input;
|
||||||
|
}
|
||||||
|
return filter->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Moving average
|
||||||
|
|
||||||
void laggedMovingAverageInit(laggedMovingAverage_t *filter, uint16_t windowSize, float *buf)
|
void laggedMovingAverageInit(laggedMovingAverage_t *filter, uint16_t windowSize, float *buf)
|
||||||
{
|
{
|
||||||
filter->movingWindowIndex = 0;
|
filter->movingWindowIndex = 0;
|
||||||
|
@ -290,11 +336,19 @@ FAST_CODE float laggedMovingAverageUpdate(laggedMovingAverage_t *filter, float i
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint16_t denom = filter->primed ? filter->windowSize : filter->movingWindowIndex;
|
const uint16_t denom = filter->primed ? filter->windowSize : filter->movingWindowIndex;
|
||||||
return filter->movingSum / denom;
|
return filter->movingSum / denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Simple fixed-point lowpass filter based on integer math
|
// Simple fixed-point lowpass filter based on integer math
|
||||||
|
|
||||||
|
void simpleLPFilterInit(simpleLowpassFilter_t *filter, int32_t beta, int32_t fpShift)
|
||||||
|
{
|
||||||
|
filter->fp = 0;
|
||||||
|
filter->beta = beta;
|
||||||
|
filter->fpShift = fpShift;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t simpleLPFilterUpdate(simpleLowpassFilter_t *filter, int32_t newVal)
|
int32_t simpleLPFilterUpdate(simpleLowpassFilter_t *filter, int32_t newVal)
|
||||||
{
|
{
|
||||||
filter->fp = (filter->fp << filter->beta) - filter->fp;
|
filter->fp = (filter->fp << filter->beta) - filter->fp;
|
||||||
|
@ -304,11 +358,13 @@ int32_t simpleLPFilterUpdate(simpleLowpassFilter_t *filter, int32_t newVal)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void simpleLPFilterInit(simpleLowpassFilter_t *filter, int32_t beta, int32_t fpShift)
|
|
||||||
|
// Mean accumulator
|
||||||
|
|
||||||
|
void meanAccumulatorInit(meanAccumulator_t *filter)
|
||||||
{
|
{
|
||||||
filter->fp = 0;
|
filter->accumulator = 0;
|
||||||
filter->beta = beta;
|
filter->count = 0;
|
||||||
filter->fpShift = fpShift;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void meanAccumulatorAdd(meanAccumulator_t *filter, const int8_t newVal)
|
void meanAccumulatorAdd(meanAccumulator_t *filter, const int8_t newVal)
|
||||||
|
@ -326,9 +382,3 @@ int8_t meanAccumulatorCalc(meanAccumulator_t *filter, const int8_t defaultValue)
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void meanAccumulatorInit(meanAccumulator_t *filter)
|
|
||||||
{
|
|
||||||
filter->accumulator = 0;
|
|
||||||
filter->count = 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,10 +19,26 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
struct filter_s;
|
struct filter_s;
|
||||||
typedef struct filter_s filter_t;
|
typedef struct filter_s filter_t;
|
||||||
|
typedef float (*filterApplyFnPtr)(filter_t *filter, float input);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FILTER_PT1 = 0,
|
||||||
|
FILTER_BIQUAD,
|
||||||
|
FILTER_PT2,
|
||||||
|
FILTER_PT3,
|
||||||
|
} lowpassFilterType_e;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FILTER_LPF, // 2nd order Butterworth section
|
||||||
|
FILTER_NOTCH,
|
||||||
|
FILTER_BPF,
|
||||||
|
} biquadFilterType_e;
|
||||||
|
|
||||||
typedef struct pt1Filter_s {
|
typedef struct pt1Filter_s {
|
||||||
float state;
|
float state;
|
||||||
|
@ -42,12 +58,6 @@ typedef struct pt3Filter_s {
|
||||||
float k;
|
float k;
|
||||||
} pt3Filter_t;
|
} pt3Filter_t;
|
||||||
|
|
||||||
typedef struct slewFilter_s {
|
|
||||||
float state;
|
|
||||||
float slewLimit;
|
|
||||||
float threshold;
|
|
||||||
} slewFilter_t;
|
|
||||||
|
|
||||||
/* this holds the data required to update samples thru a filter */
|
/* this holds the data required to update samples thru a filter */
|
||||||
typedef struct biquadFilter_s {
|
typedef struct biquadFilter_s {
|
||||||
float b0, b1, b2, a1, a2;
|
float b0, b1, b2, a1, a2;
|
||||||
|
@ -55,6 +65,17 @@ typedef struct biquadFilter_s {
|
||||||
float weight;
|
float weight;
|
||||||
} biquadFilter_t;
|
} biquadFilter_t;
|
||||||
|
|
||||||
|
typedef struct phaseComp_s {
|
||||||
|
float b0, b1, a1;
|
||||||
|
float x1, y1;
|
||||||
|
} phaseComp_t;
|
||||||
|
|
||||||
|
typedef struct slewFilter_s {
|
||||||
|
float state;
|
||||||
|
float slewLimit;
|
||||||
|
float threshold;
|
||||||
|
} slewFilter_t;
|
||||||
|
|
||||||
typedef struct laggedMovingAverage_s {
|
typedef struct laggedMovingAverage_s {
|
||||||
uint16_t movingWindowIndex;
|
uint16_t movingWindowIndex;
|
||||||
uint16_t windowSize;
|
uint16_t windowSize;
|
||||||
|
@ -63,36 +84,19 @@ typedef struct laggedMovingAverage_s {
|
||||||
bool primed;
|
bool primed;
|
||||||
} laggedMovingAverage_t;
|
} laggedMovingAverage_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef struct simpleLowpassFilter_s {
|
||||||
FILTER_PT1 = 0,
|
int32_t fp;
|
||||||
FILTER_BIQUAD,
|
int32_t beta;
|
||||||
FILTER_PT2,
|
int32_t fpShift;
|
||||||
FILTER_PT3,
|
} simpleLowpassFilter_t;
|
||||||
} lowpassFilterType_e;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef struct meanAccumulator_s {
|
||||||
FILTER_LPF, // 2nd order Butterworth section
|
int32_t accumulator;
|
||||||
FILTER_NOTCH,
|
int32_t count;
|
||||||
FILTER_BPF,
|
} meanAccumulator_t;
|
||||||
} biquadFilterType_e;
|
|
||||||
|
|
||||||
typedef float (*filterApplyFnPtr)(filter_t *filter, float input);
|
|
||||||
|
|
||||||
float nullFilterApply(filter_t *filter, float input);
|
float nullFilterApply(filter_t *filter, float input);
|
||||||
|
|
||||||
void biquadFilterInitLPF(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate);
|
|
||||||
void biquadFilterInit(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate, float Q, biquadFilterType_e filterType, float weight);
|
|
||||||
void biquadFilterUpdate(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate, float Q, biquadFilterType_e filterType, float weight);
|
|
||||||
void biquadFilterUpdateLPF(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate);
|
|
||||||
|
|
||||||
float biquadFilterApplyDF1(biquadFilter_t *filter, float input);
|
|
||||||
float biquadFilterApplyDF1Weighted(biquadFilter_t *filter, float input);
|
|
||||||
float biquadFilterApply(biquadFilter_t *filter, float input);
|
|
||||||
float filterGetNotchQ(float centerFreq, float cutoffFreq);
|
|
||||||
|
|
||||||
void laggedMovingAverageInit(laggedMovingAverage_t *filter, uint16_t windowSize, float *buf);
|
|
||||||
float laggedMovingAverageUpdate(laggedMovingAverage_t *filter, float input);
|
|
||||||
|
|
||||||
float pt1FilterGain(float f_cut, float dT);
|
float pt1FilterGain(float f_cut, float dT);
|
||||||
void pt1FilterInit(pt1Filter_t *filter, float k);
|
void pt1FilterInit(pt1Filter_t *filter, float k);
|
||||||
void pt1FilterUpdateCutoff(pt1Filter_t *filter, float k);
|
void pt1FilterUpdateCutoff(pt1Filter_t *filter, float k);
|
||||||
|
@ -108,23 +112,29 @@ void pt3FilterInit(pt3Filter_t *filter, float k);
|
||||||
void pt3FilterUpdateCutoff(pt3Filter_t *filter, float k);
|
void pt3FilterUpdateCutoff(pt3Filter_t *filter, float k);
|
||||||
float pt3FilterApply(pt3Filter_t *filter, float input);
|
float pt3FilterApply(pt3Filter_t *filter, float input);
|
||||||
|
|
||||||
|
float filterGetNotchQ(float centerFreq, float cutoffFreq);
|
||||||
|
|
||||||
|
void biquadFilterInitLPF(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate);
|
||||||
|
void biquadFilterInit(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate, float Q, biquadFilterType_e filterType, float weight);
|
||||||
|
void biquadFilterUpdate(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate, float Q, biquadFilterType_e filterType, float weight);
|
||||||
|
void biquadFilterUpdateLPF(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate);
|
||||||
|
float biquadFilterApplyDF1(biquadFilter_t *filter, float input);
|
||||||
|
float biquadFilterApplyDF1Weighted(biquadFilter_t *filter, float input);
|
||||||
|
float biquadFilterApply(biquadFilter_t *filter, float input);
|
||||||
|
|
||||||
|
void phaseCompInit(phaseComp_t *filter, const float centerFreq, const float centerPhase, const uint32_t looptimeUs);
|
||||||
|
void phaseCompUpdate(phaseComp_t *filter, const float centerFreq, const float centerPhase, const uint32_t looptimeUs);
|
||||||
|
float phaseCompApply(phaseComp_t *filter, const float input);
|
||||||
|
|
||||||
void slewFilterInit(slewFilter_t *filter, float slewLimit, float threshold);
|
void slewFilterInit(slewFilter_t *filter, float slewLimit, float threshold);
|
||||||
float slewFilterApply(slewFilter_t *filter, float input);
|
float slewFilterApply(slewFilter_t *filter, float input);
|
||||||
|
|
||||||
typedef struct simpleLowpassFilter_s {
|
void laggedMovingAverageInit(laggedMovingAverage_t *filter, uint16_t windowSize, float *buf);
|
||||||
int32_t fp;
|
float laggedMovingAverageUpdate(laggedMovingAverage_t *filter, float input);
|
||||||
int32_t beta;
|
|
||||||
int32_t fpShift;
|
|
||||||
} simpleLowpassFilter_t;
|
|
||||||
|
|
||||||
int32_t simpleLPFilterUpdate(simpleLowpassFilter_t *filter, int32_t newVal);
|
|
||||||
void simpleLPFilterInit(simpleLowpassFilter_t *filter, int32_t beta, int32_t fpShift);
|
void simpleLPFilterInit(simpleLowpassFilter_t *filter, int32_t beta, int32_t fpShift);
|
||||||
|
int32_t simpleLPFilterUpdate(simpleLowpassFilter_t *filter, int32_t newVal);
|
||||||
|
|
||||||
typedef struct meanAccumulator_s {
|
void meanAccumulatorInit(meanAccumulator_t *filter);
|
||||||
int32_t accumulator;
|
|
||||||
int32_t count;
|
|
||||||
} meanAccumulator_t;
|
|
||||||
|
|
||||||
void meanAccumulatorAdd(meanAccumulator_t *filter, const int8_t newVal);
|
void meanAccumulatorAdd(meanAccumulator_t *filter, const int8_t newVal);
|
||||||
int8_t meanAccumulatorCalc(meanAccumulator_t *filter, const int8_t defaultValue);
|
int8_t meanAccumulatorCalc(meanAccumulator_t *filter, const int8_t defaultValue);
|
||||||
void meanAccumulatorInit(meanAccumulator_t *filter);
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ typedef struct dynNotch_s {
|
||||||
|
|
||||||
int maxCenterFreq;
|
int maxCenterFreq;
|
||||||
float centerFreq[XYZ_AXIS_COUNT][DYN_NOTCH_COUNT_MAX];
|
float centerFreq[XYZ_AXIS_COUNT][DYN_NOTCH_COUNT_MAX];
|
||||||
|
|
||||||
timeUs_t looptimeUs;
|
timeUs_t looptimeUs;
|
||||||
biquadFilter_t notch[XYZ_AXIS_COUNT][DYN_NOTCH_COUNT_MAX];
|
biquadFilter_t notch[XYZ_AXIS_COUNT][DYN_NOTCH_COUNT_MAX];
|
||||||
|
|
||||||
|
@ -261,11 +261,11 @@ static FAST_CODE_NOINLINE void dynNotchProcess(void)
|
||||||
DEBUG_SET(DEBUG_FFT_TIME, 0, state.step);
|
DEBUG_SET(DEBUG_FFT_TIME, 0, state.step);
|
||||||
|
|
||||||
switch (state.step) {
|
switch (state.step) {
|
||||||
|
|
||||||
case STEP_WINDOW: // 4.1us (3-6us) @ F722
|
case STEP_WINDOW: // 4.1us (3-6us) @ F722
|
||||||
{
|
{
|
||||||
sdftWinSq(&sdft[state.axis], sdftData);
|
sdftWinSq(&sdft[state.axis], sdftData);
|
||||||
|
|
||||||
// Get total vibrational power in dyn notch range for noise floor estimate in STEP_CALC_FREQUENCIES
|
// Get total vibrational power in dyn notch range for noise floor estimate in STEP_CALC_FREQUENCIES
|
||||||
sdftNoiseThreshold = 0.0f;
|
sdftNoiseThreshold = 0.0f;
|
||||||
for (int bin = sdftStartBin; bin <= sdftEndBin; bin++) {
|
for (int bin = sdftStartBin; bin <= sdftEndBin; bin++) {
|
||||||
|
@ -359,7 +359,7 @@ static FAST_CODE_NOINLINE void dynNotchProcess(void)
|
||||||
// Convert bin to frequency: freq = bin * binResoultion (bin 0 is 0Hz)
|
// Convert bin to frequency: freq = bin * binResoultion (bin 0 is 0Hz)
|
||||||
const float centerFreq = constrainf(meanBin * sdftResolutionHz, dynNotch.minHz, dynNotch.maxHz);
|
const float centerFreq = constrainf(meanBin * sdftResolutionHz, dynNotch.minHz, dynNotch.maxHz);
|
||||||
|
|
||||||
// PT1 style smoothing moves notch center freqs rapidly towards big peaks and slowly away, up to 10x faster
|
// PT1 style smoothing moves notch center freqs rapidly towards big peaks and slowly away, up to 10x faster
|
||||||
const float cutoffMult = constrainf(peaks[p].value / sdftNoiseThreshold, 1.0f, 10.0f);
|
const float cutoffMult = constrainf(peaks[p].value / sdftNoiseThreshold, 1.0f, 10.0f);
|
||||||
const float gain = pt1FilterGain(DYN_NOTCH_SMOOTH_HZ * cutoffMult, pt1LooptimeS); // dynamic PT1 k value
|
const float gain = pt1FilterGain(DYN_NOTCH_SMOOTH_HZ * cutoffMult, pt1LooptimeS); // dynamic PT1 k value
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ static FAST_CODE_NOINLINE void dynNotchProcess(void)
|
||||||
state.step = (state.step + 1) % STEP_COUNT;
|
state.step = (state.step + 1) % STEP_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
FAST_CODE float dynNotchFilter(const int axis, float value)
|
FAST_CODE float dynNotchFilter(const int axis, float value)
|
||||||
{
|
{
|
||||||
for (int p = 0; p < dynNotch.count; p++) {
|
for (int p = 0; p < dynNotch.count; p++) {
|
||||||
value = biquadFilterApplyDF1(&dynNotch.notch[axis][p], value);
|
value = biquadFilterApplyDF1(&dynNotch.notch[axis][p], value);
|
||||||
|
|
|
@ -91,7 +91,7 @@ pt1Filter_t throttleLpf;
|
||||||
PG_REGISTER_WITH_RESET_TEMPLATE(pidConfig_t, pidConfig, PG_PID_CONFIG, 3);
|
PG_REGISTER_WITH_RESET_TEMPLATE(pidConfig_t, pidConfig, PG_PID_CONFIG, 3);
|
||||||
|
|
||||||
#if !defined(DEFAULT_PID_PROCESS_DENOM)
|
#if !defined(DEFAULT_PID_PROCESS_DENOM)
|
||||||
#if defined(STM32F411xE)
|
#if defined(STM32F411xE)
|
||||||
#define DEFAULT_PID_PROCESS_DENOM 2
|
#define DEFAULT_PID_PROCESS_DENOM 2
|
||||||
#else
|
#else
|
||||||
#define DEFAULT_PID_PROCESS_DENOM 1
|
#define DEFAULT_PID_PROCESS_DENOM 1
|
||||||
|
@ -298,7 +298,7 @@ void pidUpdateAntiGravityThrottleFilter(float throttle)
|
||||||
static float previousThrottle = 0.0f;
|
static float previousThrottle = 0.0f;
|
||||||
const float throttleInv = 1.0f - throttle;
|
const float throttleInv = 1.0f - throttle;
|
||||||
float throttleDerivative = fabsf(throttle - previousThrottle) * pidRuntime.pidFrequency;
|
float throttleDerivative = fabsf(throttle - previousThrottle) * pidRuntime.pidFrequency;
|
||||||
DEBUG_SET(DEBUG_ANTI_GRAVITY, 0, lrintf(throttleDerivative * 100));
|
DEBUG_SET(DEBUG_ANTI_GRAVITY, 0, lrintf(throttleDerivative * 100));
|
||||||
throttleDerivative *= throttleInv * throttleInv;
|
throttleDerivative *= throttleInv * throttleInv;
|
||||||
// generally focus on the low throttle period
|
// generally focus on the low throttle period
|
||||||
if (throttle > previousThrottle) {
|
if (throttle > previousThrottle) {
|
||||||
|
@ -310,7 +310,7 @@ void pidUpdateAntiGravityThrottleFilter(float throttle)
|
||||||
// lower cutoff suppresses peaks relative to troughs and prolongs the effects
|
// lower cutoff suppresses peaks relative to troughs and prolongs the effects
|
||||||
// PT2 smoothing of throttle derivative.
|
// PT2 smoothing of throttle derivative.
|
||||||
// 6 is a typical value for the peak boost factor with default cutoff of 6Hz
|
// 6 is a typical value for the peak boost factor with default cutoff of 6Hz
|
||||||
DEBUG_SET(DEBUG_ANTI_GRAVITY, 1, lrintf(throttleDerivative * 100));
|
DEBUG_SET(DEBUG_ANTI_GRAVITY, 1, lrintf(throttleDerivative * 100));
|
||||||
pidRuntime.antiGravityThrottleD = throttleDerivative;
|
pidRuntime.antiGravityThrottleD = throttleDerivative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,7 +911,7 @@ void FAST_CODE pidController(const pidProfile_t *pidProfile, timeUs_t currentTim
|
||||||
if (levelMode == LEVEL_MODE_RP) {
|
if (levelMode == LEVEL_MODE_RP) {
|
||||||
// if earth referencing is requested, attenuate yaw axis setpoint when pitched or rolled
|
// if earth referencing is requested, attenuate yaw axis setpoint when pitched or rolled
|
||||||
// and send yawSetpoint to Angle code to modulate pitch and roll
|
// and send yawSetpoint to Angle code to modulate pitch and roll
|
||||||
// code cost is 107 cycles when earthRef enabled, 20 otherwise, nearly all in cos_approx
|
// code cost is 107 cycles when earthRef enabled, 20 otherwise, nearly all in cos_approx
|
||||||
if (pidRuntime.angleEarthRef) {
|
if (pidRuntime.angleEarthRef) {
|
||||||
pidRuntime.angleYawSetpoint = currentPidSetpoint;
|
pidRuntime.angleYawSetpoint = currentPidSetpoint;
|
||||||
float maxAngleTargetAbs = pidRuntime.angleEarthRef * fmaxf( fabsf(pidRuntime.angleTarget[FD_ROLL]), fabsf(pidRuntime.angleTarget[FD_PITCH]) );
|
float maxAngleTargetAbs = pidRuntime.angleEarthRef * fmaxf( fabsf(pidRuntime.angleTarget[FD_ROLL]), fabsf(pidRuntime.angleTarget[FD_PITCH]) );
|
||||||
|
|
|
@ -432,4 +432,3 @@ void pidCopyProfile(uint8_t dstPidProfileIndex, uint8_t srcPidProfileIndex)
|
||||||
memcpy(pidProfilesMutable(dstPidProfileIndex), pidProfilesMutable(srcPidProfileIndex), sizeof(pidProfile_t));
|
memcpy(pidProfilesMutable(dstPidProfileIndex), pidProfilesMutable(srcPidProfileIndex), sizeof(pidProfile_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ void pgResetFn_gyroConfig(gyroConfig_t *gyroConfig)
|
||||||
gyroConfig->gyroMovementCalibrationThreshold = 48;
|
gyroConfig->gyroMovementCalibrationThreshold = 48;
|
||||||
gyroConfig->gyro_hardware_lpf = GYRO_HARDWARE_LPF_NORMAL;
|
gyroConfig->gyro_hardware_lpf = GYRO_HARDWARE_LPF_NORMAL;
|
||||||
gyroConfig->gyro_lpf1_type = FILTER_PT1;
|
gyroConfig->gyro_lpf1_type = FILTER_PT1;
|
||||||
gyroConfig->gyro_lpf1_static_hz = GYRO_LPF1_DYN_MIN_HZ_DEFAULT;
|
gyroConfig->gyro_lpf1_static_hz = GYRO_LPF1_DYN_MIN_HZ_DEFAULT;
|
||||||
// NOTE: dynamic lpf is enabled by default so this setting is actually
|
// NOTE: dynamic lpf is enabled by default so this setting is actually
|
||||||
// overridden and the static lowpass 1 is disabled. We can't set this
|
// overridden and the static lowpass 1 is disabled. We can't set this
|
||||||
// value to 0 otherwise Configurator versions 10.4 and earlier will also
|
// value to 0 otherwise Configurator versions 10.4 and earlier will also
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue