Skip to content

Instantly share code, notes, and snippets.

@haxiomic
Last active April 15, 2018 12:44
Show Gist options
  • Save haxiomic/2e40d6f407eca8188ede006e4b27635d to your computer and use it in GitHub Desktop.
Save haxiomic/2e40d6f407eca8188ede006e4b27635d to your computer and use it in GitHub Desktop.
Analytic spring integration
// analyitc spring integration
// useful when you want a robust single-spring simulation
stepSpring(
dt_s: number,
state: {
x: number,
v: number,
pe: number, // potential energy
}, parameters: {
tension: number,
friction: number,
}) {
// analytic integration (unconditionally stable)
// references:
// http://mathworld.wolfram.com/OverdampedSimpleHarmonicMotion.html
// http://mathworld.wolfram.com/CriticallyDampedSimpleHarmonicMotion.html
let k = parameters.tension;
let f = parameters.friction;
let t = dt_s;
let v0 = state.v;
let x0 = state.x;
let critical = k * 4 - f * f;
if (critical === 0) {
// critically damped
let w = Math.sqrt(k);
let A = x0;
let B = v0 + w * x0;
let e = Math.exp(-w * t);
state.x = (A + B * t) * e;
state.v = (B - w * (A + B * t)) * e;
} else if (critical <= 0) {
// over-damped
let sqrt = Math.sqrt(-critical);
let rp = 0.5 * (-f + sqrt);
let rn = 0.5 * (-f - sqrt);
let B = (rn * x0 - v0) / (rn - rp);
let A = x0 - B;
let en = Math.exp(rn * t);
let ep = Math.exp(rp * t);
state.x = A * en + B * ep;
state.v = A * rn * en + B * rp * ep;
} else {
// under-damped
let a = -f/2;
let b = Math.sqrt(critical * 0.25);
let phaseShift = Math.atan(b / ((v0/x0) - a));
let A = x0 / Math.sin(phaseShift);
let e = Math.exp(a * t);
let s = Math.sin(b * t + phaseShift);
let c = Math.cos(b * t + phaseShift);
state.x = A * e * s;
state.v = A * e * (a * s + b * c);
}
state.pe = 0.5 * k * state.x * state.x;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment