Skip to content

Conversation

@mahima-yoga
Copy link
Contributor

@mahima-yoga mahima-yoga commented Nov 26, 2025

Solved Problem

Airspeed scale estimation can take 10+ minutes to converge during initial flights, especially when starting from inaccurate initial values. This long convergence time is problematic for:

  • First flights of new airframes where the correct scale is unknown
  • Testing after pitot-static system modifications
  • Situations where the initial scale guess is significantly wrong

Slow convergence can lead to degraded controller performance, false airspeed validation failures and stalling/overspeeding

Solution

Introduce accelerated learning for the first 5 minutes of flight by temporarily increasing the airspeed scale process noise by 10x (100x on the psd). This allows the wind estimator's EKF to adjust the scale estimate much more rapidly.

The feature is controlled by a new boolean parameter ASPD_SCALE_FAST (default: disabled) and automatically reverts to normal estimation after 5 minutes.

TO DO:

  • Try different multiplier / time frame combinations
  • Add documentation
  • Flight test

Changelog Entry

For release notes:

Feature/Bugfix Allow learning airspeed scale faster in first 5 minutes of flight 
New parameter: ASPD_SCALE_FAST (boolean to enable fast airspeed scale learning in the first 5 minutes of flight) 

Alternatives

Rather than using a fixed 10x multiplier for 5 minutes, we could expose both the multiplier value and duration as tunable parameters. However, I don't love the idea of adding more parameters.

Current hard-coded values:

kTASScalePSDMultiplier = 100 
kTASScaleFastLearnTime = 300_s

Test coverage

SITL TEST 1 : ASPD_SCALE_FAST = 1, ASPD_SCALE_1 = 0.8 (should be around 1) (log)

image

SITL TEST 2: ASPD_SCALE_FAST = 0, ASPD_SCALE_1 = 0.8 (should be around 1)

image

SITL TEST 3: ASPD_SCALE_FAST = 1, ASPD_SCALE_1 = 0.95 (should be around 1) (log)

image

@github-actions
Copy link

🔎 FLASH Analysis

px4_fmu-v5x [Total VM Diff: 232 byte (0.01 %)]
    FILE SIZE        VM SIZE    
--------------  -------------- 
+0.0%    +232  +0.0%    +232    .text
  +0.1%     +96  +0.1%     +96    g_cromfs_image
   +24%     +48   +24%     +48    WindEstimator::update()
  +1.7%     +28  +1.7%     +28    do_not_explicitly_use_this_namespace::Param<>::update()
  +1.4%     +20  +1.4%     +20    AirspeedModule::AirspeedModule()
  +0.0%     +16  +0.0%     +16    [section .text]
  +4.7%     +12  +4.7%     +12    WindEstimator::initialise()
  +2.8%      +8  +2.8%      +8    AirspeedModule::updateParamsImpl()
  +1.5%      +8  +1.5%      +8    AirspeedModule::update_params()
  +0.1%      +8  +0.1%      +8    px4::parameters
  -1.9%     -12  -1.9%     -12    WindEstimator::fuse_beta()
+0.0%    +128  [ = ]       0    .debug_abbrev
+0.0%      +8  [ = ]       0    .debug_aranges
+0.0%     +48  [ = ]       0    .debug_frame
+0.0% +2.66Ki  [ = ]       0    .debug_info
+0.0%     +56  [ = ]       0    .debug_line
 -33.3%      -2  [ = ]       0    [Unmapped]
  +0.0%     +58  [ = ]       0    [section .debug_line]
+0.0%    +142  [ = ]       0    .debug_loclists
-0.0%     -51  [ = ]       0    .debug_rnglists
+0.0% +1.31Ki  [ = ]       0    .debug_str
+0.0%     +84  [ = ]       0    .strtab
  +1.9%     +84  [ = ]       0    do_not_explicitly_use_this_namespace::Param<>::update()
+0.0%     +32  [ = ]       0    .symtab
 -33.3%     -16  [ = ]       0    __clock_abstime2ticks_veneer
   +33%     +16  [ = ]       0    __stm32_configxfrints_veneer
   +50%     +16  [ = ]       0    __stm32_dopoll_veneer
 -25.0%     -16  [ = ]       0    __work_queue_veneer
  +1.6%     +32  [ = ]       0    do_not_explicitly_use_this_namespace::Param<>::update()
