FERRETGame engine over Babylon.js
Ferret

Cookbook: machines and circuits

The guides behind these: electric, mechanisms, links. Each recipe says what to build and what to expect; the runnable versions, with the numbers they must produce, are in tests/unit/examples/physics-cookbook-machines-and-circuits.test.ts.

1. A lamp that surges, glows and burns#

A cold tungsten filament has a small resistance and takes a big inrush; as it heats, its resistance rises ten-fold and the current falls. Overdrive it and it melts. A Lamp takes its cold resistance, its thermal parameters and its filament area:

const c = new Circuit();
c.add(new VSource('V', 'a', '0', 12));
const lamp = c.add(new Lamp('Bulb', 'a', '0', 0.476, 2e-3, 6.0e-6));
c.onEvent = e => { if (e.type === 'lamp:burnt') burnt = true; };
c.step(1e-4);

At the rated voltage the first current is several times the steady one and the hot resistance is more than ten times the cold one. At half voltage the filament stays cooler. At 30 V the lamp emits lamp:burnt. Feed lamp.T to lampLight and the scene light goes red and dim when the supply sags. The inrush is why a fuse needs a time delay.

2. Smoothing a rectified supply#

A bridge rectifier and a capacitor turn AC into DC with a ripple of about I / (2 f C). Four diodes, a capacitor and a load on a mains source:

c.add(mains('V', 'p', 'n', 20, 50));
c.add(new Diode('D1', 'p', 'o', 0.7)); c.add(new Diode('D2', 'n', 'o', 0.7));
c.add(new Diode('D3', '0', 'p', 0.7)); c.add(new Diode('D4', '0', 'n', 0.7));
c.add(new Capacitor('C', 'o', '0', 22e-3));
c.add(new Resistor('RL', 'o', '0', 100));

The output peaks at the supply peak minus two diode drops, 18.6 V for a 20 V supply. Double C, halve the ripple. Without the capacitor the output is a train of pulses to zero.

3. A transformer#

An ideal transformer gives the turns ratio and the inverse current; a real one adds winding resistance, a magnetising current and core loss, so its efficiency is below one:

c.transformer('T', 'p', '0', 's', '0', { ratio: 10, r1: 0.5, r2: 0.01, lm: 2, rcore: 5000 });

With negligible resistances the secondary voltage is the primary divided by the ratio and the primary current is the secondary current divided by it. With the real parameters the winding resistance and the magnetising current cost some voltage. circuit.phasor(ω) solves the same network in the frequency domain in one call, for a fast answer without time stepping.

4. A wind turbine lights a lamp#

The wind drives a turbine shaft; the shaft turns a DC machine used as a generator; the generator feeds a lamp. The chain closes through the shaft speed and the machine's torque:

const rotor = d.shaft({ name: 'rotor', J: 20, b: 0.5 });
d.drive(rotor, windTurbine({ radius: 2, wind: () => wind, cp: cpCurve(0.4, 7) }));
const gen = c.add(new DCMachine('G', 'a', '0', 0.5, 0.3));
d.drive(rotor, () => gen.torque);
// each step
gen.omega = rotor.omega; c.step(dt); d.step(dt, 2);

A faster wind gives a faster rotor, and the lamp power rises steeply, because the wind power goes as the cube of the speed. The lamp gets less than the wind carries, by Cp, the generator's copper loss and the friction, and never more than the Betz limit. Swap the resistor for a Lamp and light a scene light with lampLight.

5. A winch that cannot run back#

A worm gear whose lead angle is small enough (tan λ < μ) is self-locking: the load cannot turn the worm, so the hoisted weight stays where it is when the motor stops. Raise the lead angle and it runs back:

d.worm('w', worm, drum, 1, 30, leadAngle, mu);
d.drive(drum, () => 50);        // the hanging load pulls on the drum

At a lead of 3 degrees with a friction of 0.1 the drum does not move; at 15 degrees with 0.05 it runs back. Efficiency is tan λ / tan(λ + φ): a self-locking worm is always below 50 % efficient. Add a brake for a winch that must hold regardless.

6. A flywheel evens out a pulsing drive#

A single-cylinder engine delivers torque in pulses; the speed ripples. The flywheel's inertia smooths it: ten times the inertia, a tenth of the ripple.

const crank = d.shaft({ name: 'crank', J, b: 0.05, omega: 100 });
d.drive(crank, (_w, th) => 10 + 8 * Math.sin(2 * th));     // two pulses a turn
d.drive(crank, w => -0.1 * w);                              // a load

The coefficient of fluctuation is about ΔE / (J ω²). The cost of a heavy flywheel is slow response: the engine takes longer to spin up and to slow. Choose J for the ripple the player can tolerate and the response they expect.