Add alpha_beta and alpha_beta_gamma trackers - #1069
Merged
Merged
Conversation
Two fixed-gain estimators of the position and rate (and, for the third-order
one, the acceleration) of a target, returned as discrete-time StateSpace
systems whose input is the measured position and whose outputs are the
estimates. Both are observer_filter of an integrator chain with
K = [alpha, beta/Ts] and K = [alpha, beta/Ts, gamma/Ts^2], so the state is the
a-posteriori estimate and the systems are strictly proper.
The rate output is a filtered derivative of the input, available without a
separate differentiator, and the third-order filter removes the bias an
alpha-beta tracker's rate estimate carries on an accelerating signal -- worth
having when the measurement is oversampled relative to the signal, since a
longer effective memory then costs little lag.
`alpha` alone is a complete tuning: `beta` defaults to Kalata's steady-state
relation and `gamma` to beta^2/(2*alpha), which make the filters the
steady-state Kalman filters for constant-velocity and constant-acceleration
targets.
The extended help gives the alternative critically damped tuning, since the
defaults leave a complex pole pair for every alpha:
2nd order: alpha = 1 - s^2, beta = (1 - s)^2
3rd order: alpha = 1 - s^3, beta = 1.5(1 - s)^2(1 + s), gamma = (1 - s)^3
Those are stated for the gain convention used here, in which the acceleration
correction is gamma/Ts^2 alongside the rate correction beta/Ts; references
differ by factors of two depending on that choice, so the docstring says which
one it means and the tests check the relations rather than leaving them as
prose. The docstrings also note the one-sample bookkeeping these share with
observer_filter: the state is x(k|k), so the estimate that absorbed y(k)
appears at output index k+1 of a simulation.
Tests cover the shapes and defaults, agreement with the documented recurrence
under lsim, ramp tracking, equality with observer_filter of the corresponding
integrator chain, the critical-damping recipes at several radii and sample
rates, that the defaults are not critically damped, and argument validation.
No new dependencies.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PZNSHjGe7PQ7MdJg3itmCM
|
This is an automated message.
|
Inspired by ASD-STE100: one idea per sentence, active voice, no metaphor and no idiom, and consistent terms for the same thing throughout. Removed: "noise rejection is bought rather than paid for in phase", "the extra state is what it buys", "the speed knob", "sibling", "puts the poles back off the axis", "settles somewhat slower than the radius alone suggests". Long sentences with semicolons or em-dash asides are split. Statements that are really instructions are written as instructions -- "Setting only `alpha` is not enough" becomes "Do not give only `alpha`". Terms are now used consistently: "gains" rather than "triple"/"defaults"/ "values", "the filter", "the target". The note title "One-sample bookkeeping" becomes "The sample index", which is also how `alpha_beta_gamma` refers to it, and "has absorbed" becomes "includes". The technical content is unchanged, as are the doctests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PZNSHjGe7PQ7MdJg3itmCM
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1069 +/- ##
==========================================
+ Coverage 87.94% 91.74% +3.80%
==========================================
Files 42 42
Lines 5649 5730 +81
==========================================
+ Hits 4968 5257 +289
+ Misses 681 473 -208 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.








Adds
alpha_betaandalpha_beta_gamma: fixed-gain trackers of the position and rate (and, third order, the acceleration) of a target, returned as discrete-timeStateSpacesystems whose input is the measured position and whose outputs are the estimates.Both are
observer_filterof an integrator chain withK = [α, β/T_s]andK = [α, β/T_s, γ/T_s^2], so the state is the a-posteriori estimate and the systems are strictly proper. The rate output is a filtered derivative of the input, available without a separate differentiator.Why the third-order one
An α-β tracker predicts with a locally constant rate, so on a signal that is genuinely accelerating its rate estimate lags by an amount proportional to the acceleration, and no choice of
alphaandbetaremoves that bias. Predicting with the acceleration removes it. That pays when the measurement is oversampled relative to the signal, where a longer effective memory costs little lag — differentiating a quantized encoder to estimate a joint velocity is the case these were written for.Parameterization
alphaalone is a complete tuning.betadefaults to Kalata's steady-state relationβ = 2(2-α) - 4\sqrt{1-α}andgammatoβ^2/(2α), which make the filters the steady-state Kalman filters for constant-velocity and constant-acceleration targets. Atα = 0.5these areβ ≈ 0.1716andγ ≈ 0.0294.The extended help also gives the critically damped alternative, because the defaults leave a complex pole pair for every
alpha— the error always decays with an oscillatory mode. To place the error poles on the real axis at a common radiuss:α = 1 - s^2,β = (1-s)^2α = 1 - s^3,β = \tfrac{3}{2}(1-s)^2(1+s),γ = (1-s)^3with the trap stated: setting only
alphaleaves the other gains at their Kalata defaults and puts the poles straight back off the axis.These relations are stated for the gain convention used here, in which the acceleration correction is
γ/T_s^2alongside the rate correctionβ/T_s. References differ by factors of two depending on whetherγor2γis written in that position, so the docstring says which one it means, and the tests check the relations rather than leaving them as prose. I derived rather than quoted them for exactly this reason — my first draft of the second-order relation had a spurious factor of two and the test caught it.One-sample bookkeeping
Documented in a
!!! note, since it is easy to trip over: the state isx̂(k|k), so with the usualx(k+1) = Ax(k) + Bu(k)update the estimate that absorbedy(k)appears at output indexk+1of a simulation. This is the same conventionobserver_filteralready has.Tests
48 assertions in
test_synthesis.jl: shapes,Ts, strict properness and thatB == K; the default gains; agreement with the documented recurrence underlsim(transcribed as a Julia loop, compared tick by tick); ramp tracking; equality withobserver_filterof the corresponding integrator chain, which is the structural check that these really are that filter; the critical-damping recipes at five radii and three sample rates; that the defaults are not critically damped; and argument validation.No new dependencies.
lib/ControlSystemsBase/test/test_synthesis.jlpasses 141 pre-existing plus the 48 new.Happy to convert this to an issue for discussion first if you would rather — CONTRIBUTING suggests that, and I went straight to a PR because the change is self-contained and additive.
🤖 Generated with Claude Code
https://claude.ai/code/session_01PZNSHjGe7PQ7MdJg3itmCM