| |
| |
| |
| |
| |
| |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export function generateDemoTrajectories(numTrajectories = 1000, numSteps = 500, dt = 0.01, diffusion = 0.3) {
|
| const totalFloats = numTrajectories * numSteps * 3;
|
| const data = new Float32Array(totalFloats);
|
|
|
| const phi = (1 + Math.sqrt(5)) / 2;
|
| const contraction = 1 / phi;
|
|
|
| for (let b = 0; b < numTrajectories; b++) {
|
|
|
| const theta0 = Math.random() * Math.PI;
|
| const phi0 = Math.random() * 2 * Math.PI;
|
|
|
| let x = Math.sin(theta0) * Math.cos(phi0);
|
| let y = Math.sin(theta0) * Math.sin(phi0);
|
| let z = Math.cos(theta0);
|
|
|
| const baseIdx = b * numSteps * 3;
|
|
|
| for (let t = 0; t < numSteps; t++) {
|
| const idx = baseIdx + t * 3;
|
|
|
|
|
| data[idx] = x;
|
| data[idx + 1] = y;
|
| data[idx + 2] = z;
|
|
|
|
|
|
|
| const driftScale = contraction * dt;
|
| const dx_drift = -x * driftScale;
|
| const dy_drift = -y * driftScale;
|
| const dz_drift = -z * driftScale;
|
|
|
|
|
| const noiseScale = Math.sqrt(diffusion * dt);
|
| let nx = gaussianRandom() * noiseScale;
|
| let ny = gaussianRandom() * noiseScale;
|
| let nz = gaussianRandom() * noiseScale;
|
|
|
|
|
|
|
| const dot = nx * x + ny * y + nz * z;
|
| nx -= dot * x;
|
| ny -= dot * y;
|
| nz -= dot * z;
|
|
|
|
|
| x += dx_drift + nx;
|
| y += dy_drift + ny;
|
| z += dz_drift + nz;
|
|
|
|
|
| const r = Math.sqrt(x * x + y * y + z * z);
|
| if (r > 1e-8) {
|
|
|
|
|
| const targetRadius = Math.max(0.01, 1.0 - t * contraction * dt * 0.5);
|
| x = (x / r) * targetRadius;
|
| y = (y / r) * targetRadius;
|
| z = (z / r) * targetRadius;
|
| }
|
| }
|
| }
|
|
|
| return data.buffer;
|
| }
|
|
|
| |
| |
|
|
| function gaussianRandom() {
|
| let u = 0, v = 0;
|
| while (u === 0) u = Math.random();
|
| while (v === 0) v = Math.random();
|
| return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
| }
|
|
|