Move the region around the red-light diagram, and change its shape: q = k\,v holds every time.
// The red-light scenario of Lecture 1, with twelve cars.edieSim = {const v0 =15, T =1.2, s0 =2, a =1.5, b =2, lc =5, dt =0.1, stop =300, red = [16,46], n =12;const x =newArray(n).fill(null), v =newArray(n).fill(v0), rows = [];const idm = (vi, gap, dv) => a * (1- (vi / v0) **4- ((s0 +Math.max(0, vi * T + vi * dv / (2*Math.sqrt(a * b)))) /Math.max(gap,0.1)) **2);for (let k =0; k <=900; k++) {const t = k * dt, isRed = t >= red[0] && t < red[1];for (let i =0; i < n; i++) if (x[i] ===null&& t >=3* i) x[i] =0;const acc =newArray(n).fill(0);for (let i =0; i < n; i++) {if (x[i] ===null) continue;let gap =Infinity, dv =0;if (i >0&& x[i -1] !==null) { gap = x[i -1] - x[i] - lc; dv = v[i] - v[i -1]; }if (isRed && x[i] < stop && stop - x[i] -1< gap) { gap = stop - x[i] -1; dv = v[i]; } acc[i] =Math.max(-8, gap ===Infinity? a * (1- (v[i] / v0) **4) :idm(v[i], gap, dv)); }for (let i =0; i < n; i++) if (x[i] !==null) { v[i] =Math.max(0, v[i] + acc[i] * dt); x[i] += v[i] * dt; }if (k %2===0) for (let i =0; i < n; i++) if (x[i] !==null&& x[i] <=500) rows.push({t:+t.toFixed(1),car: i +1,x: x[i],v: v[i]}); }return {rows,dtSample:0.2};}
edieRegion = {const size = {"Square": [20,100],"Thin and long in time (a loop)": [80,4],"Thin and long in space (a snapshot)": [1,440]}[edieShape];const t1 =Math.max(0, edieT - size[0] /2), t2 =Math.min(90, edieT + size[0] /2);const x1 =Math.max(0, edieX - size[1] /2), x2 =Math.min(500, edieX + size[1] /2);const inside = edieSim.rows.filter(r => r.t>= t1 && r.t< t2 && r.x>= x1 && r.x< x2);const dA = d3.sum(inside, r => r.v* edieSim.dtSample), tA = inside.length* edieSim.dtSample, area = (t2 - t1) * (x2 - x1);return {t1, t2, x1, x2,q: dA / area *3600,k: tA / area *1000,v: tA ? dA / tA *3.6:NaN};}
viewof edieShape = Inputs.radio(["Square","Thin and long in time (a loop)","Thin and long in space (a snapshot)"], {value:"Square",label:"Region:"})viewof edieT = Inputs.range([5,85], {value:30,step:1,label:"Centre time (s)"})viewof edieX = Inputs.range([40,460], {value:250,step:5,label:"Centre position (m)"})
A thin box along time is what a loop detector sees; a thin box along the road is a drone snapshot; a square is neither, and the definitions still work. Lecture 2 explains why q = kv always holds in Edie’s box.
theme = Generators.observe(notify => {const read = () =>notify(document.body.classList.contains("quarto-dark") ?"dark":"light");read();const watcher =newMutationObserver(read); watcher.observe(document.body, {attributes:true,attributeFilter: ["class"]});return () => watcher.disconnect();})accent = theme ==="dark"?"#c9a0ff":"#57068c"accentRange = theme ==="dark"? ["#4b3a5c","#ecdcff"] : ["#dccbee","#3a0463"]ink = theme ==="dark"?"#f2f2f2":"black"// Plot width: Plot's default 640 px, except on a phone, where a plot is drawn to fit its card// instead of being shrunk (and its text with it). Changes only when the width actually changes.plotW = Generators.observe(notify => {let last;const read = () => {const main =document.querySelector("main"), fit = main ? main.clientWidth-50:640;const w =!document.querySelector(".reveal") && fit <640?Math.max(240,Math.floor(fit)) :640;if (w !== last) notify(last = w); };read();window.addEventListener("resize", read);return () =>window.removeEventListener("resize", read);})