Generated reference › Attitude Profile Sun Tracking — Robotics/Spacecraft Dynamics
kind: generated#block#robotics-spacecraft-dynamics

Attitude Profile Sun Tracking — Robotics/Spacecraft Dynamics

Robotics/Spacecraft_Dynamics/Attitude_Profile_Sun_Tracking · 3 input / 2 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++

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.

Attitude Profile (Sun Tracking)

Robotics / Spacecraft Dynamics

The attitude that points a spacecraft axis at the Sun, and the rotation that gets there from where it is now. The Sun's position relative to the Earth is read from JPL's Development Ephemeris at the input date. The body primary alignment vector a1 is pointed along t1 = 1000·S − X, the Sun seen from the spacecraft (S in km, X in metres). Then the spacecraft turns about that line until the body secondary alignment vector a2 comes as close as it can to a fixed secondary constraint direction t2. Everything is computed in the body axes of the current attitude q, as the Aerospace Blockset does: with q1 the shortest rotation taking a1 to the target and q2 a turn about a1 bringing a2's projection onto the constraint's, q_align = q1 ⊗ q2 and q_ideal = conj(q_align) ⊗ q/|q|.

Ports

  • JD – the date, a Julian date, [1,1]. Simulink names this port t_utc but hands it to the ephemeris unchanged, which reads it as Barycentric Dynamical Time; this block does the same, so the two agree.
  • X – the spacecraft's position from the Earth's centre, [3,1], in metres, in the ICRF frame. Unlike the nadir block, the length matters: the Sun is seen from X, not from the Earth's centre.
  • q – the current attitude, [4,1] [w; x; y; z], scalar first, in the Aerospace Toolbox's convention (quat2dcm(q) maps ICRF vectors into body axes). It need not be unit length: the block normalizes it.
  • q_align – [4,1]: the rotation from the current attitude to the ideal one, expressed in body axes.
  • q_ideal – [4,1]: the ideal attitude itself, in the same convention as q.

Parameters

  • Primary Alignment – a1, the body vector pointed at the Sun, three numbers, any nonzero length. Default [0 0 1].
  • Secondary Alignment – a2, the body vector the constraint steers, any nonzero length. Default [1 0 0].
  • Secondary Constraint – t2, the ICRF direction a2 should face, any nonzero length. Default [0 1 0].
  • Ephemeris Model – which JPL Development Ephemeris: DE405, DE421, DE423, DE430 or DE432t. Default DE430, the one Simulink's block always reads.
  • Ephemeris Folder – the folder holding JPL's published ASCII files for that model, header.4xx and the asc*.4xx data files, as Planetary Ephemeris reads them. Absolute, or relative to the project folder. ICore ships no ephemeris: you supply the files, as MATLAB's support package does, and the block refuses to run without them.
  • Use Date Range – Off (the default) or On. On limits the block to the dates between Start Date and End Date, and a code export needs it.
  • Start Date and End Date – Julian dates, default 2458849.5 (2020-01-01) and 2469807.5 (2050-01-01), Planetary Ephemeris's defaults.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

When a run is refused

An empty or unreadable Ephemeris Folder stops the run before the first step, naming the files it expected. A date the loaded data does not cover, or one outside the date range when Use Date Range is On, stops the run naming the date, as Simulink's block (its ephemeris set to Error) does.

Code export

Six targets: Python, MATLAB, Java, Rust, C and C++. The exported code carries only the 32-day ephemeris records the date range falls in, each with only the Sun's and the Earth's columns, and evaluates them by JPL's algorithm as the live block does, so Use Date Range must be On. A deployed core cannot stop, so a date outside the range answers NaN there. The three vectors are folded into the code. The hardware targets (VHDL, Verilog, SystemVerilog) and PLC Structured Text are not offered: a Julian date (2.4e6) does not fit a Q16.16 port and the records are thousands of constants, so an export to one stops and names the block.

Simulink bridge

Import and export, mapped to Aerospace Blockset's aerolibsatdyn/Attitude Profile (Sun Tracking) (the library name has a line break before the parenthesis). Primary Alignment → primaryAlignment, Secondary Alignment → secondaryAlignment and Secondary Constraint → secondaryConstraint, all 1:1 and lossless. Always written: pointingMode Point at celestial body, celestialTarget Sun, portFrame and constraintFrame ICRF, outputError and outputFinalAttitude on, tunablePointing off and every vector source Dialog. The ephemeris parameters do not cross: Simulink's block has none and always reads DE430, so a model on another DE answers that DE's Sun on this side and DE430's on the other. The Simulink block defines no SampleTime, so the rate stays on the ICore side.

Notes

  • Algebraic and stateless: the outputs depend only on this sample's inputs.
  • Not linear, so the block carries no state space.
  • The ephemeris moves the answer very little: DE430 and DE421 give quaternions that differ by at most 7.5×10−9 on the states it was measured on.
  • The degenerate cases follow Simulink's, as in the nadir block: "parallel" means the cosine is within 10−6 of ±1.
  • Verified against R2026a: over 40 random dates, positions and non-unit attitudes in two alignment configurations, this block answers what Simulink's block answers with its ephemeris set to DE421, read from the same JPL data, to rounding.

