Generated reference › EOM 3DOF Simple Variable Mass Wind Axes — Robotics/Equations Of Motion
kind: generated#block#robotics-equations-of-motion

EOM 3DOF Simple Variable Mass Wind Axes — Robotics/Equations Of Motion

Robotics/Equations_Of_Motion/EOM_3DOF_Simple_Variable_Mass_Wind_Axes · 4 input / 6 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.

EOM 3DOF Simple Variable Mass Wind Axes

Robotics / Equations Of Motion

The longitudinal equations of motion of a rigid body that burns fuel, carried in wind axes. The mass is a state driven by the mass flow rate and held between the empty and full masses; the pitch inertia follows it linearly between its empty and full values: Iyy(m) = Ie + (m − me)·(If − Ie)/(mf − me).

  • V' = Fx/m − g·sin γ, α' = Fz/(m·V) + q + g·cos γ/V, with γ = θ − α
  • m' = dm/dt, except zero while the tank is empty and draining or full and filling; q' = (M − dIyy/dt·q)/Iyy(m) with dIyy/dt = m'·(If − Ie)/(mf − me); θ' = q
  • xe' = V·cos γ, ze' = −V·sin γ

Ports

  • Fx – the force along the body x axis, a scalar [1,1].
  • Fz – the force along the body z axis (positive down), a scalar [1,1].
  • M – the pitching moment about the centre of gravity, a scalar [1,1].
  • m_dot – the mass flow rate dm/dt (negative while burning), a scalar [1,1].
  • gamma – the flight path angle γ in radians, [1,1].
  • q – the pitch rate in rad/s, [1,1].
  • Xe – the position [xe; ze] in the flat-earth frame, [2,1].
  • Vw – the velocity in wind axes, [V; 0], [2,1].
  • alpha – the angle of attack α in radians, [1,1].
  • Fuel – the fuel tank status: 1 full (m ≥ mf), −1 empty (m ≤ me), 0 otherwise, [1,1].

Parameters

  • Units – Metric (MKS) (the default) or English (velocity in ft/s). The two are the same arithmetic – the gravity is a parameter – so the choice only says which units the numbers are in.
  • Initial Airspeed – V0, a scalar. Defaults to 100.
  • Initial Flight Path Angle – γ0 in radians; the initial pitch attitude is γ0 + α0. Defaults to 0.
  • Initial Body Rotation Rate – q0 in rad/s. Defaults to 0.
  • Initial Incidence – α0 in radians. Defaults to 0.
  • Initial Position [x z] – the initial [xe ze], two values. Defaults to [0 0].
  • Initial Mass – m0, from the empty to the full mass. Defaults to 1.
  • Empty Mass – me, the lower limit. Defaults to 0.5.
  • Full Mass – mf, the upper limit, greater than the empty mass. Defaults to 3.
  • Empty Inertia – Ie, the pitch inertia at the empty mass, > 0. Defaults to 0.5.
  • Full Inertia – If, the pitch inertia at the full mass, > 0. Defaults to 3.
  • Gravity – g, a scalar. Defaults to 9.81.
  • Integration Substeps – M, how many fourth-order Runge-Kutta steps a sample is integrated with on the discrete solver and in exported code, a whole number of 1 or more. Defaults to 100. No Simulink counterpart.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. A core holds the seven states, publishes the outputs from them, and integrates one sample with the inputs held and M Runge-Kutta substeps – with M = 100, the same computation as Simulink's fixed-step ode4 at one hundredth of the sample time, the fuel limit applied at every stage and the mass clamped after every substep exactly as the Simulink block does it.

The three HDL targets are simulation-only real arithmetic, quantized at the port: a sine of a state has no Q16.16 form. The cores simulate correctly and are not offered as synthesizable.

Simulink bridge

