Skip to content

Commit 32246d2

Browse files
committed
Merge branch 'master' into 20260402_Quickflash-ESO
2 parents 0d8fe0b + 3e54f4f commit 32246d2

14 files changed

Lines changed: 2466 additions & 484 deletions

OVERVIEW.md

Lines changed: 109 additions & 25 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ cargo build --release
2525
```
2626

2727
### Usage
28+
29+
> **Notice:** Default output is **core plots only**. Use `--extended` for all plots.
30+
2831
```shell
2932
Usage: ./BlackBox_CSV_Render <input1> [<input2> ...] [OPTIONS]
3033

@@ -36,27 +39,29 @@ Usage: ./BlackBox_CSV_Render <input1> [<input2> ...] [OPTIONS]
3639

3740
=== PLOT TYPE SELECTION ===
3841

39-
Note: Plot flags are combinable. Without flags, all plots generated.
40-
41-
--step: Generate only step response plots.
42-
--motor: Generate only motor spectrum plots.
43-
--setpoint: Generate only setpoint-related plots.
44-
--pid: Generate only P, I, D activity plot.
45-
--bode: Bode plot analysis (requires chirp/sweep system-id test flight, not normal logs).
42+
--core [default] Step Response, Gyro Spectrums, D-term Spectrums,
43+
Setpoint vs Gyro, Gyro vs Unfiltered, Motor Spectrums.
44+
--extended All plots except Bode — adds PIDsum/Error, PID Activity,
45+
Setpoint Derivative, Gyro PSD, D-term PSD, and heatmaps.
46+
--step Step response only.
47+
--bode Bode only (requires chirp/sweep system-id test flight).
4648

4749
=== ANALYSIS OPTIONS ===
4850

49-
--butterworth: Show Butterworth PT1 cutoffs on gyro/D-term spectrum plots.
50-
--dps <value>: Deg/s threshold for detailed step response plots (positive number).
51+
--butterworth Show Butterworth PT1 cutoffs on gyro/D-term spectrum plots.
52+
--dps <value> Deg/s threshold for detailed step response plots (positive number).
53+
--estimate-optimal-p [EXPERIMENTAL] Optimal P estimation from throttle-punch
54+
dynamics. Requires .headers.csv; skips if absent.
5155

5256
=== GENERAL ===
5357

