Generated reference › Ideal Airspeed Correction — Robotics/Flight Parameters
kind: generated#block#robotics-flight-parameters

Ideal Airspeed Correction — Robotics/Flight Parameters

TAS CAS EAS

Robotics/Flight_Parameters/Ideal_Airspeed_Correction · 3 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Description#

The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.

Ideal Airspeed Correction

Robotics / Flight Parameters

Converts one of true (TAS), equivalent (EAS) and calibrated (CAS) airspeed into another, from the local speed of sound a and static pressure P, for dry air at γ = 1.4 measured against the sea-level a₀ = 340.2941 m/s and P₀ = 101325 Pa. With M = V/a:

  • √σ = (a₀/a) · √(P/P₀), and EAS = TAS · √σ.
  • Every leg through CAS goes out to the impact pressure and back: qc = P · ((1 + M²(γ−1)/2)γ/(γ−1) − 1) while V ≤ a, and the Rayleigh pitot relation qc = P · M²(γ+1)/2 · ((γ+1)²/(4γ − 2(γ−1)/M²))1/(γ−1) − P above it.
  • Back from qc: V = a · √(2/(γ−1) · ((qc/P + 1)(γ−1)/γ − 1)); when that lands at or above a, the supersonic relation is solved by fixed-point iteration until two passes agree to 10−5 m/s, at most 30 passes.

TAS → CAS measures qc at (P, a) and reads it back at sea level; CAS → TAS the other way round; EAS → CAS goes through TAS first and CAS → EAS through TAS last.

Ports

  • V_in – the input airspeed, of the kind Input Airspeed names, a [1,1] scalar in m/s.
  • a – the local speed of sound, a [1,1] scalar in m/s.
  • P – the local static pressure, a [1,1] scalar in pascal.
  • V_out – the output airspeed, of the kind the live output selector names, a [1,1] scalar in m/s.

Every port is scalar. The units are SI and matter: the sea-level constants above are in SI, so a pressure in another unit gives a wrong answer rather than a rescaled one.

Parameters

  • Input Airspeed – what arrives on V_in. This selects which arithmetic executes:
    • TAS – true airspeed. The default, as in Simulink.
    • EAS – equivalent airspeed.
    • CAS – calibrated airspeed.
  • Output Airspeed (from TAS) – what V_out carries when the input is TAS: EAS (the default) or CAS.
  • Output Airspeed (from EAS) – what V_out carries when the input is EAS: TAS (the default) or CAS.
  • Output Airspeed (from CAS) – what V_out carries when the input is CAS: TAS (the default) or EAS.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Only the output selector that matches Input Airspeed is live; the other two are kept, exactly as the Simulink dialog keeps them, so that a block switched back to another input finds its old choice. Together the four give the six conversions.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text.

The direction is baked in at export time: a core exports only the one conversion its configuration selects, and a TAS↔EAS core carries no iteration at all. Every constant is printed to 17 significant digits.

The three HDL targets are simulation-only: they divide by a port, take roots and fractional powers, and run a loop whose trip count depends on the data, so everything converts at the port boundary and runs in real. VHDL declares the conversion as a function beside the block's state, because a block body there has no real-valued variable of its own. The cores simulate correctly and are not offered as synthesizable. They also test the input domain first – a speed of sound or a pressure that is not positive, or a negative airspeed, gives 0 – because VHDL's math_real would otherwise abort the simulation on a root or a power outside it; the seven software targets answer the IEEE value there instead.

Simulink bridge

Import and export, mapped to Aerospace Blockset's aerolibasang/Ideal Airspeed Correction. The four parameters mirror the Simulink dialog one for one, and each enum maps 1:1, so the mapping is lossless both ways: Input Airspeed → vel_in, Output Airspeed (from TAS) → vel_out_tas, Output Airspeed (from EAS) → vel_out_eas and Output Airspeed (from CAS) → vel_out_cas, with the options spelled TAS, EAS and CAS on both sides.

Three Simulink parameters are always implied and carry no configuration here: units is Metric (MKS), matching the SI constants; method is Equation, because the other method is a three-dimensional spline over a table shipped as a data file and is not reproduced; and SubOnly ("Subsonic airspeeds only") is off, because switching it on changes the Equation answer as well – by up to 174 m/s on the same supersonic inputs, measured.