Code facts#

FactValue
registered typeRobotics/Spacecraft_Dynamics/Attitude_Profile_Sun_Tracking
familyRobotics/Spacecraft_Dynamics
solver environment classICoreBlock_0_Robotics_1_Spacecraft_Dynamics_2_Attitude_Profile_Sun_Tracking
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Spacecraft_Dynamics/Attitude_Profile_Sun_Tracking/ICoreBlock_0_Robotics_1_Spacecraft_Dynamics_2_Attitude_Profile_Sun_Tracking.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Spacecraft_Dynamics/Attitude_Profile_Sun_Tracking/ICoreBlock_0_Robotics_1_Spacecraft_Dynamics_2_Attitude_Profile_Sun_Tracking.h
default size on canvas170 × 90 px
ports at insert3 in, 2 out
code generators implementedPython, MATLAB, Java, Rust, C, C++

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleJD
2inICoreDoubleX
3inICoreDoubleq
4outICoreDoubleq_align
5outICoreDoubleq_ideal

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
Primary Alignment[0 0 1]primaryAlignment
Secondary Alignment[1 0 0]secondaryAlignment
Secondary Constraint[0 1 0]secondaryConstraint
Ephemeris ModelDE405%~%DE421%~%DE423%~%DE430%~%DE432t~~DE430not crossed
Ephemeris Folder—not crossed
Use Date RangeOff%~%On~~Offnot crossed
Start Date2458849.5not crossed
End Date2469807.5not 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 pathaerolibsatdyn/Attitude Profile\n(Sun Tracking)
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
deliberately not crossedEphemeris Model, Ephemeris Folder, Use Date Range, Start Date, End Date
always setpointingMode = Point at celestial body, celestialTarget = Sun, portFrame = ICRF, constraintFrame = ICRF, outputError = on, outputFinalAttitude = on, tunablePointing = off, primaryAlignmentSrc = Dialog, secondaryAlignmentSrc = Dialog, secondaryConstraintSrc = Dialog
ICore configSimulink parameterValue translation
Primary AlignmentprimaryAlignmentpasses through
Secondary AlignmentsecondaryAlignmentpasses through
Secondary ConstraintsecondaryConstraintpasses through

Caveat (shown to the user): X, q and the constraint are ICRF (portFrame and constraintFrame ICRF), the configuration in which the Simulink block converts nothing but the Sun's position. The ephemeris does not cross: Simulink's block always reads DE430. primaryConstraint is unused when pointing at a body and does not cross. Both outputs are written (outputError and outputFinalAttitude on). The Simulink block has no SampleTime, so the rate stays on the ICore side

Catalog contract: src/ICoreBlocks/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:

  • B0 no sample under docs/generated/samples/ — nothing to cross-check (P8.1)

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

Attitude Profile (Sun Tracking) -- the attitude that points a body axis at the Sun JD = the date (a Julian date), X = the spacecraft's position from the Earth's centre in metres, q = its current attitude (scalar first, any length). The target is the Sun seen from the spacecraft,

t1 = 1000 * S(JD) - X S = the Sun relative to the Earth, km, ICRF (JPL's PLEPH)

and the rest is the nadir sibling's: q_align points the body primary alignment vector a1 along t1 and turns the secondary a2 as close to t2 as it can, and q_ideal = conj(q_align) (x) q/|q| (ICoreAttitudeAlignment, computed in body axes).

READ FROM AND MEASURED AGAINST R2026a's aerolibsatdyn/Attitude Profile (Sun Tracking), 2026-10-02 (BLOCKS_TO_ADD_TOOLBOXES.md, on FEATURES_TO_ADD.md BF6): the nadir block's mask (MaskType "Attitude Profile") with pointingMode "Point at celestial body" and celestialTarget Sun; three inputs t_utc, X and q. Inside, CalcC1 feeds t_utc STRAIGHT into a PlanetaryEphem (CB Position: DE430, center Earth, target Sun, km, useDateRange off, action Error), scales it by 1000 ("km to m") and subtracts X. So X is in metres, and the date is used as the ephemeris' own TDB Julian date with no UTC correction, as the block does. Against a copy of the block whose CalcC1 was set to DE421, over 40 random states in 1899-1900 and two alignment configurations, this block reading the DE421 slice in testingLabs answers both quaternions to rounding (the ephemeris_blocks suite's Sun Tracking case). DE430 and DE421 move the answer by at most 7.5e-9 on those states.

⚠ ONE FRAME, as the siblings: X, q and the constraint are ICRF, Simulink's ICRF/ICRF configuration, so nothing is converted for a date beyond the Sun's position itself.

ALGEBRAIC and STATELESS.

Sample results#

No sample run is committed for this block. Samples come from the headless harness (DOCS_PLAN.md P8.1) into docs/generated/samples/; until one exists this block's behaviour is witnessed by the parity and export-verification suites, not by a plot here.