Model card: APU subsystem¶
Module: src/nous/subsystems/apu.py
Backlog: BL-005a
Builds on: ADR-0015 (APU strictly auxiliary)
Scope¶
Four auxiliary power sources composed into a single total_w offered
to the primary battery each tick. Every source is additive; none ever
delivers power directly to compute. The bus regulator on
PowerSubsystem.set_charge_w clamps the offered total to
charge_limit_w.
Sources¶
Solar PV with MPPT¶
Inputs: irradiance presented to the panel (set_solar_insolation_w)
or a direct override (set_solar_w), and panel temperature.
Output:
min(panel_w_peak, mppt_efficiency * insolation_w * temp_derate)
where temp_derate = max(0, 1 - panel_temp_derate_per_c_above_25 *
max(0, panel_temp_c - 25)).
Methanol fuel cell¶
Inputs: load fraction in [0, 1] (set_fuelcell_load_pct) or a direct
override (set_fuelcell_w).
State: fuel_g depletes at
output_w * dt / wh_per_g_fuel. When wh_per_g_fuel is omitted,
the model derives it from efficiency * 5.53 Wh/g (the methanol LHV
constant). When the tank empties, output is forced to zero regardless
of the load fraction.
Output: min(continuous_w, override_w or load_pct * continuous_w).
Vehicle tether¶
Inputs: connected flag and the bus's offered_w
(set_vehicle). When connected, output is
min(offered_w, bus_voltage_v * current_limit_a).
USB-C PD-in¶
Inputs: connected flag and a requested profile in W
(set_usb_c_pd). The negotiated output is the largest available
profile that is less than or equal to the request; if the request is
below the smallest available profile, the smallest is used. The
default_profile_w from the profile YAML is run through the same
negotiation at construction time, so a YAML default outside the
advertised set cannot leak a non-PD power level.
Total¶
total_w = solar_w + fuelcell_w + vehicle_w + usbc_w
The engine calls power.set_charge_w(apu.total_w) each tick; the
power subsystem reports charge_offered_w and charge_accepted_w
separately so the controller can see how much APU power was clipped.
Profile fields¶
apu:
solar:
panel_w_peak: 60
mppt_efficiency: 0.92
panel_temp_derate_per_c_above_25: 0.004
fuel_cell:
continuous_w: 25
fuel_capacity_g: 790 # ~1 L methanol cartridge (density 0.79 g/ml)
efficiency: 0.25 # SFC EFOY system efficiency (post-BOP)
wh_per_g_fuel: 1.4 # SFC EFOY ~0.9 L/kWh -> ~1.4 Wh/g electrical
# derived from efficiency * 5.53 Wh/g (methanol LHV) when omitted
vehicle:
bus_voltage_v: 28.0
current_limit_a: 5.0
usb_c_pd:
profiles_w: [15, 27, 45, 60, 100]
default_profile_w: 60
The legacy flat fields solar_w_peak, fuelcell_w_continuous,
fuelcell_fuel_capacity_g, and fuelcell_efficiency are still
parsed when the nested form is absent, so older profiles keep working.
Known limitations¶
- No source ever delivers AC power direct to compute. See ADR-0015.
- The MPPT model is a single efficiency multiplier, not an actual perturb-and-observe loop. A real MPPT controller hunts; the simulator pretends it has already found the maximum.
- Fuel cell startup transient is not modelled. Output appears
immediately when
load_pctrises above zero and disappears immediately when fuel runs out. - Vehicle tether contact resistance is not modelled.
offered_wis assumed to arrive at the bus voltage minus zero drop. - USB-C PD negotiation is discrete (a single profile selection per
set_usb_c_pdcall). The simulator does not model the PD message exchange itself. - No hand-crank source. A man-portable unit's emergency option, but the simulator does not model it in v0.1; an operator who needs to rehearse "battery dead, no daylight, no methanol" scenarios should treat the device as offline rather than rely on a crank model.