Import and export, mapped to Aerospace Blockset's aerolib3dof2/Simple Variable Mass 3dof (Wind Axes): Units → units (the two offered values 1:1), Initial Airspeed → v_ini, Initial Flight Path Angle → gamma_ini, Initial Body Rotation Rate → q_ini, Initial Incidence → alpha_ini, Initial Position [x z] → pos_ini, Initial Mass → mass, Empty Mass → mass_e, Full Mass → mass_f, Empty Inertia → Iyy_e, Full Inertia → Iyy_f, Gravity → g. Always emitted with axes = Wind, mtype = Simple Variable, g_in = Internal and vre_flag and mass_flag off: each of those moves that block's port list, and this block has one; mdot_flag moves none and is emitted at its default, on. The knots unit system is not offered – it converts velocities inside the integration – and an imported one is reported. The dialog's Iyy is not read by the Simulink block at this mass type (measured) and is not offered. "Sampling Time (s)" does not cross: the Simulink block is continuous and defines no SampleTime.

Notes

  • Stateful, continuous and nonlinear: seven continuous states. The outputs are states, so the block has no direct feedthrough and a loop through it is not an algebraic loop.
  • At a limit the mass stops and the inertia rate with it, so the q' equation loses its dIyy/dt term the moment the tank empties or fills. On the continuous solver the mass is held by the zero rate alone and can overshoot a limit by one solver step; the discrete solver and every exported core also clamp it, as Simulink does.
  • The airspeed divides in α', so it must stay clear of zero.

Code facts#

FactValue
registered typeRobotics/Equations_Of_Motion/EOM_3DOF_Simple_Variable_Mass_Wind_Axes
familyRobotics/Equations_Of_Motion
solver environment classICoreBlock_0_Robotics_1_Equations_Of_Motion_2_EOM_3DOF_Simple_Variable_Mass_Wind_Axes
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Equations_Of_Motion/EOM_3DOF_Simple_Variable_Mass_Wind_Axes/ICoreBlock_0_Robotics_1_Equations_Of_Motion_2_EOM_3DOF_Simple_Variable_Mass_Wind_Axes.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Equations_Of_Motion/EOM_3DOF_Simple_Variable_Mass_Wind_Axes/ICoreBlock_0_Robotics_1_Equations_Of_Motion_2_EOM_3DOF_Simple_Variable_Mass_Wind_Axes.h
default size on canvas150 × 150 px
ports at insert4 in, 6 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleFx
2inICoreDoubleFz
3inICoreDoubleM
4inICoreDoublem_dot
5outICoreDoublegamma
6outICoreDoubleq
7outICoreDoubleXe
8outICoreDoubleVw
9outICoreDoublealpha
10outICoreDoubleFuel

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
UnitsMetric (MKS)%~%English (velocity in ft/s)~~Metric (MKS)units
Initial Airspeed100v_ini
Initial Flight Path Angle0gamma_ini
Initial Body Rotation Rate0q_ini
Initial Incidence0alpha_ini
Initial Position [x z][0 0]pos_ini
Initial Mass1.0mass
Empty Mass0.5mass_e
Full Mass3.0mass_f
Empty Inertia0.5Iyy_e
Full Inertia3.0Iyy_f
Gravity9.81g
Integration Substeps100not crossed

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 pathaerolib3dof2/Simple Variable Mass 3dof (Wind Axes)
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
deliberately not crossedIntegration Substeps
always setaxes = Wind, mtype = Simple Variable, g_in = Internal, vre_flag = off, mdot_flag = on, mass_flag = off
ICore configSimulink parameterValue translation
UnitsunitsMetric (MKS) → Metric (MKS), English (velocity in ft/s) → English (velocity in ft/s)
Initial Airspeedv_inipasses through
Initial Flight Path Anglegamma_inipasses through
Initial Body Rotation Rateq_inipasses through
Initial Incidencealpha_inipasses through
Initial Position [x z]pos_inipasses through
Initial Massmasspasses through
Empty Massmass_epasses through
Full Massmass_fpasses through
Empty InertiaIyy_epasses through
Full InertiaIyy_fpasses through
Gravitygpasses through

