Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LULU filter port to iNav as a single replacement for most filters in iNav, simplifying filter configuration drastically #10145

Merged
merged 7 commits into from
Jun 24, 2024

Conversation

pjpei
Copy link
Contributor

@pjpei pjpei commented Jun 17, 2024

I implemented a new type of filter based on the LULU filter by C.H. Rohwer, a mathematician at a local university. Refer to this wikipedia entry for details on the maths: https://en.wikipedia.org/wiki/Lulu_smoothing

It took real time to optimize this to run effectively.

I would really appreciate if anyone could verify if this works OK on more craft? I'm on Discord if anyone has questions about it. I've tested a local betaflight port on multiple craft and it seems to work nicely with really low delay, and now ported to iNav I hope that it will simplify filtering.

I’ve ported this to Inav and I have found the following:
As a single filter, it’s easy enough to set the filter type to LULU for the gyro and gyro antialiasing filters, while disabling all other filtering.
Recommended starting point: Set looptime to 500hz, set anti-aliasing lpf to 1, set gyro main filter lpf to 3, set dterm lpf to static 120hz pt1, rpmfilter on one harmonic and disable all dynamic filtering.

This will cause any spikes and pits that are more than 3 samples wide to disappear. For oscillating-type noise, like is to be expected from a gyroscope, this means that any sinusoid top or bottom half will be simply snipped off, keeping only the approximate middle value of the sinusoid after filtering.

The gyro lpf is now not measured in hz, but samples, as is the antialiasing lpf. More samples = more filtering but more delay.
Using the lulu on dterm seems to be a mess as the lulu on gyrofilter causes spikes on it, so recommended to use lulu on gyro only.
I've attached a flight log of a really bad frame 40mm whoop.

The bottom line is the smoother knocks out spiky noise in full, by the amount of samples specified by the “lowpass hz” for the implementation. For example, if you set the “gyro lowpass hz” to 4, and you set the filter to LULU in CLI, you will find that any spike or dip in signal for 4 samples or less will disappear.

The LULU filter is a really low latency filter and you’ll see that if you set the sample number to 3 for the gyro LPF and the antialiasing filter samples to 1, it should work in many cases.

Below is a 40mm toothpick with a terrible frame and construction on inav running LULU at 1 sample antialiasing filter and 3 samples gyro LPF.

blackbox_log_2024-06-17_122915.TXT
image

If you look closely, you’ll see the gyro filter has some sudden changes in slope. This is unfortunately a reality of the dterm as a sinusoidal type noise filtered by LULU causes sudden jumps in the gyro value.

To mitigate the problems caused by the spiky dterm, we set a single gyro lowpass filter when needed. Rigid frames have less of an issue than this terrible ABS plastic frame, but I’ve found for rigid carbon fibre frames it can be run with a very high Hz PT1, while for frames like this 40mm one it works better with a 120Hz PT1. This removes the spiky noise and smoothes it out nicely.

On the example above, there is no other filtering done except the LULU and a 120Hz PT1, and one harmonic RPMfilter. I have disabled all dynamic filters on this whoop as well.

Config dump attached for this specific craft for completion's sake
INAV_8.0.0_cli_20240617_123346.txt

@pjpei
Copy link
Contributor Author

pjpei commented Jun 17, 2024

Note that the LULU filter really gets processor intensive above around 6-8 samples of filtering. Check CPU usage before flight!

@DzikuVx
Copy link
Member

DzikuVx commented Jun 17, 2024

Can't wait to test it!

Copy link
Member

@DzikuVx DzikuVx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pjpei amazing! Thee are few things we can improve thought

src/main/fc/config.c Show resolved Hide resolved
}
// if (gyroConfig()->adaptiveFilterMaxHz - 5 < gyroConfig()->gyro_main_lpf_hz) {
// gyroConfigMutable()->adaptiveFilterMaxHz = gyroConfig()->gyro_main_lpf_hz + 5;
// }
#endif

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a good idea to disable LULU when DYNAMIC or ADAPTIVE gyro filter is running

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we have specific filter type LULU, as implemented, this should be fixed?

