Fix waveform: timeStep increments by 1 per tick, waveZoom = px/step

Each simulation tick now advances timeStep by 1 instead of by simSpeed ms.
waveZoom directly controls pixels per step, so changing clock speed
(the real-time interval) doesn't affect visual wave width, but zooming does.
This matches GTKWave behavior where the x-axis represents clock cycles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jose Luis Montañes
2026-03-19 22:18:45 +01:00
parent c162adb1df
commit 93b8981418

View File

@@ -31,8 +31,8 @@ export function recordSample() {
if (!changed && state.timeStep > 0) return;
// Manual toggles advance by simSpeed too for consistency
state.timeStep += state.simSpeed;
// Each tick = 1 step (visual width determined by waveZoom px/step)
state.timeStep += 1;
gates.forEach(g => {
if (!waveData[g.id]) waveData[g.id] = [];
const arr = waveData[g.id];
@@ -44,8 +44,8 @@ export function recordSample() {
}
export function forceRecordSample() {
// Advance time by the current simSpeed (in ms) to reflect real time
state.timeStep += state.simSpeed;
// Each tick = 1 step
state.timeStep += 1;
state.gates.forEach(g => {
if (!state.waveData[g.id]) state.waveData[g.id] = [];
state.waveData[g.id].push({ t: state.timeStep, value: g.value });
@@ -73,10 +73,7 @@ export function setEvaluateAll(fn) {
export function updateWaveInfo() {
const totalSamples = Object.values(state.waveData).reduce((sum, arr) => sum + arr.length, 0);
const timeLabel = state.timeStep >= 1000
? `${(state.timeStep/1000).toFixed(1)}s`
: `${state.timeStep}ms`;
document.getElementById('wave-info').textContent = `T=${timeLabel} | ${totalSamples} samples`;
document.getElementById('wave-info').textContent = `T=${state.timeStep} | ${totalSamples} samples`;
}
export function clearWaveData() {
@@ -126,36 +123,37 @@ export function drawWaveforms() {
return;
}
// pxPerMs: how many pixels per millisecond of simulation time
const pxPerMs = state.waveZoom / 100; // waveZoom=20 → 0.2 px/ms
// pxPerStep: how many pixels per simulation step
const pxPerStep = state.waveZoom;
// Total width in pixels for all recorded time
const totalPx = state.timeStep * pxPerMs;
const totalPx = state.timeStep * pxPerStep;
// Visible width in ms
const visibleMs = wc.width / pxPerMs;
// Visible width in steps
const visibleSteps = wc.width / pxPerStep;
// Auto-scroll to show latest (only if near the end)
const isNearEnd = state.waveScroll >= state.timeStep - visibleMs - state.simSpeed * 2;
const isNearEnd = state.waveScroll >= state.timeStep - visibleSteps - 2;
if (totalPx > wc.width && isNearEnd) {
state.waveScroll = state.timeStep - visibleMs;
state.waveScroll = state.timeStep - visibleSteps;
}
state.waveScroll = Math.max(0, state.waveScroll);
// Helper: convert simulation time (ms) to pixel X
const tToX = (t) => (t - state.waveScroll) * pxPerMs;
// Helper: convert simulation step to pixel X
const tToX = (t) => (t - state.waveScroll) * pxPerStep;
// Draw time grid (every gridMs milliseconds)
let gridMs = 500;
if (pxPerMs * gridMs < 30) gridMs = 1000;
if (pxPerMs * gridMs < 30) gridMs = 2000;
if (pxPerMs * gridMs > 200) gridMs = 200;
if (pxPerMs * gridMs > 200) gridMs = 100;
// Draw time grid (every gridStep steps)
let gridStep = 5;
if (pxPerStep * gridStep < 30) gridStep = 10;
if (pxPerStep * gridStep < 30) gridStep = 20;
if (pxPerStep * gridStep < 30) gridStep = 50;
if (pxPerStep * gridStep > 200) gridStep = 2;
if (pxPerStep * gridStep > 200) gridStep = 1;
wctx.strokeStyle = '#151520';
wctx.lineWidth = 1;
const startT = Math.floor(state.waveScroll / gridMs) * gridMs;
for (let t = startT; t <= state.timeStep; t += gridMs) {
const startT = Math.floor(state.waveScroll / gridStep) * gridStep;
for (let t = startT; t <= state.timeStep; t += gridStep) {
const x = tToX(t);
if (x < 0 || x > wc.width) continue;
wctx.beginPath();
@@ -166,8 +164,7 @@ export function drawWaveforms() {
wctx.fillStyle = '#333';
wctx.font = '9px monospace';
wctx.textAlign = 'center';
const label = t >= 1000 ? `${(t/1000).toFixed(1)}s` : `${t}ms`;
wctx.fillText(label, x, 10);
wctx.fillText(`${t}`, x, 10);
}
// Row dividers