Source code for cubesat_specs.standards

"""Constants and constraints from the CubeSat Design Specification (CDS) Rev 14.1.

Every value in this module is directly traceable to the CDS Rev 14.1
(CP-CDS-R14.1, Cal Poly SLO, February 2022).  Section references are
given as ``§X.Y.Z``.

Source
------
https://static1.squarespace.com/static/5418c831e4b0fa4ecac1bacd/
t/62193b7fc9e72e0053f00910/1645820809779/CDS+REV14_1+2022-02-09.pdf
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Dict, Tuple

# ── Rail & Mechanical Interface (§2.2) ─────────────────────────────────────

RAIL_MIN_WIDTH_MM: float = 8.5
"""Minimum rail width measured from edge of rail to first protrusion [mm] (§2.2.5)."""

RAIL_SURFACE_ROUGHNESS_MAX_UM: float = 1.6
"""Recommended maximum rail surface roughness Ra [µm] (§2.2.6)."""

RAIL_EDGE_RADIUS_MIN_MM: float = 1.0
"""Minimum radius on rail edges [mm] (§2.2.7)."""

RAIL_END_CONTACT_AREA_MIN_MM: Tuple[float, float] = (6.5, 6.5)
"""Minimum rail end contact area on ±Z faces [mm × mm] (§2.2.8)."""

RAIL_CONTACT_PCT_MIN: float = 75.0
"""Minimum percentage of rail length in contact with dispenser rails [%] (§2.2.9).
Up to 25 % may be recessed."""

MAX_PROTRUSION_MM: float = 6.5
"""Maximum protrusion of any component from the rail plane [mm] (§2.2.3)."""

RBF_MAX_PROTRUSION_MM: float = 6.5
"""Maximum RBF-pin protrusion from rail surface when inserted [mm] (§2.3.5.2)."""

RECOMMENDED_AL_ALLOYS: Tuple[str, ...] = (
    "7075", "6061", "6082", "5005", "5052",
)
"""Aluminium alloys recommended for CubeSat structure and rails (§2.2.12.1)."""

HARD_ANODIZE_REQUIRED: bool = True
"""All aluminium surfaces in contact with dispenser rails shall be hard
anodized to prevent cold welding (§2.2.13)."""

# ── Separation Mechanism (§2.2.14) ─────────────────────────────────────────

SEPARATION_SPRING_MAX_FORCE_N: float = 6.7
"""Maximum recommended separation spring force [N] (1.5 lbf) (§2.2.14.1)."""

SEPARATION_SPRING_MIN_STROKE_MM: float = 2.5
"""Minimum recommended separation spring stroke [mm] (0.1 in) (§2.2.14.1)."""

# ── Outgassing (§2.1.7) ───────────────────────────────────────────────────

OUTGASSING_TML_MAX_PCT: float = 1.0
"""Maximum Total Mass Loss [%] (§2.1.7.1)."""

OUTGASSING_CVCM_MAX_PCT: float = 0.1
"""Maximum Collected Volatile Condensable Material [%] (§2.1.7.2)."""

# ── Magnetic Field (§2.1.8) ────────────────────────────────────────────────

MAGNETIC_FIELD_MAX_GAUSS_ABOVE_EARTH: float = 0.5
"""Maximum residual magnetic field above Earth's ambient [Gauss] (§2.1.8)."""

# ── Venting (§2.1.9) ──────────────────────────────────────────────────────

ASCENT_VENT_RATIO_MAX_M: float = 50.8
"""Maximum ventable-volume / vent-area ratio [m] (2 000 in) (§2.1.9)."""

# ── Electrical Safety (§2.3) ──────────────────────────────────────────────

MIN_DEPLOYMENT_SWITCHES: int = 1
"""Minimum number of deployment switches (§2.3.2)."""

RF_INHIBIT_COUNT: int = 3
"""Minimum independent RF-transmission inhibits (§2.3.7)."""

DEPLOYABLE_INHIBIT_COUNT: int = 3
"""Minimum independent inhibits for deployable structures (§2.3.8)."""

PROPULSION_INHIBIT_COUNT: int = 3
"""Minimum independent inhibits for propulsion activation (§2.1.4)."""

# ── Real-Time Clock (§2.3.3) ──────────────────────────────────────────────

RTC_MAX_FREQ_KHZ: float = 320.0
"""Maximum RTC oscillator frequency [kHz] (§2.3.3.2)."""

RTC_MAX_CURRENT_MA: float = 10.0
"""Maximum RTC circuit current draw [mA] (§2.3.3.3)."""

