The current online estimator fits F = m·a + c·v + k·x by total least squares on time-domain signals. It tracks stiffness passably but jitters, and in the field it does not really recover mass or damping at all. This note proposes fable_kmc, a causal frequency-domain errors-in-variables tracker, and measures both against nonparametric references on four recorded runs.
The specimen is modelled as a single-degree-of-freedom oscillator
where x is the measured displacement dm (in metres), F is the measured force fm, and v, a are its first and second time derivatives. The current online estimator (estimate_tse.m) stacks [a v x 1 F] and takes the smallest right singular vector — a total-least-squares (TLS) fit that treats every column as noisy. The pending Simulink replacement (windowed_noise_whitened_tls.m) is the same fit on short causal windows, noise-whitened and smoothed by a small Kalman filter. Both share one structural choice: they work in the time domain, and they build v and a by differentiating the displacement.
Three problems show up directly in the recorded data.
Differentiating a 30 Hz-filtered displacement twice to get acceleration destroys most of the high-frequency content that carries the mass term m·a. The offline TLS/LSE batch fits land near 26–28 kg against a specimen mass of 44.1 kg — roughly 36% low. Worse, the estimates logged by the live rig (m_hat, c_hat) sit pinned at their floor — about 0.45 kg and 0.24 N·s/m — meaning the field system is really only tracking k and reporting placeholder mass and damping.
| quantity | official (specimen ID) | batch TSE | batch LSE | as-flown log | fable |
|---|
Trim window of record 1708. "Official" is the stored specimen value from the whitened-TLS identification. Only fable recovers a physical mass and a positive damping.
This rig has appreciable hysteretic (structural) damping — a quadrature term that is roughly flat in frequency rather than proportional to it. Forcing the two-parameter viscous form c·v to absorb it drives c negative (fable with the h₀ term disabled returns c ≈ −1.9×10³ N·s/m). A negative damping estimate is not just cosmetic; it is unusable for any downstream stability or energy argument.
Because each short window is fit independently and then lightly smoothed, the stiffness track wanders. Measured as the 95th-percentile step-to-step change (per 0.25 s), the current and pending methods move 6–45% of the stiffness level; the windowed LSE reaches 74% on the stress record. That jitter is the reason a Kalman filter was bolted on — it treats a smoothing problem as a filtering problem, after the fact.
fable_kmc keeps the same physical model but estimates it where differentiation is exact and noise is separable: the frequency domain. The frequency-response function from displacement to force, H(ω) = F(ω)/X(ω), of an SDOF specimen is
Every term is linear in the parameters, and the derivative operators became exact multiplications (v→jωX, a→−ω²X) — no finite differencing, no differentiation noise. The pipeline, run causally every hop_s seconds:
Each estimate carries a 1-σ covariance from the fit and a status flag (acquiring / tracking / hold), plus a model-free low-band diagnostic k_direct = median Re H for a sanity cross-check.
The chart below is the measured FRF of record 1708 over its trim window, with fable's fitted model on top. The real part carries k (its low-frequency value) and m (its downward curvature). The imaginary part is the tell for the damping model: the data sits near a flat ≈4×10⁵ N/m, the signature of hysteretic damping. A purely viscous term c·ω with the small c the specimen actually has would be nearly zero here (lower line) — which is exactly why forcing the viscous-only model makes the fit throw c negative to compensate.
Every knob lives in fable_kmc_config.m and can be swept live in run_fable_kmc.m (a slider-style UI with a box per parameter and a Calculate button). The two that matter most are marked ★.
| parameter | default | what it does · when to change it |
|---|
Pick a record and a parameter. Every method sees only displacement and force. Fable (blue) is drawn on top; its shaded band is the 95% confidence interval, grey dots are the model-free k_direct check.
For each record the parameter track is put on a common 4 Hz grid over the trim window and scored on four axes. Lower is better on all four. Accuracy is distance from the low-band FRF anchor (see §9 on why that reference is itself only one of several defensible "true" stiffnesses). Smoothness and excursion are the honest wins; mass error is the decisive one.
| method | k median (MN/m) | |k−anchor| % | smoothness p95 % | max excursion % | m median (kg) | c median (N·s/m) |
|---|
95th-percentile step-to-step change in the stiffness track, as a percent of the stiffness level (per 0.25 s). Fable is one to two orders of magnitude steadier because smoothing is applied to the spectra, not to the output.
The play record splices one physical run into five 32-second blocks and scales the force channel by [1, 0.5, 1, 0.25, noise] with a drifting offset — a deliberately corrupted signal. The specimen never changes, so the "right" answer is a constant k; but with the force channel scaled, every method reads the apparent secant stiffness of the block. The point is not accuracy here — it is how gracefully each method moves and recovers. Fable's fast-adaptation marks (dashed red on the track) fire at the two largest transitions.
| method | block 1 (×1.0) | block 2 (×0.5) | block 3 (×1.0) | block 4 (×0.25) | block 5 (noise) |
|---|
Last valid stiffness in each block (MN/m). All methods follow the forced amplitude down and back; fable does it with the least jitter and re-converges within a few seconds of each step.
All work is confined to research/fable/stiffness/. Regenerate the data by running the harness in MATLAB, then reload this page.