Skip to content

Pulsed-Shot FSM

MIF-004 implements the local, upstream-pending eight-state pulsed-shot lifecycle finite-state machine. The state graph is:

idle -> ramp_up -> flat_top -> burn -> expansion -> dump -> recharge -> cool_down -> idle

Each transition is guarded by plasma telemetry and capacitor-bank telemetry, and every transition is recorded as a timestamped audit entry.

Guards

From To Guard
idle ramp_up bank.energy_J >= min_precharge_energy_J
ramp_up flat_top abs(plasma.coil_current_A) >= ramp_current_A
flat_top burn phase error, spatial error, and burn temperature within thresholds
burn expansion minimum burn dwell and fusion power threshold reached
expansion dump radial expansion velocity threshold reached
dump recharge bank energy is at or below dump floor
recharge cool_down bank voltage fraction reaches recharge threshold
cool_down idle plasma temperature and coil current are below cool-down thresholds

Timestamps must be non-negative and strictly increasing after the first sample.

Python API

pulsed_shot_fsm

Eight-state pulsed-shot lifecycle finite-state machine for MIF-004.

ShotState

Bases: StrEnum

Canonical pulsed-shot lifecycle states.

SchedulerAction

Bases: StrEnum

Command action emitted for the active lifecycle state.

PulsedShotSpec(min_precharge_energy_J, ramp_current_A, phase_tolerance_rad, spatial_tolerance_m, burn_temperature_eV, min_fusion_power_W, expansion_velocity_m_s, dump_energy_floor_J, recharge_voltage_fraction, cooldown_temperature_eV, cooldown_current_A, min_burn_duration_s=0.0) dataclass

Guard thresholds for the pulsed-shot lifecycle.

__post_init__()

Validate pulsed-shot FSM threshold parameters.

PlasmaState(coil_current_A, temperature_eV, phase_lock_error_rad, reference_error_m, fusion_power_W, radial_velocity_m_s) dataclass

Plasma telemetry consumed by lifecycle transition guards.

__post_init__()

Validate plasma-state telemetry used by shot scheduling.

BankTelemetry(voltage_V, voltage_max_V, energy_J) dataclass

Capacitor-bank telemetry consumed by lifecycle transition guards.

voltage_fraction property

Return bank voltage as a fraction of the declared maximum.

__post_init__()

Validate bank telemetry and freeze the derived charge fraction.

TransitionRecord(t_s, from_state, to_state, reason) dataclass

Single lifecycle transition audit entry.

to_json()

Return the stable JSON-serialisable audit representation.

SchedulerCommand(t_s, state, action, reason, transition, dwell_s) dataclass

Command emitted by one lifecycle FSM step.

PulsedShotFSM(spec)

Eight-state pulsed-shot lifecycle finite-state machine.

audit_log property

Return immutable transition audit entries.

reset()

Return to idle and clear timestamp and audit state.

transition_to(next_state, t_s, reason)

Perform a validated manual adjacent transition.

step(t_s, plasma, bank)

Evaluate lifecycle guards at t_s and emit the active-state command.

audit_log_jsonl()

Return the transition audit log as newline-delimited JSON.

Dispatch

Use scpn_mif_core.lifecycle.dispatched_pulsed_shot_fsm(...) for the fastest available measured runtime backend:

"lifecycle.pulsed_shot_fsm" = ["rust", "python"]

The pure Python PulsedShotFSM remains available for deterministic debugging and tests. The Lean surface proves adjacency determinism, absence of self-looping adjacent transitions, and the minimal eight-step cycle; it is not a runtime benchmark backend.

Acceptance

The committed acceptance campaign traverses all eight states in order, verifies strictly increasing audit timestamps, checks JSONL audit serialisation, rejects duplicate or backwards timestamps, rejects non-adjacent manual transitions, and verifies that flat-top waits when either phase or spatial lock is missing. Additional guard tests cover low precharge energy, minimum burn dwell, and dump-floor energy holds.

Python/Rust parity tests cover the full state sequence and the Rust-backed dispatch path. Lean builds SCPNMIF.PulsedShot.eight_step_cycle, SCPNMIF.PulsedShot.adjacent_transition_deterministic, and SCPNMIF.PulsedShot.idle_cycle_minimal.

Benchmarks

Measured on the local i5-11600K rig using Python 3.12.3 and Rust 1.85.0.

Group Backend Mean Result
campaign_8 Rust 2.57 us fastest
campaign_8 Python 19.68 us 7.7x slower than Rust

Raw summary: bench/results/pulsed_shot_fsm.json.

Ownership

SYNC-STATE: upstream-pending applies to all MIF-004 implementation surfaces. SCPN-MIF-CORE owns the local pulsed-shot FSM until SCPN-CONTROL receives the reusable pulsed_scenario_scheduler_v2 surface targeted for the 0.21.0 lane.