[education/kstars] kstars/ekos/guide/internalguide: AI Guide: remove unphysical DEC PE oscillator states from Harmonic Kalman filter
Jasem Mutlaq <[email protected]> Wed, 5 Aug 2026 11:02:41 +0000 (UTC)
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit f1f5ee41f8cd98a844f21ea392fb3da44f9314f2 by Jasem Mutlaq.
Committed on 05/08/2026 at 11:02.
Pushed by mutlaqja into branch 'master'.
AI Guide: remove unphysical DEC PE oscillator states from Harmonic Kalman filter
Strain-wave periodic error comes from the continuously rotating RA drive;
DEC has no equivalent mechanism. The DEC_PE_SIN/COS and DEC_PE2_SIN/COS
states had nothing real to lock onto, and with only DEC_VEL competing for
credit against the same single DEC position observation, the two became
degenerate: they drifted apart as a large, growing, mutually-cancelling
pair, leaving a small but steadily growing DEC bias as the residual.
Disconnect those states from both the process noise (computeQ) and the
observation matrix (kalmanUpdate) so no Kalman gain flows into them; they
now stay at their zero-initialized value for the session, matching the
physical reality that DEC PE doesn't exist. RA is unaffected.
M +11 -9 kstars/ekos/guide/internalguide/harmonic_guider.cpp
M +4 -0 kstars/ekos/guide/internalguide/harmonic_guider.h
https://invent.kde.org/education/kstars/-/commit/f1f5ee41f8cd98a844f21ea392fb3da44f9314f2
diff --git a/kstars/ekos/guide/internalguide/harmonic_guider.cpp b/kstars/ekos/guide/internalguide/harmonic_guider.cpp
index 3e328699c3..e11549dc31 100644
--- a/kstars/ekos/guide/internalguide/harmonic_guider.cpp
+++ b/kstars/ekos/guide/internalguide/harmonic_guider.cpp
@@ -313,20 +313,22 @@ HarmonicGuider::computeQ(double snr, double snr_delta,
Q(RA_SPRING, RA_SPRING) = 0.001 * dt;
Q(DEC_SPRING, DEC_SPRING) = 0.001 * dt;
- // PE process noise (small — PE is nearly deterministic)
+ // PE process noise (small — PE is nearly deterministic). RA only: strain-wave
+ // periodic error comes from the continuously rotating RA drive, so a DEC PE
+ // oscillator has nothing real to lock onto. With no measurement on those states
+ // either (see kalmanUpdate()), a slow sinusoid and DEC_VEL's linear ramp become
+ // degenerate over a session shorter than one PE period, and the filter settles
+ // into a large, growing, mutually-cancelling pair whose small residual is a
+ // steadily growing DEC bias.
if (m_pe_period > 0.0)
{
Q(RA_PE_SIN, RA_PE_SIN) = 0.001 * dt;
Q(RA_PE_COS, RA_PE_COS) = 0.001 * dt;
- Q(DEC_PE_SIN, DEC_PE_SIN) = 0.001 * dt;
- Q(DEC_PE_COS, DEC_PE_COS) = 0.001 * dt;
}
if (m_pe2_period > 0.0)
{
Q(RA_PE2_SIN, RA_PE2_SIN) = 0.001 * dt;
Q(RA_PE2_COS, RA_PE2_COS) = 0.001 * dt;
- Q(DEC_PE2_SIN, DEC_PE2_SIN) = 0.001 * dt;
- Q(DEC_PE2_COS, DEC_PE2_COS) = 0.001 * dt;
}
return Q;
@@ -385,20 +387,20 @@ void HarmonicGuider::kalmanPredict(double dt, double alt_deg, double parallactic
// ── Kalman update step ───────────────────────────────────────────────────────
void HarmonicGuider::kalmanUpdate(double ra_meas_px, double dec_meas_px, double snr)
{
- // Observation matrix: observe position + PE_sin
- // H extracts: ra_obs = ra_err + pe_sin_ra, dec_obs = dec_err + pe_sin_dec
+ // Observation matrix: observe position + PE_sin, RA only (see computeQ() for why
+ // DEC has no PE oscillator to observe). DEC_PE_SIN/DEC_PE2_SIN never receive a
+ // Kalman gain and stay at their zero-initialized value for the whole session.
+ // H extracts: ra_obs = ra_err + pe_sin_ra, dec_obs = dec_err
Eigen::Matrix<double, N_OBS, N_STATES> H = Eigen::Matrix<double, N_OBS, N_STATES>::Zero();
H(0, RA_POS) = 1.0;
H(1, DEC_POS) = 1.0;
if (m_pe_period > 0.0)
{
H(0, RA_PE_SIN) = 1.0;
- H(1, DEC_PE_SIN) = 1.0;
}
if (m_pe2_period > 0.0)
{
H(0, RA_PE2_SIN) = 1.0;
- H(1, DEC_PE2_SIN) = 1.0;
}
// Measurement noise from the current frame's SNR (~0.5 px at SNR 30)
diff --git a/kstars/ekos/guide/internalguide/harmonic_guider.h b/kstars/ekos/guide/internalguide/harmonic_guider.h
index ddf04144c3..4bee0ab68a 100644
--- a/kstars/ekos/guide/internalguide/harmonic_guider.h
+++ b/kstars/ekos/guide/internalguide/harmonic_guider.h
@@ -15,6 +15,10 @@
*
* The PE states evolve as a 2D rotation at the detected PE frequency, allowing
* the Kalman filter to automatically estimate PE amplitude and phase online.
+ * PE is an RA-only phenomenon (strain-wave error from the continuously rotating
+ * RA drive); pe_sin_dec/pe_cos_dec/pe2_sin_dec/pe2_cos_dec occupy state-vector
+ * slots but are never driven by process noise or observed (see computeQ() and
+ * kalmanUpdate()), so they stay at zero for the whole session.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/