feat: torque-inertia profiler & optimal P estimation (squash-rebase onto #143)#145
Conversation
…ctor (squash) Squash of all feature/torque-inertia-profiler commits for clean rebase onto master. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- extract_aircraft_key: include craft name from post-date suffix when prefix ends with BLACKBOX_LOG (fixes BTFL files where craft name follows _YYYYMMDD_HHMMSS grouping all into BTFL_BLACKBOX_LOG) - TORQUE_PROFILER_SETTLE_SAMPLES: 3 → 5 samples to better cover ESC/motor lag at 1 kHz (5 ms vs 3 ms) - TORQUE_PROFILER_ACHIEVABILITY_FACTOR: document empirical calibration origin (5" 6S freestyle / HELIO H7) - extract_punch_ratios: comment that Yaw (axis 2) is collected for diagnostics but excluded from optimal-P analysis Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All three labels now use consistent "Recommendation (X):" form matching master: conservative, moderate, and aggressive — eliminating the "Conservative recommendation:" / "Moderate recommendation:" variants that leaked in from the feature branch during conflict resolution. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When step response is optimal the conservative block already emits 'Recommendation (none): No obvious tuning adjustments needed'. The moderate else-if fallback then emitted a second redundant 'Recommendation: None (Optimal)' entry. Remove the redundant block; the conservative branch always covers the no-recommendation case. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR introduces a physics-based optimal P gain recommendation system that derives target time-to-50% (Td) from torque-inertia ratios measured in throttle-punch flight dynamics. It implements two-phase aircraft grouping and per-file analysis, adds extensive tuning constants, refactors the plot infrastructure with structured configurations, and integrates an experimental ChangesOptimal P Estimation with Physics-Derived Td Targets
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes The PR introduces substantial new functionality across multiple modules (torque-inertia profiling, optimal P analysis, two-phase orchestration, plot refactoring) with heterogeneous logic density. Key review areas: physics constant validity, Td statistics and classification correctness, aircraft grouping logic, HF energy computation, plot legend rendering with optional overlays, and main.rs pipeline orchestration. The refactored plot signature and structured configs add surface complexity but improve maintainability. Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Replace the stale prop-size / TD_TARGETS table section with accurate documentation of the new architecture: two-phase profiler (punch-event detection → aircraft grouping → OptimalPAnalysis), key constants, the aircraft grouping fix for generic BTFL filenames, and the relationship between P:D recommendations and optimal-P estimation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ec; doc cleanup - plot_step_response: show optimal-P section (including skip reason) whenever estimate_optimal_p was requested, not only when a full analysis succeeded. Fixes blank PNG legend when profiler data is insufficient. - optimal_p_estimation + plot_step_response: fall back to current P:D when recommended_pd_conservative is None (optimal step response) so D is always shown alongside the recommended P, not only when overshoot correction exists. - OVERVIEW.md: remove history/change language; replace constant values with constant names; clarify Yaw exclusion rationale and skip-reason output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ount, Experimental label, skip in PNG - Add LOW_AUTHORITY_SETPOINT_THRESHOLD_DEG_S constant and detect hover/slow-cruise logs where max setpoint < threshold; print warning in both PNG legend and console optimal-P section - Add n= sample count to Td line in PNG and console for statistical-weight context - Label Optimal P section as "Optimal P (Experimental, log-derived)" in PNG - Show skip reason in PNG even when analysis was not performed (not just on success) - D recommendation falls back to current P/D ratio when step response is optimal (no P:D change computed), ensuring D is always shown alongside optimal-P recommendation - OVERVIEW.md: add CV/consistency/low-authority reliability interpretation section Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rity - PNG skip branch: use same 'Optimal P (Experimental, log-derived)' label as success branch — skip reason line already conveys the skip; no duplicate marker needed - PNG consistency: always emit Consistency: X% line (orange with CV when poor, grey when good) so PNG matches console parity; previously only warning shown - Rename n= → windows= in PNG and console Td line — more intuitive for pilots (windows = valid step-response windows contributing to the Td mean) - OVERVIEW.md: update windows= description accordingly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both console and PNG now report: 'unreliable (>40%)' where 40 is derived from TD_COEFFICIENT_OF_VARIATION_MAX so the displayed value tracks the constant without manual updates. Verbiage aligned between outputs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
README: - Remove --prop-size (no longer exists; torque-inertia ratio is log-derived) - Update --estimate-optimal-p description to match actual CLI - Remove --prop-size from example command - Add optimal P estimation to console output section OVERVIEW: - Windowing section: clarify FRAME_LENGTH_S vs RESPONSE_LENGTH_S design (longer deconvolution window for frequency resolution; only first RESPONSE_LENGTH_S retained for display and analysis) - Optimal P Output bullet: enumerate all current dependability signals (windows=, consistency %, LOW AUTHORITY warning, skip reason) and reference the CV/reliability section for details Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove '(no prop-size required)' — the flag description stands on its own. Trim console output bullet to remove redundant LOW AUTHORITY qualifier. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
src/main.rs (1)
467-468: ⚡ Quick winReplace the new per-axis
3s withAXIS_COUNT.These arrays are part of the axis pipeline, so hardcoding
3here can drift fromsrc/axis_names.rsand the rest of the codebase.Proposed cleanup
+use crate::axis_names::AXIS_COUNT; use crate::data_analysis::torque_inertia_profiler::{extract_punch_ratios, AircraftProfile}; fn profile_aircraft_group(files: &[String], debug_mode: bool) -> AircraftProfile { - let mut all_axis_ratios: [Vec<f64>; 3] = [Vec::new(), Vec::new(), Vec::new()]; + let mut all_axis_ratios: [Vec<f64>; AXIS_COUNT] = std::array::from_fn(|_| Vec::new()); let mut files_profiled: usize = 0;- let mut optimal_p_analyses: [Option< - crate::data_analysis::optimal_p_estimation::OptimalPAnalysis, - >; 3] = [None, None, None]; - let mut optimal_p_skip_reasons: [Option<String>; 3] = [None, None, None]; + let mut optimal_p_analyses: [Option< + crate::data_analysis::optimal_p_estimation::OptimalPAnalysis, + >; AXIS_COUNT] = std::array::from_fn(|_| None); + let mut optimal_p_skip_reasons: [Option<String>; AXIS_COUNT] = + std::array::from_fn(|_| None);As per coding guidelines,
All constants go in src/constants.rs — no hardcoded magic numbers in function codeandAxis indices (0=Roll, 1=Pitch, 2=Yaw) must use the src/axis_names.rs module with AXIS_COUNT, AXIS_NAMES, and axis_name() function instead of creating redundant axis index constants.Also applies to: 1120-1123
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main.rs` around lines 467 - 468, Replace hardcoded axis-size literals with the shared AXIS_COUNT constant: in the function profile_aircraft_group (where all_axis_ratios is declared) change [Vec::new(); 3] / [Vec::new(), Vec::new(), Vec::new()] style initializations to use AXIS_COUNT (e.g., using iterators or array initialization sized by AXIS_COUNT) so the array length matches the axis_names module; do the same for the other similar declarations referenced in the review (the other per-axis arrays around the later block) and ensure code imports/uses AXIS_COUNT (and axis_name()/AXIS_NAMES where appropriate) instead of any hardcoded 3.src/plot_functions/plot_step_response.rs (1)
576-744: ⚡ Quick winHoist the new legend colors into
src/constants.rs.The experimental Optimal P legend adds several fresh inline color literals. Keeping these named in one place will match the repo rule and make the new section easier to tune consistently.
As per coding guidelines,
All constants go in src/constants.rs — no hardcoded magic numbers in function code.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/plot_functions/plot_step_response.rs` around lines 576 - 744, The new legend uses several inline RGBColor literals (e.g., RGBColor(40,40,40), RGBColor(0,100,200), RGBColor(80,80,80), RGBColor(200,100,0), RGBColor(0,150,0), RGBColor(120,60,60)) inside the plot_step_response rendering (around the Optimal P header, Td lines, consistency warning, recommendation, and skip-reason); hoist these into the central constants module as named constants (for example OPTIMAL_SECTION_DIVIDER_COLOR, OPTIMAL_P_HEADER_COLOR, LEGEND_TEXT_COLOR, CONSISTENCY_WARNING_COLOR, RECOMMENDATION_COLOR, SKIP_REASON_COLOR), export them from the constants module, and replace the inline RGBColor(...) usages in the PlotSeries constructions (and any related helper closures like append_d_recommendation if they reference colors) with the new named constants so the palette is centralized and tunable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/data_analysis/optimal_p_estimation.rs`:
- Around line 145-156: The function from_samples currently computes stats over
td_samples_ms without rejecting non-finite values; filter td_samples_ms for
finite f64 values (use f64::is_finite) and operate on that filtered
slice/iterator, returning None if the filtered set is empty, and then compute n,
mean and downstream statistics from the filtered values; apply the same
finite-value filtering fix to the other similar blocks referenced (around the
regions corresponding to lines 163-170 and 269-280) so no NaN/±inf can propagate
into mean/deviation/classification logic.
In `@src/data_analysis/torque_inertia_profiler.rs`:
- Around line 113-114: The struct field and hot-path code use hardcoded
axis/count and numeric literals (e.g., the array size [AxisProfile; 3] and magic
numbers 1000.0 and 1e-9); replace the literal 3 with AXIS_COUNT from
src/axis_names.rs and switch any manual axis-index usage to use
axis_name()/AXIS_NAMES as appropriate, and move numeric literals into
src/constants.rs (e.g., TIME_SCALE_MS, NANOSECONDS_TO_SECONDS or the existing
constant names used project-wide) and reference those constants in the profiler
computations (including the array declaration, loops, and any
scaling/multiplication operations). Update references around symbols AxisProfile
and the profiling functions that do scaling so they import and use AXIS_COUNT
and the constants instead of literal numbers.
- Line 200: The for-loop range resp_start..resp_end.saturating_sub(1)
incorrectly excludes the final adjacent sample pair; change the loop to iterate
up to resp_end - 1 inclusive so the last j/j+1 pair is processed (e.g. use an
inclusive range resp_start..=resp_end.saturating_sub(1) or otherwise compute the
end index as resp_end.saturating_sub(1) and use a standard exclusive range that
reaches that value) — update the loop that references resp_start and resp_end in
torque_inertia_profiler.rs accordingly.
In `@src/main.rs`:
- Around line 1260-1262: The stdout-only branch that prints "P gain not
available..." must also persist that reason into optimal_p_skip_reasons so the
PNG overlay legend can show it; update the else branch handling for
axis_name/axis_index to assign optimal_p_skip_reasons[axis_index] =
Some(format!("P gain not available for {}", axis_name)) (or similar descriptive
string) instead of leaving it None, ensuring any existing Option<String> is set
so the plotting code can render the skip reason.
---
Nitpick comments:
In `@src/main.rs`:
- Around line 467-468: Replace hardcoded axis-size literals with the shared
AXIS_COUNT constant: in the function profile_aircraft_group (where
all_axis_ratios is declared) change [Vec::new(); 3] / [Vec::new(), Vec::new(),
Vec::new()] style initializations to use AXIS_COUNT (e.g., using iterators or
array initialization sized by AXIS_COUNT) so the array length matches the
axis_names module; do the same for the other similar declarations referenced in
the review (the other per-axis arrays around the later block) and ensure code
imports/uses AXIS_COUNT (and axis_name()/AXIS_NAMES where appropriate) instead
of any hardcoded 3.
In `@src/plot_functions/plot_step_response.rs`:
- Around line 576-744: The new legend uses several inline RGBColor literals
(e.g., RGBColor(40,40,40), RGBColor(0,100,200), RGBColor(80,80,80),
RGBColor(200,100,0), RGBColor(0,150,0), RGBColor(120,60,60)) inside the
plot_step_response rendering (around the Optimal P header, Td lines, consistency
warning, recommendation, and skip-reason); hoist these into the central
constants module as named constants (for example OPTIMAL_SECTION_DIVIDER_COLOR,
OPTIMAL_P_HEADER_COLOR, LEGEND_TEXT_COLOR, CONSISTENCY_WARNING_COLOR,
RECOMMENDATION_COLOR, SKIP_REASON_COLOR), export them from the constants module,
and replace the inline RGBColor(...) usages in the PlotSeries constructions (and
any related helper closures like append_d_recommendation if they reference
colors) with the new named constants so the palette is centralized and tunable.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1221348f-c631-439f-b0bc-93f90e826402
📒 Files selected for processing (11)
OVERVIEW.mdREADME.mdsrc/axis_names.rssrc/constants.rssrc/data_analysis/mod.rssrc/data_analysis/optimal_p_estimation.rssrc/data_analysis/spectral_analysis.rssrc/data_analysis/tests_optimal_p.rssrc/data_analysis/torque_inertia_profiler.rssrc/main.rssrc/plot_functions/plot_step_response.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.rs: All constants go insrc/constants.rs— no hardcoded magic numbers in function code
Axis indices (0=Roll, 1=Pitch, 2=Yaw) must use thesrc/axis_names.rsmodule withAXIS_COUNT,AXIS_NAMES, andaxis_name()function instead of creating redundant axis index constants
ALWAYS useFirmware revisionheader to detect firmware type, NEVER useFirmware type
Firmware revision patterns: Betaflight usesBetaflight 4.x.xorBetaflight YYYY.MM, Emuflight usesEmuFlight 0.x.x, INAV usesINAV x.x.x
Files:
src/data_analysis/spectral_analysis.rssrc/data_analysis/tests_optimal_p.rssrc/axis_names.rssrc/data_analysis/mod.rssrc/constants.rssrc/data_analysis/optimal_p_estimation.rssrc/data_analysis/torque_inertia_profiler.rssrc/plot_functions/plot_step_response.rssrc/main.rs
OVERVIEW.md
📄 CodeRabbit inference engine (AGENTS.md)
OVERVIEW.md: For new features, add documentation inOVERVIEW.mdat proper, appropriate locations with information that is balanced or concise, never overly verbose, aligned with existing documentation style
Update Table of Contents inOVERVIEW.mdwhen adding new sections
Files:
OVERVIEW.md
🔇 Additional comments (6)
OVERVIEW.md (1)
12-12: LGTM!Also applies to: 41-41, 193-253
README.md (1)
51-51: LGTM!Also applies to: 80-82, 107-107
src/constants.rs (1)
52-55: LGTM!Also applies to: 266-353
src/axis_names.rs (1)
16-21: LGTM!Also applies to: 27-38
src/data_analysis/mod.rs (1)
9-11: LGTM!src/data_analysis/tests_optimal_p.rs (1)
3-3: ⚡ Quick winMissing input: Provide the original
<review_comment>content (and any referenced diff/snippet) so it can be rewritten with the required fixes/context.
Actionable (4): - optimal_p_estimation: filter non-finite (NaN/inf) Td samples before computing statistics in TdStats::from_samples to prevent propagation into mean/deviation/classification - torque_inertia_profiler: replace magic 1000.0 with THROTTLE_COMMAND_SCALE, 1e-9 with TORQUE_PROFILER_MIN_DT_S; both added to constants.rs - torque_inertia_profiler: fix off-by-one in derivative scan loop — resp_start..resp_end.saturating_sub(1) excluded the last valid j/j+1 pair; corrected to resp_start..resp_end - main.rs: persist skip reason into optimal_p_skip_reasons when P gain is unavailable so PNG overlay renders the reason instead of nothing Nitpicks (2): - main.rs + torque_inertia_profiler: replace all hardcoded [T; 3] axis-count literals with AXIS_COUNT (from axis_names.rs); use std::array::from_fn for initialisation - plot_step_response: hoist all inline RGBColor literals in the Optimal P legend section into named constants in constants.rs (COLOR_OPTIMAL_P_DIVIDER/HEADER/TEXT/WARNING/RECOMMENDATION/SKIP); also applies COLOR_OPTIMAL_P_WARNING to the LOW AUTHORITY warning Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- extract_punch_ratios return type: [Vec<f64>; 3] -> [Vec<f64>; AXIS_COUNT] - ms-to-samples conversions: / 1000.0 -> / OPTIMAL_P_SECONDS_TO_MS_MULTIPLIER (constant already existed; now imported and used consistently) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai, is this PR/idea/functionality proper, accurate, and worth merging? Should we consider an alternative or an additive method such as chirp-analysis? This branch works for full-flight and tuning-flights, but not chirp-logs (no punch-outs). |
|
Tip For best results, initiate chat on the files or code changes.
Is the PR Proper, Accurate, and Worth Merging?Short answer: Yes, with appropriate caveats — the experimental label is well-earned and correctly applied. Strengths ✅
Concerns / Risks
|
| This PR (punch-based) | Chirp-based | |
|---|---|---|
| Log type | Any flight with ≥5 punch-outs | Dedicated chirp-excitation flight |
| Output | Time-domain Td, P/D recommendation | Frequency-domain Bode plot, stability margins |
| Firmware req. | None | Betaflight chirp-generator PR (#13105) |
| Accessibility | High (any tuning session) | Lower (special flight needed) |
| Rigor | Good (time-domain approximation) | Higher (full FRF estimation) |
| Chirp logs | ❌ No punch-outs | ✅ Native use case |
The best path forward would be to merge this PR as-is (it's ready for its stated scope), then open a follow-up issue for a chirp-log analysis path that produces a frequency-domain plant model. The two paths could share the same --estimate-optimal-p output format or add a complementary --estimate-from-chirp mode. Since chirp logs contain no punch-outs and punch-based logs may not contain chirp excitation, both paths are needed to cover all log types.
Recommendation
Merge. The implementation is physically sound, properly guarded, and experimentally labeled. The achievability factor is the main open question but is no worse than the hardcoded tables it replaces. A follow-up issue tracking chirp-analysis support would be a good way to capture the complementary approach without blocking this PR.
Would you like me to open a follow-up GitHub issue for chirp-log analysis support?
Tests for FrameClass/TdTargetSpec/for_frame_inches — all removed with the prop-size approach in favour of the physics-derived torque-inertia profiler. File was not declared in mod.rs and was never compiled; deleted to avoid confusion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai re: Achievability factor (2.50) is empirical The factor is intentionally not generalised beyond what calibration data supports. The key mitigating detail is that That gap is not perfectly constant across craft sizes — larger/slower craft have proportionally more lag — but it is a second-order effect on top of the first-order self-calibration the log-derived ratio already provides. Attempting to model the factor as craft-dependent would require more calibration data than currently exists, and would add complexity without a clear improvement for the "Experimental" status of this feature. The constant is named, clearly documented as empirical, and easily adjusted. Pilot testing on non-5" craft is the practical path to surfacing whether further tuning is needed. No change recommended at this time. |
|
Tip For best results, initiate chat on the files or code changes.
The current design — named constant, clearly documented, easy to adjust, experimentally labeled — is the right call for this stage. Pilot testing on outlier craft sizes is exactly the right feedback mechanism. 🐇 (nodding thoughtfully) ✏️ Learnings added
|
TORQUE_PROFILER_SETTLE_SAMPLES (fixed 5 samples) was only correct at 1 kHz (5 ms). At higher loop rates the settle period was far too short: - 3.2 kHz (BMI270): 1.56 ms — before most ESCs respond - 4 kHz: 1.25 ms - 8 kHz: 0.63 ms Premature measurement produces near-zero angular acceleration, underestimates torque_inertia_ratio, inflates the Td target, and biases recommendations toward Optimal/Decrease when P may need increasing. Replace with TORQUE_PROFILER_SETTLE_MS (5.0 ms) converted to samples at runtime using the actual log sample rate. Behaviour at 1 kHz is unchanged; high-rate logs now skip the correct number of samples to clear ESC/motor lag before measuring peak angular acceleration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai Two additional commits since last exchange:
Finding: The prior constant Fix: replaced the constant with let settle_samples = (TORQUE_PROFILER_SETTLE_MS / OPTIMAL_P_SECONDS_TO_MS_MULTIPLIER * sample_rate).ceil() as usize;
|
|
Tip For best results, initiate chat on the files or code changes.
Clean-up is correct. The file was testing
This is a genuine correctness fix, not cosmetic. The math checks out:
The bug path you described is exactly right: measuring angular acceleration before ESC torque has arrived → near-zero alpha → underestimated ratio → inflated Td target → spurious Optimal/Decrease-P at high loop rates. Using the logging rate (derived from actual The 🐇 (ticks both boxes with a satisfied nod) ✏️ Learnings added
|
The profiler may report Optimal when P is too high because an oscillatory step response produces a short Td that matches the physics formula for the current (excessive) P. CV/consistency warning is the indirect signal. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai Three additional commits since last exchange:
|
|
Tip For best results, initiate chat on the files or code changes.
The blind spot is real and the reasoning is exact: oscillation shortens measured Td (the step response peaks early due to ringing), the physics formula then yields a P_optimal close to the oscillating P, and the comparison reports "Optimal" when the true state is "too high." CV scatter is the correct indirect signal to surface this — it's the only observable symptom that doesn't require knowing what "too high" means in absolute terms. The framing of this tool as a validator/refinement tool rather than a recovery tool for badly mis-tuned craft is the right boundary to draw in documentation.
The decision to reject automated diagnosis is well-justified on all three grounds:
Documentation-only with a clear investigative prompt is the right scope here. 🐇 (approves all three with a considered nod) ✏️ Learnings added
|
Add requirement note to OVERVIEW.md, README.md, and --help output. Without a .headers.csv file P gain is unavailable and optimal P estimation is skipped; all other analyses are unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bf0e53e to
421fca5
Compare
|
@coderabbitai, unexpected bug found when reviewing post-merge PNG's. please investigate and open issue ticket with problem/potential solution. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chainLet me dig into the code to confirm the root cause before opening the issue. 🏁 Script executed: Length of output: 24510 Found the bug. Let me open the issue now. 🏁 Script executed: Length of output: 61
What's happening:
The warning fires whenever The flag logic is correct; only the diagnostic message is wrong. No recommendations are silently miscalculated. Recommended fix (Option B in the issue): pattern-match which condition(s) failed and emit the appropriate reason string, e.g.:
Issue 🐇 |
|
@coderabbitai, does this (already merged) PR group the filenames/flights properly and use all flights the group to calculate estimated-optimal-p as expected? as planned planned as per #132 (comment) ? did #132 (comment) change the expected behavior and regress the intention of this PR? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chainLet me pull up the referenced comments from 🏁 Script executed: Length of output: 21718 Good — now let me read the actual merged code in 🏁 Script executed: Length of output: 3643 🏁 Script executed: Length of output: 275 Good — the two-phase grouping architecture IS present. Now let me read the actual implementations to verify correctness. 🏁 Script executed: Length of output: 9487
Here's the full picture: Is the grouping implemented as planned?Yes — exactly. The two-phase pipeline is present and correct: All flights in a group contribute their throttle-punch ratios to a single Did comment
|
| Filename | Extracted Key |
|---|---|
EMUF_BLACKBOX_LOG_FOXEERF722V4_426_20240406_132335_notes.19.csv |
EMUF_BLACKBOX_LOG_FOXEERF722V4_426 ✅ |
EMUF_BLACKBOX_LOG_FOXEERF722V4_426_20240406_161530_notes.01.csv |
EMUF_BLACKBOX_LOG_FOXEERF722V4_426 ✅ (same group) |
BTFL_BLACKBOX_LOG_20250517_130413_STELLARH7DEV.02.csv |
BTFL_BLACKBOX_LOG_STELLARH7DEV ✅ |
BTFL_BLACKBOX_LOG_20250517_160413_STELLARH7DEV.01.csv |
BTFL_BLACKBOX_LOG_STELLARH7DEV ✅ (same group) |
BTFL_BLACKBOX_LOG_20250517_130413_APEX5.01.csv |
BTFL_BLACKBOX_LOG_APEX5 ✅ (different group) |
no_date_pattern_here.csv |
no_date_pattern_here (unique, full stem) ✅ |
One minor edge case to be aware of
If a BTFL file has notes in the suffix like BTFL_BLACKBOX_LOG_20250517_130413_STELLARH7DEV_notes.02.csv, the craft key becomes BTFL_BLACKBOX_LOG_STELLARH7DEV_notes — which still groups correctly (all sessions with that suffix land in the same group), just with _notes appended to the key. Harmless in practice.
Summary: The merged PR #145 implements aircraft-based grouping correctly, aggregates all flights in a group for the profiling phase, and the BTFL craft-name-after-datetime case is handled. No regression from the concern raised in #4501386876.
🐇 (•‿•) ← relieved it all shipped correctly
AI Generated Pull-request
Binaries: https://github.com/nerdCopter/BlackBox_CSV_Render/actions/runs/26246804179?pr=145
Summary
Physics-aware optimal P gain estimation added as an experimental optional feature (
--estimate-optimal-p), complementing the existing P:D ratio recommendations. Inspired by Brian White's (@bw1129, PIDtoolbox) insight that optimal response timing is aircraft-specific and governed by the power-to-rotational-inertia ratio. Where PIDtoolbox derives targets from known prop size, this implementation measures the torque-inertia ratio directly from throttle-punch events in the log — no prop-size input required.Clean squash-rebase replacement for the closed #141 (84-commit branch → single diff rebased onto master at
56c4aa4post-#143), with all subsequent fixups applied on top.Lineage: #132 → #141 → #145
#132 is the original development PR for this feature. It carries the full pre-squash commit history, all CodeRabbit AI review passes, pilot testing, binary test artifacts, and the iterative change of functional direction — from a prop-size-aware empirical table approach to the current log-derived torque-inertia profiler. #132 is the primary reference for the reasoning behind each design decision. It was kept open throughout development as a working branch and was subsequently superseded by the squash-rebase.
#141 was the first squash attempt, closed in favour of this PR when the branch was found to still carry excess commits.
This PR (#145) is the clean single-diff squash of all #132 work, rebased onto master, with all post-merge fixups applied on top.
Feature: Torque-Inertia Profiler & Optimal P Estimation
How it works
Phase 1 — Aircraft profiling (per group, before per-file processing)
extract_aircraft_key()strips_YYYYMMDD_HHMMSStimestamps so sessions from the same aircraft share one profile. When the filename prefix ends withBLACKBOX_LOG(Betaflight/EmuFlight generic naming), the craft name from the post-date suffix is appended (BTFL_BLACKBOX_LOG_CRAFTNAME,EMUF_BLACKBOX_LOG_CRAFTNAME) to prevent distinct aircraft collapsing into one group.extract_punch_ratios()detects throttle-punch events (setpoint[3]step ≥THROTTLE_PUNCH_MIN_DELTAwithinTHROTTLE_PUNCH_WINDOW_MS) and measures peak angular acceleration in the gyro response window, divided by the normalised throttle delta →torque_inertia_ratioper axis.AircraftProfile(median + half-IQR spread, Roll and Pitch only). Yaw is collected for diagnostic completeness but excluded from optimal-P analysis — Yaw dynamics differ structurally from Roll/Pitch and the formula is not calibrated for Yaw.TORQUE_PROFILER_MIN_EVENTSpunch events; insufficient events produce a skip reason in both console and PNG.Phase 2 — Per-file optimal-P analysis
Td_ms = TORQUE_PROFILER_TD_CALC_K / sqrt((P / TORQUE_PROFILER_P_SCALE) × torque_inertia_ratio) × TORQUE_PROFILER_ACHIEVABILITY_FACTORTORQUE_PROFILER_ACHIEVABILITY_FACTORbridges the physics formula to real-world flight (ESC lag, motor startup, prop wash); empirically calibrated on a 5" 6S freestyle build.OptimalPAnalysisclassifies asIncrease,Optimal,Decrease, orInvestigate.Requirements
.headers.csvmetadata file must be present alongside each input CSV (produced byblackbox_decodeor the modern alternativebbl_parser). Without it, P gain values are unavailable and optimal P estimation is skipped with a skip reason shown in console and PNG. All other analyses (step response, spectrums, P:D recommendations) remain unaffected.Output (console + PNG legend overlay)
Optimal P (Experimental, log-derived)section header — always the same label whether analysis succeeded or was skippedwindows=count, physics-derived target, deviation %LOW/MODERATE/HIGH)> TD_COEFFICIENT_OF_VARIATION_MAX)[LOW AUTHORITY]warning when max setpoint across valid windows is belowLOW_AUTHORITY_SETPOINT_THRESHOLD_DEG_S(hover/slow-cruise logs produce noise-dominated Td measurements, making recommendations unreliable regardless of CV)Relationship to existing P:D recommendations
The two features are complementary and appear simultaneously:
Fixes & Refinements Applied Post-Rebase
extract_aircraft_key()now appends craft name forBLACKBOX_LOG-prefixed files so logs from different aircraft don't collapse into one profileTORQUE_PROFILER_SETTLE_SAMPLES(a fixed sample count, correct only at 1 kHz) withTORQUE_PROFILER_SETTLE_MS = 5.0converted to samples at runtime from the actual log sample rate. At high loop rates (BMI270 3.2 kHz, 4 kHz, 8 kHz) the old constant measured before ESCs responded, underestimatingtorque_inertia_ratioand biasing recommendations. Behaviour at 1 kHz is unchanged.AXIS_COUNTconstant throughout; magic1000.0divisors replaced withTHROTTLE_COMMAND_SCALEandOPTIMAL_P_SECONDS_TO_MS_MULTIPLIER;1e-9dt guard replaced withTORQUE_PROFILER_MIN_DT_S; response window loop off-by-one correctedtests_optimal_p.rscoveredFrameClass/TdTargetSpec/for_frame_inches— all removed with the prop-size approach; file was never declared inmod.rsand never compiledplot_step_response.rsto match console ("Recommendation (conservative):"/"Recommendation (moderate):")"Recommendation: None (Optimal)"no longer appears alongside"Recommendation (none): No obvious tuning adjustments needed"for optimal-response axes"Optimal P (Experimental, log-derived)"— the skip-reason line already explains the outcomeConsistency: X%emitted for every result (grey when good, orange with CV and threshold when poor), matching console paritywindows=replacesn=: more intuitive for pilots — number of valid step-response windows contributing to the Td meanunreliable (>40%)where 40 is derived fromTD_COEFFICIENT_OF_VARIATION_MAX, so the displayed value tracks the constantDocs
FRAME_LENGTH_S(deconvolution resolution) is intentionally longer thanRESPONSE_LENGTH_S(display/analysis); only the firstRESPONSE_LENGTH_Sof each estimated step response is retained[LOW AUTHORITY]is the indirect signal; experienced pilots should start from a lower P if gains feel high[LOW AUTHORITY]documented as an investigative signal — rules out hover/low-energy inputs as the scatter cause; remaining causes include propwash, inconsistent maneuvers, and oscillation from over-P--help:.headers.csvrequirement documented — P gain is unavailable without it; skip reason is shown; all other analyses unaffected--prop-sizeremoved (no longer exists);--estimate-optimal-pdescription and examples updated; optimal P added to console output sectionRemaining Open Items (post-merge)
--estimate-optimal-pflag required); these are coupled and tracked togetherTest Plan
cargo build --releasepasses cleanlycargo clippyzero warnings--step --estimate-optimal-pon logs with deliberate throttle-punch sequences (≥TORQUE_PROFILER_MIN_EVENTSper aircraft group).headers.csvabsent → skip reason shown in console and PNG, all other plots unaffected🤖 Generated with Claude Code