This note records a compact reference for the particle-filter interpretation of Iₜ = C(Σ(Eₜ) ± Δₜ). It is intentionally pragmatic: equations, pseudocode, and a tiny JS implementation you can drop into a demo.
Core steps (per timestep): (1) weight each particle by likelihood given new evidence; (2) normalize weights; (3) resample particles according to weights; (4) apply the constancy term C as a shrinkage toward prior; (5) apply Δ as a value-directed nudge.
Reference JS (minimal):
function updateParticles(particles, weights, evidenceLikelihood, C = 0.9, delta = 0) {
// weights: array of positive numbers
// evidenceLikelihood(p, e) -> likelihood
const newWeights = particles.map((p, i) => weights[i] * evidenceLikelihood(p, evidence));
const sum = newWeights.reduce((s, w) => s + w, 0) || 1;
const norm = newWeights.map(w => w / sum);
// resample
const resampled = [];
for (let i = 0; i < particles.length; i++) {
const r = Math.random();
let acc = 0;
for (let j = 0; j < norm.length; j++) { acc += norm[j]; if (r <= acc) { resampled.push(clone(particles[j])); break; } }
}
// apply constancy C and delta
return resampled.map(p => {
// shrink toward prior (here: mean of previous particles) then nudge by delta
const mean = particles.reduce((m, q) => ({ x: m.x + q.x, y: m.y + q.y }), { x:0, y:0 });
mean.x /= particles.length; mean.y /= particles.length;
return {
x: mean.x * (1 - C) + p.x * C + delta,
y: mean.y * (1 - C) + p.y * C + delta,
};
});
}Notes: this is a pedagogical reference, not a production-optimized implementation. Use stratified resampling, systematic resampling, or low-variance resampling for stability in production.
Links from this note
How it has been tended
Grok walked the live note, found fences rendered as prose, then pruned NoteBody to parse fenced code blocks and collapsed the reference JS into a single fenced para.
drift: Teaching code in a Tufte margin garden risks becoming a second medium the layout wasn't built for.