summaryrefslogtreecommitdiff
path: root/web-timeplot/src/test-data-generators.js
diff options
context:
space:
mode:
Diffstat (limited to 'web-timeplot/src/test-data-generators.js')
-rw-r--r--web-timeplot/src/test-data-generators.js530
1 files changed, 0 insertions, 530 deletions
diff --git a/web-timeplot/src/test-data-generators.js b/web-timeplot/src/test-data-generators.js
deleted file mode 100644
index 02bc0ad..0000000
--- a/web-timeplot/src/test-data-generators.js
+++ /dev/null
@@ -1,530 +0,0 @@
-/**
- * Test Data Generators - Classes for generating fake/test data patterns
- *
- * These generators produce various types of synthetic data for testing
- * and visualizing the waterfall graphs with realistic patterns.
- */
-
-/**
- * Base class for all data generators
- */
-class DataGenerator {
- constructor(config = {}) {
- this.sampleRate = config.sampleRate || 100; // Samples per second
- this.amplitude = config.amplitude || 1.0;
- this.offset = config.offset || 0.0;
- this.time = 0;
- }
-
- /**
- * Generate a single sample at the current time
- * @returns {number} The generated value
- */
- sample() {
- throw new Error('sample() must be implemented by subclass');
- }
-
- /**
- * Generate an array of samples
- * @param {number} count - Number of samples to generate
- * @returns {Array<number>} Array of generated values
- */
- generateSamples(count) {
- const samples = [];
- for (let i = 0; i < count; i++) {
- samples.push(this.sample());
- this.time += 1 / this.sampleRate;
- }
- return samples;
- }
-
- /**
- * Generate a line of points for waterfall display
- * @param {number} pointCount - Number of points in the line
- * @param {number} width - Width of the display area
- * @returns {Array<{x: number, y: number}>} Array of points
- */
- generateLine(pointCount, width) {
- const points = [];
- const samples = this.generateSamples(pointCount);
-
- for (let i = 0; i < pointCount; i++) {
- const x = (i / pointCount) * width;
- const y = samples[i] * this.amplitude + this.offset;
- points.push({ x, y });
- }
-
- return points;
- }
-
- reset() {
- this.time = 0;
- }
-}
-
-/**
- * Sine Wave Generator - Classic sinusoidal wave
- */
-export class SineWaveGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.frequency = config.frequency || 1.0; // Hz
- this.phase = config.phase || 0.0; // Radians
- }
-
- sample() {
- const value = Math.sin(2 * Math.PI * this.frequency * this.time + this.phase);
- return value;
- }
-}
-
-/**
- * Square Wave Generator - Digital-style square wave
- */
-export class SquareWaveGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.frequency = config.frequency || 1.0;
- this.dutyCycle = config.dutyCycle || 0.5; // 0.0 to 1.0
- }
-
- sample() {
- const period = 1 / this.frequency;
- const phase = (this.time % period) / period;
- return phase < this.dutyCycle ? 1.0 : -1.0;
- }
-}
-
-/**
- * Sawtooth Wave Generator - Linear ramp wave
- */
-export class SawtoothWaveGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.frequency = config.frequency || 1.0;
- }
-
- sample() {
- const period = 1 / this.frequency;
- const phase = (this.time % period) / period;
- return 2 * phase - 1; // -1 to 1
- }
-}
-
-/**
- * Triangle Wave Generator - Linear up/down wave
- */
-export class TriangleWaveGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.frequency = config.frequency || 1.0;
- }
-
- sample() {
- const period = 1 / this.frequency;
- const phase = (this.time % period) / period;
- return phase < 0.5
- ? 4 * phase - 1
- : 3 - 4 * phase;
- }
-}
-
-/**
- * White Noise Generator - Random noise
- */
-export class WhiteNoiseGenerator extends DataGenerator {
- sample() {
- return Math.random() * 2 - 1; // -1 to 1
- }
-}
-
-/**
- * Pink Noise Generator - 1/f noise (more realistic than white noise)
- */
-export class PinkNoiseGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- // Paul Kellet's refined method
- this.b0 = 0;
- this.b1 = 0;
- this.b2 = 0;
- this.b3 = 0;
- this.b4 = 0;
- this.b5 = 0;
- this.b6 = 0;
- }
-
- sample() {
- const white = Math.random() * 2 - 1;
- this.b0 = 0.99886 * this.b0 + white * 0.0555179;
- this.b1 = 0.99332 * this.b1 + white * 0.0750759;
- this.b2 = 0.96900 * this.b2 + white * 0.1538520;
- this.b3 = 0.86650 * this.b3 + white * 0.3104856;
- this.b4 = 0.55000 * this.b4 + white * 0.5329522;
- this.b5 = -0.7616 * this.b5 - white * 0.0168980;
- const pink = this.b0 + this.b1 + this.b2 + this.b3 + this.b4 + this.b5 + this.b6 + white * 0.5362;
- this.b6 = white * 0.115926;
- return pink * 0.11; // Normalize
- }
-}
-
-/**
- * Perlin Noise Generator - Smooth, continuous noise
- */
-export class PerlinNoiseGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.frequency = config.frequency || 1.0;
- this.octaves = config.octaves || 4;
- this.persistence = config.persistence || 0.5;
- }
-
- // Simple 1D Perlin-like noise
- noise(x) {
- const i = Math.floor(x);
- const f = x - i;
-
- // Fade curve
- const u = f * f * (3 - 2 * f);
-
- // Hash function for pseudo-random gradients
- const hash = (n) => {
- n = (n << 13) ^ n;
- return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
- };
-
- return (1 - u) * hash(i) + u * hash(i + 1);
- }
-
- sample() {
- let value = 0;
- let amplitude = 1;
- let frequency = this.frequency;
- let maxValue = 0;
-
- for (let i = 0; i < this.octaves; i++) {
- value += this.noise(this.time * frequency) * amplitude;
- maxValue += amplitude;
- amplitude *= this.persistence;
- frequency *= 2;
- }
-
- return value / maxValue;
- }
-}
-
-/**
- * Pulse/Spike Generator - Random spikes/pulses
- */
-export class PulseGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.pulseRate = config.pulseRate || 0.05; // Probability per sample
- this.pulseWidth = config.pulseWidth || 0.01; // Duration in seconds
- this.pulseAmplitude = config.pulseAmplitude || 1.0;
- this.currentPulse = null;
- }
-
- sample() {
- // Check if we're in a pulse
- if (this.currentPulse) {
- if (this.time >= this.currentPulse.endTime) {
- this.currentPulse = null;
- } else {
- return this.pulseAmplitude;
- }
- }
-
- // Random chance to start new pulse
- if (Math.random() < this.pulseRate) {
- this.currentPulse = {
- startTime: this.time,
- endTime: this.time + this.pulseWidth,
- };
- return this.pulseAmplitude;
- }
-
- return 0;
- }
-}
-
-/**
- * Burst Generator - Bursts of activity with quiet periods
- */
-export class BurstGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.burstDuration = config.burstDuration || 1.0; // Seconds
- this.quietDuration = config.quietDuration || 2.0; // Seconds
- this.burstFrequency = config.burstFrequency || 5.0; // Hz during burst
- this.currentState = 'quiet';
- this.stateStartTime = 0;
- }
-
- sample() {
- const elapsed = this.time - this.stateStartTime;
-
- // State transitions
- if (this.currentState === 'quiet' && elapsed >= this.quietDuration) {
- this.currentState = 'burst';
- this.stateStartTime = this.time;
- } else if (this.currentState === 'burst' && elapsed >= this.burstDuration) {
- this.currentState = 'quiet';
- this.stateStartTime = this.time;
- }
-
- // Generate value based on state
- if (this.currentState === 'burst') {
- return Math.sin(2 * Math.PI * this.burstFrequency * this.time);
- } else {
- return 0;
- }
- }
-}
-
-/**
- * Chirp Generator - Frequency sweep signal
- */
-export class ChirpGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.startFreq = config.startFreq || 0.5; // Hz
- this.endFreq = config.endFreq || 10.0; // Hz
- this.duration = config.duration || 5.0; // Seconds
- }
-
- sample() {
- const t = this.time % this.duration;
- const progress = t / this.duration;
- const freq = this.startFreq + (this.endFreq - this.startFreq) * progress;
- return Math.sin(2 * Math.PI * freq * t);
- }
-}
-
-/**
- * Composite Generator - Combine multiple generators
- */
-export class CompositeGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.generators = config.generators || [];
- this.weights = config.weights || this.generators.map(() => 1.0);
- }
-
- sample() {
- let sum = 0;
- let weightSum = 0;
-
- for (let i = 0; i < this.generators.length; i++) {
- sum += this.generators[i].sample() * this.weights[i];
- weightSum += this.weights[i];
- }
-
- return weightSum > 0 ? sum / weightSum : 0;
- }
-
- generateSamples(count) {
- const samples = [];
- for (let i = 0; i < count; i++) {
- samples.push(this.sample());
- // Advance all child generators
- this.generators.forEach(gen => gen.time += 1 / gen.sampleRate);
- }
- return samples;
- }
-}
-
-/**
- * FM (Frequency Modulation) Generator - One signal modulates another
- */
-export class FMGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.carrierFreq = config.carrierFreq || 5.0; // Hz
- this.modulatorFreq = config.modulatorFreq || 0.5; // Hz
- this.modulationIndex = config.modulationIndex || 2.0;
- }
-
- sample() {
- const modulator = Math.sin(2 * Math.PI * this.modulatorFreq * this.time);
- const instantFreq = this.carrierFreq + this.modulationIndex * modulator;
- return Math.sin(2 * Math.PI * instantFreq * this.time);
- }
-}
-
-/**
- * Exponential Decay Generator - Exponentially decaying signal
- */
-export class ExponentialDecayGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.decayRate = config.decayRate || 1.0; // 1/seconds
- this.oscillationFreq = config.oscillationFreq || 5.0; // Hz
- }
-
- sample() {
- const envelope = Math.exp(-this.decayRate * this.time);
- const oscillation = Math.sin(2 * Math.PI * this.oscillationFreq * this.time);
- return envelope * oscillation;
- }
-}
-
-/**
- * Step Function Generator - Random walk / brownian motion
- */
-export class RandomWalkGenerator extends DataGenerator {
- constructor(config = {}) {
- super(config);
- this.stepSize = config.stepSize || 0.1;
- this.currentValue = 0;
- this.bounds = config.bounds || { min: -5, max: 5 };
- }
-
- sample() {
- // Random step
- const step = (Math.random() - 0.5) * this.stepSize;
- this.currentValue += step;
-
- // Apply bounds
- this.currentValue = Math.max(this.bounds.min, Math.min(this.bounds.max, this.currentValue));
-
- return this.currentValue;
- }
-}
-
-// ============================================================================
-// Example Usage and Presets
-// ============================================================================
-
-/**
- * Factory function to create common test scenarios
- */
-export class TestDataFactory {
- static createSimpleSine(amplitude = 30) {
- return new SineWaveGenerator({
- frequency: 2.0,
- amplitude: amplitude,
- sampleRate: 100,
- });
- }
-
- static createNoisySine(amplitude = 30) {
- const sine = new SineWaveGenerator({
- frequency: 2.0,
- amplitude: amplitude * 0.8,
- sampleRate: 100,
- });
-
- const noise = new WhiteNoiseGenerator({
- amplitude: amplitude * 0.2,
- sampleRate: 100,
- });
-
- return new CompositeGenerator({
- generators: [sine, noise],
- weights: [1.0, 1.0],
- });
- }
-
- static createComplexPattern(amplitude = 30) {
- const low = new SineWaveGenerator({
- frequency: 0.5,
- amplitude: amplitude * 0.4,
- sampleRate: 100,
- });
-
- const mid = new SineWaveGenerator({
- frequency: 3.0,
- amplitude: amplitude * 0.3,
- sampleRate: 100,
- });
-
- const high = new SineWaveGenerator({
- frequency: 8.0,
- amplitude: amplitude * 0.2,
- sampleRate: 100,
- });
-
- const noise = new PinkNoiseGenerator({
- amplitude: amplitude * 0.1,
- sampleRate: 100,
- });
-
- return new CompositeGenerator({
- generators: [low, mid, high, noise],
- weights: [1.0, 1.0, 1.0, 1.0],
- });
- }
-
- static createBurstySignal(amplitude = 30) {
- return new BurstGenerator({
- amplitude: amplitude,
- burstDuration: 0.5,
- quietDuration: 1.5,
- burstFrequency: 10.0,
- sampleRate: 100,
- });
- }
-
- static createSmoothNoise(amplitude = 30) {
- return new PerlinNoiseGenerator({
- amplitude: amplitude,
- frequency: 2.0,
- octaves: 3,
- persistence: 0.5,
- sampleRate: 100,
- });
- }
-
- static createFrequencySweep(amplitude = 30) {
- return new ChirpGenerator({
- amplitude: amplitude,
- startFreq: 0.5,
- endFreq: 10.0,
- duration: 3.0,
- sampleRate: 100,
- });
- }
-
- static createModulatedSignal(amplitude = 30) {
- return new FMGenerator({
- amplitude: amplitude,
- carrierFreq: 5.0,
- modulatorFreq: 0.3,
- modulationIndex: 3.0,
- sampleRate: 100,
- });
- }
-
- static createRandomWalk(amplitude = 30) {
- return new RandomWalkGenerator({
- stepSize: 0.5,
- bounds: { min: -amplitude, max: amplitude },
- sampleRate: 100,
- });
- }
-}
-
-/**
- * Example: How to use with WaterfallGraph
- *
- * // Create a generator
- * const generator = TestDataFactory.createComplexPattern(30);
- *
- * // In your graph's addLine method:
- * addLine(time, graphIdx) {
- * const line = {
- * points: generator.generateLine(this.pointsPerLine, this.width),
- * yOffset: 0,
- * color: this.generateColor(time),
- * };
- * this.lines.push(line);
- * }
- *
- * // Or generate custom samples:
- * const samples = generator.generateSamples(100);
- * const points = samples.map((y, i) => ({
- * x: (i / samples.length) * width,
- * y: y
- * }));
- */