-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Conversation
Note that the LULU filter really gets processor intensive above around 6-8 samples of filtering. Check CPU usage before flight! |
Can't wait to test it! |
There was a problem hiding this 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
Outdated
} | ||
// if (gyroConfig()->adaptiveFilterMaxHz - 5 < gyroConfig()->gyro_main_lpf_hz) { | ||
// gyroConfigMutable()->adaptiveFilterMaxHz = gyroConfig()->gyro_main_lpf_hz + 5; | ||
// } | ||
#endif | ||
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
src/main/fc/settings.yaml
Outdated
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 |
There was a problem hiding this comment.
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
src/main/fc/settings.yaml
Outdated
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 |
There was a problem hiding this comment.
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
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 |
There was a problem hiding this comment.
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.
I see there's still changes requested? I think I did complete all the changes that were specified, please note if I missed any :) |
My testing settings are: set looptime = 500 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. |
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. |
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
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