@@ -244,9 +244,10 @@ static void initGyroFilter(filterApplyFnPtr *applyFn, filter_t state[], uint16_t
{
*applyFn = nullFilterApply;
if (cutoff > 0) {
*applyFn = (filterApplyFnPtr)pt1FilterApply;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should not be modified in this way, because it changes how both gyro LPF work. By doing so you just enabled double LULU on gyro data

The distinction should happen inside static void gyroInitFilters(void) by adding a new setting to run lulu on gyro

description: "Gyro processing anti-aliasing filter cutoff frequency. In normal operation this filter setting should never be changed. In Hz"
default_value: 250
description: "Gyro processing anti-aliasing filter cutoff frequency. In normal operation this filter setting should never be changed. In samples"
default_value: 1
field: gyro_anti_aliasing_lpf_hz
max: 1000
- name: gyro_main_lpf_hz
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setting shold not be changed, but a new one like 'gyro_lulu_sample_count` added

description: "Gyro processing anti-aliasing filter cutoff frequency. In normal operation this filter setting should never be changed. In Hz"
default_value: 250
description: "Gyro processing anti-aliasing filter cutoff frequency. In normal operation this filter setting should never be changed. In samples"
default_value: 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not run lulu on antialiasing filter at all. It makes no sense as this filter is only to remove aliasing effect between acquisition and processing

src/main/fc/settings.yaml Show resolved Hide resolved
src/main/common/lulu.c Outdated Show resolved Hide resolved
@pjpei
Copy link
Contributor Author

pjpei commented Jun 17, 2024

Thanks for the review! I made the changes as requested. I added a gyro filter mode "LULU" which is different from the current 3, and that sorts out much of the issues in the previous pull request.

description: "Gyro processing anti-aliasing filter cutoff frequency. In normal operation this filter setting should never be changed. In samples"
default_value: 1
description: "Gyro processing anti-aliasing filter cutoff frequency. In normal operation this filter setting should never be changed. In Hz"
default_value: 250
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this with a bit higher antialiasing filter frequency of 400, the LULU filter seems to be happy with it. We might want to change this to 400 or similar if lulu is used as a default.

@pjpei
Copy link
Contributor Author

pjpei commented Jun 18, 2024

I see there's still changes requested? I think I did complete all the changes that were specified, please note if I missed any :)

@pjpei pjpei requested a review from DzikuVx June 18, 2024 09:03
@pjpei
Copy link
Contributor Author

pjpei commented Jun 20, 2024

My testing settings are:

set looptime = 500
set gyro_anti_aliasing_lpf_hz = 1000
set gyro_lulu_sample_count = 3
set gyro_filter_mode = LULU
set dynamic_gyro_notch_enabled = OFF
set dterm_lpf_hz = 120
set dterm_lpf_type = PT1
set yaw_lpf_hz = 0
set switch_disarm_delay = 0

Note the gyro_lulu_sample_count might need to be higher and might go to 2 for sturdy frames. Don't think the other settings need to really change much.

@pjpei
Copy link
Contributor Author

pjpei commented Jun 21, 2024

I thought a drawing would work nice for setting the gyro_lulu_sample_count value.

A good starting point is in my mind half the sample count of the large oscillatory vibration, as indicated below. If the oscillation goes up-down-up in a sine-like fashion, it would be half the wavelength we set the samples to. So if the full up-down-up motion goes from zero to top, to bottom, to zero that would mean half the distance from thebegin to the end of this description of a single up-down sinusoidal wave. The LULU smoother would then remove the peak and the pit, leaving only the center value of the sinewave after filtering.

I've found that on my quads a value of 2-3 works well, but for others we might need differing values.

lulu

@DzikuVx DzikuVx merged commit 6e5704f into iNavFlight:master Jun 24, 2024
22 checks passed
@MrD-RC MrD-RC added this to the 8.0 milestone Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants