feat(fw_perf_model): Warn in FW_R_LIM is infeasible due to empty airspeed range (#27547)

* feat(fw_perf_model): warn in max bank infeasible due to empty airspeed range

* style(fw_perf_model): refer explicitly to max airspeed param

and only implicitly to max bank, so users will be inclined to adjust the
former.

* docs(fw-tuning): add section on roll compensation and effect on airspeed limits

* docs(fw-tuning): fix LaTeX

 - wrap text in \text{} so it does not render as if it were variable
   names
 - fix incorrect double escaping which made \sqrt{} and \frac{} not
   render
 - replace \over with \frac - the latter is nicer and handles more edge
   cases

* docs(fw-tuning): fix typo

In the above equation (supposed to be rearranged) there is only C_L, no C_D.

* docs(fw-tuning): correct mistake

only stall and min airspeed are load factor (due to bank) compensated in
the performance model, not trim.
This commit is contained in:
Balduin
2026-06-04 16:35:48 +02:00
committed by GitHub
parent 5368e5f1fd
commit a1fa38025e
3 changed files with 46 additions and 12 deletions

View File

@@ -39,7 +39,7 @@ The minimum sink rate is set in [FW_T_SINK_MIN](../advanced_config/parameter_ref
If the [Basic TECS tuning](../config_fw/position_tuning_guide_fixedwing.md#tecs-tuning-altitude-and-airspeed) was not done in standard sea level conditions then the [FW_T_SINK_MIN](../advanced_config/parameter_reference.md#FW_T_SINK_MIN) parameter must be modified by multiplying with correction factor $P$ (where $\rho$ is the air density during tuning):
$$P = \sqrt{\rho\over{\rho_{sealevel}}}$$
$$P = \sqrt{\frac{\rho}{\rho_{\text{sealevel}}}}$$
For more information see [Effect of Density on minimum sink rate](#effect-of-density-on-minimum-sink-rate).
@@ -49,7 +49,7 @@ The trim throttle is set using [FW_THR_TRIM](../advanced_config/parameter_refere
If basic tuning was not done in standard sealevel conditions then the value for [FW_THR_TRIM](../advanced_config/parameter_reference.md#FW_THR_TRIM) must be modified by multiplying with correction factor $P$:
$$P = \sqrt{\rho\over{\rho_{sealevel}}}$$
$$P = \sqrt{\frac{\rho}{\rho_{\text{sealevel}}}}$$
For more information see [Effect of Density on Trim Throttle](#effect-of-density-on-trim-throttle)
@@ -63,7 +63,7 @@ This is provided for interest only, and may be of interest to developers who wan
In the following sections we will use the notation $\hat X$ to specify that this value is a calibrated value of the variable $X$.
By calibrated we mean the value of that variable measured at sea level in standard atmospheric conditions, and when vehicle weight was equal to [WEIGHT_BASE](../advanced_config/parameter_reference.md#WEIGHT_BASE).
E.g. by $\hat{\dot{h}}_{max}$ we specify the maximum climb rate the vehicle can achieve at [WEIGHT_BASE](../advanced_config/parameter_reference.md#WEIGHT_BASE) at sea level in standard atmospheric conditions.
E.g. by $\hat{\dot{h}}_{\text{max}}$ we specify the maximum climb rate the vehicle can achieve at [WEIGHT_BASE](../advanced_config/parameter_reference.md#WEIGHT_BASE) at sea level in standard atmospheric conditions.
### Effect of Weight on Maximum Climb Rate
@@ -71,7 +71,7 @@ The maximum climb rate ([FW_T_CLMB_MAX](../advanced_config/parameter_reference.m
From the steady state equations of motions of an airplane we find that the maximum climb rate can be written as:
$$\dot{h}_{max} = { V * ( Thrust - Drag ) \over{m*g}}$$
$$\dot{h}_{\text{max}} = \frac{V \cdot (\text{Thrust} - \text{Drag})}{m \cdot g}$$
where `V` is the true airspeed and `m` is the vehicle mass.
From this equation we see that the maximum climb rates scales with vehicle mass.
@@ -82,7 +82,7 @@ The minimum sink rate ([FW_T_SINK_MIN](../advanced_config/parameter_reference.md
The minimum sink rate can be written as:
$$\dot{h}_{min} = \sqrt{2mg\over{\rho S}} f(C_L, C_D)$$
$$\dot{h}_{\text{min}} = \sqrt{\frac{2mg}{\rho S}}\, f(C_L, C_D)$$
where $\rho$ is the air density, S is the wing surface reference area and $f(C_L, C_D)$ is a function of the polars, lift and drag.
@@ -94,30 +94,38 @@ The minimum airspeed ([FW_AIRSPD_MIN](../advanced_config/parameter_reference.md#
In steady state flight we can demand that lift should equal weight of the vehicle:
$$Lift = mg = {1\over{2}} \rho V^2 S C_L$$
$$\text{Lift} = mg = \frac{1}{2} \rho V^2 S C_L$$
rearranging this equation for airspeed gives:
$$V = \\sqrt{\\frac{2mg}{\\rho S C_D }}$$
$$V = \sqrt{\frac{2mg}{\rho S C_L}}$$
From this equation we see that if we assume a constant angle of attack (which we generally desire), the vehicle weight affects airspeed with a square root relation.
Therefore, the airspeed limits mentioned above are all scaled using the square root of the weight ratio.
### Effect of Bank Angle on Airspeed Limits
Flying a coordinated, level turn at bank angle $\phi$ increases the load factor by $\frac{1}{\cos{\phi}}$. This is similar to the added load factor due to weight (section above), and thus the stall and minimum airspeeds are increased by an additional factor of $\sqrt{\frac{1}{\cos{\phi}}}$.
The maximum airspeed ([FW_AIRSPD_MAX](../advanced_config/parameter_reference.md#FW_AIRSPD_MAX)) is _not_ compensated in this way, as it can represent structural limits of the airframe.
It can be that at maximum bank angle [FW_R_LIM](../advanced_config/parameter_reference.md#FW_R_LIM), the maximum airspeed is _lower_ than the minimum airspeed (compensated for weight ratio and bank angle). This means the allowed airspeed range is empty at that bank angle. If a system is configured like this, a warning on the ground station is shown.
### Effect of Density on Maximum Climb Rate
The maximum climb rate is set using [FW_T_CLMB_MAX](../advanced_config/parameter_reference.md#FW_T_CLMB_MAX).
As we have seen previously, the maximum climb rate can be formulated as:
$$\dot{h}_{max} = { V * ( Thrust - Drag ) \over{m*g}}$$
$$\dot{h}_{\text{max}} = \frac{V \cdot (\text{Thrust} - \text{Drag})}{m \cdot g}$$
The air density affects the airspeed, the thrust and the drag and modelling this effects is not straight forward.
However, we can refer to literature and experience, which suggest that for a propeller airplane the maximum climb rate reduces approximately linear with the air density.
Therefore, we can write the maximum climb rate as:
$$\dot{h}_{max} = \hat{\dot{h}} * {\rho_{sealevel} \over{\rho}} K$$
$$\dot{h}_{\text{max}} = \hat{\dot{h}} \cdot \frac{\rho_{\text{sealevel}}}{\rho} K$$
where $\rho_{sealevel}$ is the air density at sea level in the standard atmosphere and K is a scaling factor which determines the slope of the function.
where $\rho_{\text{sealevel}}$ is the air density at sea level in the standard atmosphere and K is a scaling factor which determines the slope of the function.
Rather than trying to identify this constants, the usual practice in aviation is to specify a service ceiling altitude at which the vehicle is still able to achieve a minimum specified climb rate.
### Effect of Density on Minimum Sink Rate
@@ -126,7 +134,7 @@ The minimum sink rate is set using [FW_T_SINK_MIN](../advanced_config/parameter_
In previous sections we have seen the formula for the minimum sink rate:
$$\dot{h}_{min} = \sqrt{2mg\over{\rho S}} f(C_L, C_D)$$
$$\dot{h}_{\text{min}} = \sqrt{\frac{2mg}{\rho S}}\, f(C_L, C_D)$$
This shows that the minimum sink rate scales with the square root of the inverse air density.

View File

@@ -218,6 +218,31 @@ bool PerformanceModel::runSanityChecks() const
ret = false;
}
const float max_bank_loadfactor = 1 / cosf(math::radians(_param_fw_r_lim.get()));
const float min_airspd_at_max_bank = getMinimumCalibratedAirspeed(max_bank_loadfactor, /*flaps_setpoint = */0.0f);
if (min_airspd_at_max_bank > _param_fw_airspd_max.get()) {
// Flying the maximum bank angle requires an airspeed above FW_AIRSPD_MAX.
// To mitigate, choose between these (or a combination):
// - Allow higher airspeeds (formula from getMinimumCalibratedAirspeed):
// FW_AIRSPD_MAX >= FW_AIRSPD_MIN * sqrt(WEIGHT_GROSS/WEIGHT_BASE) * sqrt(1/cos(FW_R_LIM))
// - Decrease max bank angle (same inequality, solved for FW_R_LIM):
// FW_R_LIM <= acos((FW_AIRSPD_MIN/FW_AIRSPD_MAX)**2 * (WEIGHT_GROSS/WEIGHT_BASE))
// If flying with a range of weight ratios, take the worst case (heaviest) for both these formulas.
/* EVENT
* @description
* - <param>FW_AIRSPD_MIN</param>: {1:.1}
* - <param>FW_AIRSPD_MAX</param>: {2:.1}
* - <param>FW_R_LIM</param>: {3:.1}
*/
events::send<float, float, float>(events::ID("fixedwing_position_control_conf_invalid_maxbank_infeasible"), events::Log::Error,
"Invalid configuration: FW_AIRSPD_MAX too low to sustain max bank angle",
_param_fw_airspd_min.get(), _param_fw_airspd_max.get(), _param_fw_r_lim.get());
ret = false;
}
return ret;
}

View File

@@ -137,7 +137,8 @@ private:
(ParamFloat<px4::params::FW_THR_MIN>) _param_fw_thr_min,
(ParamFloat<px4::params::FW_THR_ASPD_MIN>) _param_fw_thr_aspd_min,
(ParamFloat<px4::params::FW_THR_ASPD_MAX>) _param_fw_thr_aspd_max,
(ParamFloat<px4::params::FW_AIRSPD_FLP_SC>) _param_fw_airspd_flp_sc
(ParamFloat<px4::params::FW_AIRSPD_FLP_SC>) _param_fw_airspd_flp_sc,
(ParamFloat<px4::params::FW_R_LIM>) _param_fw_r_lim
)
/**