Skip to main content

Playground · research instrument

DSP · Audio

Speaker Power Compression

A lumped thermal RC model of voice-coil heating under continuous drive. Dial in power, cooling architecture, and copper TCR — watch temperature, resistance rise, SPL sag, and the steady-state destination in real time.

Independent research instrument — not claimed as MakerPortal shipped product code. Methods, equations, assumptions, and limitations are disclosed so you can inspect what the page does and does not establish.

Thermal Controls

Cooling architecture presets
Coil temp
20.0°C

°C

Re
6.20

Ω

Current
4.92

A RMS

Elect. power
150

W

SPL compression
0.00

dB

Coil tau
22.5

τ (s)

Steady-state T
395

°C

Time history — Temperature & SPL compression0.0 s simulated

Motor cross-section & thermal gradient

Ambient: 20°CCoil: 20°CMagnet structure: 20°C
Power sweep — Steady-state temperature vs. input power

Essence

Your speaker gets quieter the longer you punish it. That's copper doing math.

Set Pin=150P_{in} = 150 W, walk away, come back five minutes later. The amp still reads 150 W on the dial, but the cone is moving less. You lost 2 dB. Not to the amp, not to the air — to heat.

Every I2RI^2 R watt that doesn't become sound becomes temperature inside a few grams of copper wire. Copper's resistance climbs about 0.39%0.39\% per degree — α=0.00393\alpha = 0.00393 K1K^{-1} — so as it heats, it draws less current from the same voltage. Less current means less BlIBl \cdot I force, so less SPL. The system quietly negotiates itself down. Engineers call it power compression, and in live sound it eats headroom for breakfast.

Past 200°C the glue that holds the coil to the former softens. Past 300°C you smell it. This simulation lets you watch that negotiation in real time: temperature, resistance, current, electrical power, SPL sag, all coupled. No hidden knobs.

The intuition — heat has mass and insulation

If you've seen an electrical RC circuit, you already know the thermal one. Temperature is voltage, heat flow is current, thermal resistance RthR_{th} is how hard it is to push heat out, thermal capacitance CthC_{th} is how much heat you must dump in to raise the temperature one degree.

Map it: the coil dumps PeP_e watts into Cth_vC_{th\_v}, the small fast can — 10 to 15 J/K in the code. It leaks to the magnet through Rth_vR_{th\_v}. The magnet is the big slow can, Cth_m=250C_{th\_m} = 250 J/K, barely warming at first, then storing that heat for minutes. It leaks to ambient through Rth_mR_{th\_m}. Two cans, two time constants:

τv=Rth_vCth_v\tau_v = R_{th\_v} C_{th\_v} — coil, seconds
τm=Rth_mCth_m\tau_m = R_{th\_m} C_{th\_m} — magnet, minutes
e.g. standard preset: τv22.5\tau_v \approx 22.5 s, τm250\tau_m \approx 250 s

Now add copper's twist. Re(T)=Re0(1+α(T20))R_e(T) = R_{e0}(1+\alpha(T-20)). As TvT_v climbs, ReR_e climbs. The amp is modeled as constant-voltage — Vin2=PinputRe0V_{in}^2 = P_{input} R_{e0} — so actual electrical power Pe=Vin2/Re(T)P_e = V_{in}^2 / R_e(T) drops as it heats. That's a stabilizing negative feedback on temperature, but a direct hit to SPL. You trade loudness for survival.

  • Hot coil \to higher ReR_e \to lower I=Vin/ReI = V_{in}/R_e \to lower BlI.
  • Lower II \to slightly less heating, so temperature asymptotes rather than running away.
  • But SPLcomp=20log10(Re/Re0)SPL_{comp} = -20\log_{10}(R_e/R_{e0}) keeps sliding negative — you hear it as compression.

Short bursts mostly charge Cth_vC_{th\_v}. Long, heavy drive also charges Cth_mC_{th\_m}, and that magnet won't cool quickly when you stop. That is why a speaker can sound fine for one song and dull for the next, even at the same meter reading.

Think of it like

