Nonlinear Second Order Actuator — Robotics/Actuators And Drivetrain
Robotics/Actuators_And_Drivetrain/Nonlinear_Second_Order_Actuator · 1 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.
Nonlinear Second-Order Actuator
Robotics / Actuators and Drivetrain
The fin or servo actuator of the Linear Second-Order Actuator with the three limits a real one has. With ωn the natural frequency, ζ the damping ratio and vmax the rate limit:
- us = sat(u, xmin, xmax) – the demand is held inside the deflection limits.
- r = sat(us − x, ±2ζvmax/ωn) – the rate limit, applied to the tracking error.
- x'' = ωn²·r − 2ζωn·x', with x held in [xmin, xmax] and x' in ±vmax. When x reaches a limit its rate is set to zero.
The error saturation is what makes vmax the steady slewing rate: with r pinned at its limit, x' settles at exactly vmax.
Ports
- Input – u, the demanded position, a scalar [1,1], in the unit the limits are given in (radians by default).
- Output – x, the actual position, a scalar [1,1], always inside [xmin, xmax].
Parameters
- Natural Frequency (rad/s) – ωn, a scalar > 0. Defaults to 1.
- Damping Ratio – ζ, a scalar > 0. Defaults to 0.3.
- Maximum Deflection – xmax. Defaults to 20° in radians, 0.349.
- Minimum Deflection – xmin, below xmax. Defaults to −0.349.
- Rate Limit – vmax, a scalar > 0, in position units per second. Defaults to 500°/s in radians, 8.73.
- Initial Position – x at t = 0. Defaults to 0.
- Initial Velocity – x' at t = 0. Defaults to 0.
- Integration Substeps – M, the number of fourth-order Runge-Kutta steps each sample is integrated with, a whole number of 1 or more. Defaults to 100, which reproduces Simulink's fixed-step ode4 at one hundredth of the sample time exactly. This one has 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. Every core runs the same map as the simulation: the demand held for a sample, M Runge-Kutta substeps with the limits applied after each, and the output taken before the update. The derived constants (ωn², 2ζωn, the error limit and the substep) are folded at export time; there is no tunable parameter object. A core does 4·M derivative evaluations per sample.
The three HDL targets are simulation-only real
arithmetic, quantized at the port: a loop of saturated Runge-Kutta stages is not a
fixed-point datapath. The cores simulate correctly and are not offered as
synthesizable.
Simulink bridge
Import and export, mapped to Aerospace Blockset's
aerolibactuator/Nonlinear Second-Order Actuator: Natural
Frequency (rad/s) → wn_fin, Damping Ratio →
z_fin, Maximum Deflection → fin_max,
Minimum Deflection → fin_min, Rate Limit →
fin_maxrate, Initial Position → fin_act_0
and Initial Velocity → fin_act_vel. Integration
Substeps does not cross: the Simulink block is continuous and its solver
decides. "Sampling Time (s)" does not cross either: the Simulink block
defines no SampleTime parameter, measured on R2026a.
Notes
- Discrete-only and stateful. The limits are part of the state's evolution – reaching a position limit resets the rate – and a state reset is not something a continuous derivative can say. So the block samples its input at its own rate, holds it, and integrates across the sample with M Runge-Kutta substeps. Against a continuous Simulink model run at a fixed step of Ts/M this is the same computation; against a variable-step one it differs by the solver's own error near a limit.
- The output does not depend on the input at the same instant, so a feedback loop through the block is not an algebraic loop.
- For an actuator that never reaches its limits, the Linear Second-Order Actuator is the same dynamics as a real state space.
Code facts#
| Fact | Value |
|---|---|
| registered type | Robotics/Actuators_And_Drivetrain/Nonlinear_Second_Order_Actuator |
| family | Robotics/Actuators_And_Drivetrain |
| solver environment class | ICoreBlock_0_Robotics_1_Actuators_And_Drivetrain_2_Nonlinear_Second_Order_Actuator |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Actuators_And_Drivetrain/Nonlinear_Second_Order_Actuator/ICoreBlock_0_Robotics_1_Actuators_And_Drivetrain_2_Nonlinear_Second_Order_Actuator.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Actuators_And_Drivetrain/Nonlinear_Second_Order_Actuator/ICoreBlock_0_Robotics_1_Actuators_And_Drivetrain_2_Nonlinear_Second_Order_Actuator.h |
| default size on canvas | 120 × 80 px |
| ports at insert | 1 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | — |
| 2 | out | ICoreDouble | — |
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 variable | Default | Simulink parameter |
|---|---|---|
Natural Frequency (rad/s) | 1 | wn_fin |
Damping Ratio | 0.3 | z_fin |
Maximum Deflection | 0.3490658503988659 | fin_max |
Minimum Deflection | -0.3490658503988659 | fin_min |
Rate Limit | 8.7266462599716466 | fin_maxrate |
Initial Position | 0 | fin_act_0 |
Initial Velocity | 0 | fin_act_vel |
Integration Substeps | 100 | not 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.
Simulink bridge#
| support | Support::Both |
| Simulink path | aerolibactuator/Nonlinear Second-Order Actuator |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| deliberately not crossed | Integration Substeps |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Natural Frequency (rad/s) | wn_fin | passes through |
Damping Ratio | z_fin | passes through |
Maximum Deflection | fin_max | passes through |
Minimum Deflection | fin_min | passes through |
Rate Limit | fin_maxrate | passes through |
Initial Position | fin_act_0 | passes through |
Initial Velocity | fin_act_vel | passes through |
Caveat (shown to the user): aerolibactuator/Nonlinear Second-Order Actuator is continuous and has NO SampleTime parameter (verified against the R2026a block dialog), so "Sampling Time (s)" does not cross. "Integration Substeps" is how this block integrates across a sample and has no Simulink counterpart: a continuous model's solver decides that
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).
Nonlinear Second-Order Actuator — the fin actuator with its demand, rate and position limits Per sample, the demand u is held and the state (x, v) is advanced by M RK4 substeps of h = Ts/M on
us = min(max(u, xmin), xmax) Demand limits r = min(max(us - x, -R), R), R = ((vmax*2)*zeta)/wn dv = wn^2 * r - (2*zeta*wn) * v, dx = v dx := 0 when x sits on a limit and v points out; dv := 0 when v sits on +-vmax and dv points out
and after EACH substep: x > xmax -> x = xmax, v = 0; x < xmin -> x = xmin, v = 0; v = min(max(v, -vmax), vmax). The output is the pre-update position, min(max(x, xmin), xmax).
⚠ MEASURED AGAINST R2026a BEFORE ANY OF IT WAS WRITTEN. The masked subsystem is Saturate (Demand limits) -> Sum -> Saturate (rate limit*2*zeta/wn) -> Gain wn^2 -> Sum with Gain 2*zeta*wn on x' -> Second-Order Integrator LIMITED (x in [xmin, xmax], x' in +-vmax, zero-crossing on, reinit off). Three clamp rules were prototyped against Simulink's fixed-step ode4 at Ts/100 on a rig that sat on a limit for 39 % of 500 samples:
derivative gating alone 4.41e-2 gating + clamping x and x' 4.42e-2 gating + clamping + ZEROING x' at an x limit 0 <- this block
so the Second-Order Integrator resets its rate when the position saturates, even with "reinitialize dx/dt" off -- the thing no doc page says. With M = 100 this block is that reference, arithmetic operation for arithmetic operation.
A DISCRETE-ONLY block, for the reason the header gives: a state reset is not a derivative. All ten backends run the same map; the three HDL ones in SIMULATION-ONLY real arithmetic.
Sample results#
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | -0.008721 … 0.02343 |
ramp | Ramp: slope 1 from t = 0 | 0 … 0.3491 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.1891 … 0.2788 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -0.03292 … 0.07704 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit fc85ac64df179e0aadfcbe797a2731524d14cbb9 · produced by docsSample --out <folder> --blocks Linear_Second_Order_Actuator Nonlinear_Second_Order_Actuator Wind_Shear_Model Discrete_Wind_Gust_Model Julian_Date_Conversion --steps 60 · data docs/generated/samples/Robotics__Actuators_And_Drivetrain__Nonlinear_Second_Order_Actuator.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).