> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hardwave.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Transient Simulation

> Run time-domain transient simulations and access time-series results in Hardwave

Transient simulation steps the graph through time and records a value at every time step for every output port. Components with internal state (motors, capacitors, inductors, batteries) advance their state using `ODESolver` integration.

## Configuration

```python theme={null}
from hardwave.simulation import SimulationGraph, SimulationEngine, SimulationConfig
from hardwave.solvers import SimulationDomain
from hardwave.stdlib.components.motors import DCMotor

graph = SimulationGraph()
graph.add_component(DCMotor("motor", param_values={
    "winding_resistance": 2.0,
    "winding_inductance": 5e-4,
    "back_emf_constant":  0.05,
    "rotor_inertia":      1e-4,
}))

engine = SimulationEngine(graph)
config = SimulationConfig(
    domain=SimulationDomain.TRANSIENT,
    t_start=0.0,
    t_end=1.0,
    dt=0.0001,        # 0.1 ms; use small dt for stiff electrical dynamics
)
engine.configure(config)

result = engine.run(
    inputs={"motor": {"voltage": 12.0, "load_torque": 0.2}},
    config=config,
)
```

## Time series

```python theme={null}
t, omega = result.get_time_series("motor", "angular_velocity")
t, current = result.get_time_series("motor", "current")

print(f"Final speed:   {omega[-1]:.1f} rad/s")
print(f"Final current: {current[-1]*1000:.1f} mA")

# Runtime fault diagnostics (e.g. thermal runaway, over-discharge)
for d in result.get_faults():
    print(f"t={d.timestamp:.3f}s  {d.code}: {d.message}")
```

<Warning>
  Calling `get_time_series()` on a steady-state result raises `SimulationResultError`.
</Warning>

## Export to pandas

```python theme={null}
df = result.to_dataframe()
print(df.head())
# Columns: time, motor.angular_velocity, motor.current, motor.winding_temp
```

## Serialize results

```python theme={null}
import json
snapshot = result.to_dict()
# Keys: domain, time_array, outputs, diagnostics
```

Attach a snapshot when calling `graph.save(..., result=result)` to display outputs and charts in the cloud dashboard. See [Saving Graphs](/graphs/saving).

## Interactive step mode

For real-time or interactive applications, step the engine manually:

```python theme={null}
from hardwave.simulation import SimulationConfig

engine.configure(SimulationConfig(dt=0.001))

state = {}
for step in range(1000):
    t = step * 0.001
    outputs, state, diagnostics = engine.step(
        inputs={"motor": {"voltage": 12.0, "load_torque": 0.2}},
        t=t,
        state=state,
        step_index=step,
    )
    omega = outputs["motor"]["angular_velocity"]
    for d in diagnostics:
        if d.level.value == "fault":
            print(f"Fault at t={t}: {d.message}")
```

`step()` returns `(outputs, new_state, diagnostics)`.

## Algebraic vs. dynamic components

At each time step, `engine.step()` is called for every component:

* Components with `ODESolver` (e.g. `DCMotor`, `Capacitor`, `LiPoCell`) advance internal state via RK4 or scipy integration
* Algebraic components (e.g. `Resistor`, `ThermostatController`, `ServoMotor`) are re-solved from current inputs at each step
* Fault-aware components (`DCMotor`, `LiPoCell`) evaluate operating limits after each step and may enter a degraded fault state

<Card title="Component Faults and Health" icon="triangle-exclamation" href="/guides/component-faults">
  Motor thermal runaway, battery over-discharge, and FaultMode
</Card>

To see a signal ramp over time with an algebraic servo, drive the external input from a time-varying function or swap in a motor component that uses `ODESolver`.