# ── Operational Timers (§2.4) ─────────────────────────────────────────────

DEPLOYABLE_WAIT_MINUTES: int = 30
"""Minimum wait time before deploying booms/antennas/panels after
deployment-switch activation [minutes] (§2.4.4)."""

RF_SILENCE_MINUTES: int = 45
"""Minimum wait time before first RF transmission after on-orbit
deployment [minutes] (§2.4.5)."""

# ── Battery Guideline (§2.1.5) ────────────────────────────────────────────

BATTERY_FAA_GUIDELINE_WH: float = 100.0
"""FAA carry-on lithium-ion battery limit used as guideline [Wh] (§2.1.5).
This is a *recommendation*, not a hard CDS requirement."""

# ── Orbital Debris (§2.4.3) ───────────────────────────────────────────────

REENTRY_ENERGY_MAX_J: float = 15.0
"""Maximum re-entry kinetic energy per component [J] (§2.4.3.1)."""

# ── Pyrotechnics (§2.1.2 / §2.1.3) ───────────────────────────────────────

PYROTECHNICS_STANDARD: str = "AFSPCMAN 91-710 Vol. 3"
"""Pyrotechnics and propulsion systems shall conform to this standard."""

# ── Testing Philosophy (§3) ───────────────────────────────────────────────
# CDS Rev 14.1 does NOT specify vibration levels, shock levels, thermal-
# vacuum profiles, or a minimum natural frequency.  All test levels and
# durations are delegated to the Launch Provider (§3.1.1, §3.2.2, §3.3.1).
# When the LV environment is unknown, GSFC-STD-7000A (GEVS) and
# SMC-S-016 may be used as *guides* — but their levels are "not guaranteed
# to encompass or satisfy all LV testing environments" (§3, para 2).

VIBRATION_NOTE: str = (
    "CDS Rev 14.1 §3.1.1: random vibration levels are defined by the "
    "Launch Provider.  No default levels are specified in the CDS.  "
    "GSFC-STD-7000A (GEVS) and SMC-S-016 may be used as guides."
)

SHOCK_NOTE: str = (
    "CDS Rev 14.1 §3.3.1.1: shock testing is typically not required "
    "for CubeSats."
)


# ── Convenience aggregate ─────────────────────────────────────────────────

