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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user