The Simulink block defines no SampleTime, so the rate stays on the ICore side.

Notes

  • Stateful, with direct feedthrough. The output depends on the input at the same instant, and on one held value: every supersonic solve starts from the answer of the previous supersonic solve (340.2941 m/s for the first one in a run). That is how the Simulink block iterates, and measured against it this matters – starting from the subsonic estimate instead, as the MATLAB function correctairspeed does, lands up to 8.8×10−6 m/s away. A TAS↔EAS conversion never touches the held value.
  • A solve still moving after 30 passes stops the Simulink simulation with a convergence error; this block stops there too and reports the thirtieth pass. Negative or NaN inputs likewise stop Simulink with an assertion, and are simply computed here.
  • Not linear, so the block carries no state space and model reduction correctly reports it as unmergeable.

Code facts#

FactValue
registered typeRobotics/Flight_Parameters/Ideal_Airspeed_Correction
familyRobotics/Flight_Parameters
solver environment classICoreBlock_0_Robotics_1_Flight_Parameters_2_Ideal_Airspeed_Correction
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Flight_Parameters/Ideal_Airspeed_Correction/ICoreBlock_0_Robotics_1_Flight_Parameters_2_Ideal_Airspeed_Correction.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Flight_Parameters/Ideal_Airspeed_Correction/ICoreBlock_0_Robotics_1_Flight_Parameters_2_Ideal_Airspeed_Correction.h
default size on canvas144 × 112 px
ports at insert3 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleV_in
2inICoreDoublea
3inICoreDoubleP
4outICoreDoubleV_out

Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.

Configuration variables#

Config variableDefaultSimulink parameter
Input AirspeedTAS%~%EAS%~%CAS~~TASvel_in
Output Airspeed (from TAS)EAS%~%CAS~~EASvel_out_tas
Output Airspeed (from EAS)TAS%~%CAS~~TASvel_out_eas
Output Airspeed (from CAS)TAS%~%EAS~~TASvel_out_cas

Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.

supportSupport::Both
Simulink pathaerolibasang/Ideal Airspeed Correction
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
always setunits = Metric (MKS), method = Equation, SubOnly = off
ICore configSimulink parameterValue translation
Input Airspeedvel_inTAS → TAS, EAS → EAS, CAS → CAS
Output Airspeed (from TAS)vel_out_tasEAS → EAS, CAS → CAS
Output Airspeed (from EAS)vel_out_easTAS → TAS, CAS → CAS
Output Airspeed (from CAS)vel_out_casTAS → TAS, EAS → EAS

Caveat (shown to the user): the three ports are the airspeed, the speed of sound and the static pressure, all scalar and all SI. The four parameters are the dialog itself: vel_in, and one output selector per input value, of which vel_in decides which is live -- so each crosses to its own parameter and nothing is ever read into the wrong one. 'method' is always Equation (the Table Lookup method is a 3-D spline over a data file and is not reproduced), 'units' always Metric (MKS), and 'SubOnly' always off -- measured in R2026a, switching it on moves the Equation answer by up to 174 m/s. The Simulink block has no SampleTime, so the rate stays on the ICore side. ⚠ THE DIRECTION IS A MODE: the six conversions run different arithmetic, and four of them iterate

Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.

The verdict above is tools/docs/check_block_descriptions.py (P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.

File banner (developer view)#

The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).

Ideal Airspeed Correction -- true, equivalent and calibrated airspeed, each from another Dry air at gamma = 1.4, measured against the sea-level a0 = 340.2941 m/s and P0 = 101325 Pa. With M = V/a:

sqrt(sigma) = (a0 / a) * sqrt(P * (1/P0)) TAS <-> EAS, one multiply q_c = P * ((1 + M^2 (g-1)/2)^(g/(g-1)) - 1) V <= a (isentropic) q_c = P * M^2 (g+1)/2 * ((g+1)^2 / (4g - 2(g-1)/M^2))^(1/(g-1)) - P V > a (Rayleigh) V = sqrt(((q_c/P + 1)^((g-1)/g) - 1) / (g-1) * 2) * a and when that lands at or above a, the supersonic relation is solved by fixed-point iteration, V' = a * sqrt(((q_c/P + 1) * 2 / (g+1)) / ((g+1)^2 / (4g - (a/V)^2 * 2 (g-1)))^(1/(g-1))) until two passes agree to 1e-5 m/s, at most 30 passes.

