-
Notifications
You must be signed in to change notification settings - Fork 8
/
analysis.js
144 lines (117 loc) · 4.51 KB
/
analysis.js
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
function removeOffset(wave) {
// Calculate the mean of the wave data
const mean = wave.reduce((acc, val) => acc + val, 0) / wave.length;
// Subtract the mean from each data point to remove the offset
const correctedWave = wave.map(val => val - mean);
return correctedWave;
}
function calculateMedian(values) {
if (values.length === 0) return 0;
values.sort((a, b) => a - b);
let half = Math.floor(values.length / 2);
if (values.length % 2) {
return values[half];
} else {
return (values[half - 1] + values[half]) / 2.0;
}
}
function averagePairs(values) {
let result = [];
let length = values.length;
length = length % 2 !== 0 ? length - 1 : length;
for (let i = 0; i < length; i += 2) {
let pairSum = values[i];
pairSum += values[i + 1];
let pairAverage = pairSum / 2;
result.push(pairAverage);
}
return result;
}
function findPhaseDifference(waveA, waveB, ts) {
// Check if both waveforms have the same length
if (waveA.length !== waveB.length) {
return { gain: NaN, freq: NaN, phase_rad: NaN };
}
waveA = removeOffset(waveA);
waveB = removeOffset(waveB);
// Initialize arrays to store amplitudes and periods
let waveA_amplitudes = [];
let waveB_amplitudes = [];
let periods = [];
let phaseDifferences = [];
const length = waveA.length;
// Initialize variables for zero-crossing detection and RMS calculation
let waveA_polarity = 0;
let prevWaveA_polarity = 0;
let waveB_polarity = 0;
let prevWaveB_polarity = 0;
let found_zeroCrossing = false;
let waveA_sumSquares_P = 0;
let waveB_sumSquares_P = 0;
let periodCounter = 0;
let phaseCounter = 0;
for (let i = 0; i < length; i++) {
// Determine current polarity of waveA
prevWaveA_polarity = waveA_polarity;
waveA_polarity = (waveA[i] > 0) ? 1 : -1;
// Determine current polarity of waveB
prevWaveB_polarity = waveB_polarity;
waveB_polarity = (waveB[i] > 0) ? 1 : -1;
// Detect zero-crossings of waveA to calculate periods and amplitudes
let waveA_zeroCrossing = 0;
if ((waveA_polarity + prevWaveA_polarity) === 0) {
if (waveA_polarity === 1) {
waveA_zeroCrossing = 1; // positive edge
} else {
waveA_zeroCrossing = -1; // negative edge
}
}
if(!found_zeroCrossing) {
if(waveA_zeroCrossing === 1) {
found_zeroCrossing = true;
}
else {
continue;
}
}
// Count phase differences between waveA and waveB
if (waveA_polarity * waveB_polarity < 0) {
phaseCounter++;
} else {
if (phaseCounter > 0) {
if (waveA_polarity * prevWaveA_polarity > 0) {
phaseDifferences.push(-phaseCounter);
} else if (waveB_polarity * prevWaveB_polarity > 0) {
phaseDifferences.push(phaseCounter);
}
}
phaseCounter = 0;
}
// On zero-crossing of waveA, calculate RMS and reset counters
if (waveA_zeroCrossing === 1 && periodCounter > 0) {
waveA_amplitudes.push(Math.sqrt(waveA_sumSquares_P / periodCounter));
waveB_amplitudes.push(Math.sqrt(waveB_sumSquares_P / periodCounter));
periods.push(periodCounter);
waveA_sumSquares_P = 0;
waveB_sumSquares_P = 0;
periodCounter = 0;
}
// Accumulate squares of waveform values for RMS calculation
waveA_sumSquares_P += waveA[i] * waveA[i];
waveB_sumSquares_P += waveB[i] * waveB[i];
periodCounter++;
}
// Calculate median values for amplitude, period, and phase difference
const waveA_ampl = calculateMedian(waveA_amplitudes);
const waveB_ampl = calculateMedian(waveB_amplitudes);
const gain = waveB_ampl / waveA_ampl;
periodCounter = calculateMedian(periods);
const freq = 1 / (periodCounter * ts);
// Calculating the average of the counts measured on the positive polarity side and the negative polarity side of the sine wave.
phaseDifferences = averagePairs(phaseDifferences);
phaseCounter = calculateMedian(phaseDifferences);
const phase_time = phaseCounter * ts;
const phase_rad = (2 * Math.PI * freq) * phase_time;
// Return calculated values
return { gain: gain, freq: freq, phase_rad: phase_rad };
}