Two buckets connected by a slow pipe. You pour water (power) into the small top bucket (coil). It drains through a narrow hose (Rth_vR_{th\_v}) into a huge bottom tank (magnet). The top bucket's water level is temperature. Now imagine the faucet gets stingier as the top bucket fills — higher water level pinches the inlet. Level stabilizes, but flow out the BlI tap drops. That's compression.

Where architecture matters

Standard basket: Rth_v1.5R_{th\_v} \approx 1.5 K/W, sluggish cooling
Vented pole: Rth_v0.8R_{th\_v} \approx 0.8, much better exhaust
Ferrofluid: Rth_v0.4R_{th\_v} \approx 0.4, fluid bridges the gap

Same Cth_vC_{th\_v} range (10–15 J/K) but cutting Rth_vR_{th\_v} by 3× cuts τv\tau_v and the final temperature almost proportionally. Check the lower plot — curves separate hard at high power.

The math — from copper physics to code

1. Copper doesn't keep its resistance

The base fact of this whole sim is linear TCR:

Re(T)=Re0[1+α(T20)]R_e(T) = R_{e0}\,[1 + \alpha\,(T - 20)]α=0.00393K1 (copper, code ALPHA_CU)\alpha = 0.00393\,K^{-1} \text{ (copper, code }ALPHA\_CU\text{)}

At 150°C, Re1.51×Re0R_e \approx 1.51 \times R_{e0}. A nominal 6.2Ω6.2\,\Omega coil is now 9.4Ω9.4\,\Omega. The amp hasn't changed. Ohm's law has.

2. Constant-voltage amp model

The slider says "Input power" in RMS watts. That value is interpreted as power into a cold coil. Code stores it as PinputP_{input} and defines the drive voltage once:

Vin2=PinputRe0V_{in}^2 = P_{input}\,R_{e0}Pe(Tv)=Vin2Re(Tv)=PinputRe0Re(Tv)P_e(T_v) = \frac{V_{in}^2}{R_e(T_v)} = \frac{P_{input}R_{e0}}{R_e(T_v)}I(Tv)=VinRe(Tv)I(T_v) = \frac{V_{in}}{R_e(T_v)}

So PeP_e falls as the coil heats. If you wanted a constant-power source, you'd hold PeP_e fixed and temperature would climb faster. Real amps behave closer to constant-voltage into a resistive load, so this is the honest choice for SPL loss.

3. Two coupled thermal ODEs

This is the lumped ladder the code actually integrates with explicit Euler every PHYSICS_DT=0.02PHYSICS\_DT = 0.02 s:

dTvdt=Pe(Tv)TvTmRth_vCth_vdTmdt=TvTmRth_vTmTambRth_mCth_m\begin{aligned} \frac{dT_v}{dt} &= \frac{P_e(T_v) - \frac{T_v - T_m}{R_{th\_v}}}{C_{th\_v}} \\ \frac{dT_m}{dt} &= \frac{\frac{T_v - T_m}{R_{th\_v}} - \frac{T_m - T_{amb}}{R_{th\_m}}}{C_{th\_m}} \end{aligned}

Inside stepPhysics(), heatFlowVC_to_Mag = (T_coil - T_mag)/Rth_v and heatFlowMag_to_Amb = (T_mag - Tamb)/Rth_m. The update is T_coil += dT_coil with dT_coil = (Pe - flow)/Cth_v * dt. That is exactly the math above.

The rolling chart keeps WINDOW_SECONDS=60WINDOW\_SECONDS = 60 simulated seconds, sampling about 30 Hz, with MAX_BUFFER = 1800 points. Time reads as simulated seconds, not wall-clock — accelerated by the slider up to 40×40\times, safely stepping with an accumulator and a 200-iteration cap per frame.

4. SPL compression from lost current

Force is BlIBl \cdot I. If BlBl held constant, FI1/ReF \propto I \propto 1/R_e. Sound pressure is proportional to force, so:

ΔL=20log10 ⁣(Re(Tv)Re0)  [dB]\Delta L = -20\,\log_{10}\!\left(\frac{R_e(T_v)}{R_{e0}}\right)\;[\text{dB}]

