From 93b89814186f987057faf5a46d8132b91e837656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Monta=C3=B1es?= Date: Thu, 19 Mar 2026 22:18:45 +0100 Subject: [PATCH] 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 --- js/waveform.js | 51 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/js/waveform.js b/js/waveform.js index fe38711..200a611 100644 --- a/js/waveform.js +++ b/js/waveform.js @@ -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