Trigonometric Function — Control Systems/Base Blocks
Control_Systems/Base_Blocks/Trigonometric_Function · 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.
Trigonometric Function
Control Systems / Base Blocks
Applies one of thirteen trigonometric or hyperbolic functions to its input, entry by entry. Which function is applied is chosen by the Function parameter, and one of them – the four-quadrant arctangent – takes a second input. Angles are in radians throughout.
Ports
- u1 – the signal the function is applied to, of any size [m,n]. For Four-Quadrant Arctangent this is the numerator (the "y" operand).
- u2 – present only for Four-Quadrant Arctangent, where it is the denominator (the "x" operand). Either the SAME size [m,n] as u1, or a scalar [1,1], which is then applied to every entry of u1. Any other size is an error rather than a guess. The port is not added or removed for you: set the input port count to match the function you chose.
- Output – the result y, the SAME size [m,n] as u1 for every one of the thirteen. This block never reshapes a signal.
Parameters
- Function – which function is applied. This selects the
arithmetic rather than retuning it, so each option is a separate code path.
- Sine (sin(u)) – y = sin(u), u in radians. This is the default, as in Simulink. Defined for every real input.
- Cosine (cos(u)) – y = cos(u). Defined everywhere.
- Tangent (tan(u)) – y = tan(u). Defined everywhere a double can represent, but unbounded near odd multiples of π/2, where a small change in the input makes a large change in the output.
- Arcsine (asin(u)) – y = asin(u) in [−π/2, π/2]. Domain [−1, 1]; outside it the result is NaN.
- Arccosine (acos(u)) – y = acos(u) in [0, π]. Domain [−1, 1]; outside it the result is NaN.
- Arctangent (atan(u)) – y = atan(u) in (−π/2, π/2). Defined everywhere.
- Four-Quadrant Arctangent (atan2(u1,u2)) – two inputs. y = atan2(u₁, u₂) in (−π, π], the angle of the point (u₂, u₁), using the signs of BOTH operands to place the quadrant. Defined everywhere, including u₂ = 0; at the origin it is 0.
- Hyperbolic Sine (sinh(u)) – y = sinh(u). Defined everywhere.
- Hyperbolic Cosine (cosh(u)) – y = cosh(u). Defined everywhere, and never less than 1.
- Hyperbolic Tangent (tanh(u)) – y = tanh(u) in (−1, 1). Defined everywhere.
- Hyperbolic Arcsine (asinh(u)) – y = asinh(u). Defined everywhere.
- Hyperbolic Arccosine (acosh(u)) – y = acosh(u). Domain 1, +∞); below 1 the result is NaN.
- Hyperbolic Arctangent (atanh(u)) – y = atanh(u). Domain (−1, 1); at ±1 the result is ±Inf and beyond them NaN.
- 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. The function is fixed into the generated arithmetic at export time rather than exposed as a tunable parameter: it selects which code is emitted, so there is nothing left to retune on the generated core.
The seven software targets agree exactly, including out of domain, where they
all produce IEEE NaN or ±Inf. MATLAB needs one extra step to get there:
its asin, acos, acosh and
atanh return a complex number outside their domains, so the
generated MATLAB maps those entries to NaN first and keeps the result real.
Two targets lack the inverse hyperbolics entirely – Java and
PLC Structured Text – and build them from logarithms; the other
five call the library function, which is more accurate near zero than the
logarithmic form.
The three HDL targets are simulation-only for all thirteen. There is
no sine in the Q16.16 datapath to call, so the generated cores convert at the
port boundary and evaluate in real arithmetic – correct in
simulation, but not offered as synthesizable. They carry neither NaN nor
infinity, so out of domain they answer 0 where the software targets
answer NaN or ±Inf.
Simulink bridge
Import and export, mapped to simulink/Math Operations/Trigonometric
Function. "Function" to Operator, one option for one option
(sin, cos, tan, asin,
acos, atan, atan2, sinh,
cosh, tanh, asinh, acosh,
atanh), so that round trip is lossless for the thirteen this block
offers; "Sampling Time (s)" to SampleTime, as on every block.
Neither side carries the port count as a parameter: Simulink moves its own
ports when Operator is set, and an imported model brings the port
list the operator implies back with it. Three parameters are always written out
because this block has no choice to offer behind them –
ApproximationMethod is None, which pins the result to
the exact library function rather than Simulink's CORDIC or lookup
approximation; OutputSignalType is real, since ICore
signals are real doubles; and AngleUnit is radian.
Two of Simulink's fifteen operators are not offered. sincos produces TWO outputs, and every operator here has one – use two blocks sharing an input. cos + jsin produces a COMPLEX output, and ICore signals are real doubles. A Simulink model using either is reported on import rather than silently mapped to something else.
Notes
- Algebraic, with no state: the output depends only on the current input.
- Not linear in any of the thirteen, so the block deliberately carries no state space and model reduction reports it as unmergeable.
- Angles are in radians. Simulink's
AngleUnitalso offers revolutions; this block does not, and always writesradian. Scale with a Gain of 2π to work in revolutions. - Changing Function to or from Four-Quadrant Arctangent does not add or remove the second port for you. The block reports the mismatch when the model is built rather than editing the diagram underneath you.
- Hyperbolic Cosine and Hyperbolic Sine grow exponentially: an input beyond about 710 overflows a double to ±Inf in every target.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Base_Blocks/Trigonometric_Function |
| family | Control_Systems/Base_Blocks |
| solver environment class | ICoreBlock_0_Control_Systems_1_Base_Blocks_2_Trigonometric_Function |
| source | [src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Base_Blocks/Trigonometric_Function/ICoreBlock_0_Control_Systems_1_Base_Blocks_2_Trigonometric_Function.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Base_Blocks/Trigonometric_Function/ICoreBlock_0_Control_Systems_1_Base_Blocks_2_Trigonometric_Function.h |
| default size on canvas | 80 × 70 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 | u1 |
| 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 |
|---|---|---|
Function | Sine (sin(u))%~%Cosine (cos(u))%~%Tangent (tan(u))%~%Arcs… | Operator |
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 | simulink/Math Operations/Trigonometric Function |
| port-count rule | PortsParam::TrigFunctionOperator |
SampleTime parameter | yes |
| always set | ApproximationMethod = None, OutputSignalType = real, AngleUnit = radian |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Function | Operator | Sine (sin(u)) → sin, Cosine (cos(u)) → cos, Tangent (tan(u)) → tan, Arcsine (asin(u)) → asin, Arccosine (acos(u)) → acos, Arctangent (atan(u)) → atan, Four-Quadrant Arctangent (atan2(u1,u2)) → atan2, Hyperbolic Sine (sinh(u)) → sinh, Hyperbolic Cosine (cosh(u)) → cosh, Hyperbolic Tangent (tanh(u)) → tanh, Hyperbolic Arcsine (asinh(u)) → asinh, Hyperbolic Arccosine (acosh(u)) → acosh, Hyperbolic Arctangent (atanh(u)) → atanh |
Caveat (shown to the user): the thirteen real operators map 1:1 onto Simulink's Operator values, so the choice is lossless in both directions; the second input port that atan2 needs is implied by the function rather than carried by a parameter. Simulink's sincos (two outputs) and 'cos + jsin' (complex output) are NOT offered -- ICore signals are real doubles and every operator here has one output -- so a model using either is reported rather than mapped to a different function
Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0Ports lists 3 entries for 2 ports (1 in, 1 out) — grouped, or one undocumented? a reader must say
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).
Trigonometric Function -- Simulink's Trigonometric Function, the thirteen REAL operators "Function" selects WHICH code runs, so every option is a mode rather than a tuning, and one of them changes the block's SHAPE as well as its arithmetic: atan2 takes a SECOND input port, exactly as it does in Simulink, with u1 the numerator and u2 the denominator.
Four conventions are worth stating, because they are the only places the ten targets could have drifted from each other or from Simulink:
- OUT OF DOMAIN. asin and acos are defined on [-1, 1], acosh on [1, +Inf), atanh on
(-1, 1). The seven software targets all produce IEEE NaN (or +/-Inf at atanh's two endpoints) and agree exactly -- except MATLAB, whose asin, acos, acosh and atanh return COMPLEX numbers outside their domains rather than NaN, so those bodies map the offending entries to NaN first and keep the result real, matching the other six. This is the same guard, for the same reason, that Math Function applies to log and log10.
- THE INVERSE HYPERBOLICS ARE CALLED, NOT REBUILT, wherever the target has them. C, C++,
Rust, Verilog, SystemVerilog and VHDL all supply asinh/acosh/atanh; Java and IEC Structured Text do not, and build them from logarithms. That split is deliberate rather than tidy: log(x + sqrt(x*x + 1)) loses significance to cancellation for small negative x, where the library asinh is exact, so a target that HAS the primitive must use it or it would disagree with the reference near zero -- which is where the stimulus spends most of its samples.
- ATAN2 AT THE ORIGIN. atan2(0, 0) is 0 in C, MATLAB and every software target here.
VHDL's math_real ARCTAN(Y, X) ASSERTS on that pair rather than returning a value, which would abort the simulation, so the VHDL body guards it -- as do the two Verilogs, which have no infinity or NaN to fall back on either.
- HDL. There is no fixed-point sine to call, so the three HDL backends are SIMULATION-ONLY
for all thirteen: they convert at the port boundary and evaluate in
real. They also carry neither NaN nor infinity, so out of domain they answer 0 where the software targets answer NaN or +/-Inf.TWO OF SIMULINK'S FIFTEEN ARE NOT OFFERED, and the catalog entry says so rather than letting them fail obscurely:
sincosproduces two outputs, andcos + jsinproduces a complex one. See the header.Algebraic and stateless. No state space -- see the header for why.
Sample results#
| t | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 |
|---|---|---|
| 0 | -2 | -0.9093 |
| 0.4 | 0.5 | 0.4794 |
| 0.8 | -2 | -0.9093 |
| 1.2 | 0.5 | 0.4794 |
| 1.6 | -2 | -0.9093 |
| 2 | 0.5 | 0.4794 |
| 2.4 | -2 | -0.9093 |
| 2.8 | 0.5 | 0.4794 |
| 3.2 | -2 | -0.9093 |
| 3.6 | 0.5 | 0.4794 |
| 4 | -2 | -0.9093 |
| 4.4 | 0.5 | 0.4794 |
| 4.8 | -2 | -0.9093 |
| 5.2 | 0.5 | 0.4794 |
Every 4th of 60 samples, from the table stimulus.
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 … 0.8415 |
ramp | Ramp: slope 1 from t = 0 | -0.9999 … 0.9996 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.8415 … 0.8412 |
step | Step: 0 -> 1 at t = 1 s | 0 … 0.8415 |
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 ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__Base_Blocks__Trigonometric_Function.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).