At 1.5×Re01.5\times R_{e0}, that's -3.5 dB — you need 2.2×2.2\times electrical power to make up what heat stole. The top canvas draws this alongside temperature, so you see compression lag temperature slightly — it tracks ReR_e, which tracks TvT_v.

5. Where it settles — steady-state solve

Set derivatives to zero. Heat in equals heat out through the series RthR_{th}:

Vin2Re0[1+α(Tss20)]=TssTambRth_v+Rth_m\frac{V_{in}^2}{R_{e0}[1+\alpha(T_{ss}-20)]} = \frac{T_{ss}-T_{amb}}{R_{th\_v}+R_{th\_m}}

That's implicit in TssT_{ss} because ReR_e depends on it. Code function steadyStateTemp(P_input, Re0, Tamb, alpha, Rth_v, Rth_m) Newton-iterates 60 times: residual r=Pe(TTamb)/Rthr = P_e - (T-T_{amb})/R_{th}, derivative dr/dT=dPe/dT1/Rthdr/dT = dP_e/dT - 1/R_{th}, TTr/(dr/dT)T \gets T - r/(dr/dT). Initial guess ignores TCR: Tguess=Tamb+PinputRthT_{guess} = T_{amb} + P_{input}R_{th}. Result shows as the dashed TssT_{ss} line and the "Steady-state T" badge. The power-sweep canvas uses the same solver at 100 power points up to 2×Pinput2\times P_{input}.

State vector

x=[Tv,Tm]\mathbf{x} = [T_v, T_m]^{\top}

Two states, two time scales. Code keeps them as T_coil and T_mag, plus simulatedTime. No hidden integrators pulling tricks.

Variables you actually touch

Rth_vR_{th\_v} coil-to-magnet K/W — slider rth_vrth\_v
Cth_vC_{th\_v} coil J/K — slider cth_vcth\_v
Rth_mR_{th\_m}, Cth_mC_{th\_m} magnet side — preset only
α\alpha copper TCR — slider, default 0.00393
PinputP_{input}, Re0R_{e0}, TambT_{amb} direct controls
PHYSICS_DT=0.02PHYSICS\_DT=0.02, WINDOW_SECONDS=60WINDOW\_SECONDS=60

Time constant decoded

τ=RthCth  [s]\tau = R_{th}C_{th}\;[s]

After one τ\tau, the step response reaches 63%63\%. Standard basket: τv=1.5×15=22.5\tau_v=1.5\times15=22.5 s. You see it on the top plot — knee around 20–30 s. Ferrofluid slashes Rth_vR_{th\_v} to 0.4, so τv4\tau_v \approx 4 s and TssT_{ss} drops dramatically, but Cth_vC_{th\_v} also 10 J/K in that preset, keeping it responsive.

Integrator honesty

Forward Euler, fixed 0.02 s, is stable here because thermal times are seconds, not microseconds. The accumulator pattern decouples sim time from frame rate, and time acceleration is a multiplier on elapsed wall time. No implicit solver, no artificial damping — what you see is the ODE, stepped honestly.

Playbook — what to push, what to watch

Start here

150 W, Standard basket, 20°C. The default. Hit Play — coil climbs toward 150\sim 150–200°C depending on Re0R_{e0}, SPL sags about -1 to -2 dB over 60 s. Watch τv\tau_v: time readout shows the early rise is steep, then bends as magnet warms. That's Cth_mC_{th\_m} waking up.

Crank it

1000 W. Same cooling, 5×5\times heat. TssT_{ss} in the code's Newton solver jumps beyond 400°C — well past the 200°C adhesive warning. Current drops from 10\sim 10 A to 6\sim 6 A, electrical power actually falls as it heats. You asked for 1000 W, you get 600\sim 600 W hot. The red banner is not theatrical.

Swap to Ferrofluid. Same 1000 W now settles near 180–220°C, SPL sag about half. The power-sweep chart shows why: the orange-red curve (your current architecture) pulls down to green when you click that preset. Ferrofluid bridges the 0.2 mm gap with liquid that conducts heat — Rth_v=0.4R_{th\_v} = 0.4 vs 1.5. Physics you can buy.

