1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
import { BaseSource } from './base-source.js';
function clamp(value, min, max) {
return Math.min(max, Math.max(min, value));
}
function createDeterministicNoise(seed) {
const x = Math.sin(seed * 12.9898) * 43758.5453;
return x - Math.floor(x);
}
export class SyntheticWaveSource extends BaseSource {
constructor(config = {}) {
super({
sampleRateHz: 60,
preset: 'telemetry',
amplitude: 1,
noise: 0.08,
...config,
});
this.sourceType = 'synthetic-wave';
this.lastEmittedPlotTimeMs = 0;
}
start(startTimeMs = 0) {
super.start();
this.lastEmittedPlotTimeMs = startTimeMs;
}
stop() {
super.stop();
}
reset(startTimeMs = 0) {
this.lastEmittedPlotTimeMs = startTimeMs;
}
sampleValue(timeMs) {
const seconds = timeMs / 1000;
const amplitude = this.config.amplitude;
const noise = this.config.noise;
const grain = (createDeterministicNoise(timeMs * 0.017) - 0.5) * 2 * noise;
switch (this.config.preset) {
case 'chirp': {
const sweep = Math.sin(seconds * seconds * 1.4);
return amplitude * (0.7 * sweep + 0.3 * Math.sin(seconds * 7.5)) + grain;
}
case 'burst': {
const burstPhase = (seconds % 6) - 1.5;
const burst = Math.sin(seconds * 9.5) * Math.exp(-(burstPhase ** 2) * 0.8);
return amplitude * (0.45 * Math.sin(seconds * 2.1) + burst) + grain;
}
case 'telemetry':
default: {
const carrier = Math.sin(seconds * 2.2);
const secondary = 0.35 * Math.cos(seconds * 6.4 + Math.sin(seconds * 0.8));
const envelope = 0.15 * Math.sin(seconds * 0.33);
return amplitude * (carrier + secondary + envelope) + grain;
}
}
}
update(currentPlotTimeMs) {
if (!this.running) {
return [];
}
const intervalMs = 1000 / clamp(this.config.sampleRateHz, 1, 240);
if (currentPlotTimeMs < this.lastEmittedPlotTimeMs) {
this.lastEmittedPlotTimeMs = currentPlotTimeMs;
return [];
}
const points = [];
while (this.lastEmittedPlotTimeMs + intervalMs <= currentPlotTimeMs) {
this.lastEmittedPlotTimeMs += intervalMs;
points.push({
timeMs: this.lastEmittedPlotTimeMs,
value: this.sampleValue(this.lastEmittedPlotTimeMs),
sourceId: 'synthetic-wave',
});
}
return points;
}
}
|