this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add load-end probe (probe 2) in blue throughout

- style.css: add --probe2: #4a88ff
- getTheme: expose probe2
- drawCircuit: blue dots at xLoad on top+bottom wire for probe 2
- drawProbeSim: add VL trace from sim.nodeV[N] in probe2 color; include
VL in y-range; show VS/VL readouts separately
- drawProbe: add VL trace from bounce.loadEvents in probe2 color; include
VL in y-range; show VS/VL readouts separately; update title

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

+86 -34
+85 -34
render.js
··· 30 30 warn: get("--warn"), 31 31 ok: get("--ok"), 32 32 tdr: get("--tdr"), 33 + probe2: get("--probe2"), 33 34 }; 34 35 } 35 36 ··· 306 307 circleFill(ctx, xRight, yBot, 3.5, theme.ink); 307 308 } 308 309 309 - // Probe point — dots on top and bottom wire between switch and T-line input 310 + // Probe 1 — dots on top and bottom wire between switch and T-line input 310 311 const xDetect = Math.round((xSwitch + 18 + xTL0) / 2); 311 312 circleFill(ctx, xDetect, yTop, 5.5, theme.tdr); 312 313 circleFill(ctx, xDetect, yBot, 5.5, theme.tdr); 314 + 315 + // Probe 2 — dots at the load node (far end of last T-line) 316 + circleFill(ctx, xLoad, yTop, 5.5, theme.probe2); 317 + circleFill(ctx, xLoad, yBot, 5.5, theme.probe2); 313 318 ctx.fillStyle = theme.tdr; 314 319 ctx.font = "11px ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial"; 315 320 ctx.textAlign = "left"; ··· 745 750 const tMax = timeHorizon_; 746 751 const xOfT = (t) => padL + (t / tMax) * plotW_; 747 752 748 - const vArr = sim.nodeV[0]; 753 + const vArr = sim.nodeV[0]; 754 + const vArrL = sim.nodeV[sim.nodeV.length - 1]; 749 755 let vMax = 0, vMin = 0; 750 756 for (let k = 0; k < sim.nSteps; k++) { 751 - if (vArr[k] > vMax) vMax = vArr[k]; 752 - if (vArr[k] < vMin) vMin = vArr[k]; 757 + if (vArr[k] > vMax) vMax = vArr[k]; 758 + if (vArr[k] < vMin) vMin = vArr[k]; 759 + if (vArrL[k] > vMax) vMax = vArrL[k]; 760 + if (vArrL[k] < vMin) vMin = vArrL[k]; 753 761 } 754 762 vMax = Math.max(vMax, 0.01); 755 763 const span_ = Math.max(vMax - vMin, 0.05); ··· 758 766 const yOfV_ = (v) => padT + (vHi_ - v) / (vHi_ - vLo_) * plotH_; 759 767 760 768 ctx.fillStyle = theme_.muted; ctx.font = "12px ui-sans-serif, system-ui"; 761 - ctx.fillText("Probe \u2014 V at source node vs time", padL + 8, padT + 14); 769 + ctx.fillText("Probe \u2014 node voltages vs time", padL + 8, padT + 14); 762 770 763 771 const vStep_ = niceStep(vHi_ - vLo_, 4); 764 772 ctx.strokeStyle = theme_.grid; ctx.lineWidth = 1; ··· 810 818 811 819 const tnClamped_ = Math.min(tn, tMax); 812 820 const kEnd = Math.min(Math.round(tnClamped_ / sim.dt), sim.nSteps - 1); 821 + 822 + // VS trace (probe 1 — orange) 813 823 ctx.strokeStyle = theme_.tdr; ctx.lineWidth = 2.2; 814 824 ctx.beginPath(); 815 825 for (let k = 0; k <= kEnd; k++) { 816 826 const t = k * sim.dt; 817 827 if (k === 0) ctx.moveTo(xOfT(t), yOfV_(vArr[k])); 818 828 else ctx.lineTo(xOfT(t), yOfV_(vArr[k])); 829 + } 830 + ctx.stroke(); 831 + 832 + // VL trace (probe 2 — blue) 833 + ctx.strokeStyle = theme_.probe2; ctx.lineWidth = 2.2; 834 + ctx.beginPath(); 835 + for (let k = 0; k <= kEnd; k++) { 836 + const t = k * sim.dt; 837 + if (k === 0) ctx.moveTo(xOfT(t), yOfV_(vArrL[k])); 838 + else ctx.lineTo(xOfT(t), yOfV_(vArrL[k])); 819 839 } 820 840 ctx.stroke(); 821 841 ··· 826 846 } 827 847 828 848 const kNow = Math.max(0, Math.min(Math.round(tn / sim.dt), sim.nSteps - 1)); 829 - ctx.fillStyle = theme_.tdr; ctx.font = "13px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"; 849 + ctx.font = "13px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"; 830 850 ctx.textAlign = "right"; 831 - ctx.fillText("V(det) = " + vArr[kNow].toFixed(4) + " V", padL + plotW_ - 6, padT + 18); 851 + ctx.fillStyle = theme_.tdr; 852 + ctx.fillText("VS = " + vArr[kNow].toFixed(4) + " V", padL + plotW_ - 6, padT + 18); 853 + ctx.fillStyle = theme_.probe2; 854 + ctx.fillText("VL = " + vArrL[kNow].toFixed(4) + " V", padL + plotW_ - 6, padT + 34); 832 855 ctx.textAlign = "left"; 833 856 } 834 857 ··· 848 871 const xOfT = (t) => padL + (t / tMax) * plotW; 849 872 850 873 const { sumEventsAtTime, sumEventsWithRise, sumEventsWithLinearRamp } = TLPhysics; 851 - const vsAtTime = (t) => { 852 - if (riseTimeTr <= 0 || riseShape === "step") return sumEventsAtTime(bounce.srcEvents, t); 853 - if (riseShape === "linear") return sumEventsWithLinearRamp(bounce.srcEvents, t, riseTimeTr); 854 - return sumEventsWithRise(bounce.srcEvents, t, riseTimeTr); 874 + const eventsAt = (evts, t) => { 875 + if (riseTimeTr <= 0 || riseShape === "step") return sumEventsAtTime(evts, t); 876 + if (riseShape === "linear") return sumEventsWithLinearRamp(evts, t, riseTimeTr); 877 + return sumEventsWithRise(evts, t, riseTimeTr); 855 878 }; 879 + const vsAtTime = (t) => eventsAt(bounce.srcEvents, t); 880 + const vlAtTime = (t) => eventsAt(bounce.loadEvents, t); 856 881 857 - // y range from all srcEvents (cumulative sum) 858 - const events = [...bounce.srcEvents].sort((a, b) => a.t - b.t); 882 + // y range from both srcEvents and loadEvents cumulative sums 883 + const events = [...bounce.srcEvents].sort((a, b) => a.t - b.t); 884 + const eventsL = [...bounce.loadEvents].sort((a, b) => a.t - b.t); 859 885 let cumV = 0, vMax = 0, vMin = 0; 860 886 for (const ev of events) { 861 887 cumV += ev.dV; 862 888 if (cumV > vMax) vMax = cumV; 863 889 if (cumV < vMin) vMin = cumV; 864 890 } 891 + cumV = 0; 892 + for (const ev of eventsL) { 893 + cumV += ev.dV; 894 + if (cumV > vMax) vMax = cumV; 895 + if (cumV < vMin) vMin = cumV; 896 + } 865 897 vMax = Math.max(vMax, 0.01); 866 898 vMin = Math.min(vMin, 0); 867 899 const span = Math.max(vMax - vMin, 0.05); ··· 872 904 // Title 873 905 ctx.fillStyle = theme.muted; 874 906 ctx.font = "12px ui-sans-serif, system-ui"; 875 - ctx.fillText("Probe \u2014 V at source node vs time", padL + 8, padT + 14); 907 + ctx.fillText("Probe \u2014 node voltages vs time", padL + 8, padT + 14); 876 908 877 909 // Grid lines 878 910 const vStep = niceStep(vHi - vLo, 4); ··· 940 972 ctx.font = "12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"; 941 973 ctx.fillText("t / \u03C4d", padL + plotW + 6, padT + plotH + 4); 942 974 943 - // VS(t) trace up to tn 944 975 const tnClamped = Math.min(tn, tMax); 945 976 const smooth = riseTimeTr > 0 && riseShape !== "step"; 946 - ctx.strokeStyle = theme.tdr; 947 - ctx.lineWidth = 2.2; 948 - ctx.beginPath(); 949 977 950 - if (smooth) { 951 - const SAMPLES = 500; 952 - for (let i = 0; i <= SAMPLES; i++) { 953 - const t = (i / SAMPLES) * tnClamped; 954 - const v = vsAtTime(t); 955 - if (i === 0) ctx.moveTo(xOfT(t), yOfV(v)); 956 - else ctx.lineTo(xOfT(t), yOfV(v)); 957 - } 958 - } else { 959 - // Staircase: horizontal segment then vertical jump at each srcEvent 978 + // Helper: draw a staircase trace from an event list 979 + function drawStaircase(evts, color) { 980 + ctx.strokeStyle = color; ctx.lineWidth = 2.2; 981 + ctx.beginPath(); 960 982 let prevV = 0; 961 983 ctx.moveTo(xOfT(0), yOfV(0)); 962 - for (const ev of events) { 984 + for (const ev of evts) { 963 985 if (ev.t > tnClamped) break; 964 986 ctx.lineTo(xOfT(ev.t), yOfV(prevV)); 965 987 prevV += ev.dV; 966 988 ctx.lineTo(xOfT(ev.t), yOfV(prevV)); 967 989 } 968 990 ctx.lineTo(xOfT(tnClamped), yOfV(prevV)); 991 + ctx.stroke(); 969 992 } 970 - ctx.stroke(); 993 + 994 + // VS trace (probe 1 — orange) 995 + if (smooth) { 996 + ctx.strokeStyle = theme.tdr; ctx.lineWidth = 2.2; 997 + ctx.beginPath(); 998 + for (let i = 0; i <= 500; i++) { 999 + const t = (i / 500) * tnClamped; 1000 + if (i === 0) ctx.moveTo(xOfT(t), yOfV(vsAtTime(t))); 1001 + else ctx.lineTo(xOfT(t), yOfV(vsAtTime(t))); 1002 + } 1003 + ctx.stroke(); 1004 + } else { 1005 + drawStaircase(events, theme.tdr); 1006 + } 1007 + 1008 + // VL trace (probe 2 — blue) 1009 + if (smooth) { 1010 + ctx.strokeStyle = theme.probe2; ctx.lineWidth = 2.2; 1011 + ctx.beginPath(); 1012 + for (let i = 0; i <= 500; i++) { 1013 + const t = (i / 500) * tnClamped; 1014 + if (i === 0) ctx.moveTo(xOfT(t), yOfV(vlAtTime(t))); 1015 + else ctx.lineTo(xOfT(t), yOfV(vlAtTime(t))); 1016 + } 1017 + ctx.stroke(); 1018 + } else { 1019 + drawStaircase(eventsL, theme.probe2); 1020 + } 971 1021 972 1022 // Current-time cursor (vertical dashed line) 973 1023 if (tn > 0 && tn <= tMax) { ··· 978 1028 ctx.setLineDash([]); 979 1029 } 980 1030 981 - // Current voltage readout 982 - const vNow = vsAtTime(tnClamped); 983 - ctx.fillStyle = theme.tdr; 1031 + // Current voltage readouts 984 1032 ctx.font = "13px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"; 985 1033 ctx.textAlign = "right"; 986 - ctx.fillText("V(det) = " + vNow.toFixed(4) + " V", padL + plotW - 6, padT + 18); 1034 + ctx.fillStyle = theme.tdr; 1035 + ctx.fillText("VS = " + vsAtTime(tnClamped).toFixed(4) + " V", padL + plotW - 6, padT + 18); 1036 + ctx.fillStyle = theme.probe2; 1037 + ctx.fillText("VL = " + vlAtTime(tnClamped).toFixed(4) + " V", padL + plotW - 6, padT + 34); 987 1038 ctx.textAlign = "left"; 988 1039 } 989 1040
+1
style.css
··· 9 9 --warn: #ffd166; 10 10 --ok: #7CFF9B; 11 11 --tdr: #eb5e34; 12 + --probe2: #4a88ff; 12 13 } 13 14 html, body { height: 100%; background: var(--bg); color: var(--ink); margin: 0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; } 14 15 .wrap { max-width: 1100px; margin: 0 auto; padding: 18px 14px 28px; }