Eclipse Shadow Model — Robotics/Celestial Phenomena
Robotics/Celestial_Phenomena/Eclipse_Shadow_Model · 2 input / 2 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.
Eclipse Shadow Model
Robotics / Celestial Phenomena
How much of the Sun's disc a spacecraft can see past the body it orbits. With r the spacecraft's position and s the Sun's, both measured from the centre of the shadowing body, R that body's radius and Rs the Sun's, the block answers the visible fraction of the solar disc and the shadow region by one of two models:
- Cylindrical – the shadow is a cylinder of radius R pointing away from the Sun. With u = s/|s|, d = r·u and p = |r − d·u|, the spacecraft is in umbra (fraction 0) when d < 0 and p < R, and in sunlight (fraction 1) otherwise. There is no penumbra.
- Dual cone – the Sun and the body are two discs as seen from the spacecraft, of apparent radii a = asin(Rs/|s − r|) and b = asin(R/|r|), whose centres are c = acos((−r)·(s − r) / (|r|·|s − r|)) apart. Sunlight when c ≥ a + b; umbra when c < b − a; antumbra, fraction 1 − b²/a², when c < a − b; otherwise penumbra, fraction 1 − A/(πa²) with A the exact area in which the two discs overlap, A = a²acos(x/a) + b²acos((c − x)/b) − c·y, x = (c² + a² − b²)/(2c), y = √(a² − x²).
Ports
- r_sc – the spacecraft's position r, one [3,1] column [x; y; z] from the centre of the shadowing body, in any inertial frame.
- r_sun – the Sun's position s, one [3,1] in the same frame, from the same centre, in the same length unit as r_sc and both radii.
- fraction – the visible fraction of the solar disc, [1,1], from 0 (none) to 1 (all). The cylindrical model only ever answers 0 or 1.
- region – the shadow region, [1,1]: 0 umbra, 1 sunlight, 2 penumbra, 3 antumbra – the Aerospace Blockset's own numbering. The cylindrical model only ever answers 0 or 1.
Parameters
- Shadow Model – which geometry runs. This selects the
arithmetic, not just a value:
- Cylindrical – the cheap approximation: a sharp shadow with no penumbra, the Sun taken as infinitely far away.
- Dual cone – umbra, penumbra and antumbra, with the Sun's real size and distance. The default.
- Central Body Radius – R, the radius of the body casting the shadow, a positive scalar in the positions' unit. Defaults to 6378137, Earth's equatorial radius in metres.
- Sun Radius – Rs, a positive scalar in the same unit; read only by the dual-cone model. Defaults to 695700000, the Sun's nominal radius in metres.
- 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 chosen model is fixed at export time – a core exported as Cylindrical contains no dual-cone arithmetic – and both radii are baked into the emitted code rather than published as tunable parameters.
The three hardware targets are simulation-only: two
arcsines, three arccosines and up to five square roots do not belong in a
Q16.16 datapath, so the arithmetic runs in real inside a function
and only the ports are fixed point. Those ports hold nothing beyond about
±32767, and the Sun is 1.496×108 km from the Earth,
so a hardware export needs its positions and radii in a unit that brings the
Sun inside that range – Earth radii work (the Sun is then about
23455 away and one Q16.16 step is about 97 m); metres and kilometres do not,
and the fixed-point conversion wraps rather than saturating. The same step
means a sample within about 10−5 of a shadow boundary can
land on the other side of it in hardware than in software.
Simulink bridge
None, deliberately. The Aerospace Blockset's Eclipse Shadow Model
(aerolibcelestial, both its Cylindrical and its Dual Cone entry)
takes only the spacecraft's position on its one input and computes the
Sun's itself, from a JPL DE ephemeris against a Julian date. This block takes
the Sun on a port instead, so the two port lists cannot match and no parameter
mapping could turn one into the other; wire an ephemeris in front of this block
to reproduce the Simulink one. The geometry was checked against MathWorks' own
implementation rather than against the block (see Notes). The per-block
Sampling Time (s) → SampleTime pair that every other block carries has
nothing to cross to here.
Notes
- Algebraic and stateless: the outputs depend only on this sample's inputs.
- Not linear, so the block carries no state space and model reduction correctly reports it as unmergeable.
- A spacecraft inside the body (|r| < R) is in umbra, fraction 0, in both models. The Simulink block stops the run with an error there by default.
- A spacecraft at or inside the Sun (|s − r| ≤ Rs) is in sunlight, and a Sun at the body's centre makes the cylindrical model answer sunlight everywhere outside the body.
- Verified against R2026a: over 59997 points in four geometries this block's arithmetic agrees with the Aerospace Toolbox's own cylindrical and dual-cone estimators on every cylindrical answer and every dual-cone region, and on the dual-cone fraction to within 4.4×10−11 (bit for bit on 94.5 % of the points). Every length and dot product sums its three terms from z to x, because MATLAB's do; summed from x to z the cylindrical model disagreed on 729 points at the shadow's edge.
- Only one body casts a shadow. The Simulink block can also count the Moon when the central body is the Earth; here a second copy of this block, with the Moon as its central body, gives that separately.
Code facts#
| Fact | Value |
|---|---|
| registered type | Robotics/Celestial_Phenomena/Eclipse_Shadow_Model |
| family | Robotics/Celestial_Phenomena |
| solver environment class | ICoreBlock_0_Robotics_1_Celestial_Phenomena_2_Eclipse_Shadow_Model |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Celestial_Phenomena/Eclipse_Shadow_Model/ICoreBlock_0_Robotics_1_Celestial_Phenomena_2_Eclipse_Shadow_Model.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Celestial_Phenomena/Eclipse_Shadow_Model/ICoreBlock_0_Robotics_1_Celestial_Phenomena_2_Eclipse_Shadow_Model.h |
| default size on canvas | 170 × 90 px |
| ports at insert | 2 in, 2 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 | r_sc |
| 2 | in | ICoreDouble | r_sun |
| 3 | out | ICoreDouble | fraction |
| 4 | out | ICoreDouble | region |
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 |
|---|---|---|
Shadow Model | std::string(MODEL_CYLINDRICAL)%~%MODEL_DUAL_CONE~~MODEL_D… | — |
Central Body Radius | cFmt(EARTH_RADIUS) | — |
Sun Radius | cFmt(SUN_RADIUS) | — |
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::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): the Aerospace Blockset's Eclipse Shadow Model (aerolibcelestial, both its Cylindrical and its Dual Cone entry -- one block type) takes only the spacecraft's position on its single input and computes the Sun's itself from a JPL DE ephemeris and a Julian date. This block takes the Sun's position on a second port instead, so the port lists cannot match and no parameter mapping turns one into the other. Put an ephemeris in front of this block to reproduce the Simulink one
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).
Eclipse Shadow Model -- how much of the Sun a spacecraft sees past the body it orbits r = the spacecraft's position, s = the Sun's, both from the centre of the shadowing body; R = that body's radius, Rs = the Sun's. Two models, chosen by Shadow Model:
Cylindrical u = s/|s|, d = r.u, p = |r - d*u| fraction 0 and region 0 (umbra) when d < 0 and p < R, else 1 and 1 Dual cone a = asin(Rs/|s - r|), b = asin(R/|r|), c = acos((-r).(s - r)/(|r||s - r|)) c >= a + b sunlight 1 region 1 c < b - a umbra 0 region 0 c < a - b antumbra 1 - b^2/a^2 region 3 otherwise penumbra 1 - A/(pi*a^2) region 2 A = a^2*acos(x/a) + b^2*acos((c - x)/b) - c*y, x = (c^2 + a^2 - b^2)/(2c), y = sqrt(a^2 - x^2)
The arithmetic, its measurement against MathWorks' implementation and its four guards are documented once, in ICoreEclipseShadowSupport.cpp; this block's simulation calls that file and its ten generators emit the same statements in the same order.
⚠ ONE BLOCK, TWO LIBRARY ENTRIES. The Aerospace Blockset lists "Eclipse Shadow Model (Cylindrical)" and "Eclipse Shadow Model (Dual Cone)" separately, but they are one block type, EclipseShadowModel, differing only in the
shadowModelparameter -- measured with get_param on both in R2026a. So here they are one block with a Shadow Model choice, and the choice is a MODE: the two run entirely different arithmetic and each has a rig of its own.⚠ WHY THERE IS NO SIMULINK BRIDGE. The Simulink block takes ONE input, the spacecraft's position, and computes the Sun's (and optionally the Moon's) from a JPL DE ephemeris against a Julian date --
ephemerisModelDE405/421/423/430/432t, a start date, a time source. This block takes the Sun's position on its second port instead, so the two cannot share a port list and no parameter mapping can make one into the other. An ephemeris is its own row of work (the Planetary Ephemeris block), and a user wires one in front of this block.⚠ AND THE SIMULINK BLOCK CANNOT BE RUN HERE AT ALL. Every set_param on it, and every simulation, loads the "Ephemeris Data for Aerospace Toolbox" support package, which is not installed on the machine this was measured on -- so the reference is the pair of estimator functions the Aerospace Toolbox's satellite scenario uses, which take the same inputs as the block's compiled cylindrical and dual-cone routines and answer in the same region codes.
⚠ THE HARDWARE TARGETS ARE SIMULATION-ONLY, and a Q16.16 port changes what a user must feed them. Two arcsines, three arccosines and five square roots do not belong in a fixed-point datapath, so the three HDL bodies compute in
realand quantize only at the ports. But the
Sample results#
Plotted: vector — Sine Wave, [3,1]: amplitudes 1/2/3 at 2 rad/s (tried only because every scalar stimulus was refused)
Category dynamic · sample time 0.1 · 60 steps · commit 6280f52f3 · produced by docsSample --out <folder> --blocks Rational_Resample,Three_Axis_Accelerometer,Three_Axis_Gyroscope,Three_Axis_Inertial_Measurement_Unit,Eclipse_Shadow_Model,To_String,String_To_ASCII,ASCII_To_String,Substring,String_Constant,String_Concatenate,String_Compare,String_Length --steps 60 · data docs/generated/samples/Robotics__Celestial_Phenomena__Eclipse_Shadow_Model.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).