54-
--debug: Show detailed metadata during processing.
55-
-h, --help: Show this help message and exit.
56-
-V, --version: Show version information.
58+
--debug Show detailed metadata during processing.
59+
-h, --help Show this help message and exit.
60+
-V, --version Show version information.
5761
```
5862
5963
Arguments can be in any order. Wildcards (e.g., *.csv) are shell-expanded and work with mixed file/directory patterns.
64+
6065
### Example execution commands
6166
```shell
6267
./target/release/BlackBox_CSV_Render path/to/BTFL_Log.csv
@@ -71,35 +76,41 @@ Arguments can be in any order. Wildcards (e.g., *.csv) are shell-expanded and wo
7176
./target/release/BlackBox_CSV_Render path/to/ -R --step --output-dir ./step-only
7277
```
7378
```shell
74-
./target/release/BlackBox_CSV_Render path/to/ --setpoint --output-dir ./setpoint-only
79+
./target/release/BlackBox_CSV_Render path/to/ --extended --output-dir ./all-plots
7580
```
7681
```shell
77-
./target/release/BlackBox_CSV_Render path/to/ --step --setpoint --motor --output-dir ./all-selective
82+
./target/release/BlackBox_CSV_Render path/to/BTFL_Log.csv --step --estimate-optimal-p
7883
```
7984
8085
### Output
8186
8287
#### PNG Files Generated
88+
89+
**Core (default):**
8390
- `*_Step_Response_stacked_plot_*.png` — Step response analysis with P:D recommendations
84-
- `*_PIDsum_PIDerror_Setpoint_stacked.png` — PIDsum, PID error, and setpoint traces
8591
- `*_SetpointVsGyro_stacked.png` — Setpoint vs. filtered gyro comparison
8692
- `*_GyroVsUnfilt_stacked.png` — Filtered vs. unfiltered gyro comparison with delay estimates
8793
- `*_Gyro_Spectrums_comparative.png` — Frequency-domain gyro amplitude spectrums
88-
- `*_Gyro_PSD_comparative.png` — Gyro power spectral density (dB scale)
8994
- `*_D_Term_Spectrums_comparative.png` — Frequency-domain D-term amplitude spectrums
95+
- `*_Motor_Spectrums_stacked.png` — Motor output frequency analysis (supports any motor count; colors wrap every 8 motors)
96+
97+
**Extended (`--extended` adds these to the core set):**
98+
- `*_PIDsum_PIDerror_Setpoint_stacked.png` — PIDsum, PID error, and setpoint traces
99+
- `*_PID_Activity_stacked.png` — P, I, D term activity over time
100+
- `*_SetpointDerivative_stacked.png` — Setpoint rate-of-change / feed-forward proxy
101+
- `*_Gyro_PSD_comparative.png` — Gyro power spectral density (dB scale)
90102
- `*_D_Term_PSD_comparative.png` — D-term power spectral density (dB scale)
91103
- `*_D_Term_Heatmap_comparative.png` — D-term throttle/frequency heatmap
92104
- `*_Gyro_PSD_Spectrogram_comparative.png` — Gyro spectrogram (PSD vs. time)
93105
- `*_Throttle_Freq_Heatmap_comparative.png` — Throttle/frequency heatmap analysis
94-
- `*_Motor_Spectrums_stacked.png` — Motor output frequency analysis (supports any motor count; colors wrap every 8 motors)
95-
- `*_PID_Activity_stacked.png` — P, I, D term activity over time (stacked plot showing all three PID components)
96106
97107
#### Console Output:
98108
- Current P:D ratio and peak analysis with response assessment
99109
- Conservative and Moderate tuning recommendations (with D/D-Min/D-Max values)
100110
- Warning indicators for severe overshoot or unreasonable ratios
101111
- Gyro filtering delay estimates (filtered vs. unfiltered, with confidence)
102112
- Filter configuration parsing and spectrum peak detection summaries
113+
- Optimal P estimation (`--estimate-optimal-p`): Td timing, target deviation, noise level, consistency, P/D recommendations and skip-reason warnings
103114
- Use `--debug` flag for additional metadata: header information, flight data key mapping, sample header values, and debug mode identification
104115
105116
#### Code and Output Overview

src/axis_names.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,29 @@
1313
/// Panics if index is greater than 2
1414
#[allow(dead_code)]
1515
pub fn axis_name(index: usize) -> &'static str {
16-
match index {
17-
0 => "Roll",
18-
1 => "Pitch",
19-
2 => "Yaw",
20-
_ => panic!(
16+
AXIS_NAMES.get(index).copied().unwrap_or_else(|| {
17+
panic!(
2118
"Invalid axis index: {}. Expected 0 (Roll), 1 (Pitch), or 2 (Yaw)",
2219
index
23-
),
24-
}
20+
)
21+
})
2522
}
2623

2724
/// Number of axes (Roll, Pitch, Yaw)
2825
pub const AXIS_COUNT: usize = 3;
2926

27+
/// Number of primary control axes (Roll, Pitch only - excludes Yaw)
28+
pub const ROLL_PITCH_AXIS_COUNT: usize = 2;
29+
3030
/// Get all axis names as a static array
3131
pub const AXIS_NAMES: [&str; AXIS_COUNT] = ["Roll", "Pitch", "Yaw"];
3232

33-
// Compile-time check to prevent drift between AXIS_COUNT and AXIS_NAMES.len()
33+
// Compile-time assertions to prevent invariant drift
3434
const _: [(); AXIS_COUNT] = [(); AXIS_NAMES.len()];
35+
const _: () = assert!(
36+
ROLL_PITCH_AXIS_COUNT > 0 && ROLL_PITCH_AXIS_COUNT < AXIS_COUNT,
37+
"ROLL_PITCH_AXIS_COUNT must be > 0 and < AXIS_COUNT"
38+
);
3539

3640
#[cfg(test)]
3741
mod tests {

src/constants.rs

Lines changed: 129 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ pub const DEFAULT_SETPOINT_THRESHOLD: f64 = 500.0; // Default setpoint threshold
4949

5050
// Constants for filtering data based on movement and flight phase.
5151
pub const MOVEMENT_THRESHOLD_DEG_S: f64 = 20.0; // Minimum setpoint/gyro magnitude (from PTB/PlasmaTree)
52+
/// Mean window-max setpoint (deg/s) thresholds for Setpoint Authority classification.
53+
/// LOW < 100 dps : hover/slow-cruise — Moderate/Aggressive recommendations suppressed.
54+
/// MODERATE 100–250 dps : normal flight inputs.
55+
/// HIGH > 250 dps : aggressive/race inputs.
56+
pub const LOW_AUTHORITY_SETPOINT_THRESHOLD_DEG_S: f32 = 100.0;
57+
pub const HIGH_AUTHORITY_SETPOINT_THRESHOLD_DEG_S: f32 = 250.0;
5258
pub const EXCLUDE_START_S: f64 = 3.0; // Exclude seconds from the start of the log
5359
pub const EXCLUDE_END_S: f64 = 3.0; // Exclude seconds from the end of the log
5460

@@ -189,6 +195,14 @@ pub const COLOR_STEP_RESPONSE_LOW_SP: &RGBColor = &LIGHTBLUE;
189195
pub const COLOR_STEP_RESPONSE_HIGH_SP: &RGBColor = &ORANGE;
190196
pub const COLOR_STEP_RESPONSE_COMBINED: &RGBColor = &RED;
191197

198+
// Optimal P Estimation Legend Colors
199+
pub const COLOR_OPTIMAL_P_DIVIDER: RGBColor = RGBColor(40, 40, 40);
200+
pub const COLOR_OPTIMAL_P_HEADER: RGBColor = RGBColor(0, 100, 200);
201+
pub const COLOR_OPTIMAL_P_TEXT: RGBColor = RGBColor(80, 80, 80);
202+
pub const COLOR_OPTIMAL_P_WARNING: RGBColor = RGBColor(200, 100, 0);
203+
pub const COLOR_OPTIMAL_P_RECOMMENDATION: RGBColor = RGBColor(0, 150, 0);
204+
pub const COLOR_OPTIMAL_P_SKIP: RGBColor = RGBColor(120, 60, 60);
205+
192206
// Stroke widths for lines
193207
pub const LINE_WIDTH_PLOT: u32 = 1; // Width for plot lines
194208
pub const LINE_WIDTH_LEGEND: u32 = 2; // Width for legend lines
@@ -221,26 +235,26 @@ pub const PD_RATIO_MIN_CHANGE_THRESHOLD: f64 = 0.05; // Minimum P:D ratio change
221235
// Note: Works for all aircraft sizes including 10"+ where D > P (P:D < 1.0)
222236
pub const PD_RATIO_CONSERVATIVE_MULTIPLIER: f64 = 0.85; // Conservative: reduce P:D by 15% (≈+17.6% D)
223237
pub const PD_RATIO_MODERATE_MULTIPLIER: f64 = 0.75; // Moderate: reduce P:D by 25% (≈+33.3% D)
238+
pub const PD_RATIO_AGGRESSIVE_MULTIPLIER: f64 = 0.65; // Aggressive: reduce P:D by 35% (≈+53.8% D)
224239

225-
// Peak range adjustment multipliers for different overshoot levels
226-
// These create a graduated response based on step response quality
227-
pub const PEAK_ACCEPTABLE_MULTIPLIER: f64 = 0.95; // Acceptable (1.05-1.10): Small adjustment, +≈5.3% D
228-
pub const PEAK_MINOR_MULTIPLIER: f64 = 0.92; // Minor overshoot (1.11-1.15): Moderate adjustment, +≈8.7% D
229-
pub const PEAK_MODERATE_MULTIPLIER: f64 = 0.88; // Moderate overshoot (1.16-1.20): Larger adjustment, +≈13.6% D
230-
231-
// Peak range thresholds for step response quality assessment
232-
pub const PEAK_OPTIMAL_MIN: f64 = 0.95; // Optimal response: 0.95-1.04 (0-5% overshoot/undershoot)
240+
// Step response quality zone thresholds
241+
pub const PEAK_UNDERSHOOT_MAX: f64 = 1.00; // < this = undershoot: Recommendation (conservative) D decrease
242+
pub const PEAK_OPTIMAL_MIN: f64 = 1.02; // near-optimal ends / sweet spot start; 1.00–1.02 = near optimal (none), 1.02–1.08 = optimal (none)
233243
#[allow(dead_code)]
234-
pub const PEAK_OPTIMAL_MAX: f64 = 1.04;
235-
pub const PEAK_ACCEPTABLE_MIN: f64 = 1.05; // Acceptable: 1.05-1.10 (5-10% overshoot)
236-
pub const PEAK_ACCEPTABLE_MAX: f64 = 1.10;
237-
#[allow(dead_code)]
238-
pub const PEAK_MINOR_MIN: f64 = 1.11; // Minor overshoot: 1.11-1.15 (11-15% overshoot)
239-
pub const PEAK_MINOR_MAX: f64 = 1.15;
240-
pub const PEAK_MODERATE_MIN: f64 = 1.16; // Moderate overshoot: 1.16-1.20 (16-20% overshoot)
241-
#[allow(dead_code)]
242-
pub const PEAK_MODERATE_MAX: f64 = 1.20;
243-
pub const PEAK_SIGNIFICANT_MIN: f64 = 1.20; // Significant overshoot: >1.20 (>20% overshoot)
244+
pub const PEAK_OPTIMAL_MAX: f64 = 1.08; // sweet spot end
245+
pub const PEAK_ACCEPTABLE_MIN: f64 = 1.08; // 1.08–1.12 = acceptable: Recommendation (conservative) D increase
246+
pub const PEAK_ACCEPTABLE_MAX: f64 = 1.12; // above this = overshoot territory
247+
pub const PEAK_SIGNIFICANT_MIN: f64 = 1.20; // > this = significant overshoot: conservative + moderate + aggressive
248+
249+
// Target peak value for undershoot correction: centre of the optimal sweet spot
250+
pub const PEAK_OPTIMAL_TARGET: f64 = (PEAK_OPTIMAL_MIN + PEAK_OPTIMAL_MAX) / 2.0;
251+
252+
// Peak range adjustment multipliers for different overshoot/undershoot levels
253+
// These create a graduated response based on step response quality
254+
pub const PEAK_ACCEPTABLE_MULTIPLIER: f64 = 0.98; // Acceptable (PEAK_ACCEPTABLE_MIN–PEAK_ACCEPTABLE_MAX): +≈2% D
255+
pub const PEAK_OVERSHOOT_MULTIPLIER: f64 = 0.92; // Overshoot (PEAK_ACCEPTABLE_MAX–PEAK_SIGNIFICANT_MIN): +≈8.7% D
256+
pub const PEAK_VALUE_MIN_CLAMP: f64 = 0.1; // Minimum peak value clamp to prevent divide-by-zero in undershoot multiplier
257+
pub const D_STEP_OPTIONAL: u32 = 1; // D decrement for optional near-optimal fine-tune hint
244258

245259
// Sanity check limits for P:D ratio recommendations
246260
// Note: MIN_REASONABLE_PD_RATIO of 0.3 accommodates large aircraft where D > P
@@ -282,4 +296,100 @@ pub const COLOR_ESO_MEAS: &RGBColor = &LIGHTBLUE; // Measured gyro rate
282296
pub const COLOR_ESO_HAT: &RGBColor = &ORANGE; // ESO estimated rate (omega_hat)
283297
pub const COLOR_ESO_FHAT: &RGBColor = &GREEN; // ESO disturbance estimate (f_hat, scaled)
284298

285-
// src/constants.rs
299+
// High-frequency noise analysis for P headroom estimation
300+
// D-term energy above this frequency threshold indicates noise constraints
301+
pub const DTERM_HF_CUTOFF_HZ: f64 = 200.0; // Frequency above which high-frequency noise is measured
302+
pub const DTERM_HF_ENERGY_THRESHOLD: f64 = 0.15; // 15% of total D-term energy (high noise level)
303+
pub const DTERM_HF_ENERGY_MODERATE: f64 = 0.10; // 10% of total D-term energy (moderate noise level)
304+
305+
// Response consistency quality control
306+
// Ensures Td measurements are reliable across multiple step responses
307+
pub const TD_CONSISTENCY_MIN_THRESHOLD: f64 = 0.70; // 70% of responses within tolerance (was 85%)
308+
pub const TD_COEFFICIENT_OF_VARIATION_MAX: f64 = 0.40; // 40% CV (std/mean) is acceptable for noisy flight logs (was 20%)
309+
310+
// P headroom estimation multipliers
311+
// Conservative approach for users who want safe incremental improvements
312+
pub const P_HEADROOM_CONSERVATIVE_MULTIPLIER: f64 = 1.05; // +5% from current P
313+
// Moderate approach for experienced pilots
314+
pub const P_HEADROOM_MODERATE_MULTIPLIER: f64 = 1.10; // +10% from current P
315+
// Aggressive approach for optimization (use with caution)
316+
#[allow(dead_code)]
317+
pub const P_HEADROOM_AGGRESSIVE_MULTIPLIER: f64 = 1.15; // +15% from current P (reserved for future use)
318+
319+
// P reduction multipliers (when Td is too fast or noise is too high)
320+
pub const P_REDUCTION_MODERATE_MULTIPLIER: f64 = 0.95; // -5% from current P
321+
#[allow(dead_code)]
322+
pub const P_REDUCTION_AGGRESSIVE_MULTIPLIER: f64 = 0.90; // -10% from current P
323+
324+
// Td statistics computation constants
325+
pub const MIN_TD_MS: f64 = 0.1; // Minimum valid Td (time to 50%) in milliseconds (domain-appropriate threshold)
326+
pub const TD_MEAN_EPSILON: f64 = 1e-12; // Threshold for near-zero mean values (avoid division by zero)
327+
pub const TD_SAMPLES_MIN_FOR_STDDEV: usize = 2; // Minimum samples needed for std dev calculation
328+
329+
// Td deviation thresholds (percentage deviation from target)
330+
// Deviation thresholds for classifying Td behavior
331+
// Note: The thresholds are intentionally asymmetric — there is no separate
332+
// 'moderately faster' threshold. Faster-than-target deviations are treated
333+
// more strictly because they often indicate potential oscillation or unsafe
334+
// aggressive tuning. Therefore any significant speed-up beyond
335+
// TD_DEVIATION_SIGNIFICANTLY_FASTER_THRESHOLD is flagged immediately. Slower
336+
// deviations are given two thresholds (moderate and significant) to allow
337+
// finer-grained handling when Td is lagging behind the target.
338+
pub const TD_DEVIATION_SIGNIFICANTLY_SLOWER_THRESHOLD: f64 = 30.0; // > 30% slower
339+
pub const TD_DEVIATION_MODERATELY_SLOWER_THRESHOLD: f64 = 15.0; // > 15% slower
340+
pub const TD_DEVIATION_SIGNIFICANTLY_FASTER_THRESHOLD: f64 = -15.0; // < -15% faster
341+
342+
// Optimal P estimation data collection thresholds
343+
pub const OPTIMAL_P_MIN_DTERM_SAMPLES: usize = 100; // Minimum D-term samples for noise analysis
344+
pub const OPTIMAL_P_SECONDS_TO_MS_MULTIPLIER: f64 = 1000.0; // Convert seconds to milliseconds
345+
346+
// Torque-Inertia Profiler constants
347+
// Used by torque_inertia_profiler.rs to derive aircraft-specific Td targets from
348+
// throttle-punch events in flight logs, replacing the empirical frame-class table.
349+
350+
/// Maximum throttle command value in firmware units (setpoint[3] range: 0–1000).
351+
/// Divide raw delta by this to normalise to 0.0–1.0.
352+
pub const THROTTLE_COMMAND_SCALE: f64 = 1000.0;
353+
354+
/// Minimum time delta (seconds) for angular-acceleration computation in the torque profiler.
355+
/// Guards against division by near-zero or identical consecutive timestamps.
356+
pub const TORQUE_PROFILER_MIN_DT_S: f64 = 1e-9;
357+
358+
/// Minimum throttle increase (in 0–1000 units) to qualify as a throttle punch.
359+
pub const THROTTLE_PUNCH_MIN_DELTA: f64 = 200.0;
360+
361+
/// Time window (ms) within which the throttle increase must occur to count as a punch.
362+
pub const THROTTLE_PUNCH_WINDOW_MS: f64 = 50.0;
363+
364+
/// Window (ms) after punch onset in which to measure peak angular acceleration.
365+
pub const THROTTLE_RESPONSE_WINDOW_MS: f64 = 150.0;
366+
367+
/// Minimum number of throttle-punch events required for a reliable Td target.
368+
/// Analysis is skipped (with a console warning) when this threshold is not met.
369+
pub const TORQUE_PROFILER_MIN_EVENTS: usize = 5;
370+
371+
/// Minimum normalised command delta (0–1) for a punch event to be valid.
372+
pub const TORQUE_PROFILER_MIN_CMD_DELTA_NORMALIZED: f64 = 0.10;
373+
374+
/// Time (ms) to skip at the start of the gyro response window after a throttle punch.
375+
/// Converted to samples at runtime using the actual log sample rate, so it is
376+
/// correct for all loop rates (1 kHz, 3.2 kHz BMI270, 4 kHz, 8 kHz, etc.).
377+
/// 5 ms covers typical DSHOT ESC/motor lag; increase for slow 50 Hz PWM ESCs.
378+
pub const TORQUE_PROFILER_SETTLE_MS: f64 = 5.0;
379+
380+
/// Numerator constant for Td calculation: K = π × 1000 / 2
381+
/// Td_ms = K / sqrt((P / P_SCALE) × torque_inertia_ratio)
382+
pub const TORQUE_PROFILER_TD_CALC_K: f64 = 1_570.796_326_794_896_6;
383+
384+
/// Betaflight/EmuFlight P gain scaling factor.
385+
/// Converts raw firmware P gain (e.g. 45) to an effective physical gain.
386+
/// This constant may require empirical calibration; starting value: 100.0.
387+
pub const TORQUE_PROFILER_P_SCALE: f64 = 100.0;
388+
389+
/// Real-world achievability factor for physics-derived Td targets.
390+
/// Bridges the gap between theoretical torque capacity and actual flight performance
391+
/// (accounts for ESC lag, motor startup, prop-wash efficiency, etc).
392+
/// Higher values = more relaxed targets.
393+
/// Empirically calibrated on a 5" 6S freestyle build (HELIO H7); may need
394+
/// adjustment for significantly heavier or lighter aircraft classes.
395+
pub const TORQUE_PROFILER_ACHIEVABILITY_FACTOR: f64 = 2.50;

src/data_analysis/calc_step_response.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,57 @@ use crate::types::StepResponseResult;
88

99
use crate::constants::{
1010
APPLY_INDIVIDUAL_RESPONSE_Y_CORRECTION, ENABLE_NORMALIZED_STEADY_STATE_MEAN_CHECK,
11-
FRAME_LENGTH_S, INITIAL_GYRO_SMOOTHING_WINDOW, MOVEMENT_THRESHOLD_DEG_S,
11+
FRAME_LENGTH_S, HIGH_AUTHORITY_SETPOINT_THRESHOLD_DEG_S, INITIAL_GYRO_SMOOTHING_WINDOW,
12+
LOW_AUTHORITY_SETPOINT_THRESHOLD_DEG_S, MOVEMENT_THRESHOLD_DEG_S,
1213
NORMALIZED_STEADY_STATE_MAX_VAL, NORMALIZED_STEADY_STATE_MEAN_MAX,
1314
NORMALIZED_STEADY_STATE_MEAN_MIN, NORMALIZED_STEADY_STATE_MIN_VAL, RESPONSE_LENGTH_S,
1415
STEADY_STATE_END_S, STEADY_STATE_START_S, SUPERPOSITION_FACTOR, TUKEY_ALPHA,
1516
Y_CORRECTION_MIN_UNNORMALIZED_MEAN_ABS,
1617
};
1718

19+
/// Setpoint authority classification derived from the mean of per-window max setpoints.
20+
/// Describes how aggressively the pilot flew during the step-response windows.
21+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22+
pub enum SetpointAuthority {
23+
Low, // mean < LOW_AUTHORITY_SETPOINT_THRESHOLD_DEG_S
24+
Moderate, // LOW..HIGH
25+
High, // >= HIGH_AUTHORITY_SETPOINT_THRESHOLD_DEG_S
26+
}
27+
28+
impl SetpointAuthority {
29+
pub fn name(&self) -> &'static str {
30+
match self {
31+
Self::Low => "LOW",
32+
Self::Moderate => "MODERATE",
33+
Self::High => "HIGH",
34+
}
35+
}
36+
37+
pub fn is_low(&self) -> bool {
38+
matches!(self, Self::Low)
39+
}
40+
}
41+
42+
/// Compute SetpointAuthority and mean window-max setpoint from QC-passed window data.
43+
/// Returns None if the slice is empty.
44+
pub fn compute_setpoint_authority(
45+
valid_window_max_setpoints: &[f32],
46+
) -> Option<(SetpointAuthority, f32)> {
47+
if valid_window_max_setpoints.is_empty() {
48+
return None;
49+
}
50+
let mean =
51+
valid_window_max_setpoints.iter().sum::<f32>() / valid_window_max_setpoints.len() as f32;
52+
let level = if mean < LOW_AUTHORITY_SETPOINT_THRESHOLD_DEG_S {
53+
SetpointAuthority::Low
54+
} else if mean < HIGH_AUTHORITY_SETPOINT_THRESHOLD_DEG_S {
55+
SetpointAuthority::Moderate
56+
} else {
57+
SetpointAuthority::High
58+
};
59+
Some((level, mean))
60+
}
61+
1862
use crate::data_analysis::fft_utils;
1963

2064
// tukeywin, winstacker_contiguous, wiener_deconvolution_window, cumulative_sum,

src/data_analysis/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ pub mod derivative;
66
pub mod fft_utils;
77
pub mod filter_delay;
88
pub mod filter_response;
9+
pub mod optimal_p_estimation;
910
pub mod spectral_analysis;
11+
pub mod torque_inertia_profiler;
1012
pub mod transfer_function_estimation;
1113

1214
// src/data_analysis/mod.rs

0 commit comments

Comments
 (0)