Planets¶
A Planet is a world-level entity: a planet-fixed frame, standing
disturbances on the shared fields, and initial-state factories.
manta.Planet ¶
Body-fixed rotating planet frame + field-disturbance source.
Args:
name — identifier (used in repr + lookups).
position — planet center in WorldFrame (m). Default origin.
rotation_axis — unit rotation axis in WorldFrame. Default (0,0,1).
omega — angular rate, rad/s. Positive ⇒ right-hand-rule
rotation about rotation_axis. Earth sidereal
is ~7.272e-5 rad/s; default 0 (non-rotating).
Source code in manta/planets/base.py
R_world_from_planet ¶
3×3 rotation matrix from PlanetFrame to WorldFrame at time t.
Source code in manta/planets/base.py
omega_vec_world ¶
planet_to_world ¶
Position + velocity of a point that, in PlanetFrame at time
t, has coords (p_planet, v_planet). Returns (p_world, v_world).
Velocity transform: v_world = R · v_planet + ω × (p_world − planet.position)
Source code in manta/planets/base.py
position_world_sym ¶
omega_world_sym ¶
R_world_from_planet_sym ¶
3×3 MX rotation from PlanetFrame to WorldFrame at symbolic t.
Rodrigues' formula with angle = omega·t. Branch-free.
Source code in manta/planets/base.py
world_to_planet_sym ¶
Symbolic Cartesian position/velocity in this planet's frame.
p_world and v_world must be Vec3[WorldFrame] values.
The returned values are Vec3[PlanetFrame]. The method mirrors
:meth:world_to_planet exactly and intentionally contains no
geodetic conversion.
Source code in manta/planets/base.py
planet_to_world_sym ¶
Symbolic inverse of :meth:world_to_planet_sym, Cartesian only.
Source code in manta/planets/base.py
position ¶
Return a PlanetState wrapping a PlanetFrame position. Pass
directly to World.add_craft(..., position=...) to seed the
craft's initial WorldFrame position from PlanetFrame coords.
Source code in manta/planets/base.py
velocity ¶
Return a PlanetState wrapping a PlanetFrame velocity.
local_tangent_basis ¶
Local East/North/Up unit vectors (WorldFrame) at a WorldFrame point — a purely Cartesian local-tangent frame, no lon needed.
Up comes from :meth:surface_normal, which is radial for the
generic Cartesian planet. North is the spin axis projected into
that tangent plane and East = North × Up.
Where North is undefined — the planet isn't rotating, or the
point sits on the spin axis — it falls back to a stable
tangential reference (world +x, else +y), so the basis is always
well-formed (only its azimuth is then arbitrary). Returns
(east, north, up).
Source code in manta/planets/base.py
surface_normal ¶
Cartesian outward normal used to orient a local Scene.
The base planet has no reference ellipsoid or geodesy contract, so its only meaningful convention is radial. Concrete planets can override this using the same Cartesian geometry as their fields.
Source code in manta/planets/base.py
local_tangent_orientation ¶
World-from-craft quaternion (w, x, y, z) placing the craft in
the local-tangent frame at WorldFrame point position: body
forward (+x) along North, up (+z) along the Cartesian surface normal, yawed
by heading (radians, right-handed about Up — 0 faces North).
Cartesian and general: 'North' is the spin-axis tangential
projection (see local_tangent_basis).
Source code in manta/planets/base.py
scene_at ¶
A local Scene anchored at PlanetFrame point position — a
ground patch with a human-friendly East/North/Up frame, used to
place craft and to translate poses/state for reporting + rendering.
position is in the planet-fixed frame (origin at the planet
centre), so a point on the surface is a planet-radius vector — with
the planet left at the world origin you place a craft anywhere on
it. The scene's axes are the local tangent frame there (+z surface
normal, +x north),
optionally yawed by heading (radians) about up. See Scene for
the full API (at_rest, relative, world_pose).
Source code in manta/planets/base.py
register_disturbances ¶
Called by Sim(world) to attach this planet's standing
contributions to the world's shared fields. A planet is the
world's gravity declaration: an override must register the
GravityField (world.get_or_create_field(GravityField)) even when
it adds no gravity source, or the world refuses to resolve.
Subclasses (Earth,
Moon, ...) override to install gravity / ocean / atmosphere /
magnetic-dipole disturbances. Base default: register the (empty)
GravityField and nothing else — a bare Planet is a deliberate
zero-gravity frame, not an undeclared one.
Subclasses should use world.get_or_create_field(FieldClass) to
get the shared instance, then .add(disturbance).
Source code in manta/planets/base.py
manta.planets.Earth ¶
Earth(name='earth', *, position=(0.0, 0.0, 0.0), rotation_rate=None, rotation_axis=(0.0, 0.0, 1.0), flattening=FLATTENING, sea_level=0.0, water_density=1025.0, ocean_current=(0.0, 0.0, 0.0), air_density=1.225, sea_level_temperature=T0_ISA, lapse_rate=LAPSE_ISA, gravity_mu=MU, include_j2=None, dipole_moment=0.0, waves=None, surface_collision=True, surface_smoothing=0.0)
Bases: Planet
Standard Earth preset.
Args:
name — identifier. Default "earth".
position — planet center in WorldFrame (m).
rotation_rate — angular rate, rad/s. Default: Earth's true
sidereal rate (Earth.SIDEREAL). Pass 0.0 for a
non-rotating Earth. Most users never set this —
place craft with earth.scene_at(...) instead.
flattening — of the reference ellipsoid. Default WGS-84
(Earth.FLATTENING); 0 gives a sphere of
radius R_EQ.
sea_level — normal offset of the ocean's top above the
reference ellipsoid, m. Default 0 (the sea
surface IS the ellipsoid, as for a WGS-84
altitude with no geoid model).
water_density — ocean density, kg/m³. Default 1025 (seawater).
air_density — atmosphere density at sea level, kg/m³. Default
1.225 (ISA). Sets the sea-level pressure via the
ideal-gas law P0 = ρ0·R·T0; aloft the air
follows the ISA troposphere (lapse + ideal gas),
so density is no longer a pure exponential.
sea_level_temperature — ISA sea-level temperature T0, K. Default
288.15. Drops with altitude at lapse_rate.
lapse_rate — ISA troposphere temperature lapse, K/m. Default
6.5e-3.
gravity_mu — gravitational parameter μ (m³/s²). 0 disables
gravity. Default Earth.MU.
include_j2 — register the J2 oblateness perturbation
alongside the point-mass term. Default None
→ on whenever flattening > 0, off for a
sphere. Point mass + J2 + the centrifugal
term of the spinning frame make the ellipsoid
an equipotential to O(f²), so gravity is
normal to the sea surface (residual tangential
acceleration < 1e-4 m/s²); with a point mass
alone a craft at rest on the ellipsoid would
feel a ~1.7e-2 m/s² pull toward the equator.
An explicit False is honoured (physically
inconsistent on an oblate Earth — for isolated
gravity tests only).
dipole_moment — magnetic dipole strength, A·m². 0 disables
magnetic. Default 0.
waves — optional SeaWaves: a sinusoidal moving sea
surface (boundary elevation + underwater
orbital velocity). Default None (flat sea).
surface_collision — register the sea surface (the ellipsoid
raised by sea_level) as a solid
CollisionField obstacle (a rough model of
the surface), so Collider-footed craft can
stand anywhere on the planet without a
per-site ground plane. Default True.
surface_smoothing — m. Blend the water/air switch over this
length (a C¹ Hermite step in altitude) instead
of a hard if_else. Physically: a finite-size
volume element crosses the surface over its
own diameter; numerically it turns point-
sampled buoyancy from bang-bang into a smooth
ramp (a floating hull finds a stable draft, a
surface-piercing foil gets a smooth lift-vs-
height slope). Default 0 (hard boundary).
Source code in manta/planets/earth.py
planet_radius
property
¶
Equatorial radius of the sea surface, R_EQ + sea_level (m).
Also the radius that sets the surface gravity g0 = μ / R² the
hydrostatic and barometric columns use — a single value for the
whole planet, so those columns carry the equatorial g0 at every
latitude (the pole is 0.5% stronger). The dynamics use the real
gravity field; only the fluid pressure profiles take this
shortcut.
sea_surface ¶
The mean sea surface as a solid Ellipsoid — the reference
ellipsoid raised by sea_level, in WorldFrame about the planet
centre. Its signed_height_sym is the signed height every
Earth field is built on.
Source code in manta/planets/earth.py
surface_normal ¶
Outward normal of Earth's Cartesian reference ellipsoid.
Source code in manta/planets/earth.py
manta.planets.Scene ¶
A local East/North/Up frame fixed in a planet's body frame.
Construct via planet.scene_at(position, heading=...) rather than
directly. position is the anchor point in PlanetFrame (typically a
point on the surface); the scene's axes are the local tangent frame
there — +z along the planet's Cartesian surface normal (radial for the
base planet), +x north (the planet spin axis projected into the tangent
plane), +y = up×north — optionally yawed by heading (radians) about up.
Source code in manta/planets/scene.py
R_world_from_scene ¶
3×3 rotation from the scene frame to WorldFrame at time t.
origin_world ¶
world_pose ¶
(origin_world, quat_world_from_scene) at time t — the scene's
own pose, to publish as a parent/anchor entity for rendering.
Source code in manta/planets/scene.py
at_rest ¶
Initial state for a craft at rest in the scene (co-rotating
with the planet) at scene-frame coordinate position, yawed
heading (radians) about local up from the scene's north.
Returns a kwargs dict (position, velocity, orientation,
angular_velocity, all WorldFrame) to splat into
World.add_craft::
w.add_craft(sub, **scene.at_rest((0, 0, -0.2))) # 0.2 m down
w.add_craft(buoy, **scene.at_rest(heading=np.radians(35)))
The orbital velocity ω × r and body spin rate R_craftᵀ·ω are
filled in so the craft is genuinely fixed to the planet (a gyro
reads the planet's spin; it does not drift through the co-rotating
sea/air).
Source code in manta/planets/scene.py
relative ¶
Re-express a craft's WorldFrame state in the scene frame.
state is a per-craft state dict (as from sim.state[name] or
ekf.state_dict()[name]): position/velocity (WorldFrame),
orientation (world-from-craft quaternion), angular_velocity
(body rates). Returns a dict of the same shape with:
position— in scene coordinates,orientation— scene-from-craft quaternion,velocity— velocity relative to the co-rotating scene (i.e. relative to the ground), in scene coords,angular_velocity— body rate relative to the scene's spin (zero for a craft sitting still on the ground).
Any other keys (part states like joint angles) pass through
unchanged. t is the sim time the state was sampled at (needed for
a spinning planet; default 0).
Source code in manta/planets/scene.py
manta.planets.PlanetState ¶
Initial-state value carrying its PlanetFrame origin.
Resolved by World.add_craft at compile time via
planet.planet_to_world(...).
Source code in manta/planets/state.py
manta.planets.SeaWaves
dataclass
¶
Planar deep-water sinusoid riding a planet's sea surface.
The surface elevation (above the mean sea surface) is
η(p, t) = amplitude · cos(k·ξ − ω·t), ξ = p_planet · direction
with k = 2π/wavelength and ω = k·c. The phase speed c defaults to
the deep-water dispersion relation c = √(g·λ / 2π). Underwater, the
fluid carries the matching first-order orbital velocity — particles
circle with radius amplitude at the surface, decaying as e^{k·z}
with depth — so drag surfaces and foils feel the moving water, not
just the moving boundary. The pressure carries the matching
depth-attenuated dynamic term ρ·g·η·e^{k·z} on top of the mean
hydrostatic column, so a submerged pressure sensor sees the waves
at the physically correct (depth-filtered) amplitude — the signal a
wave-detecting barometer works with.
direction is a planet-frame vector (normalized; its vertical
component at the point of interest should be ~0). The wave is a
PLANAR field in planet coordinates — valid for a local patch of
ocean, not a globe-wrapping solution.
Args: amplitude — m (crest height above mean sea level). wavelength — m (crest-to-crest). direction — planet-frame propagation direction. Default +x. speed — phase speed override, m/s. None → deep-water dispersion using the planet's surface gravity.