Too Many Frames?
Just as we are concerned with bottlenecks and other obstacles to delivering performant code, we must also be aware of the users experience on higher end systems. On even a moderate desktop this code is perfectly happy delivering 240 frames per second, which is far to fast for the learner to examine the wave function's physical evolution.
You can never have too many frames! We assume a nominal frame rate of 60 FPS, and put any additional frames to work producing a smoother animation. At 60 FPS we execute a nominal number of finite difference steps per frame, above 60 FPS we reduce the finite difference steps per frame proportionately. As we saw when doing performance measurements all the information we need to determine the actual FPS is available through the requestAnimationFrame mechanism.
It is also clear that we can no longer use the simple frame count to limit the duration of the simulation. Instead, we switch to counting the number of FDTD steps.
Start with a set of parameters that describe and track our progress through the simulation. We can tune how
fast the simulation progresses by changing the NOMINAL_STEPS_PER_FRAME or the
NOMINAL_FPS.
// Number of finite difference steps to compute and animate, ~1500 frames at 60 FPS
const MAX_STEPS = 750000;
// Number of delta t time steps per frame
const NOMINAL_STEPS_PER_FRAME = 500;
const NOMINAL_FPS = 60.0;
const SECONDS_PER_MILLISECOND = .001;
// FDTD steps so far
let nsteps = 0;
// The requestAnimationFrame provided time stamp for the last frame.
let lastFrameTime = 0.0;
The nextFrame method tracks the time between animated frames, and adjusts the simulation steps per
animation frame downward when the frame rate exceeds 60 FPS. When finished, it resubmits itself for the next
frame.
/**
* Compute and display the next frame of our simulation. Also maintain an FPS
* display.
*
* @param currentFrameTime A high @link{https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp|resolution
* time stamp} for the end of the previous frame rendering.
*/
function nextFrame(currentFrameTime) {
let stepsThisFrame;
currentFrameTime *= SECONDS_PER_MILLISECOND;
if (lastFrameTime) {
const deltaT = currentFrameTime-lastFrameTime;
fpsDisplay.innerText = (1.0/deltaT).toFixed(2);
stepsThisFrame = Math.min(1.0, deltaT*NOMINAL_FPS) * NOMINAL_STEPS_PER_FRAME;
} else {
stepsThisFrame = NOMINAL_STEPS_PER_FRAME;
}
schrodinger.step(stepsThisFrame);
schrodingerResults.render(schrodinger.getWaveFunctionBuffer0());
nsteps += stepsThisFrame;
lastFrameTime = currentFrameTime;
if (nsteps < MAX_STEPS) {
requestAnimationFrame(nextFrame)
}
}