LCOV - code coverage report
Current view: top level - ffb - FFBEngine.h (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 1 1
Test Date: 2026-03-18 19:01:10 Functions: 100.0 % 1 1
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : #ifndef FFBENGINE_H
       2                 :             : #define FFBENGINE_H
       3                 :             : 
       4                 :             : #include <cmath>
       5                 :             : #include <algorithm>
       6                 :             : #include <vector>
       7                 :             : #include <mutex>
       8                 :             : #include <atomic>
       9                 :             : #include <iostream>
      10                 :             : #include <chrono>
      11                 :             : #include <array>
      12                 :             : #include <cstring>
      13                 :             : #include "io/lmu_sm_interface/InternalsPluginWrapper.h"
      14                 :             : #include "AsyncLogger.h"
      15                 :             : #include "MathUtils.h"
      16                 :             : #include "PerfStats.h"
      17                 :             : #include "VehicleUtils.h"
      18                 :             : 
      19                 :             : #ifdef _WIN32
      20                 :             : #define NOINLINE __declspec(noinline)
      21                 :             : #else
      22                 :             : #define NOINLINE __attribute__((noinline))
      23                 :             : #endif
      24                 :             : 
      25                 :             : // Bring common math into scope
      26                 :             : using namespace ffb_math;
      27                 :             : // Default FFB calculation timestep. Used by FFBCalculationContext (defined before
      28                 :             : // FFBEngine, so cannot reference FFBEngine::DEFAULT_CALC_DT directly).
      29                 :             : // Note: FFBEngine also has a private member of the same name; this file-scope
      30                 :             : // constant does NOT trigger GCC's -Wchanges-meaning because it is only looked up
      31                 :             : // inside FFBCalculationContext, not inside FFBEngine's own class body.
      32                 :             : static constexpr double DEFAULT_CALC_DT = 0.0025; // 400 Hz (1/400 s)
      33                 :             : 
      34                 :             : 
      35                 :             : // ChannelStats moved to PerfStats.h
      36                 :             : 
      37                 :             : enum class LoadTransform {
      38                 :             :     LINEAR = 0,
      39                 :             :     CUBIC = 1,
      40                 :             :     QUADRATIC = 2,
      41                 :             :     HERMITE = 3
      42                 :             : };
      43                 :             : 
      44                 :             : // 1. Define the Snapshot Struct (Unified FFB + Telemetry)
      45                 :             : #include "FFBSnapshot.h"
      46                 :             : 
      47                 :             : // Refactored Managers
      48                 :             : #include "FFBSafetyMonitor.h"
      49                 :             : #include "FFBMetadataManager.h"
      50                 :             : #include "FFBDebugBuffer.h"
      51                 :             : 
      52                 :             : // BiquadNotch moved to MathUtils.h
      53                 :             : 
      54                 :             : // Helper Result Struct for calculate_axle_grip
      55                 :             : struct GripResult {
      56                 :             :     double value;           // Final grip value
      57                 :             :     bool approximated;      // Was approximation used?
      58                 :             :     double original;        // Original telemetry value
      59                 :             :     double slip_angle;      // Calculated slip angle (if approximated)
      60                 :             : };
      61                 :             : 
      62                 :             : struct Preset;
      63                 :             : 
      64                 :             : namespace FFBEngineTests { class FFBEngineTestAccess; }
      65                 :             : 
      66                 :             : struct FFBCalculationContext {
      67                 :             :     double dt = DEFAULT_CALC_DT;
      68                 :             :     double car_speed = 0.0;       // Absolute m/s
      69                 :             :     double car_speed_long = 0.0;  // Longitudinal m/s (Raw)
      70                 :             :     double speed_gate = 1.0;
      71                 :             :     double texture_load_factor = 1.0;
      72                 :             :     double brake_load_factor = 1.0;
      73                 :             :     double avg_front_load = 0.0;
      74                 :             :     double avg_front_grip = 0.0;
      75                 :             : 
      76                 :             :     // Diagnostics
      77                 :             :     bool frame_warn_load = false;
      78                 :             :     bool frame_warn_grip = false;
      79                 :             :     bool frame_warn_rear_grip = false;
      80                 :             :     bool frame_warn_dt = false;
      81                 :             : 
      82                 :             :     // Intermediate results
      83                 :             :     double grip_factor = 1.0;     // 1.0 = full grip, 0.0 = no grip
      84                 :             :     double sop_base_force = 0.0;
      85                 :             :     double sop_unboosted_force = 0.0; // For snapshot compatibility
      86                 :             :     double lat_load_force = 0.0;  // New v0.7.154 (Issue #282)
      87                 :             :     double rear_torque = 0.0;
      88                 :             :     double yaw_force = 0.0;
      89                 :             :     double scrub_drag_force = 0.0;
      90                 :             :     double gyro_force = 0.0;
      91                 :             :     double avg_rear_grip = 0.0;
      92                 :             :     double calc_rear_lat_force = 0.0;
      93                 :             :     double avg_rear_load = 0.0;
      94                 :             :     double long_load_force = 0.0; // New #301
      95                 :             : 
      96                 :             :     // Effect outputs
      97                 :             :     double road_noise = 0.0;
      98                 :             :     double slide_noise = 0.0;
      99                 :             :     double lockup_rumble = 0.0;
     100                 :             :     double spin_rumble = 0.0;
     101                 :             :     double bottoming_crunch = 0.0;
     102                 :             :     double abs_pulse_force = 0.0;
     103                 :             :     double soft_lock_force = 0.0;
     104                 :             :     double gain_reduction_factor = 1.0;
     105                 :             : };
     106                 :             :     
     107                 :             : // FFB Engine Class
     108                 :             : class FFBEngine {
     109                 :             : public:
     110                 :             :     using ParsedVehicleClass = ::ParsedVehicleClass;
     111                 :             : 
     112                 :             :     // Buffer size constants (declared first so they can be used as array bounds below)
     113                 :             :     static constexpr int STR_BUF_64 = 64;
     114                 :             : 
     115                 :             :     // Settings (GUI Sliders)
     116                 :             :     bool m_dynamic_normalization_enabled = false; // Issue #207: Structural force normalization toggle
     117                 :             :     bool m_auto_load_normalization_enabled = false; // Stage 3: Vibration Normalization (Load-based)
     118                 :             :     float m_vibration_gain = 1.0f; // Issue #206: Global vibration scaling
     119                 :             :     float m_gain;
     120                 :             :     float m_understeer_effect;
     121                 :             :     float m_understeer_gamma = 1.0f; // NEW: Gamma curve for understeer
     122                 :             :     float m_sop_effect;
     123                 :             :     float m_lat_load_effect = 0.0f; // New v0.7.121 (Issue #213 add, not replace)
     124                 :             :     LoadTransform m_lat_load_transform = LoadTransform::LINEAR; // New v0.7.154 (Issue #282)
     125                 :             :     float m_long_load_effect = 0.0f; // Renamed from dynamic_weight_gain (#301)
     126                 :             :     LoadTransform m_long_load_transform = LoadTransform::LINEAR; // New #301
     127                 :             :     float m_min_force;
     128                 :             : 
     129                 :             :     // Smoothing Settings (v0.7.47)
     130                 :             :     float m_long_load_smoothing; // Renamed from dynamic_weight_smoothing (#301)
     131                 :             :     float m_grip_smoothing_steady;
     132                 :             :     float m_grip_smoothing_fast;
     133                 :             :     float m_grip_smoothing_sensitivity;
     134                 :             : 
     135                 :             :     // Configurable Smoothing & Caps (v0.3.9)
     136                 :             :     float m_sop_smoothing_factor;
     137                 :             :     float m_texture_load_cap = 1.5f; 
     138                 :             :     float m_brake_load_cap = 1.5f;   
     139                 :             :     float m_sop_scale;
     140                 :             :     
     141                 :             :     // v0.4.4 Features
     142                 :             :     float m_wheelbase_max_nm;
     143                 :             :     float m_target_rim_nm;
     144                 :             :     bool m_invert_force = true;
     145                 :             :     
     146                 :             :     // Base Force Debugging (v0.4.13)
     147                 :             :     float m_steering_shaft_gain;
     148                 :             :     float m_ingame_ffb_gain = 1.0f; // New v0.7.71 (Issue #160)
     149                 :             :     int m_torque_source = 0; 
     150                 :             :     bool m_torque_passthrough = false;
     151                 :             : 
     152                 :             :     // New Effects (v0.2)
     153                 :             :     float m_oversteer_boost;
     154                 :             :     float m_rear_align_effect;
     155                 :             :     float m_kerb_strike_rejection = 0.0f; // NEW: Kerb strike rejection slider
     156                 :             :     float m_sop_yaw_gain;
     157                 :             :     float m_gyro_gain;
     158                 :             :     float m_gyro_smoothing;
     159                 :             :     float m_yaw_accel_smoothing;
     160                 :             :     float m_chassis_inertia_smoothing;
     161                 :             :     
     162                 :             :     bool m_lockup_enabled;
     163                 :             :     float m_lockup_gain;
     164                 :             :     // NEW Lockup Tuning (v0.5.11)
     165                 :             :     float m_lockup_start_pct = 5.0f;
     166                 :             :     float m_lockup_full_pct = 15.0f;
     167                 :             :     float m_lockup_rear_boost = 1.5f;
     168                 :             :     float m_lockup_gamma = 2.0f;           
     169                 :             :     float m_lockup_prediction_sens = 50.0f; 
     170                 :             :     float m_lockup_bump_reject = 1.0f;     
     171                 :             :     
     172                 :             :     bool m_abs_pulse_enabled = true;      
     173                 :             :     float m_abs_gain = 1.0f;               
     174                 :             :     
     175                 :             :     bool m_spin_enabled;
     176                 :             :     float m_spin_gain;
     177                 :             : 
     178                 :             :     // Texture toggles
     179                 :             :     bool m_slide_texture_enabled;
     180                 :             :     float m_slide_texture_gain;
     181                 :             :     float m_slide_freq_scale;
     182                 :             :     
     183                 :             :     bool m_road_texture_enabled;
     184                 :             :     float m_road_texture_gain;
     185                 :             :     
     186                 :             :     // Bottoming Effect (v0.3.2)
     187                 :             :     bool m_bottoming_enabled = true;  
     188                 :             :     float m_bottoming_gain = 1.0f;    
     189                 :             : 
     190                 :             :     // Soft Lock (Issue #117)
     191                 :             :     bool m_soft_lock_enabled = true;
     192                 :             :     float m_soft_lock_stiffness = 20.0f;
     193                 :             :     float m_soft_lock_damping = 0.5f;
     194                 :             : 
     195                 :             :     float m_slip_angle_smoothing;
     196                 :             :     
     197                 :             :     // NEW: Grip Estimation Settings (v0.5.7)
     198                 :             :     float m_optimal_slip_angle;
     199                 :             :     float m_optimal_slip_ratio;
     200                 :             :     
     201                 :             :     // NEW: Steering Shaft Smoothing (v0.5.7)
     202                 :             :     float m_steering_shaft_smoothing;
     203                 :             :     
     204                 :             :     // v0.4.41: Signal Filtering Settings
     205                 :             :     bool m_flatspot_suppression = false;
     206                 :             :     float m_notch_q = 2.0f; 
     207                 :             :     float m_flatspot_strength = 1.0f; 
     208                 :             :     
     209                 :             :     // Static Notch Filter (v0.4.43)
     210                 :             :     bool m_static_notch_enabled = false;
     211                 :             :     float m_static_notch_freq = 11.0f;
     212                 :             :     float m_static_notch_width = 2.0f; 
     213                 :             :     float m_yaw_kick_threshold = 0.2f; 
     214                 :             : 
     215                 :             :     // Unloaded Yaw Kick (Braking/Lift-off) - v0.7.164 (Issue #322)
     216                 :             :     float m_unloaded_yaw_gain = 0.0f;
     217                 :             :     float m_unloaded_yaw_threshold = 0.2f;
     218                 :             :     float m_unloaded_yaw_sens = 1.0f;
     219                 :             :     float m_unloaded_yaw_gamma = 0.5f;
     220                 :             :     float m_unloaded_yaw_punch = 0.05f;
     221                 :             : 
     222                 :             :     // Power Yaw Kick (Acceleration) - v0.7.164 (Issue #322)
     223                 :             :     float m_power_yaw_gain = 0.0f;
     224                 :             :     float m_power_yaw_threshold = 0.2f;
     225                 :             :     float m_power_slip_threshold = 0.10f;
     226                 :             :     float m_power_yaw_gamma = 0.5f;
     227                 :             :     float m_power_yaw_punch = 0.05f;
     228                 :             : 
     229                 :             :     // v0.6.23: User-Adjustable Speed Gate
     230                 :             :     float m_speed_gate_lower = 1.0f; 
     231                 :             :     float m_speed_gate_upper = 5.0f; 
     232                 :             : 
     233                 :             :     // REST API Fallback (Issue #221)
     234                 :             :     bool m_rest_api_enabled = false;
     235                 :             :     int m_rest_api_port = 6397;
     236                 :             : 
     237                 :             :     // v0.6.23: Additional Advanced Physics (Reserved for future use)
     238                 :             :     float m_road_fallback_scale = 0.05f;
     239                 :             :     bool m_understeer_affects_sop = false;
     240                 :             :     
     241                 :             :     // ===== SLOPE DETECTION (v0.7.0 -> v0.7.3 stability fixes) =====
     242                 :             :     bool m_slope_detection_enabled = false;
     243                 :             :     int m_slope_sg_window = 15;
     244                 :             :     float m_slope_sensitivity = 0.5f;            
     245                 :             : 
     246                 :             :     float m_slope_smoothing_tau = 0.04f;         
     247                 :             : 
     248                 :             :     // NEW v0.7.3: Stability fixes
     249                 :             :     float m_slope_alpha_threshold = 0.02f;    
     250                 :             :     float m_slope_decay_rate = 5.0f;          
     251                 :             :     bool m_slope_confidence_enabled = true;   
     252                 :             :     float m_slope_confidence_max_rate = 0.10f; 
     253                 :             : 
     254                 :             :     // NEW v0.7.11: Min/Max Threshold System
     255                 :             :     float m_slope_min_threshold = -0.3f;   
     256                 :             :     float m_slope_max_threshold = -2.0f;   
     257                 :             : 
     258                 :             :     // NEW v0.7.40: Advanced Features
     259                 :             :     float m_slope_g_slew_limit = 50.0f;
     260                 :             :     bool m_slope_use_torque = true;
     261                 :             :     float m_slope_torque_sensitivity = 0.5f;
     262                 :             : 
     263                 :             :     // Signal Diagnostics
     264                 :             :     double m_debug_freq = 0.0; 
     265                 :             :     double m_theoretical_freq = 0.0; 
     266                 :             : 
     267                 :             :     // Rate Monitoring (Issue #129)
     268                 :             :     double m_ffb_rate = 0.0;
     269                 :             :     double m_telemetry_rate = 0.0;
     270                 :             :     double m_hw_rate = 0.0;
     271                 :             :     double m_torque_rate = 0.0;
     272                 :             :     double m_gen_torque_rate = 0.0;
     273                 :             :     double m_physics_rate = 0.0; // New v0.7.117 (Issue #217)
     274                 :             : 
     275                 :             :     // Warning States (Console logging)
     276                 :             :     bool m_warned_load = false;
     277                 :             :     bool m_warned_grip = false;
     278                 :             :     bool m_warned_rear_grip = false; 
     279                 :             :     bool m_warned_dt = false;
     280                 :             :     bool m_warned_lat_force_front = false;
     281                 :             :     bool m_warned_lat_force_rear = false;
     282                 :             :     bool m_warned_susp_force = false;
     283                 :             :     bool m_warned_susp_deflection = false;
     284                 :             :     bool m_warned_vert_deflection = false; 
     285                 :             :     
     286                 :             :     // Diagnostics (v0.4.5 Fix)
     287                 :             :     struct GripDiagnostics {
     288                 :             :         bool front_approximated = false;
     289                 :             :         bool rear_approximated = false;
     290                 :             :         double front_original = 0.0;
     291                 :             :         double rear_original = 0.0;
     292                 :             :         double front_slip_angle = 0.0;
     293                 :             :         double rear_slip_angle = 0.0;
     294                 :             :     } m_grip_diag;
     295                 :             :     
     296                 :             :     // Hysteresis for missing load
     297                 :             :     int m_missing_load_frames = 0;
     298                 :             :     int m_missing_lat_force_front_frames = 0;
     299                 :             :     int m_missing_lat_force_rear_frames = 0;
     300                 :             :     int m_missing_susp_force_frames = 0;
     301                 :             :     int m_missing_susp_deflection_frames = 0;
     302                 :             :     int m_missing_vert_deflection_frames = 0; 
     303                 :             : 
     304                 :             :     // Internal state
     305                 :             :     TelemInfoV01 m_working_info; // Persistent storage for upsampled telemetry
     306                 :             :     double m_last_telemetry_time = -1.0;
     307                 :             : 
     308                 :             :     ffb_math::LinearExtrapolator m_upsample_lat_patch_vel[4];
     309                 :             :     ffb_math::LinearExtrapolator m_upsample_long_patch_vel[4];
     310                 :             :     ffb_math::LinearExtrapolator m_upsample_vert_deflection[4];
     311                 :             :     ffb_math::LinearExtrapolator m_upsample_susp_force[4];
     312                 :             :     ffb_math::LinearExtrapolator m_upsample_brake_pressure[4];
     313                 :             :     ffb_math::LinearExtrapolator m_upsample_rotation[4];
     314                 :             :     ffb_math::LinearExtrapolator m_upsample_steering;
     315                 :             :     ffb_math::LinearExtrapolator m_upsample_throttle;
     316                 :             :     ffb_math::LinearExtrapolator m_upsample_brake;
     317                 :             :     ffb_math::LinearExtrapolator m_upsample_local_accel_x;
     318                 :             :     ffb_math::LinearExtrapolator m_upsample_local_accel_y;
     319                 :             :     ffb_math::LinearExtrapolator m_upsample_local_accel_z;
     320                 :             :     ffb_math::LinearExtrapolator m_upsample_local_rot_accel_y;
     321                 :             :     ffb_math::LinearExtrapolator m_upsample_local_rot_y;
     322                 :             :     ffb_math::HoltWintersFilter  m_upsample_shaft_torque;
     323                 :             : 
     324                 :             :     double m_prev_vert_deflection[4] = {0.0, 0.0, 0.0, 0.0}; 
     325                 :             :     double m_prev_vert_accel = 0.0; 
     326                 :             :     double m_prev_slip_angle[4] = {0.0, 0.0, 0.0, 0.0}; 
     327                 :             :     double m_prev_load[4] = {0.0, 0.0, 0.0, 0.0}; // NEW: Smoothed load state
     328                 :             :     double m_prev_rotation[4] = {0.0, 0.0, 0.0, 0.0};    
     329                 :             :     double m_prev_brake_pressure[4] = {0.0, 0.0, 0.0, 0.0}; 
     330                 :             :     
     331                 :             :     // Gyro State (v0.4.17)
     332                 :             :     double m_prev_steering_angle = 0.0;
     333                 :             :     double m_steering_velocity_smoothed = 0.0;
     334                 :             :     
     335                 :             :     // Yaw Acceleration Smoothing State (v0.4.18)
     336                 :             :     double m_yaw_accel_smoothed = 0.0;
     337                 :             :     double m_prev_yaw_rate = 0.0;     // New v0.7.144 (Solution 2)
     338                 :             :     bool m_yaw_rate_seeded = false;   // New v0.7.144 (Solution 2)
     339                 :             :     double m_prev_yaw_rate_log = 0.0;
     340                 :             : 
     341                 :             :     // REPLACE m_prev_derived_yaw_accel WITH THESE:
     342                 :             :     double m_fast_yaw_accel_smoothed = 0.0;
     343                 :             :     double m_prev_fast_yaw_accel = 0.0;
     344                 :             :     bool m_yaw_accel_seeded = false;       // New v0.7.164 (Issue #322)
     345                 :             : 
     346                 :             :     // NEW: Vulnerability gate smoothing
     347                 :             :     double m_unloaded_vulnerability_smoothed = 0.0;
     348                 :             :     double m_power_vulnerability_smoothed = 0.0;
     349                 :             : 
     350                 :             :     // Derived Acceleration State (Issue #278)
     351                 :             :     TelemVect3 m_prev_local_vel = {};
     352                 :             :     bool m_local_vel_seeded = false;
     353                 :             :     double m_derived_accel_y_100hz = 0.0;
     354                 :             :     double m_derived_accel_z_100hz = 0.0;
     355                 :             :     bool m_yaw_rate_log_seeded = false;
     356                 :             : 
     357                 :             :     // Internal state for Steering Shaft Smoothing (v0.5.7)
     358                 :             :     double m_steering_shaft_torque_smoothed = 0.0;
     359                 :             : 
     360                 :             :     // Kinematic Smoothing State (v0.4.38)
     361                 :             :     double m_accel_x_smoothed = 0.0;
     362                 :             :     double m_accel_z_smoothed = 0.0; 
     363                 :             :     
     364                 :             : 
     365                 :             :     // Phase Accumulators for Dynamic Oscillators
     366                 :             :     double m_kerb_timer = 0.0; // NEW: Kerb strike attenuation timer
     367                 :             :     double m_lockup_phase = 0.0;
     368                 :             :     double m_spin_phase = 0.0;
     369                 :             :     double m_slide_phase = 0.0;
     370                 :             :     double m_abs_phase = 0.0; 
     371                 :             :     double m_bottoming_phase = 0.0;
     372                 :             :     
     373                 :             :     // Phase Accumulators for Dynamic Oscillators (v0.6.20)
     374                 :             :     float m_abs_freq_hz = 20.0f;
     375                 :             :     float m_lockup_freq_scale = 1.0f;
     376                 :             :     float m_spin_freq_scale = 1.0f;
     377                 :             :     
     378                 :             :     // Internal state for Bottoming (Method B)
     379                 :             :     double m_prev_susp_force[4] = {0.0, 0.0, 0.0, 0.0};
     380                 :             : 
     381                 :             :     // Seeding state (Issue #379)
     382                 :             :     bool m_derivatives_seeded = false;
     383                 :             : 
     384                 :             :     // New Settings (v0.4.5)
     385                 :             :     int m_bottoming_method = 0; 
     386                 :             :     float m_scrub_drag_gain; 
     387                 :             : 
     388                 :             :     // Smoothing State
     389                 :             :     double m_sop_lat_g_smoothed = 0.0;
     390                 :             :     double m_sop_load_smoothed = 0.0; // New v0.7.121
     391                 :             :     
     392                 :             :     // Filter Instances (v0.4.41)
     393                 :             :     BiquadNotch m_notch_filter;
     394                 :             :     BiquadNotch m_static_notch_filter;
     395                 :             : 
     396                 :             :     // Slope Detection Buffers (Circular) - v0.7.0
     397                 :             :     static constexpr int SLOPE_BUFFER_MAX = 41;  
     398                 :             :     std::array<double, SLOPE_BUFFER_MAX> m_slope_lat_g_buffer = {};
     399                 :             :     std::array<double, SLOPE_BUFFER_MAX> m_slope_slip_buffer = {};
     400                 :             :     int m_slope_buffer_index = 0;
     401                 :             :     int m_slope_buffer_count = 0;
     402                 :             : 
     403                 :             :     // Slope Detection State (Public for diagnostics) - v0.7.0
     404                 :             :     double m_slope_current = 0.0;
     405                 :             :     double m_slope_grip_factor = 1.0;
     406                 :             :     double m_slope_smoothed_output = 1.0;
     407                 :             : 
     408                 :             :     // NEW v0.7.38: Input Smoothing State
     409                 :             :     double m_slope_lat_g_smoothed = 0.0;
     410                 :             :     double m_slope_slip_smoothed = 0.0;
     411                 :             : 
     412                 :             :     // NEW v0.7.38: Steady State Logic
     413                 :             :     double m_slope_hold_timer = 0.0;
     414                 :             :     static constexpr double SLOPE_HOLD_TIME = 0.25; 
     415                 :             : 
     416                 :             :     // NEW v0.7.38: Debug members for Logger
     417                 :             :     double m_debug_slope_raw = 0.0;
     418                 :             :     double m_debug_slope_num = 0.0;
     419                 :             :     double m_debug_slope_den = 0.0;
     420                 :             : 
     421                 :             :     // NEW v0.7.40: Advanced Slope Detection State
     422                 :             :     double m_slope_lat_g_prev = 0.0;
     423                 :             :     std::array<double, SLOPE_BUFFER_MAX> m_slope_torque_buffer = {};
     424                 :             :     std::array<double, SLOPE_BUFFER_MAX> m_slope_steer_buffer = {};
     425                 :             :     double m_slope_torque_smoothed = 0.0;
     426                 :             :     double m_slope_steer_smoothed = 0.0;
     427                 :             :     double m_slope_torque_current = 0.0;
     428                 :             :     
     429                 :             :     // NEW v0.7.40: More Debug members
     430                 :             :     double m_debug_slope_torque_num = 0.0;
     431                 :             :     double m_debug_slope_torque_den = 0.0;
     432                 :             :     double m_debug_lat_g_slew = 0.0;
     433                 :             : 
     434                 :             :     // Dynamic Weight State (v0.7.46)
     435                 :             :     double m_static_front_load = 0.0; 
     436                 :             :     double m_static_rear_load = 0.0; // New v0.7.164 (Issue #322)
     437                 :             :     bool m_static_load_latched = false;
     438                 :             :     double m_smoothed_vibration_mult = 1.0;
     439                 :             :     double m_long_load_smoothed = 1.0; // Renamed from dynamic_weight_smoothed (#301)
     440                 :             :     double m_front_grip_smoothed_state = 1.0; 
     441                 :             :     double m_rear_grip_smoothed_state = 1.0;  
     442                 :             : 
     443                 :             :     // Metadata Manager (Option A Extracted)
     444                 :             :     FFBMetadataManager m_metadata;
     445                 :             : 
     446                 :             :     // Logging intermediate values (exposed for AsyncLogger)
     447                 :             :     double m_slope_dG_dt = 0.0;       
     448                 :             :     double m_slope_dAlpha_dt = 0.0;   
     449                 :             : 
     450                 :             :     // Frequency Estimator State (v0.4.41)
     451                 :             :     double m_last_crossing_time = 0.0;
     452                 :             :     double m_torque_ac_smoothed = 0.0; 
     453                 :             :     double m_prev_ac_torque = 0.0;
     454                 :             : 
     455                 :             :     // Safety Monitor (Option A Extracted)
     456                 :             :     FFBSafetyMonitor m_safety;
     457                 :             : 
     458                 :             :     // Telemetry Stats
     459                 :             :     ChannelStats s_torque;
     460                 :             :     ChannelStats s_front_load;
     461                 :             :     ChannelStats s_front_grip;
     462                 :             :     ChannelStats s_lat_g;
     463                 :             :     std::chrono::steady_clock::time_point last_log_time;
     464                 :             : 
     465                 :             :     // Thread-Safe Buffer (Producer-Consumer)
     466                 :             :     FFBDebugBuffer m_debug_buffer{100}; // DEBUG_BUFFER_CAP
     467                 :             :     
     468                 :             :     friend class FFBEngineTests::FFBEngineTestAccess;
     469                 :             :     friend struct Preset;
     470                 :             : 
     471                 :             :     FFBEngine();
     472                 :             : 
     473                 :         141 :     std::vector<FFBSnapshot> GetDebugBatch() { return m_debug_buffer.GetBatch(); }
     474                 :             : 
     475                 :             :     // UI Reference & Physics Multipliers (v0.4.50)
     476                 :             :     static constexpr float BASE_NM_SOP_LATERAL      = 1.0f;
     477                 :             :     static constexpr float BASE_NM_REAR_ALIGN       = 3.0f;
     478                 :             :     static constexpr float BASE_NM_YAW_KICK         = 5.0f;
     479                 :             :     static constexpr float BASE_NM_GYRO_DAMPING     = 1.0f;
     480                 :             :     static constexpr float BASE_NM_SLIDE_TEXTURE    = 1.5f;
     481                 :             :     static constexpr float BASE_NM_ROAD_TEXTURE     = 2.5f;
     482                 :             :     static constexpr float BASE_NM_LOCKUP_VIBRATION = 4.0f;
     483                 :             :     static constexpr float BASE_NM_SPIN_VIBRATION   = 2.5f;
     484                 :             :     static constexpr float BASE_NM_SCRUB_DRAG       = 5.0f;
     485                 :             :     static constexpr float BASE_NM_BOTTOMING        = 1.0f;
     486                 :             :     static constexpr float BASE_NM_SOFT_LOCK        = 50.0f;
     487                 :             : 
     488                 :             : private:
     489                 :             :     static constexpr double MIN_SLIP_ANGLE_VELOCITY = 0.5; // m/s
     490                 :             :     static constexpr double REAR_TIRE_STIFFNESS_COEFFICIENT = 15.0; 
     491                 :             :     static constexpr double MAX_REAR_LATERAL_FORCE = 6000.0; // N
     492                 :             :     static constexpr double REAR_ALIGN_TORQUE_COEFFICIENT = 0.001; // Nm per N
     493                 :             :     static constexpr double KERB_LOAD_CAP_MULT = 1.5;
     494                 :             :     static constexpr double KERB_DETECTION_THRESHOLD_M_S = 0.8;
     495                 :             :     static constexpr double KERB_HOLD_TIME_S = 0.1;
     496                 :             :     static constexpr double DEFAULT_STEERING_RANGE_RAD = 9.4247; 
     497                 :             :     static constexpr double GYRO_SPEED_SCALE = 10.0;
     498                 :             :     static constexpr double WEIGHT_TRANSFER_SCALE = 2000.0; // N per G
     499                 :             :     static constexpr double MIN_VALID_SUSP_FORCE = 10.0; // N 
     500                 :             :     static constexpr double LOCKUP_FREQ_MULTIPLIER_REAR = 0.3;  
     501                 :             :     static constexpr double LOCKUP_AMPLITUDE_BOOST_REAR = 1.5;  
     502                 :             :     static constexpr double AXLE_DIFF_HYSTERESIS = 0.01;  
     503                 :             :     static constexpr double ABS_PEDAL_THRESHOLD = 0.5;  
     504                 :             :     static constexpr double ABS_PRESSURE_RATE_THRESHOLD = 2.0;  
     505                 :             :     static constexpr double PREDICTION_BRAKE_THRESHOLD = 0.02;  
     506                 :             :     static constexpr double PREDICTION_LOAD_THRESHOLD = 50.0;
     507                 :             : 
     508                 :             :     double m_auto_peak_front_load = 4500.0; // DEFAULT_AUTO_PEAK_LOAD
     509                 :             : 
     510                 :             :     static constexpr double HPF_TIME_CONSTANT_S = 0.1;
     511                 :             :     static constexpr double ZERO_CROSSING_EPSILON = 0.05;
     512                 :             :     static constexpr double MIN_FREQ_PERIOD = 0.005;
     513                 :             :     static constexpr double MAX_FREQ_PERIOD = 1.0;
     514                 :             :     static constexpr double RADIUS_FALLBACK_DEFAULT_M = 0.33;
     515                 :             :     static constexpr double RADIUS_FALLBACK_MIN_M = 0.1;
     516                 :             :     static constexpr double UNIT_CM_TO_M = 100.0;
     517                 :             :     static constexpr double GRAVITY_MS2 = 9.81;
     518                 :             :     static constexpr double EPSILON_DIV = 1e-9;
     519                 :             :     static constexpr double TORQUE_SPIKE_RATIO = 3.0;
     520                 :             :     static constexpr double TORQUE_SPIKE_MIN_NM = 15.0;
     521                 :             :     static constexpr int    MISSING_TELEMETRY_WARN_THRESHOLD = 50;
     522                 :             :     static constexpr double PHASE_WRAP_LIMIT = 50.0;
     523                 :             :     static constexpr double LAT_G_CLEAN_LIMIT = 8.0;
     524                 :             :     static constexpr double TORQUE_SLEW_CLEAN_LIMIT = 1000.0;
     525                 :             :     static constexpr double TORQUE_ROLL_AVG_TAU = 1.0;
     526                 :             : 
     527                 :             :     static constexpr float  PEAK_TORQUE_DECAY = 0.005f;
     528                 :             :     static constexpr float  PEAK_TORQUE_FLOOR = 1.0f;
     529                 :             :     static constexpr float  PEAK_TORQUE_CEILING = 100.0f;
     530                 :             :     static constexpr float  GAIN_SMOOTHING_TAU = 0.25f;
     531                 :             :     static constexpr float  STRUCT_MULT_SMOOTHING_TAU = 0.25f;
     532                 :             :     static constexpr float  IDLE_SPEED_MIN_M_S = 3.0f;
     533                 :             :     static constexpr float  IDLE_BLEND_FACTOR = 0.1f;
     534                 :             :     static constexpr float  SESSION_PEAK_DECAY_RATE = 0.005f;
     535                 :             : 
     536                 :             :     static constexpr double DT_EPSILON = 0.000001;
     537                 :             :     static constexpr double DEFAULT_DT = 0.0025;
     538                 :             :     static constexpr double SPEED_EPSILON = 1.0;
     539                 :             :     static constexpr double ACCEL_EPSILON = 1.0;
     540                 :             :     static constexpr double G_FORCE_THRESHOLD = 3.0;
     541                 :             :     static constexpr double SPEED_HIGH_THRESHOLD = 10.0;
     542                 :             :     static constexpr double LOAD_SAFETY_FLOOR = 3000.0;
     543                 :             :     static constexpr double LOAD_DECAY_RATE = 100.0;
     544                 :             :     static constexpr double COMPRESSION_KNEE_THRESHOLD = 1.5;
     545                 :             :     static constexpr double COMPRESSION_KNEE_WIDTH = 0.5;
     546                 :             :     static constexpr double COMPRESSION_RATIO = 4.0;
     547                 :             :     static constexpr double VIBRATION_EMA_TAU = 0.1;
     548                 :             :     static constexpr double USER_CAP_MAX = 10.0;
     549                 :             :     static constexpr double CLIPPING_THRESHOLD = 0.99;
     550                 :             :     static constexpr int    STR_MAX_64 = 63;
     551                 :             :     static constexpr int    STR_MAX_256 = 255;
     552                 :             :     static constexpr int    MISSING_LOAD_WARN_THRESHOLD = 20;
     553                 :             :     static constexpr double LONG_LOAD_MIN = 0.0; // Relaxed #301
     554                 :             :     static constexpr double LONG_LOAD_MAX = 10.0; // Increased #301
     555                 :             :     static constexpr double MIN_TAU_S = 0.0001;
     556                 :             :     static constexpr double ALPHA_MIN = 0.001;
     557                 :             :     static constexpr double ALPHA_MAX = 1.0;
     558                 :             :     static constexpr double DUAL_DIVISOR = 2.0;
     559                 :             :     static constexpr double HALF_PERIOD_MULT = 0.5;
     560                 :             :     static constexpr double MIN_NOTCH_WIDTH_HZ = 0.1;
     561                 :             :     static constexpr int    VEHICLE_NAME_CHECK_IDX = 10;
     562                 :             :     static constexpr int    DEBUG_BUFFER_CAP = 100;
     563                 :             :     static constexpr double OVERSTEER_BOOST_MULT = 2.0;
     564                 :             :     static constexpr double MIN_YAW_KICK_SPEED_MS = 5.0;
     565                 :             :     static constexpr double MIN_SLIP_WINDOW = 0.01;
     566                 :             :     static constexpr double SAWTOOTH_SCALE = 2.0;
     567                 :             :     static constexpr double SAWTOOTH_OFFSET = 1.0;
     568                 :             :     static constexpr double FFB_EPSILON = 0.0001;
     569                 :             :     static constexpr double SOFT_LOCK_MUTE_THRESHOLD_NM = 0.1;
     570                 :             :     static constexpr double SOP_SMOOTHING_MAX_TAU = 0.1;
     571                 :             : 
     572                 :             :     // Default Values
     573                 :             :     static constexpr float  DEFAULT_SAFETY_SLEW_FULL_SCALE_TIME_S = 1.0f; // matches Issue #316 expectations
     574                 :             :     static constexpr float  DEFAULT_SAFETY_WINDOW_DURATION = 0.0f;
     575                 :             :     static constexpr float  DEFAULT_SAFETY_GAIN_REDUCTION = 0.3f;
     576                 :             :     static constexpr float  DEFAULT_SAFETY_SMOOTHING_TAU = 0.2f;
     577                 :             :     static constexpr float  DEFAULT_SPIKE_DETECTION_THRESHOLD = 500.0f;
     578                 :             :     static constexpr float  DEFAULT_IMMEDIATE_SPIKE_THRESHOLD = 1500.0f;
     579                 :             : 
     580                 :             :     static constexpr bool   DEFAULT_STUTTER_SAFETY_ENABLED = false;
     581                 :             :     static constexpr float  DEFAULT_STUTTER_THRESHOLD = 1.5f;
     582                 :             : 
     583                 :             :     static constexpr double MIN_LFM_ALPHA = 0.001;
     584                 :             :     static constexpr double G_LIMIT_5G = 5.0;
     585                 :             :     static constexpr double SMOOTHNESS_LIMIT_0999 = 0.999;
     586                 :             :     static constexpr double BOTTOMING_RH_THRESHOLD_M = 0.002;
     587                 :             :     static constexpr double BOTTOMING_IMPULSE_THRESHOLD_N_S = 100000.0;
     588                 :             :     static constexpr double BOTTOMING_IMPULSE_RANGE_N_S = 200000.0;
     589                 :             :     static constexpr double BOTTOMING_LOAD_MULT = 2.5;
     590                 :             :     static constexpr double BOTTOMING_INTENSITY_SCALE = 0.05;
     591                 :             :     static constexpr double BOTTOMING_FREQ_HZ = 50.0;
     592                 :             :     static constexpr double SPIN_THROTTLE_THRESHOLD = 0.05;
     593                 :             :     static constexpr double SPIN_SLIP_THRESHOLD = 0.2;
     594                 :             :     static constexpr double SPIN_SEVERITY_RANGE = 0.5;
     595                 :             :     static constexpr double SPIN_TORQUE_DROP_FACTOR = 0.6;
     596                 :             :     static constexpr double SPIN_BASE_FREQ = 10.0;
     597                 :             :     static constexpr double SPIN_FREQ_SLIP_MULT = 2.5;
     598                 :             :     static constexpr double SPIN_MAX_FREQ = 80.0;
     599                 :             :     static constexpr double LOCKUP_BASE_FREQ = 10.0;
     600                 :             :     static constexpr double LOCKUP_FREQ_SPEED_MULT = 1.5;
     601                 :             :     static constexpr double SLIDE_VEL_THRESHOLD = 1.5;
     602                 :             :     static constexpr double SLIDE_BASE_FREQ = 10.0;
     603                 :             :     static constexpr double SLIDE_FREQ_VEL_MULT = 5.0;
     604                 :             :     static constexpr double SLIDE_MAX_FREQ = 250.0;
     605                 :             :     static constexpr double LOCKUP_ACCEL_MARGIN = 2.0;
     606                 :             :     static constexpr double LOW_PRESSURE_LOCKUP_THRESHOLD = 0.1;
     607                 :             :     static constexpr double LOW_PRESSURE_LOCKUP_FIX = 0.5;
     608                 :             :     static constexpr double ABS_PULSE_MAGNITUDE_SCALER = 2.0;
     609                 :             :     static constexpr double PERCENT_TO_DECIMAL = 100.0;
     610                 :             :     static constexpr double SCRUB_VEL_THRESHOLD = 0.001;
     611                 :             :     static constexpr double SCRUB_FADE_RANGE = 0.5;
     612                 :             : 
     613                 :             :     static constexpr double DEFLECTION_DELTA_LIMIT = 0.01;
     614                 :             :     static constexpr double DEFLECTION_ACTIVE_THRESHOLD = 1e-6;
     615                 :             :     static constexpr double DEFLECTION_NEAR_ZERO_M = 1e-6;       // Near-zero threshold for susp/vert deflection checks (m)
     616                 :             :     static constexpr double MIN_VALID_LAT_FORCE_N = 1.0;          // Minimum lateral force to consider data present (N)
     617                 :             :     static constexpr double ROAD_TEXTURE_SPEED_THRESHOLD = 5.0;
     618                 :             :     static constexpr double DEFLECTION_NM_SCALE = 50.0;
     619                 :             :     static constexpr double ACCEL_ROAD_TEXTURE_SCALE = 0.05;
     620                 :             :     static constexpr double DEBUG_FREQ_SMOOTHING = 0.9;
     621                 :             :     static constexpr double GAIN_REDUCTION_MAX = 50.0;
     622                 :             :     double m_session_peak_torque = 25.0; // DEFAULT_SESSION_PEAK_TORQUE
     623                 :             :     double m_smoothed_structural_mult = 1.0 / 25.0; 
     624                 :             :     double m_rolling_average_torque = 0.0; 
     625                 :             :     double m_last_raw_torque = 0.0; 
     626                 :             :     bool m_was_allowed = true; // Track transition for filter reset
     627                 :             : 
     628                 :             :     // Diagnostic Log Cooldowns (v0.7.x)
     629                 :             :     double m_last_core_nan_log_time = -999.0;
     630                 :             :     double m_last_aux_nan_log_time = -999.0;
     631                 :             :     double m_last_math_nan_log_time = -999.0;
     632                 :             : 
     633                 :             :     void update_static_load_reference(double current_front_load, double current_rear_load, double speed, double dt);
     634                 :             :     void InitializeLoadReference(const char* className, const char* vehicleName);
     635                 :             :     
     636                 :             : public:
     637                 :             :     double calculate_raw_slip_angle_pair(const TelemWheelV01& w1, const TelemWheelV01& w2);
     638                 :             :     double calculate_slip_angle(const TelemWheelV01& w, double& prev_state, double dt);
     639                 :             :     
     640                 :             : GripResult calculate_axle_grip(const TelemWheelV01& w1,
     641                 :             :                               const TelemWheelV01& w2,
     642                 :             :                               double avg_axle_load,
     643                 :             :                               bool& warned_flag,
     644                 :             :                               double& prev_slip1,
     645                 :             :                               double& prev_slip2,
     646                 :             :                               double& prev_load1, // NEW: State for load smoothing
     647                 :             :                               double& prev_load2, // NEW: State for load smoothing
     648                 :             :                               double car_speed,
     649                 :             :                               double dt,
     650                 :             :                               const char* vehicleName,
     651                 :             :                               const TelemInfoV01* data,
     652                 :             :                               bool is_front);
     653                 :             : 
     654                 :             :     double approximate_load(const TelemWheelV01& w);
     655                 :             :     double approximate_rear_load(const TelemWheelV01& w);
     656                 :             :     double calculate_manual_slip_ratio(const TelemWheelV01& w, double car_speed_ms);
     657                 :             :     NOINLINE double calculate_slope_grip(double lateral_g, double slip_angle, double dt, const TelemInfoV01* data = nullptr);
     658                 :             :     double calculate_slope_confidence(double dAlpha_dt);
     659                 :             :     double calculate_wheel_slip_ratio(const TelemWheelV01& w);
     660                 :             : 
     661                 :             :     double calculate_force(const TelemInfoV01* data, const char* vehicleClass = nullptr, const char* vehicleName = nullptr, float genFFBTorque = 0.0f, bool allowed = true, double override_dt = -1.0, signed char mControl = 0);
     662                 :             : 
     663                 :             :     void UpdateMetadata(const struct SharedMemoryObjectOut& data);
     664                 :             :     double apply_signal_conditioning(double raw_torque, const TelemInfoV01* data, FFBCalculationContext& ctx);
     665                 :             :     void ResetNormalization();
     666                 :             : 
     667                 :             : private:
     668                 :             :     void calculate_sop_lateral(const TelemInfoV01* data, FFBCalculationContext& ctx);
     669                 :             :     NOINLINE void calculate_gyro_damping(const TelemInfoV01* data, FFBCalculationContext& ctx);
     670                 :             :     NOINLINE void calculate_abs_pulse(const TelemInfoV01* data, FFBCalculationContext& ctx);
     671                 :             :     void calculate_lockup_vibration(const TelemInfoV01* data, FFBCalculationContext& ctx);
     672                 :             :     void calculate_wheel_spin(const TelemInfoV01* data, FFBCalculationContext& ctx);
     673                 :             :     void calculate_slide_texture(const TelemInfoV01* data, FFBCalculationContext& ctx);
     674                 :             :     void calculate_road_texture(const TelemInfoV01* data, FFBCalculationContext& ctx);
     675                 :             :     void calculate_suspension_bottoming(const TelemInfoV01* data, FFBCalculationContext& ctx);
     676                 :             :     void calculate_soft_lock(const TelemInfoV01* data, FFBCalculationContext& ctx);
     677                 :             : };
     678                 :             : 
     679                 :             : #endif // FFBENGINE_H
        

Generated by: LCOV version 2.0-1