# Electricity

# Electricity

Package `@ferret/physics-electric`, capability `electric`.

## What it is for

Anything that runs on current: a torch with a battery that runs down, a kettle on a fuse, a garage-door motor that stalls, a generator turned by a windmill, a relay, a lamp that burns out when over-volted, a wire that overheats inside a wall.

Motors turn shafts of mechanisms (skill `ferret`) and generators are turned by them. Heaters feed parts of heat (skill `ferret-physics-heat`). Every protection device reports what it did as an event.

## How a circuit works

A `Circuit` is a list of elements, each connecting two named nodes (`'0'` is ground). Every step the circuit solves for the voltage at every node, so Ohm's and Kirchhoff's laws hold exactly. Nothing is scripted: a lamp dims when the battery sags, because the battery's voltage falls with its charge and with the current it delivers.

Energy is accounted for. `circuit.balance()` returns what the sources delivered, what was dissipated, what is stored in capacitors and inductors, and the error, which stays tiny. That makes the electrical side trustworthy when you tie it to heat and motion.

If you throw a switch, call `circuit.restart()` so the next step does not ring.

## The parts

| You want | Use | Notes |
|---|---|---|
| Resistor, capacitor, coil | `Resistor`, `Capacitor`, `Inductor` | |
| A constant or varying supply | `VSource`, `ISource`, `mains` (peak and frequency), `threePhase` | |
| Switch, diode | `Switch`, `Diode`, `Zener` | |
| **Battery** | `Battery(name, a, b, capacityAh, rInt, vFull, vEmpty)` | the voltage falls with charge; it warms by `I²r`; raises `battery:empty` |
| **Lamp** | `Lamp(name, a, b, R0)` | the filament's temperature balances input against radiation, and its resistance follows; raises `lamp:burnt` at melting |
| **Heater** | `Heater(name, a, b, R, alpha)` | its power goes into a part of heat (skill `ferret-physics-heat`); its resistance follows that part's temperature |
| **Fuse** | `Fuse(name, a, b, i2t)` | blows when the accumulated `I²t` passes the rating; `circuit:blown` |
| **Breaker** | `Breaker(name, a, b, rated, tau, magnetic)` | trips slowly on moderate overload and at once on a short; `breaker.reset()` closes it |
| **Wire** | `Wire(name, a, b, ohmPerM, length, ampacity, heatCapacity)` | heats up under load, raises `circuit:overheat` when it reaches the insulation limit |
| Transformer | `circuit.transformer`, `IdealTransformer` | winding resistance, magnetising inductance, core loss |
| **DC motor or generator** | `DCMachine(name, a, b, k, Ra, La)` | torque `k·i`; a generator when the shaft drives it |
| Induction motor | `InductionMotor` | torque against slip |
| Others | `Coil`, `Relay`, `Thermistor`, `Potentiometer`, `SolarCell`, `Rcd` | |

`magnetForce` is the pull of an electromagnet, `railForce` the push in a rail gun.

```ts
import { Circuit, VSource, Resistor, Capacitor } from '@ferret/physics-electric';

const c = new Circuit();
c.add(new VSource('V', 'a', '0', 5));
c.add(new Resistor('R', 'a', 'b', 1000));
c.add(new Capacitor('C', 'b', '0', 1e-6));
c.step(1e-5);
c.voltage('b');          // the capacitor charges along 1 − e^(−t/RC)
```

Half of what the source delivers ends up in the capacitor and half as heat in the resistor, as it should.

## Gameplay ideas

- **A battery that runs down.** A 1 Ah cell loaded by 0.5 A lasts two hours. Read `soc` for the state of charge and `heat` for what was lost inside.
- **Sizing protection.** A fuse blows when the current's square times time passes its rating. A kettle on a 10 A breaker, a wire thinner than its load, a residual-current device on a wet floor are all one circuit away.
- **A motor.** It runs at `V/k − R·T/k²`: the drive voltage over its constant, less a droop under load. Held still it draws `V/R`, which is how a jammed motor burns out.
- **A generator.** Drive the same machine from outside with a resistor across it and it produces `k·ω` volts, loading the shaft by `k·I`. A windmill that lights a lamp is two parts and a wire.

## Heat a part

`el.bindHeater(circuit, heaterName, entity)` sends the heater's power into the entity's part of heat (skill `ferret-physics-heat`) every step. A 24 V supply across a 10 Ω heater warms a part by `V²/R` watts. The part's temperature, in turn, changes the heater's resistance (`alpha`).

## Tying a motor to a shaft

```ts
const el = electric();
host.register(el);
host.enable('electric');

const circuit = el.addCircuit('main');
circuit.add(new VSource('V', 'a', '0', 12));
const motor = circuit.add(new DCMachine('M', 'a', '0', 0.05, 0.5));

el.bindMachine('main', motor, drivetrain, shaft);    // speed and torque are exchanged every sub-step
```

The drivetrain is stepped by whoever owns it: the machine (skill `ferret`) capability or your own loop. `bindInduction` does the same for an induction motor.

## In a world

The capability steps each circuit in sub-steps of at most `maxStep` (1 ms).

Events: `circuit:blown`, `circuit:trip`, `circuit:short` (a source carries more than `shortCurrent`), `circuit:overheat`, `battery:empty`, `lamp:burnt`, `motor:stall`, each with `{ circuit, element, time }`.

Commands: `circuit.info`, `circuit.state { circuit }` (node voltages, element currents and powers, balance), `circuit.add { circuit, kind, name, a, b, value? }`, `meter.read { circuit, node }`.

## Parameters

| Value | Default | Effect |
|---|---|---|
| `maxStep` | 0.001 s | longest circuit sub-step |
| `shortCurrent` | 1000 A | a source current above this is a short circuit |

## Works with

heat (skill `ferret-physics-heat`): heaters warm parts. mechanisms (skill `ferret`): motors and generators on shafts; a windmill drives a generator and a generator lights a lamp (links (skill `ferret-physics-links`)). liquids (skill `ferret`): a pump's `pumpLoad` is the mechanical side of an electric motor.

## Cost

A dense solve per circuit per sub-step, for a few dozen nodes; lamps and diodes add iterations. Raise `maxStep` for slow circuits, and keep it at or below a tenth of the fastest time constant (`RC`, `L/R`, `1/f`).

## When it does not behave

| Symptom | Cause |
|---|---|
| Voltages are NaN or enormous | a node with no path to ground, or a voltage source across a short; add a resistor or fix the wiring |
| A switch makes a spike | call `circuit.restart()` after throwing it |
| A motor does not turn | `machine.omega` is not copied from the shaft, the shaft has no drive from the machine, or the sign of `k` is reversed |
| `circuit:short` fires | a source carries more than `shortCurrent`; either it is a real short, or raise the value for a high-power bus |
| A lamp never burns | its voltage is below what melts the filament; `Lamp.T` shows the temperature |
| Energy does not close | the step is too coarse for a resonating circuit: lower `maxStep` |

Worked numbers (RC charging and energy balance, battery run time, fuse and breaker timing, motor speed, stall current) are in `tests/unit/examples/physics-electric.test.ts`.

## Reference

`electric`, `ElectricCapability`, `Circuit`, `Battery`, `Fuse`, `Breaker`, `Wire`, `Lamp`, `Heater`, `DCMachine`, `InductionMotor`, `mains`.
