Module 4: Human Factors, Regulations, and Space Policy
This notebook explains why policy and regulation matter to engineers.
What you’ll learn
The main “policy buckets” that shape space missions
Who does what (FAA, FCC, ITU, UNOOSA, and international equivalents)
A tiny toy risk model you can tweak (for intuition)
Important note
This is not legal advice — it’s an engineering‑focused overview to build intuition.
1) Why policy shows up in engineering
Even a technically perfect spacecraft can fail as a mission if: - It can’t get a launch / reentry license - It can’t legally use radio spectrum - It creates unacceptable debris risk - It violates planetary protection or safety rules
So teams treat policy like another set of constraints — like mass, power, and delta‑V.
Code
import numpy as npimport pandas as pdimport matplotlib.pyplot as pltplt.style.use("dark_background")plt.rcParams.update( {"figure.dpi": 110,"axes.titlesize": 14,"axes.labelsize": 12,"xtick.labelsize": 10,"ytick.labelsize": 10,"legend.fontsize": 10, })ACCENT ="#00d4ff"DANGER ="#ff4d6d"GOOD ="#7CFC00"print("Environment ready. Let's look at policy constraints.")
Environment ready. Let's look at policy constraints.
Contamination control requirements that affect spacecraft design and operations
Different countries have different agencies, but the structure is similar.
3) A toy “policy risk” score (for intuition)
Real compliance is not a single number, but it’s still useful to build intuition.
We’ll make a very simple score from 0–100: - 0–30: low - 30–60: medium - 60–100: high
You’ll see how mission choices (orbit altitude, comms, imaging, crewed vs uncrewed) change the score.
Code
MISSION_PRESETS = {"LEO communications satellite": {"crewed": False,"earth_observation": False,"uses_spectrum": True,"altitude_km": 550,"disposal_plan": True, },"LEO Earth observation satellite": {"crewed": False,"earth_observation": True,"uses_spectrum": True,"altitude_km": 650,"disposal_plan": True, },"GEO communications satellite": {"crewed": False,"earth_observation": False,"uses_spectrum": True,"altitude_km": 35786,"disposal_plan": True, },"Crewed capsule (LEO)": {"crewed": True,"earth_observation": False,"uses_spectrum": True,"altitude_km": 400,"disposal_plan": True, },"Mars transfer spacecraft": {"crewed": False,"earth_observation": False,"uses_spectrum": True,"altitude_km": 0,"disposal_plan": False,"planetary_protection": True, },}def policy_risk_score(mission: dict) ->dict:"""Return a breakdown + total score (0-100). Toy model for learning only.""" breakdown = {}# Launch / reentry licensing tends to be more intense for crewed or high-energy missions. launch =15if mission.get("crewed"): launch +=20if mission.get("planetary_protection"): launch +=10 breakdown["launch_reentry"] =min(30, launch)# Spectrum always matters if you transmit. spectrum =15if mission.get("uses_spectrum") else0 breakdown["spectrum"] = spectrum# Earth observation tends to add licensing + data controls. eo =15if mission.get("earth_observation") else0 breakdown["remote_sensing"] = eo# Debris risk is often higher in crowded LEO and depends on disposal plan. alt = mission.get("altitude_km", 0) debris =5if300<= alt <=2000: # crowded LEO debris +=20elif alt >2000: debris +=10ifnot mission.get("disposal_plan", False): debris +=15 breakdown["debris"] =min(35, debris) total =sum(breakdown.values())return {"breakdown": breakdown, "total": min(100, total)}def plot_breakdown(label: str): result = policy_risk_score(MISSION_PRESETS[label]) parts = result["breakdown"]# Keep category order stable (visual consistency) order = ["launch_reentry", "spectrum", "remote_sensing", "debris"] names = [k for k in order if k in parts] values = np.array([parts[k] for k in names]) labels_pretty = {"launch_reentry": "Launch/Reentry","spectrum": "Spectrum","remote_sensing": "Remote sensing","debris": "Debris", } colors = {"launch_reentry": ACCENT,"spectrum": "#ffd166","remote_sensing": "#c77dff","debris": DANGER, } display_names = [labels_pretty.get(k, k) for k in names] bar_colors = [colors.get(k, ACCENT) for k in names] fig, ax = plt.subplots(figsize=(11, 3.9)) bars = ax.barh(display_names, values, color=bar_colors, alpha=0.85) ax.set_xlim(0, 40) ax.set_title(f"Toy policy risk breakdown — {label}\nTotal score: {result['total']}/100") ax.set_xlabel("toy risk points") ax.grid(True, axis="x", alpha=0.25)for b in bars: ax.text(b.get_width() +0.6, b.get_y() + b.get_height() /2, f"{b.get_width():.0f}", va="center") plt.tight_layout() plt.show()plot_breakdown("LEO Earth observation satellite")
4) Compare mission presets (visual overview)
A single mission breakdown is useful.
But learners usually understand faster when they can compare multiple missions at once.
We’ll plot a stacked breakdown for all presets: - each bar = one mission - each segment = one policy bucket
Code
order = ["launch_reentry", "spectrum", "remote_sensing", "debris"]labels_pretty = {"launch_reentry": "Launch/Reentry","spectrum": "Spectrum","remote_sensing": "Remote sensing","debris": "Debris",}colors = {"launch_reentry": ACCENT,"spectrum": "#ffd166","remote_sensing": "#c77dff","debris": DANGER,}rows = []for name, m in MISSION_PRESETS.items(): out = policy_risk_score(m) row = {"mission": name, "total": out["total"]}for k in order: row[k] = out["breakdown"].get(k, 0) rows.append(row)df_all = pd.DataFrame(rows).set_index("mission")df_all = df_all.sort_values("total")fig, ax = plt.subplots(figsize=(12, 5.2))left = np.zeros(len(df_all))for k in order: vals = df_all[k].values ax.barh(df_all.index, vals, left=left, color=colors[k], alpha=0.85, label=labels_pretty[k]) left = left + vals# Total labelsfor i, (mission, row) inenumerate(df_all.iterrows()): ax.text(row["total"] +1.0, i, f"{int(row['total'])}", va="center")ax.set_xlim(0, 100)ax.set_title("Toy policy risk comparison across mission presets")ax.set_xlabel("toy risk score contribution (0–100)")ax.grid(True, axis="x", alpha=0.25)ax.legend(loc="lower right")plt.tight_layout()plt.show()
5) What can I do next?
Run the full project (more scenarios + structured categories):
cd src/Module_04_Human_Factors/Projects/Space_Policy_Calculatorpip install -r requirements.txtpython calculator.py
Try these quick exercises:
Change the preset in plot_breakdown(...) to:
"GEO communications satellite"
"Crewed capsule (LEO)"
"Mars transfer spacecraft"
Which category dominates for each, and why?
Add one new mission preset (your choice) and see where it lands in the stacked comparison.
References to explore: - UNOOSA debris guidelines - ITU spectrum coordination basics - National licensing regulators (FAA in the US, and equivalents elsewhere)