eleven9Silicon
// Linear Systems · Reference Library

SUPER
POSITION

If a system is linear — meaning it doesn't mix or warp inputs — you can solve it in pieces and stack the answers. That's the whole thing.

Linear Algebra ODEs Signal Processing
// 01 — Foundation

What is Linearity?

An operator L is linear if it satisfies exactly two rules. Call them homogeneity and additivity:

L[α·u] = α·L[u] // scaling: pull constants out L[u + v] = L[u] + L[v] // additivity: distribute over sums // Combining both: L[α·u + β·v] = α·L[u] + β·L[v]

Think of it geometrically. A linear operator is a flat transformation of space — it can stretch, rotate, reflect. But it can't fold, warp, or curve. Lines through the origin stay lines. The origin stays fixed. No mixing of coordinates in nonlinear ways.

"Linear" means the operator is the same machine no matter what input you feed it. It doesn't behave differently at large vs. small inputs. It has no memory of previous states. It's stateless, scale-invariant, additive.

Examples of linear vs. nonlinear

OperationLinear?Why
d/dt [ f(t) ]✓ YesDerivative distributes over sums, pulls out constants
∫ f(t) dt✓ YesIntegration distributes, constants come out
Matrix multiply Ax✓ YesA(u+v) = Au + Av by matrix algebra
y² or y·y'✗ NoProducts of the unknown — breaks additivity
sin(y) or eʸ✗ NoNonlinear functions of y — can't factor out
// Demo 01 — Geometric Linearity Test

Watch what L does to a vector. Linear transforms keep grid lines straight and origin fixed. Toggle nonlinear mode to see what breaks.

1.5
0.5
-0.3
1.2
// 02 — Linear Algebra

Ax = b:
The Solution Structure

A linear system Ax = b has a beautiful decomposition. The complete solution is always a particular solution plus the null space:

x_general = x_particular + x_homogeneous where: A · x_p = b // particular: hits the target A · x_h = 0 // homogeneous: invisible to A (null space) Why it works: A(x_p + x_h) = A·x_p + A·x_h = b + 0 = b ✓

Geometrically: x_particular is one arrow that points at b. The null space is a flat subspace through the origin that A crushes to zero. You can shift x_p anywhere within that flat subspace and still land on b.

Also: if you have multiple targets, split them. If b = b₁ + b₂, solve Ax₁ = b₁ and Ax₂ = b₂ separately, then add x₁ + x₂. That's superposition of sources.

// Demo 02 — Superposition of Sources

Drag the two source vectors b₁ (gold) and b₂ (teal). Their particular solutions x₁ and x₂ appear. The full solution x₁+x₂ (rose) always satisfies A(x₁+x₂) = b₁+b₂.

■ b₁, x₁ ■ b₂, x₂ ■ x₁ + x₂ (total) ■ null space
// Superposition in JavaScript — Ax = b
function solve2x2(A, b) {
  // Cramer's rule for 2x2
  const det = A[0][0] * A[1][1] - A[0][1] * A[1][0];
  return [
    (b[0] * A[1][1] - b[1] * A[0][1]) / det,
    (A[0][0] * b[1] - A[1][0] * b[0]) / det
  ];
}

const A  = [[2, 1], [1, 3]];
const b1 = [3, 0];   // first source
const b2 = [0, 4];   // second source

const x1 = solve2x2(A, b1);  // particular for b1
const x2 = solve2x2(A, b2);  // particular for b2

// Superposition: just add them
const x_total = [x1[0] + x2[0], x1[1] + x2[1]];

// Verify: A·x_total should equal b1 + b2
const b_total = [b1[0]+b2[0], b1[1]+b2[1]];
// ✓ same result as solving A·x = b_total directly
// 03 — Differential Equations

L[y] = g(t):
ODE Superposition

The exact same structure appears. A linear ODE uses L as a differential operator:

L[y] = aₙ(t)·y⁽ⁿ⁾ + … + a₁(t)·y' + a₀(t)·y = g(t) // L is linear because derivatives distribute: L[αu + βv] = αL[u] + βL[v] // same math as matrices! // General solution: y = y_h + y_p y_h: solves L[y] = 0 (free/natural response) y_p: solves L[y] = g(t) (forced/driven response)

y_h captures what the system "wants to do" on its own — its natural frequencies. y_p captures how the system responds to the external forcing g(t). They're independent, and linearity lets you add them freely.

Superposition of forcing terms

If the forcing has multiple pieces, split and conquer:

g(t) = g₁(t) + g₂(t) + … + gₖ(t) // Solve each separately: L[yₚ₁] = g₁(t) L[yₚ₂] = g₂(t) // Then stack: yₚ = yₚ₁ + yₚ₂ // works because L distributes
This is exactly why Fourier analysis is so powerful: decompose any input g(t) into sinusoids, find the particular response to each sinusoid independently, then superpose. The system never cares that you split the work.
// Demo 03 — Wave Superposition (ODE Solutions)

Two particular solutions to y'' + ω²y = Asin(ωt) at different frequencies. Watch how they add. Toggle components on/off to see each piece.

1.0
1.0
2.3
0.6
// ODE superposition — animated wave demo
const t_vals = linspace(0, 4 * Math.PI, 500);

// Two forcing frequencies
const ω1 = 1.0, A1 = 1.0;
const ω2 = 2.3, A2 = 0.6;

// Particular solution to y'' + ω²y = A·sin(Ωt)
// with Ω ≠ ω → y_p = A/(ω²-Ω²) · sin(Ωt)
function yp(t, ω_nat, Ω_drive, A) {
  const denom = ω_nat ** 2 - Ω_drive ** 2;
  return (A / denom) * Math.sin(Ω_drive * t);
}

// Superposed solution — just add
const y_sum = t_vals.map(t =>
  yp(t, 3.0, ω1, A1) + yp(t, 3.0, ω2, A2)
);
// Demo 04 — Homogeneous + Particular = General Solution

For y'' + 2γy' + ω₀²y = cos(ωt). The natural response decays (damped oscillator). The particular (steady-state) persists. Their sum is the full solution.

0.3
1.2
// 04 — Mental Model

Geometry of
Superposition

Here's the visual intuition that ties it all together. In 2D vector space, A transforms the plane. The solution to Ax = b is a point in input space that maps to b in output space. The null space is the flat direction A is blind to.

// Demo 05 — Input Space / Output Space Geometry

Left: input space (x). Right: output space (b = Ax). The particular solution x_p maps exactly to b. Any null space shift stays invisible — A crushes it to 0.

0.0
1.0
0.5

The One Sentence Summary

1
Linearity = permission to decompose. If L distributes, you can split any problem into pieces.
2
Solve each piece independently. No coupling. No interaction. Each piece lives in its own lane.
3
Add the results. The sum automatically satisfies the full equation. Linear systems are deaf to how you sliced the work.
4
General solution = particular + homogeneous. True in matrices AND ODEs AND circuits AND everywhere L is linear.
// Universal superposition pattern — works everywhere
function solveLinearSystem(L, sources) {
  // sources = [g1, g2, g3, ...]  (right-hand side terms)

  // Step 1: solve homogeneous
  const y_h = solveHomogeneous(L);

  // Step 2: solve particular for EACH source independently
  const y_particulars = sources.map(g => solveParticular(L, g));

  // Step 3: superpose — just add everything
  const y_p = y_particulars.reduce((sum, ypi) => add(sum, ypi));

  // General solution
  return add(y_h, y_p);

  // This works whether L is a matrix, d/dt, or any linear operator.
  // Linearity is the only requirement.
}