Every leg through CAS goes out to an impact pressure and back: TAS -> CAS measures q_c at (P, a) and reads it back at sea level; CAS -> TAS measures it at sea level and reads it back at (P, a); EAS -> CAS goes through TAS first and CAS -> EAS through TAS last.

MEASURED AGAINST R2026a, and the measurement changed the design twice.

(1) THE ITERATION HOLDS ITS STATE BETWEEN SAMPLES. aerolibasang/Ideal Airspeed Correction is a masked subsystem, not a call to correctairspeed.m. Its supersonic solve is a do-while While Iterator (ResetStates = held) around a Memory whose initial condition is a0, inside an Enabled subsystem whose StatesWhenEnabling is also held. So every supersonic solve STARTS FROM THE PREVIOUS SUPERSONIC ANSWER -- a0 for the first one -- where correctairspeed.m starts from the subsonic estimate. Both stop within 1e-5 of the same fixed point, so they differ by up to 8.8e-6 m/s: over 60 samples mixing both regimes the .m function misses the real block by 8.7e-6 on every CAS leg, and a held start reproduces it to 2.8e-13. This block therefore carries one held value, seeded at a0 at the start of every run, and marks its output as having a side effect.

(2) THE ARITHMETIC IS WRITTEN IN THE MASK'S OWN ASSOCIATION ORDER -- (as/a)^2 * ((g-1)/2), P * (1/101325), ((q_c/P + 1) * 2 / (g+1)) / power -- read off the product blocks' input lists, so the ten exports and the C++ reference round the same way Simulink does. The subsonic test is the mask's too: q_c is isentropic while a >= V, the airspeed is subsonic while the estimate is < a.

At V = 180.5, a = 330.7, P = 70000.7 the six legs answer 154.37974384045492 (TAS->EAS), 156.0572861008105 (TAS->CAS), 211.03966873834395 (EAS->TAS), 183.12580360879352 (EAS->CAS), 208.09018528543956 (CAS->TAS) and 177.97733795057596 (CAS->EAS).

⚠ THE THREE HDL TARGETS ARE SIMULATION-ONLY: a division by a port, roots, powers with a

Sample results#

Ideal Airspeed Correction — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sampleIdeal Airspeed Correction — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-202012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0

32 sample(s) were non-finite (nan/inf) and are absent from the plot; they are in the table below and in the JSON.

tin ICoreDouble-Out-0in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0
0-2-2-2nan
0.40.50.50.50.7559
0.8-2-2-2nan
1.20.50.50.50.7559
1.6-2-2-2nan
20.50.50.50.7559
2.4-2-2-2nan
2.80.50.50.50.7559
3.2-2-2-2nan
3.60.50.50.50.7559
4-2-2-2nan
4.40.50.50.50.7559
4.8-2-2-2nan
5.20.50.50.50.7559

Every 4th of 60 samples, from the table stimulus.

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)1.069 … 1.069
rampRamp: slope 1 from t = 00.3381 … 2.597
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias0.1683 … 1.069
stepStep: 0 -> 1 at t = 1 s1.069 … 1.069

Plotted: table — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample

Category static · sample time 0.1 · 60 steps · commit 383c0ecf1501cf1d43d89b8f688fc2fcad5e9b52 · produced by docsSample --out <folder> --blocks Ideal_Airspeed_Correction WGS84_Gravity_Model Linear_Regression_Predictor Linear_Classifier_Predictor Crossover_Pilot_Model Precision_Pilot_Model Tustin_Pilot_Model FIR_Least_Squares_Design FIR_Equiripple_Design Cartesian_To_Keplerian_Elements Keplerian_Elements_To_Cartesian --steps 60 · data docs/generated/samples/Robotics__Flight_Parameters__Ideal_Airspeed_Correction.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).