Find the constants

Measure τ\tau. Pause at ambient, hit Play, time how long to get 63%63\% of TssTambT_{ss}-T_{amb}. That's τ\tau — compare to Rth_vCth_vR_{th\_v}C_{th\_v} badge. Now lower Cth_vC_{th\_v} to 0.5 J/K (custom). Rise becomes near-instant — you removed thermal inertia. Raise it to 50 J/K and you get a slow cooker.

Ambient matters. Set Tamb=40°CT_{amb} = 40°C — a summer stage. TvT_v baseline lifts by 20 K, TssT_{ss} lifts by the same plus a little extra because hotter start means higher ReR_e means a touch less power. Small, but real.

Tweaks that matter

Time acceleration

Physics dtdt stays PHYSICS_DT=0.02PHYSICS\_DT = 0.02 s — speed just runs more steps per render frame (capped at 200 per frame). At 40×40\times you watch minutes of thermal drift in seconds. At 1×1\times you can see the sampling — data points every 0.033 s — and feel how τm\tau_m really dominates long runs.

Power sweep + show all architectures

Top marker shows current live TcoilT_{coil} vs steady-state TssT_{ss} at PinputP_{input}. When they diverge, you're still in transient. Click "Show all architectures" — three dashed curves use PRESETS directly: standard 1.5/1.0, vented 0.8/0.4, ferrofluid 0.4/0.3 for Rth_v/Rth_mR_{th\_v}/R_{th\_m}. Slope at low power is Rth_v+Rth_mR_{th\_v}+R_{th\_m}: linear for cold.

200°C warning

At 200°C the SVG coil turns orange-red via coilHexColor() and the top plot shades the danger zone. Not arbitrary — most voice-coil adhesives (polyimide) soften around there. The simulation still runs hotter, but reality would have already distorted or seized.

Where the code lives

steadyStateTemp() Newton solve, stepPhysics() Euler ladder, renderTimeCanvas() dual stacked plot with Tamb and Tss asymptotes, renderSweepCanvas() pre-computed 100-point curves. Sampling interval 0.033 s, WINDOWSECONDS=60WINDOW_SECONDS=60 window trim. No magic.

Honesty — what this is and isn't

What is real physics

Lumped two-time-constant thermal network, copper TCR α=0.00393\alpha=0.00393, constant-voltage interpretation Vin2=PinputRe0V_{in}^2 = P_{input}R_{e0}, coupled ODEs as written, Newton solve for steady-state, SPL compression as 20log10(Re/Re0)-20\log_{10}(R_e/R_{e0}). Time constants τ=RthCth\tau=R_{th}C_{th} behave exactly as labeled. Numbers track a real 15" woofer within a factor of two.

What it simplifies

Uniform temperature — real coil has hot spots near the gap exit. Constant RthR_{th}, CthC_{th} — in reality convection scales with ΔT\Delta T and gap airflow modulates with excursion. No radiation term T4\propto T^4. No frequency dependence — music is peaky, RMS is a crude average. No eddy-current heating in pole pieces, no Bl(T)Bl(T) drop from magnet demagnetization, no former material or adhesive thermal conductance, no excursion-driven pumping. The model overestimates low-frequency heating and underestimates HF cooling — take it as a clear, teachable bounding case.

If you want to push further: make Rth_vR_{th\_v} a function of xcoil(t)x_{coil}(t) to model pumping, add a third node for pole piece with its own CC, let Bl=Bl0[1β(Tm20)]Bl = Bl_0[1 - \beta(T_m-20)] for ferrite tempco, or drive Pe(t)P_e(t) from a real audio envelope instead of continuous sine. All fit inside the same ladder — more nodes, same idea.

Anatomy of the simulator

Every slider, pixel, and readout traces back to the two coupled thermal ODEs. Here is what each piece of the dashboard is doing and why it is built that way.