[docs] @dataclass(frozen=True) class CDSConstraints: """All CDS Rev 14.1 constraints collected in a single object. This is a convenience wrapper that mirrors the module-level constants. """ # Mechanical rail_min_width_mm: float = RAIL_MIN_WIDTH_MM rail_surface_roughness_max_um: float = RAIL_SURFACE_ROUGHNESS_MAX_UM rail_edge_radius_min_mm: float = RAIL_EDGE_RADIUS_MIN_MM rail_end_contact_area_min_mm: Tuple[float, float] = RAIL_END_CONTACT_AREA_MIN_MM rail_contact_pct_min: float = RAIL_CONTACT_PCT_MIN max_protrusion_mm: float = MAX_PROTRUSION_MM rbf_max_protrusion_mm: float = RBF_MAX_PROTRUSION_MM separation_spring_max_force_n: float = SEPARATION_SPRING_MAX_FORCE_N separation_spring_min_stroke_mm: float = SEPARATION_SPRING_MIN_STROKE_MM # Outgassing outgassing_tml_max_pct: float = OUTGASSING_TML_MAX_PCT outgassing_cvcm_max_pct: float = OUTGASSING_CVCM_MAX_PCT # Magnetic magnetic_field_max_gauss: float = MAGNETIC_FIELD_MAX_GAUSS_ABOVE_EARTH # Electrical min_deployment_switches: int = MIN_DEPLOYMENT_SWITCHES rf_inhibit_count: int = RF_INHIBIT_COUNT deployable_inhibit_count: int = DEPLOYABLE_INHIBIT_COUNT propulsion_inhibit_count: int = PROPULSION_INHIBIT_COUNT rtc_max_freq_khz: float = RTC_MAX_FREQ_KHZ rtc_max_current_ma: float = RTC_MAX_CURRENT_MA # Operational timers deployable_wait_minutes: int = DEPLOYABLE_WAIT_MINUTES rf_silence_minutes: int = RF_SILENCE_MINUTES # Battery battery_faa_guideline_wh: float = BATTERY_FAA_GUIDELINE_WH # Debris reentry_energy_max_j: float = REENTRY_ENERGY_MAX_J
CDS = CDSConstraints() """Singleton instance of all CDS Rev 14.1 constraints.""" # ═══════════════════════════════════════════════════════════════════════════ # PocketQube Standard Issue 1 (7 June 2018) # ═══════════════════════════════════════════════════════════════════════════ # Contributors: TU Delft, Alba Orbital, GAUSS Srl # Source: https://static1.squarespace.com/static/53d7dcdce4b07a1cdbbc08a4/ # t/5b34c395352f5303fcec6f45/1530184648111/PocketQube+Standard+issue+1+-+Published.pdf # ── General (§2.1) ──────────────────────────────────────────────────────── PQ_PYROTECHNICS_ALLOWED: bool = False """PQ-Gen-02: Pyrotechnics shall not be allowed on board.""" PQ_OUTGASSING_TML_MAX_PCT: float = 1.0 """PQ-Gen-04: Maximum Total Mass Loss [%] (per ECSS-Q-70-02C).""" PQ_OUTGASSING_CVCM_MAX_PCT: float = 0.1 """PQ-Gen-04: Maximum Collected Volatile Condensable Material [%].""" # ── Mechanical (§2.2) ───────────────────────────────────────────────────── PQ_COMPONENT_ENVELOPE_MM: float = 7.0 """PQ-Mech-08: Maximum protrusion for components [mm].""" PQ_DEPLOYABLE_ENVELOPE_MM: float = 10.0 """PQ-Mech-08: Maximum protrusion for deployables (requires waiver) [mm].""" PQ_RAIL_CLAMP_WIDTH_MM: float = 2.0 """PQ-Mech-07: Rail clamping width on each side of sliding backplate [mm].""" PQ_MIN_CONTACT_SURFACE_MM: float = 21.5 """PQ-Mech-10: Minimum contact surface from both sides on Z+ axis [mm].""" PQ_MIN_KILL_SWITCHES: int = 2 """PQ-Mech-12: Minimum number of kill switches.""" PQ_BACKPLATE_THICKNESS_MM: float = 1.6 """Sliding backplate thickness [mm] (Table 1, all sizes).""" PQ_BACKPLATE_DIMENSIONS: Dict[str, Tuple[float, float, float]] = { "1p": (58.0, 64.0, 1.6), "2p": (58.0, 128.0, 1.6), "3p": (58.0, 192.0, 1.6), } """Sliding backplate (X × Z × thickness) per form factor [mm] (Table 1).""" # ── Mass (§2.2.2) ───────────────────────────────────────────────────────── PQ_MASS_PER_UNIT_KG: float = 0.250 """PQ-Mass-01: Maximum mass per 1P unit [kg].""" PQ_CG_MAX_OFFSET_CM: float = 1.0 """PQ-Mass-04: Max CG offset from geometric centre [cm] (all axes).""" # ── Materials (§2.2.3) ──────────────────────────────────────────────────── PQ_RECOMMENDED_BASEPLATE_MATERIALS: Tuple[str, ...] = ( "FR4", "Al-7075", "Al-6061", "Al-6065", "Al-6082", ) """PQ-Mat-02: Recommended baseplate materials.""" PQ_HARD_ANODIZE_REQUIRED: bool = True """PQ-Mat-03: Metallic deployer-contact surfaces shall be hard anodized.""" # ── Convenience aggregate ─────────────────────────────────────────────────
[docs] @dataclass(frozen=True) class PQSConstraints: """All PocketQube Standard Issue 1 constraints collected in a single object.""" # General pyrotechnics_allowed: bool = PQ_PYROTECHNICS_ALLOWED outgassing_tml_max_pct: float = PQ_OUTGASSING_TML_MAX_PCT outgassing_cvcm_max_pct: float = PQ_OUTGASSING_CVCM_MAX_PCT # Mechanical component_envelope_mm: float = PQ_COMPONENT_ENVELOPE_MM deployable_envelope_mm: float = PQ_DEPLOYABLE_ENVELOPE_MM rail_clamp_width_mm: float = PQ_RAIL_CLAMP_WIDTH_MM min_contact_surface_mm: float = PQ_MIN_CONTACT_SURFACE_MM min_kill_switches: int = PQ_MIN_KILL_SWITCHES backplate_thickness_mm: float = PQ_BACKPLATE_THICKNESS_MM # Mass mass_per_unit_kg: float = PQ_MASS_PER_UNIT_KG cg_max_offset_cm: float = PQ_CG_MAX_OFFSET_CM # Materials hard_anodize_required: bool = PQ_HARD_ANODIZE_REQUIRED
PQS = PQSConstraints() """Singleton instance of all PocketQube Standard Issue 1 constraints."""