Delayed feedback and bounded control
Simulate a point mass, inject one change at a time and measure tracking versus effort.
Study guide & lesson outline
LEARNING CONTRACTUnderstand → implement → investigate
Goal: explain the mechanism in this lesson, reproduce one example and test a failure case. Reading alone does not mark mastery.
- Understand: state assumptions, shapes/units and a counterexample.
- Implement: reproduce a numerical example and inspect boundaries.
- Investigate: compare one alternative under a matched budget.
Prerequisite & prediction
Study the prerequisite lesson →Does clipping force to 5 N guarantee no overshoot?
Hint 1: identify the mechanism
A bounded force changes velocity; it does not remove momentum.
Reveal analysis after predicting
No. State and velocity still evolve; delayed feedback can drive overshoot even when every force is within its limit.
Run the reference implementation
{
"baseline": {
"config": {
"delay": 0
},
"finalError": 0.0013615041560250951,
"overshoot": 0.18748702554551544,
"saturationSteps": 25,
"maxForce": 5,
"first": {
"time": 0.01,
"x": 0,
"v": 0.05,
"force": 5
},
"last": {
"time": 4,
"x": 1.001361504156025,
"v": -0.010752819203442319,
"force": 0.018092826086232645
}
},
"delayed": {
"config": {
"delay": 10
},
"finalError": 0.008125716946019934,
"overshoot": 0.3147122500242969,
"saturationSteps": 54,
"maxForce": 5,
"first": {
"time": 0.01,
"x": 0,
"v": 0.05,
"force": 5
},
"last": {
"time": 4,
"x": 0.9918742830539801,
"v": 0.03304393949300494,
"force": 0.03608296388340165
}
},
"massShift": {
"config": {
"delay": 0,
"mass": 2
},
"finalError": 0.0009019295580974251,
"overshoot": 0.32158346698785345,
"saturationSteps": 41,
"maxForce": 5,
"first": {
"time": 0.01,
"x": 0,
"v": 0.025,
"force": 5
},
"last": {
"time": 4,
"x": 1.0009019295580974,
"v": 0.12493732365183198,
"force": -0.3768011508587378
}
},
"limitation": "Teaching simulator; no collision geometry, contacts, sensor noise or hardware safety validation."
}Initial output is computed at build time; the button recomputes it in your browser. No model, GPU or hardware is involved.
Complete implementation & test runner
Download all four files into one folder. Run node check.mjs. The checks exercise all three projects; no installation or API key is required.
// Explicit Euler point-mass simulator. Units: kg, m, s, N. No hardware control.
export function simulate({delay=0,mass=1,kp=10,kd=3,limit=5,dt=.01,steps=400}={}) {
if (!Number.isInteger(delay)||delay<0||delay>100||!Number.isInteger(steps)||steps<1||steps>10000||![mass,kp,kd,limit,dt].every(Number.isFinite)||mass<=0||dt<=0||limit<0) throw Error('Invalid configuration');
let x=0,v=0,peak=0,clamps=0;const history=[{x,v}],trace=[];
for(let t=0;t<steps;t++){
const sensed=history[Math.max(0,history.length-1-delay)];
const proposed=kp*(1-sensed.x)-kd*sensed.v;
const force=Math.max(-limit,Math.min(limit,proposed));
if(force!==proposed)clamps++;
const nextX=x+dt*v;v+=dt*force/mass;x=nextX;peak=Math.max(peak,x);
history.push({x,v});trace.push({time:(t+1)*dt,x,v,force});
}
return {finalError:Math.abs(1-x),overshoot:Math.max(0,peak-1),saturationSteps:clamps,
maxForce:Math.max(...trace.map(r=>Math.abs(r.force))),trace};
}
export function run(){const summarize=config=>{const {trace,...metrics}=simulate(config);return {config,...metrics,first:trace[0],last:trace.at(-1)}};return {baseline:summarize({delay:0}),delayed:summarize({delay:10}),massShift:summarize({delay:0,mass:2}),
limitation:'Teaching simulator; no collision geometry, contacts, sensor noise or hardware safety validation.'}}
Inspect executable acceptance tests
import assert from 'node:assert/strict';
import {run as attention,softmax,attend,full,cached} from './attention.mjs';
import {run as retrieval,retrieve} from './retrieval.mjs';
import {run as control,simulate} from './control.mjs';
assert.ok(attention().passes);assert.throws(()=>softmax([-Infinity,-Infinity]));assert.throws(()=>attend([1,2],[[1]],[[1]]));
assert.equal(retrieval().baseline.accuracy,.4);assert.equal(retrieval().treatment.accuracy,1);assert.equal(retrieve('unseen vocabulary'),null);
const result=control();assert.ok(result.baseline.maxForce<=5);assert.ok(result.delayed.maxForce<=5);assert.equal(simulate({steps:1}).trace[0].x,0);assert.equal(simulate({steps:1}).trace[0].v,.05);assert.throws(()=>simulate({mass:0}));
// Full and cached paths must reject inconsistent shapes, not just the single-query helper.
assert.throws(()=>full([[1,2]],[[1]],[[1]]),/Shape mismatch/);
assert.throws(()=>cached([[1,2]],[],[]),/sequence shape/);
console.log('PASS: 12 capstone checks. Toy arithmetic and invariants only; no GPU or hardware benchmark.');
Transfer task & ablation
Sweep delay 0/5/10/20 while fixing mass, gains and integration step. Then repeat with half the step to detect numerical artifacts.
Rubric
Declare units and Euler convention; enforce actuator bounds; isolate delay from mass; report overshoot, error and model limitations.
Score each of the four criteria 0 (missing), 1 (with help), 2 (independent evidence). Passing requires 2 on every criterion. A self-check is not a certification.
Reference report & your report
Reference configuration: exactly the constants in run(); no random sampling. Observed fixture results are shown above. Reproduce first, then change one factor and record its effect.
No contacts, collisions or real sensors. This project cannot certify hardware safety or reproduce robot foundation-model results.
Hypothesis: Code revision / runtime: Dataset or fixture version: Baseline: One-factor intervention: Raw outputs and acceptance tests: Negative result / failure case: What this does NOT establish: Next falsifiable hypothesis:
Assumptions, implementation & acceptance
Explicit Euler uses old velocity for the position update. Force saturation is in newtons; delay is an integer number of steps. No contact dynamics, collisions or real hardware guarantees are modeled.
Implementation, invariants and declared evidence boundary reviewed; existing acceptance tests remain part of the suite.
Before running: predict a boundary case
Explicit Euler uses old velocity for the position update. Force saturation is in newtons; delay is an integer number of steps. No contact dynamics, collisions or real hardware guarantees are modeled.
Hint: isolate the assumption
Keep the baseline input fixed, change one parameter or boundary, and compare both the numerical result and the claimed units. A passing example verifies this fixture only.
Minimal executable example
Save the example and linked modules in one folder. Use Node.js 22 or newer, then run node project-control.mjs. No third-party runtime dependencies.
import {run} from './project-control-core.mjs';
console.log(run());Test and transfer
Explicit Euler uses old velocity for the position update. Force saturation is in newtons; delay is an integer number of steps. No contact dynamics, collisions or real hardware guarantees are modeled.
Record input, code version, expected result and observed result in the notebook below. Then construct a counterexample that violates the assumption above and explain why the original conclusion no longer follows.
Download complete kit (.tar.gz) · Complete reference kit and regression checksPredict, test and keep evidence
Before revealing an answer, predict one result. After the exercise, record the discrepancy and a transfer test. Saved locally across language editions.
Open notebook / export / clear →The mathematical review scope is recorded per lesson. It does not establish empirical paper reproduction; report suspected errors in your notes. Review scope