The time-history canvas

  1. 01

    Dual stacked plot. Top half: coil temperature TvT_v in red, with a dashed TambT_{amb} baseline and a dotted TssT_{ss} asymptote. Bottom half: SPL compression in blue — same 20log10(Re/Re0)-20\log_{10}(R_e/R_{e0}) formula, different axis. The two traces share one x-axis so you see compression lagging temperature directly.

  2. 02

    Danger zone shading. The region above 200°C is tinted red. It is not cosmetic — the warning banner fires from the same threshold. The shade persists even if the actively controlled slider briefly pushes past.

  3. 03

    Rolling window. Only the most recent WINDOW_SECONDS=60WINDOW\_SECONDS = 60 simulated seconds are visible. The buffer trims with a while-loop on each data push — MAX_BUFFER = 1800 points at ~30 Hz. The x-axis always ends at the current time, so you read left-to-right like an oscilloscope.

  4. 04

    Live dot indicator. The most recent data point is a filled circle on each trace — red on the temperature curve, blue on the SPL curve — so you can tell at a glance where the sim is right now relative to the history.

Controls, readouts, and the motor SVG

  1. 01

    Seven metric readouts. Coil temp (color-coded: green below 80°C, yellow to 150°C, orange to 200°C, red above), ReR_e (live from TCR), current, electrical power (drops as resistance climbs), SPL compression in dB, coil thermal time constant τv=Rth_vCth_v\tau_v = R_{th\_v}C_{th\_v}, and the Newton-solved steady-state TssT_{ss}. They all derive from one state vector [Tv,Tm][T_v, T_m]^{\top}.

  2. 02

    Cooling architecture presets. Standard, vented pole-piece, ferrofluid — each swaps Rth_v,Cth_v,Rth_m,Cth_mR_{th\_v}, C_{th\_v}, R_{th\_m}, C_{th\_m} from the PRESETS map. The custom button unlocks the thermal-parameter sliders for manual tweaking. Toggling back to a preset restores its exact values.

  3. 03

    Motor cross-section SVG. Voice-coil rectangles are colored by the coilHexColor() function — a three-segment gradient from copper-orange through red to danger-red based on temperature normalized against TambT_{amb}. Heat-flow arrows fade opacity with the temperature gradient. Not a physics solver, just an honest visual indicator.

  4. 04

    Power sweep canvas. Pre-computes TssT_{ss} at 100 power points up to 2×Pinput2\times P_{input} using the same Newton solver. The live operating point is a filled circle; a separate hollow circle shows current TcoilT_{coil} when it diverges from steady-state (transient). The "Show all architectures" toggle overlays dashed curves for standard, vented, and ferrofluid presets — revealing how Rth_vR_{th\_v} separates the curves at high power.

  5. 05

    The render loop. Runs a fixed PHYSICS_DT=0.02PHYSICS\_DT = 0.02 s Euler step via an accumulator pattern decoupled from frame rate. Time acceleration (up to 40×40\times) is a multiplier on wall-clock elapsed time, capped at 200 steps per frame to prevent spiral-of-death. All canvases repaint every frame; the sim pauses when off-screen via IntersectionObserver.

Gear behind this build

Akous · DSP audio stack · 33 picks

Audio DSP hardware33

More gear across every app: the full Gear list →

Two gotchas worth knowing

Adhesive failure is the real limit

The 200°C warning is not some conservative safety margin. Polyimide adhesives — the standard for bonding copper windings to the former — soften around 200°C. At that point the wire can de-bond, rub the magnet gap, and short-circuit. The simulation happily runs past 400°C because it is just numbers — in a real driver, you would have already smelled the failure.

Constant-voltage assumption

The sim models the amplifier as an ideal voltage source: Vin2=PinputRe0V_{in}^2 = P_{input}R_{e0} is computed once and held constant. A real amplifier's output impedance, rail sag under sustained load, and the reactive component of the driver's impedance all modify the actual voltage at the terminals. This means the sim slightly underestimates SPL compression at very high power — real amps droop more.

The solver, copyable

The two functions driving every number on this page. The first is a Newton iteration for steady-state temperature; the second is the explicit Euler step that advances the two coupled ODEs. Both run in the browser — hit copy and drop them into your own thermal model.