-2.4%    -232  [ = ]       0    [Unmapped]
+0.0% +4.41Ki  +0.0%    +232    TOTAL

px4_fmu-v6x [Total VM Diff: 128 byte (0.01 %)]
    FILE SIZE        VM SIZE    
--------------  -------------- 
+0.0%    +128  +0.0%    +128    .text
  +0.1%    +104  +0.1%    +104    g_cromfs_image
   +24%     +48   +24%     +48    WindEstimator::update()
  +1.7%     +28  +1.7%     +28    do_not_explicitly_use_this_namespace::Param<>::update()
  +1.4%     +20  +1.4%     +20    AirspeedModule::AirspeedModule()
  +0.0%     +16  +0.0%     +16    [section .text]
  +4.7%     +12  +4.7%     +12    WindEstimator::initialise()
  +2.8%      +8  +2.8%      +8    AirspeedModule::updateParamsImpl()
  +1.5%      +8  +1.5%      +8    AirspeedModule::update_params()
  +0.1%      +8  +0.1%      +8    px4::parameters
  -5.6%      -4  -5.6%      -4    ConstLayer::containedAsBitset()
 -25.0%      -4 -25.0%      -4    ConstLayer::contains()
 -14.3%      -4 -14.3%      -4    ConstLayer::get()
  -2.5%      -4  -2.5%      -4    param_find_internal()
 -20.0%      -4 -20.0%      -4    param_for_index
  -4.5%      -4  -4.5%      -4    param_for_used_index
  -1.8%      -4  -1.8%      -4    param_foreach
  -1.7%      -4  -1.7%      -4    param_get
  -1.4%      -4  -1.4%      -4    param_get_default_value
  -1.9%     -12  -1.9%     -12    WindEstimator::fuse_beta()
  -4.5%     -20  -4.5%     -20    param_reset_specific
 -102.1%     -56 -102.1%     -56    [14 Others]
+0.0%    +128  [ = ]       0    .debug_abbrev
+0.0%      +8  [ = ]       0    .debug_aranges
+0.0%     +28  [ = ]       0    .debug_frame
+0.0% +2.60Ki  [ = ]       0    .debug_info
-0.0%     -42  [ = ]       0    .debug_line
 -28.6%      -2  [ = ]       0    [Unmapped]
  -0.0%     -40  [ = ]       0    [section .debug_line]
+0.0%     +77  [ = ]       0    .debug_loclists
-0.0%     -62  [ = ]       0    .debug_rnglists
  [NEW]      +2  [ = ]       0    [Unmapped]
  -0.0%     -64  [ = ]       0    [section .debug_rnglists]
+0.0% +1.31Ki  [ = ]       0    .debug_str
+0.0%     +84  [ = ]       0    .strtab
  +1.9%     +84  [ = ]       0    do_not_explicitly_use_this_namespace::Param<>::update()
+0.0%     +32  [ = ]       0    .symtab
  +100%     +16  [ = ]       0    ConstLayer::containedAsBitset()
  +100%     +16  [ = ]       0    ConstLayer::contains()
 -33.3%     -16  [ = ]       0    ConstLayer::store()
   +25%     +16  [ = ]       0    DynamicSparseLayer::DynamicSparseLayer()
  -0.4%     -48  [ = ]       0    [section .symtab]
  +1.6%     +32  [ = ]       0    do_not_explicitly_use_this_namespace::Param<>::update()
  +100%     +16  [ = ]       0    param_for_index
  +100%     +16  [ = ]       0    param_get_index
 -25.0%     -16  [ = ]       0    param_import_internal()
-2.3%    -128  [ = ]       0    [Unmapped]
+0.0% +4.16Ki  +0.0%    +128    TOTAL

Updated: 2025-11-26T15:55:36

@mahima-yoga mahima-yoga requested a review from sfuhrer November 26, 2025 15:56
@mahima-yoga
Copy link
Contributor Author

@sfuhrer I still want to play around a bit with the kTASScalePSDMultiplier and kTASScaleFastLearnTime but feel free to review the implementation already

@mahima-yoga mahima-yoga marked this pull request as ready for review November 26, 2025 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants