Lots of stuff
This commit is contained in:
184
src/hooks/useSatelliteDesign.js
Normal file
184
src/hooks/useSatelliteDesign.js
Normal file
@@ -0,0 +1,184 @@
|
||||
import { useState, useEffect, useMemo } from 'react'
|
||||
import {
|
||||
calcOrbit,
|
||||
calcPowerBudget,
|
||||
calcLinkBudget,
|
||||
calcThermalBalance,
|
||||
calcMassBudget,
|
||||
} from '../engine/satelliteCalcs.js'
|
||||
|
||||
const LS_KEY = 'rockettools_satellite'
|
||||
|
||||
const DEFAULTS = {
|
||||
orbitInputs: {
|
||||
altitudeKm: 500,
|
||||
betaAngleDeg: 0,
|
||||
},
|
||||
powerInputs: {
|
||||
formFactor: '3U',
|
||||
solarCellType: 'GaAs',
|
||||
etaCell: 0.28,
|
||||
etaPacking: 0.85,
|
||||
deployablePanelArea: 0,
|
||||
etaCharge: 0.95,
|
||||
etaDischarge: 0.97,
|
||||
DOD: 0.30,
|
||||
P_sunlight_load: 3.0,
|
||||
P_eclipse_load: 2.0,
|
||||
degradationPerYear: -0.03,
|
||||
designLife: 2,
|
||||
},
|
||||
linkInputs: {
|
||||
P_tx_W: 1.0,
|
||||
G_tx_dBi: 6.0,
|
||||
L_feed_dB: 1.0,
|
||||
frequencyMHz: 437,
|
||||
modulation: 'BPSK',
|
||||
elevationAngleDeg: 5,
|
||||
L_atm_dB: 0.5,
|
||||
L_point_dB: 1.0,
|
||||
G_rx_dBi: 12.0,
|
||||
T_sys_K: 290,
|
||||
dataRateBps: 9600,
|
||||
Eb_N0_req_dB: 9.6,
|
||||
},
|
||||
thermalInputs: {
|
||||
alpha: 0.90,
|
||||
epsilon: 0.85,
|
||||
A_sun: 0.01,
|
||||
A_earth: 0.01,
|
||||
A_rad: 0.02,
|
||||
Q_int: 3.0,
|
||||
},
|
||||
subsystems: {
|
||||
adcs: {
|
||||
controlMode: 'sun-pointing',
|
||||
pointingAccuracyDeg: 5,
|
||||
reactionWheels: false,
|
||||
magnetorquers: true,
|
||||
mass: 200,
|
||||
avgPower: 0.5,
|
||||
peakPower: 1.0,
|
||||
},
|
||||
comms: {
|
||||
frequencyMHz: 437,
|
||||
P_tx_W: 1.0,
|
||||
antennaType: 'dipole',
|
||||
modulation: 'BPSK',
|
||||
mass: 100,
|
||||
avgPower: 1.0,
|
||||
peakPower: 2.0,
|
||||
},
|
||||
cdh: {
|
||||
processor: 'ARM Cortex-M4',
|
||||
storageGB: 2,
|
||||
housekeepingRateHz: 1,
|
||||
mass: 120,
|
||||
avgPower: 0.8,
|
||||
peakPower: 1.2,
|
||||
},
|
||||
eps: {
|
||||
batteryChemistry: 'Li-ion',
|
||||
solarCellType: 'GaAs',
|
||||
mass: 300,
|
||||
},
|
||||
structure: {
|
||||
materialId: 'al_6061_t6',
|
||||
configuration: 'standard',
|
||||
mass: 400,
|
||||
},
|
||||
propulsion: {
|
||||
type: 'none',
|
||||
propellant: '',
|
||||
mass: 0,
|
||||
avgPower: 0,
|
||||
peakPower: 0,
|
||||
},
|
||||
payload: {
|
||||
name: '',
|
||||
type: '',
|
||||
mass: 0,
|
||||
avgPower: 0,
|
||||
peakPower: 0,
|
||||
interface: 'UART',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
function loadFromStorage() {
|
||||
try {
|
||||
const raw = localStorage.getItem(LS_KEY)
|
||||
return raw ? JSON.parse(raw) : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function useSatelliteDesign() {
|
||||
const saved = useMemo(() => loadFromStorage(), [])
|
||||
|
||||
const [orbitInputs, setOrbitInputs] = useState(saved?.orbitInputs ?? DEFAULTS.orbitInputs)
|
||||
const [powerInputs, setPowerInputs] = useState(saved?.powerInputs ?? DEFAULTS.powerInputs)
|
||||
const [linkInputs, setLinkInputs] = useState(saved?.linkInputs ?? DEFAULTS.linkInputs)
|
||||
const [thermalInputs, setThermalInputs] = useState(saved?.thermalInputs ?? DEFAULTS.thermalInputs)
|
||||
const [subsystems, setSubsystems] = useState(saved?.subsystems ?? DEFAULTS.subsystems)
|
||||
|
||||
// Persist all state slices on any change
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem(LS_KEY, JSON.stringify({
|
||||
orbitInputs, powerInputs, linkInputs, thermalInputs, subsystems,
|
||||
}))
|
||||
} catch {}
|
||||
}, [orbitInputs, powerInputs, linkInputs, thermalInputs, subsystems])
|
||||
|
||||
// ── Calculation chain (pure useMemo, no side effects) ──
|
||||
const orbitData = useMemo(() => calcOrbit(orbitInputs), [orbitInputs])
|
||||
const powerBudget = useMemo(() => calcPowerBudget(orbitData, powerInputs), [orbitData, powerInputs])
|
||||
const linkBudget = useMemo(() => calcLinkBudget(orbitData, linkInputs), [orbitData, linkInputs])
|
||||
const thermalBalance = useMemo(() => calcThermalBalance(orbitData, thermalInputs), [orbitData, thermalInputs])
|
||||
const massBudget = useMemo(() => calcMassBudget(subsystems, powerInputs.formFactor), [subsystems, powerInputs.formFactor])
|
||||
|
||||
// ── Setters ──
|
||||
|
||||
/** Patch a single key in orbitInputs */
|
||||
function setOrbitInput(key, value) {
|
||||
setOrbitInputs(prev => ({ ...prev, [key]: value }))
|
||||
}
|
||||
|
||||
/** Patch a single key in powerInputs */
|
||||
function setPowerInput(key, value) {
|
||||
setPowerInputs(prev => ({ ...prev, [key]: value }))
|
||||
}
|
||||
|
||||
/** Patch a single key in linkInputs */
|
||||
function setLinkInput(key, value) {
|
||||
setLinkInputs(prev => ({ ...prev, [key]: value }))
|
||||
}
|
||||
|
||||
/** Patch a single key in thermalInputs */
|
||||
function setThermalInput(key, value) {
|
||||
setThermalInputs(prev => ({ ...prev, [key]: value }))
|
||||
}
|
||||
|
||||
/** Patch one or more fields of a specific subsystem */
|
||||
function setSubsystem(key, patch) {
|
||||
setSubsystems(prev => ({ ...prev, [key]: { ...prev[key], ...patch } }))
|
||||
}
|
||||
|
||||
return {
|
||||
// State slices
|
||||
orbitInputs, setOrbitInput,
|
||||
powerInputs, setPowerInput,
|
||||
linkInputs, setLinkInput,
|
||||
thermalInputs, setThermalInput,
|
||||
subsystems, setSubsystem,
|
||||
|
||||
// Computed results
|
||||
orbitData,
|
||||
powerBudget,
|
||||
linkBudget,
|
||||
thermalBalance,
|
||||
massBudget,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user