steadyStateTemp + stepPhysics

function steadyStateTemp(P_input, Re0, Tamb, alpha, Rth_v, Rth_m) {
  const Rth = Rth_v + Rth_m;
  const VinSq = P_input * Re0;
  const T_REF = 20;
  let T = Tamb + P_input * Rth;
  for (let i = 0; i < 60; i++) {
    const ReT = Re0 * (1 + alpha * (T - T_REF));
    const Pe = VinSq / ReT;
    const residual = Pe - (T - Tamb) / Rth;
    if (Math.abs(residual) < 1e-6) break;
    const dPe_dT = -VinSq * Re0 * alpha / (ReT * ReT);
    const dRes_dT = dPe_dT - 1 / Rth;
    T -= residual / dRes_dT;
  }
  return Math.max(Tamb, Math.min(Tamb + 1000, T));
}

function stepPhysics(dt) {
  const ReT = Re0 * (1 + alpha * (T_coil - T_REF));
  const VinSq = P_input * Re0;
  const Pe = VinSq / ReT;
  const heatVC = (T_coil - T_mag) / Rth_v;
  const heatMag = (T_mag - Tamb) / Rth_m;
  T_coil += (Pe - heatVC) / Cth_v * dt;
  T_mag += (heatVC - heatMag) / Cth_m * dt;
}

const ReT = Re0 * (1 + alpha * (T_coil - T_REF));
const splComp = -20 * Math.log10(ReT / Re0);

Frequently asked questions

What is power compression in a loudspeaker?

Power compression is the SPL loss that happens when a voice coil heats up under sustained drive. Copper's electrical resistance increases about 0.39% per degree Celsius. As the coil gets hotter, less current flows for the same amplifier voltage, so the cone moves less. The amplifier meter still reads the same output setting, but the speaker is quieter — typically 1–3 dB for a pro woofer driven hard.

Why does copper resistance change with temperature?

Copper's electrons scatter off thermal lattice vibrations. More temperature means stronger vibrations, more scattering, higher resistance. The relationship is nearly linear over the range voice coils operate in: Re(T) = Re0 × (1 + α × (T − 20°C)) where α = 0.00393 K⁻¹. At 200°C the resistance is about 1.7× the cold value.

How much does ferrofluid actually help with cooling?

Ferrofluid bridges the air gap between the voice coil and the magnet pole pieces with a heat-conducting liquid — it replaces still air (a good insulator) with a much better thermal path. In this sim the ferrofluid preset cuts Rth_v from 1.5 to 0.4 K/W, which drops the steady-state temperature at 300 W from over 350°C to about 150°C. In real drivers the effect is similar: ferrofluid can increase power handling by 2–4× before hitting the same coil temperature.

What temperature kills a voice coil?

The epoxy or polyimide adhesive that bonds the copper wire to the former softens around 200°C. At that point the windings can delaminate, rub the gap, and short-circuit. Some specialty adhesives survive 250–300°C but most pro-audio drivers use standard formulations. The simulation shows a warning banner at 200°C for this reason — it is not a theoretical limit, it is the glue.

How do I measure my own driver's thermal constants?

Drive the speaker with a known DC voltage and measure the voice-coil resistance as it heats (current = V / R). The resistance follows R(t) = Re0 × (1 + α × (T(t) − 20°C)), so you can extract T(t) from a resistance measurement. Fit the temperature curve to an exponential: T(t) = Tamb + (Tss − Tamb) × (1 − e^(−t/τ)). The time constant τ = Rth_v × Cth_v. You can repeat with different back enclosures to separate Rth_v from Rth_m — the magnet's Cth_m dominates the slow tail.

Shareable still

The instrument, captured—not illustrated.

This 16:9 frame is rendered from the real browser instrument above. It is the page's canonical preview for image search, link unfurls, and posts that need to show what the tool actually does.

Download 1280 × 720 JPEG
Speaker Power Compression — live MakerPortal instrument screenshot
Canonical capture · real UI · no generated scientific artwork