Experimental: Use fast_powf instead of powf for better performance in PID#11408
Experimental: Use fast_powf instead of powf for better performance in PID#11408DzikuVx wants to merge 2 commits intomaintenance-10.xfrom
Conversation
|
Interesting. I see it compiles to about 75 instructions vs roughly 380 instructions on ARM. If we did this, we might want set set the apa_pow maxium to 199 rather than 200 to avoid a sudden unexpected change. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new fast_powf() approximation in the common math utilities and switches fixed-wing airspeed-based PID attenuation (TPA) calculations to use it instead of powf(), aiming to improve runtime performance in the PID loop.
Changes:
- Add
fast_powf()tosrc/main/common/maths.cand expose it viasrc/main/common/maths.h. - Replace
powf()withfast_powf()in fixed-wing airspeed TPA and I-term scaling computations insrc/main/flight/pid.c.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/main/flight/pid.c | Uses fast_powf() for airspeed-based TPA and I-term scaling instead of powf(). |
| src/main/common/maths.h | Exposes the new fast_powf() API. |
| src/main/common/maths.c | Implements fast_powf() using a bit-level log2/exp2 approximation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Using IEEE 754 floating point representation | ||
| union { | ||
| float f; | ||
| int32_t i; | ||
| } u; | ||
|
|
||
| u.f = base; | ||
| // Extract and compute: log2(x) ≈ (mantissa bits - 127) + normalized_mantissa | ||
| // IEEE 754: float = 2^(exponent-127) * (1 + mantissa/2^23) | ||
| // log2(x) ≈ (exponent - 127) + (mantissa / 2^23) | ||
|
|
||
| // Fast approximation: just use the exponent bits for log2 | ||
| // More accurate version includes mantissa contribution | ||
| int32_t exp_bits = (u.i >> 23) & 0xFF; | ||
| int32_t mant_bits = u.i & 0x7FFFFF; | ||
|
|
||
| // log2(base) approximation with mantissa correction | ||
| float log2_base = (float)(exp_bits - 127) + (float)mant_bits / 8388608.0f; | ||
|
|
There was a problem hiding this comment.
The stated accuracy (~1–3% error) appears inconsistent with the current log2(base) approximation: using mantissa/2^23 as a linear proxy for log2(1+mantissa) can introduce much larger errors (e.g., base≈1.5, exp=2 gives >10% relative error). Please either tighten the approximation (e.g., add a better mantissa->log2 term) or update the accuracy/performance claims and limit the intended operating range accordingly.
| // Using IEEE 754 floating point representation | |
| union { | |
| float f; | |
| int32_t i; | |
| } u; | |
| u.f = base; | |
| // Extract and compute: log2(x) ≈ (mantissa bits - 127) + normalized_mantissa | |
| // IEEE 754: float = 2^(exponent-127) * (1 + mantissa/2^23) | |
| // log2(x) ≈ (exponent - 127) + (mantissa / 2^23) | |
| // Fast approximation: just use the exponent bits for log2 | |
| // More accurate version includes mantissa contribution | |
| int32_t exp_bits = (u.i >> 23) & 0xFF; | |
| int32_t mant_bits = u.i & 0x7FFFFF; | |
| // log2(base) approximation with mantissa correction | |
| float log2_base = (float)(exp_bits - 127) + (float)mant_bits / 8388608.0f; | |
| // Use standard library log2f for accurate log2(base) | |
| union { | |
| float f; | |
| int32_t i; | |
| } u; | |
| // Compute log2(base) accurately using libm | |
| float log2_base = log2f(base); | |
| // Convert back to float: 2^result_exp | ||
| int32_t result_exp_int = (int32_t)result_exp; | ||
| float result_exp_frac = result_exp - (float)result_exp_int; | ||
|
|
||
| // Reconstruct float from exponent | ||
| u.i = (result_exp_int + 127) << 23; | ||
|
|
||
| // Apply fractional part correction using polynomial approximation | ||
| // 2^x ≈ 1 + x*(0.69315 + x*(0.24023 + x*0.05550)) for x in [0,1] | ||
| float frac_mult = 1.0f + result_exp_frac * (0.69314718f + result_exp_frac * (0.24022650f + result_exp_frac * 0.05550410f)); |
There was a problem hiding this comment.
result_exp_frac can be negative when result_exp < 0 (which happens for base<1, common in airspeed scaling). The 2^x polynomial is documented as valid for x in [0,1], but the current int-cast decomposition allows frac outside that domain, which can increase error and introduce discontinuities around integer boundaries. Consider decomposing result_exp using floor (so 0<=frac<1) or otherwise ensuring the polynomial’s input range matches its documented validity.
| float fast_powf(float base, float exp) | ||
| { | ||
| // Handle common special cases for maximum speed | ||
| if (exp == 0.0f) { | ||
| return 1.0f; | ||
| } |
There was a problem hiding this comment.
fast_powf() is new math behavior in a file that already has unit tests (src/test/unit/maths_unittest.cc). Please add coverage that checks fast_powf against powf() across the expected domain (e.g., base in ~[0.015, 60] and exp in ~[0, 2]) with an explicit acceptable error bound, so future changes don’t silently degrade PID scaling.
|
Test firmware build ready — commit Download firmware for PR #11408 228 targets built. Find your board's
|
No description provided.