Caveat (shown to the user): aerolib3dof2/Simple Variable Mass 3dof (Wind Axes) is continuous and has NO SampleTime parameter (verified against the R2026a block dialog). axes, mtype, g_in, vre_flag and mass_flag are pinned because each moves that block's port list (measured); mdot_flag moves none and is pinned at its measured default; the kts unit system is not offered because it converts velocities inside the integration; the dialog's Iyy is not read at this mass type (measured); "Integration Substeps" is how this block integrates a sample and has no counterpart

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).

Simple Variable Mass 3dof (Wind Axes) -- longitudinal rigid-body equations of motion, simple variable mass State [V alpha q theta xe ze m], gamma = theta - alpha. Inputs Fx, Fz, M and the mass flow rate dm/dt. The mass is a STATE limited to [m_e, m_f], and the inertia is interpolated between its empty and full values:

Iyy(m) = Iyy_e + (m - m_e)*k, k = (Iyy_f - Iyy_e)/(m_f - m_e) m' = dm/dt, except 0 while m <= m_e with dm/dt < 0 or m >= m_f with dm/dt > 0 q' = (M - (k*m')*q)/Iyy(m) V' = Fx/m - g*sin(gamma) alpha' = (Fz/(m*V) + q) + g*cos(gamma)/V and m is clamped to [m_e, m_f] after every step.

⚠ MEASURED AGAINST R2026a (a compiled EOM3DOFNoAccel block), and the LIMIT is where the candidates split: inside the limits the equations reproduce the block to the last printed digit, and through a limit crossing in EITHER direction exactly one of sixteen candidate limit rules did -- the gate tested on the RAW mass at every Runge-Kutta stage, the raw stage mass in F/m and in Iyy(m), and the state clamped after the step. A gate decided once per step (a Simulink limited Integrator's rule) is out by 4e-6; a gate on the clamped mass by 9e-10. The rest of what the measurement settled:

  • The dialog's Iyy is NOT read: the inertia is Iyy(m) from the empty and full values alone.
  • The last output is the fuel tank status: +1 at m >= m_f, -1 at m <= m_e, 0 between.
  • "Metric" and "English (velocity in ft/s)" are the same arithmetic; kts is not offered (it

converts velocities inside the integration). axes, mtype, g_in, vre_flag and mass_flag move the Simulink block's port list and are pinned; mdot_flag moves none and is pinned at its measured default.

A continuous block with a real derivative, like the fixed-mass pair; the discrete path and every exported core run ICoreEomRk4's map -- M RK4 substeps in ode4's association, the clamp as its post-step -- which at M = 100 is Simulink's fixed-step ode4 at Ts/100, step for step.

Sample results#

EOM 3DOF Simple Variable Mass Wind Axes — Step: 0 -> 1 at t = 1 sEOM 3DOF Simple Variable Mass Wind Axes — Step: 0 -> 1 at t = 1 s0200400600012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0out ICoreDouble-Out-1out ICoreDouble-Out-2 [2x1] entry 0

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)-0.525 … 0
rampRamp: slope 1 from t = 0-0.5653 … 0
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-0.5237 … 0
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-0.5311 … 0

Plotted: step — Step: 0 -> 1 at t = 1 s

Category dynamic · sample time 0.1 · 60 steps · commit 9a488f18c · produced by docsSample --out <folder> --blocks EOM_3DOF_Custom_Variable_Mass_Body_Axes EOM_3DOF_Custom_Variable_Mass_Wind_Axes EOM_3DOF_Simple_Variable_Mass_Body_Axes EOM_3DOF_Simple_Variable_Mass_Wind_Axes --steps 60 · data docs/generated/samples/Robotics__Equations_Of_Motion__EOM_3DOF_Simple_Variable_Mass_Wind_Axes.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).