Commit fddd046
feat: always-on markdown report from computed analysis outputs (#156)
* feat: always-on markdown statistical report per processed file
Automatically writes <stem>_report.md alongside PNGs on every run.
No flag required. Includes firmware/config metadata, per-axis signal
statistics (mean/std/min/max/rms for gyro, setpoint, P/I/D/F), and
linked (not inline) references to all generated PNG files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add BodeAxisResult return type to plot_bode_analysis
Returns per-axis StabilityMargins from Bode analysis for downstream
report collection. Early-exit paths return empty vec. Suppress
dead_code until report wiring in a follow-up commit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add MotorOscillationResult return type to plot_motor_spectrums
Returns per-motor oscillation analysis (detected flag, peak/avg in
50-200 Hz range, overall max amplitude) for downstream report collection.
Restructures the oscillation-check loop to build typed results instead
of printing only. Early-exit paths return empty vec.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: structured markdown report from computed analysis outputs
Replaces raw CSV-stats report with typed structs capturing the same
analysis results already printed to console — no CSV re-reading,
no println duplication.
- report.rs: rewritten with FlightReport, StepAxisReport, DTermRec;
generate_markdown_report(&FlightReport, &Path) formats P:D ratios,
step response assessments and D-term recommendations, Optimal P
analysis, Bode stability margins, motor oscillation, and PNG links
- plot_bode.rs: remove unused axis field from BodeAxisResult;
drop #[allow(dead_code)] now that fields are consumed by the report
- plot_motor_spectrums.rs: drop #[allow(dead_code)] from MotorOscillationResult
- main.rs: capture pd_ratios_for_report, build step_reports from
existing analysis arrays (re-computing aggressive tier inline),
clone optimal_p_analyses before move into OptimalPConfig, capture
motor_results and bode_results from plot function returns, assemble
FlightReport and call new generate_markdown_report
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(report): add setpoint authority to step response report section
StepAxisReport gains setpoint_authority_name/mean fields populated from
the already-computed compute_setpoint_authority() result in main.rs.
Report displays authority level and mean dps under each axis's step
response section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(report): add gyro filtering delay and spectrum peaks section
plot_gyro_spectrums now returns GyroAnalysisResult containing the
average filtering delay (already computed via cross-correlation) and
per-axis primary unfiltered spectrum peaks. FlightReport stores this
as gyro_analysis; the report emits a Gyro Analysis section with delay
and a peaks table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(report): add D-term filtering delay and spectrum peaks section
plot_d_term_spectrums now returns Vec<DTermAxisResult> with per-axis
primary peak (freq/amplitude) and filtering delay (ms + confidence)
already computed by d_term_delay::calculate_d_term_filtering_delay_comparison.
FlightReport stores dterm_results; the report emits a D-Term Analysis
table with delay and primary peak per axis.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(report): all spectrum peaks per axis; per-axis gyro delay with confidence
- Store full peaks Vec (primary + subordinates up to MAX_PEAKS_TO_LABEL=3)
in both GyroSpectrumAxisResult and DTermAxisResult instead of first-only
- DelayAnalysisResult gains axis_delays Vec so per-axis (delay_ms, confidence)
is surfaced from calculate_average_filtering_delay_comparison
- GyroSpectrumAxisResult carries per-axis delay_ms/delay_confidence sourced
from axis_delays; GyroAnalysisResult.average_delay_ms removed (superseded)
- Report tables for Gyro Analysis and D-Term Analysis now share identical
column format: Axis | Delay (ms) | Confidence | Peak | Freq (Hz) | Amplitude
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: filter config section, D-term N/A disambiguation, step warnings in report (#153)
Add three new report sections from console output that were missing:
1. Filter Configuration: per-axis LPF1/LPF2/IMUF table + dynamic notch and
RPM filter lines. Parses AllFilterConfigs, DynamicNotchConfig, RpmFilterConfig
from header metadata via filter_response. Works for BF (unified), EmuFlight
(per-axis), HELIOSPRING (IMUF PTn), and EmuFlight pseudo-Kalman.
2. D-term N/A disambiguation: DTermAxisDelay struct replaces Vec<Option<DelayResult>>,
carrying na_reason alongside the result. Possible reasons: "D gain disabled",
"Low signal correlation", "Insufficient samples", "No D-term data". Report
now shows e.g. "N/A (Low signal correlation)" instead of bare "N/A".
3. Step response warnings: warnings: Vec<String> on StepAxisReport captures severe
overshoot and unreasonable P:D ratio alerts that previously only appeared on
console. Rendered as bold "⚠ Warning:" lines after recommendations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: document gyroUnfilt debug fallback in report metadata
When gyroUnfilt data comes from debug[0-2] channels instead of dedicated
gyroUnfilt columns, add a ⚠ note in Metadata with the debug mode name
(e.g. GYRO_SCALED, RC_SMOOTHING). Pilots need to know that unfiltered gyro
spectrums and filtering delay calculations in that report are derived from
debug channels, not actual gyroUnfilt — affecting their interpretation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: clone root_name_string before move into FlightReport
root_name_string was moved into FlightReport.root_name then
borrowed again by plot_eso_output; clone before the move.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: correct na_reason and fmt_imuf fallback
Two issues flagged by CodeRabbit review:
1. d_term_delay.rs: split the combined gyroUnfilt/d_term unavailability
guard into separate checks so na_reason correctly reflects the actual
cause — 'No gyroUnfilt data' vs 'No D-term data'. Previously both
conditions silently fell through with 'No D-term data', misleading
pilots whose log lacked gyroUnfilt but had D-term data.
2. report.rs fmt_imuf: change the catch-all ptn_order arm from '2×PT1'
to 'PT?' so an unknown or zero order renders visibly wrong rather than
silently plausible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: document always-on markdown report in README and OVERVIEW
Fill in the empty 'Generated Reports' section in OVERVIEW.md and add
a 'Markdown Report' subsection to README.md Output section. Both now
describe the always-on *_report.md output, its sections, and when
optional sections (Optimal P, Bode) appear.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: address CodeRabbit inline findings from PR#156 review
Four issues resolved:
1. ESO PNG missing from report: moved report generation to after the ESO
block so png_links is complete. Also adds the ESO stacked PNG to
png_links on success.
2. Error propagation: replaced log-and-continue match on
generate_markdown_report with ? operator so a write failure
propagates out of process_file().
3. Empty axis_delays in plot_setpoint_vs_gyro.rs: changed Vec::new()
fallback to vec![None; AXIS_NAMES.len()] to satisfy the per-axis
indexing contract expected by downstream consumers.
4. Hardcoded axis counts: replaced [Option<f64>; 3], [None, None, None],
[Vec::new()...] and 0..2 introduced by the report wiring with
AXIS_COUNT, std::array::from_fn, and ROLL_PITCH_AXIS_COUNT.
Deferred: png_links as second source of truth (heavy refactor — tracked
as follow-up).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>1 parent 0d47da9 commit fddd046
14 files changed
Lines changed: 983 additions & 56 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
182 | 182 | | |
183 | 183 | | |
184 | 184 | | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
185 | 190 | | |
186 | 191 | | |
187 | 192 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
107 | 111 | | |
108 | 112 | | |
109 | 113 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
15 | 22 | | |
16 | 23 | | |
17 | 24 | | |
| |||
44 | 51 | | |
45 | 52 | | |
46 | 53 | | |
47 | | - | |
48 | | - | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
49 | 64 | | |
50 | 65 | | |
51 | 66 | | |
52 | 67 | | |
53 | 68 | | |
54 | | - | |
| 69 | + | |
55 | 70 | | |
56 | 71 | | |
57 | 72 | | |
58 | 73 | | |
59 | | - | |
| 74 | + | |
60 | 75 | | |
61 | 76 | | |
62 | | - | |
63 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
64 | 84 | | |
65 | 85 | | |
66 | 86 | | |
| |||
112 | 132 | | |
113 | 133 | | |
114 | 134 | | |
115 | | - | |
116 | | - | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
117 | 141 | | |
118 | 142 | | |
119 | 143 | | |
| |||
141 | 165 | | |
142 | 166 | | |
143 | 167 | | |
| 168 | + | |
144 | 169 | | |
145 | 170 | | |
146 | 171 | | |
| |||
157 | 182 | | |
158 | 183 | | |
159 | 184 | | |
| 185 | + | |
160 | 186 | | |
161 | 187 | | |
162 | 188 | | |
| |||
175 | 201 | | |
176 | 202 | | |
177 | 203 | | |
| 204 | + | |
178 | 205 | | |
179 | 206 | | |
180 | 207 | | |
| |||
203 | 230 | | |
204 | 231 | | |
205 | 232 | | |
206 | | - | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
207 | 237 | | |
208 | 238 | | |
209 | 239 | | |
210 | 240 | | |
211 | 241 | | |
| 242 | + | |
212 | 243 | | |
213 | 244 | | |
214 | 245 | | |
| |||
221 | 252 | | |
222 | 253 | | |
223 | 254 | | |
224 | | - | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
225 | 259 | | |
226 | 260 | | |
227 | 261 | | |
228 | 262 | | |
229 | 263 | | |
| 264 | + | |
230 | 265 | | |
231 | 266 | | |
232 | 267 | | |
| |||
235 | 270 | | |
236 | 271 | | |
237 | 272 | | |
238 | | - | |
| 273 | + | |
239 | 274 | | |
240 | 275 | | |
241 | 276 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
188 | 188 | | |
189 | 189 | | |
190 | 190 | | |
| 191 | + | |
191 | 192 | | |
192 | 193 | | |
193 | 194 | | |
| |||
274 | 275 | | |
275 | 276 | | |
276 | 277 | | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
277 | 285 | | |
278 | 286 | | |
279 | 287 | | |
| |||
298 | 306 | | |
299 | 307 | | |
300 | 308 | | |
| 309 | + | |
301 | 310 | | |
302 | 311 | | |
303 | 312 | | |
304 | 313 | | |
305 | 314 | | |
| 315 | + | |
306 | 316 | | |
307 | 317 | | |
308 | 318 | | |
309 | 319 | | |
310 | 320 | | |
311 | 321 | | |
| 322 | + | |
312 | 323 | | |
313 | 324 | | |
314 | 325 | | |
| |||
325 | 336 | | |
326 | 337 | | |
327 | 338 | | |
| 339 | + | |
| 340 | + | |
328 | 341 | | |
329 | 342 | | |
330 | 343 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
0 commit comments