Skip to content

Commit 1579412

Browse files
committed
WIP
1 parent ba9977b commit 1579412

File tree

5 files changed

+44
-59
lines changed

5 files changed

+44
-59
lines changed

src/app/muscle-strength/page.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@ import { useTheme } from "next-themes";
3636

3737
const MuscleStrength = () => {
3838
const [isDisplay, setIsDisplay] = useState<boolean>(true); // Display state
39-
// UI States for Popovers and Buttons
4039
const sampingrateref = useRef<number>(250);
41-
42-
// Canvas Settings & Channels
4340
const [isFilterPopoverOpen, setIsFilterPopoverOpen] = useState(false);
4441
const connectedDeviceRef = useRef<any | null>(null); // UseRef for device tracking
4542
const canvasContainerRef = useRef<HTMLDivElement>(null);
@@ -712,10 +709,7 @@ const MuscleStrength = () => {
712709
const env2 = envelope2.getEnvelope(Math.abs(channelData[2]));
713710
const env3 = envelope3.getEnvelope(Math.abs(channelData[3]));
714711
updateData(channelData, [env1, env2, env3]);
715-
716712
setBandPowerData([env1, env2, env3]);
717-
718-
719713
channelData = [];
720714
envData = [];
721715
samplesReceivedRef.current += 1;

src/app/npg-lite/page.tsx

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -334,26 +334,16 @@ const NPG_Ble = () => {
334334

335335
let prevSampleCounter: number | null = null;
336336
let channelData: number[] = [];
337-
const notchFilters = Array.from(
338-
{ length: maxCanvasElementCountRef.current },
339-
() => new Notch()
340-
);
341-
const EXGFilters = Array.from(
342-
{ length: maxCanvasElementCountRef.current },
343-
() => new EXGFilter()
344-
);
345-
const pointoneFilter = Array.from(
346-
{ length: maxCanvasElementCountRef.current },
347-
() => new HighPassFilter()
348-
);
349-
350-
notchFilters.forEach((filter) => {
337+
const notchFiltersRef = useRef(Array.from({ length: maxCanvasElementCountRef.current }, () => new Notch()));
338+
const exgFiltersRef = useRef(Array.from({ length: maxCanvasElementCountRef.current }, () => new EXGFilter()));
339+
const pointoneFilterRef = useRef(Array.from({ length: maxCanvasElementCountRef.current }, () => new HighPassFilter()));
340+
notchFiltersRef.current.forEach((filter) => {
351341
filter.setbits(sampingrateref.current);
352342
});
353-
EXGFilters.forEach((filter) => {
343+
exgFiltersRef.current.forEach((filter) => {
354344
filter.setbits("12", sampingrateref.current);
355345
});
356-
pointoneFilter.forEach((filter) => {
346+
pointoneFilterRef.current.forEach((filter) => {
357347
filter.setSamplingRate(sampingrateref.current);
358348
});
359349

@@ -381,8 +371,8 @@ const NPG_Ble = () => {
381371
for (let channel = 0; channel < numChannels; channel++) {
382372
const sample = dataView.getInt16(1 + (channel * 2), false);
383373
channelData.push(
384-
notchFilters[channel].process(
385-
EXGFilters[channel].process(pointoneFilter[channel].process(sample), appliedEXGFiltersRef.current[channel]),
374+
notchFiltersRef.current[channel].process(
375+
exgFiltersRef.current[channel].process(pointoneFilterRef.current[channel].process(sample), appliedEXGFiltersRef.current[channel]),
386376
appliedFiltersRef.current[channel]
387377
)
388378
);

src/components/Connection.tsx

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import React, { useState, useRef, useCallback, useEffect } from "react";
33
import { Button } from "./ui/button";
44
import { Input } from "./ui/input";
5-
import { EXGFilter, Notch,HighPassFilter } from './filters';
5+
import { EXGFilter, Notch, HighPassFilter } from './filters';
66
import { useTheme } from "next-themes";
77
import { useRouter } from "next/navigation"; // Import useRouter
88
import { getCustomColor, lightThemeColors } from './Colors';
@@ -99,7 +99,7 @@ const Connection: React.FC<ConnectionProps> = ({
9999

100100
// States and Refs for Connection & Recording
101101
const [isDeviceConnected, setIsDeviceConnected] = useState<boolean>(false); // Track if the device is connected
102-
const [isserial, setIsserial] = useState(false); // Track if the device is connected
102+
const [isSerial, setIsSerial] = useState(false); // Track if the device is connected
103103

104104
const [FFTDeviceConnected, setFFTDeviceConnected] = useState<boolean>(false); // Track if the device is connected
105105
const isDeviceConnectedRef = useRef<boolean>(false); // Ref to track if the device is connected
@@ -120,7 +120,6 @@ const Connection: React.FC<ConnectionProps> = ({
120120
const [recordingElapsedTime, setRecordingElapsedTime] = useState<number>(0); // State to store the recording duration
121121
const [customTimeInput, setCustomTimeInput] = useState<string>(""); // State to store the custom stop time input
122122
const [leftArrowClickCount, setLeftArrowClickCount] = useState(0); // Track how many times the left arrow is clicked
123-
const [popoverVisible, setPopoverVisible] = useState(false);
124123
const [selectedBitsValue, setSelectedBitsValue] = useState<BitSelection>(10);
125124
const existingRecordRef = useRef<any | undefined>(undefined);
126125
const devicenameref = useRef<string>("");
@@ -346,10 +345,7 @@ const Connection: React.FC<ConnectionProps> = ({
346345
}
347346
}
348347
};
349-
350-
//////////////////////////////////
351348
const workerRef = useRef<Worker | null>(null);
352-
353349
const initializeWorker = () => {
354350
if (!workerRef.current) {
355351
workerRef.current = new Worker(new URL('../../workers/indexedDBWorker.ts', import.meta.url), {
@@ -379,13 +375,11 @@ const Connection: React.FC<ConnectionProps> = ({
379375
});
380376

381377
};
382-
if (FFTDeviceConnected) {
383-
// If FFT device is connected, send only the selected channel
384-
setSelectedChannelsInWorker([selectedChannel]);
385-
} else {
386-
// Otherwise, send all selected channels
387-
setSelectedChannelsInWorker(selectedChannels);
388-
}
378+
useEffect(() => {
379+
const channels = FFTDeviceConnected ? [selectedChannel] : selectedChannels;
380+
setSelectedChannelsInWorker(channels);
381+
}, [FFTDeviceConnected, selectedChannel, selectedChannels]);
382+
389383
const processBuffer = async (bufferIndex: number, canvasCount: number, selectChannel: number[]) => {
390384
if (!workerRef.current) {
391385
initializeWorker();
@@ -736,7 +730,7 @@ const Connection: React.FC<ConnectionProps> = ({
736730
} else {
737731
console.error("Readable stream not available");
738732
}
739-
setIsserial(true);
733+
setIsSerial(true);
740734

741735
setSelectedChannels(initialSelectedChannelsRef.current);
742736
Connection(true);
@@ -755,7 +749,7 @@ const Connection: React.FC<ConnectionProps> = ({
755749

756750
} catch (error) {
757751
await disconnectDevice();
758-
setIsserial(false);
752+
setIsSerial(false);
759753
console.error("Error connecting to device:", error);
760754
toast.error("Failed to connect to device.");
761755
}
@@ -771,7 +765,7 @@ const Connection: React.FC<ConnectionProps> = ({
771765
const savedPorts = JSON.parse(localStorage.getItem('savedDevices') || '[]');
772766
let port = null;
773767
const ports = await navigator.serial.getPorts();
774-
setIsserial(true);
768+
setIsSerial(true);
775769
if (savedPorts.length > 0) {
776770
port = ports.find((p) => {
777771
const info = p.getInfo();
@@ -960,7 +954,7 @@ const Connection: React.FC<ConnectionProps> = ({
960954
writerRef.current = null;
961955
}
962956
}
963-
setIsserial(false);
957+
setIsSerial(false);
964958
snapShotRef.current?.fill(false);
965959
if (readerRef.current) {
966960
try {
@@ -1288,7 +1282,7 @@ const Connection: React.FC<ConnectionProps> = ({
12881282
const SYNC_BYTE1 = 0xc7; // First synchronization byte to identify the start of a packet
12891283
const SYNC_BYTE2 = 0x7c; // Second synchronization byte
12901284
const END_BYTE = 0x01; // End byte to signify the end of a packet
1291-
let previousCounter: number | null = null; // Variable to store the previous counter value for loss detection
1285+
const prevSampleCounterRef = useRef<number | null>(null); // Variable to store the previous counter value for loss detection
12921286
const notchFilters = Array.from({ length: maxCanvasElementCountRef.current }, () => new Notch());
12931287
const EXGFilters = Array.from({ length: maxCanvasElementCountRef.current }, () => new EXGFilter());
12941288
const pointoneFilter = Array.from({ length: maxCanvasElementCountRef.current }, () => new HighPassFilter());
@@ -1383,17 +1377,17 @@ const Connection: React.FC<ConnectionProps> = ({
13831377

13841378
}
13851379

1386-
if (previousCounter !== null) {
1380+
if (prevSampleCounterRef.current !== null) {
13871381
// If there was a previous counter value, check for data loss
1388-
const expectedCounter: number = (previousCounter + 1) % 256; // Calculate the expected counter value
1382+
const expectedCounter: number = (prevSampleCounterRef.current + 1) % 256; // Calculate the expected counter value
13891383
if (counter !== expectedCounter) {
13901384
// Check for data loss by comparing the current counter with the expected counter
13911385
console.warn(
1392-
`Data loss detected! Previous counter: ${previousCounter}, Current counter: ${counter}`
1386+
`Data loss detected! Previous counter: ${prevSampleCounterRef.current}, Current counter: ${counter}`
13931387
);
13941388
}
13951389
}
1396-
previousCounter = counter; // Update the previous counter with the current counter
1390+
prevSampleCounterRef.current = counter; // Update the previous counter with the current counter
13971391
buffer.splice(0, endByteIndex + 1); // Remove the processed packet from the buffer
13981392
} else {
13991393
buffer.splice(0, syncIndex + 1); // If packet is incomplete, remove bytes up to the sync byte
@@ -1549,7 +1543,7 @@ const Connection: React.FC<ConnectionProps> = ({
15491543
<PopoverTrigger asChild>
15501544
<Button
15511545
className="flex items-center gap-1 py-2 px-4 rounded-xl font-semibold"
1552-
onClick={() => (isDeviceConnected ? isserial ? disconnectDevice() : disconnect() : connectToDevice())}
1546+
onClick={() => (isDeviceConnected ? isSerial ? disconnectDevice() : disconnect() : connectToDevice())}
15531547
disabled={isLoading}
15541548
>
15551549
{isLoading ? (

src/components/FFT.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ const FFT = forwardRef(
251251
return mags;
252252
}
253253

254-
private fft(real: Float32Array, imag: Float32Array) {
254+
private fft(real: Float32Array, imag: Float32Array): void {
255255
const n = this.size;
256256
let j = 0;
257257
for (let i = 0; i < n - 1; i++) {
@@ -263,16 +263,19 @@ const FFT = forwardRef(
263263
while (k <= j) { j -= k; k /= 2; }
264264
j += k;
265265
}
266-
for (let len = 2; len <= n; len *= 2) {
267-
const half = len / 2;
268-
for (let i = 0; i < n; i += len) {
269-
for (let j = i, k = 0; j < i + half; j++, k++) {
270-
const tRe = real[j + half] * this.cosTable[k] - imag[j + half] * this.sinTable[k];
271-
const tIm = real[j + half] * this.sinTable[k] + imag[j + half] * this.cosTable[k];
272-
real[j + half] = real[j] - tRe;
273-
imag[j + half] = imag[j] - tIm;
274-
real[j] += tRe;
275-
imag[j] += tIm;
266+
for (let l = 2; l <= n; l *= 2) {
267+
const le2 = l / 2;
268+
for (let k = 0; k < le2; k++) {
269+
const kth = k * (n / l);
270+
const c = this.cosTable[kth], s = this.sinTable[kth];
271+
for (let i = k; i < n; i += l) {
272+
const i2 = i + le2;
273+
const tr = c * real[i2] - s * imag[i2];
274+
const ti = c * imag[i2] + s * real[i2];
275+
real[i2] = real[i] - tr;
276+
imag[i2] = imag[i] - ti;
277+
real[i] += tr;
278+
imag[i] += ti;
276279
}
277280
}
278281
}

src/components/filters.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ export class HighPassFilter {
2525

2626
// Set the sampling rate (250 or 500 Hz)
2727
setSamplingRate(samplingRate: number): void {
28+
if (this.currentSamplingRate !== samplingRate) {
29+
// flush history because the biquad coefficients changed
30+
this.z1 = this.z2 = this.x1 = 0;
31+
}
2832
this.currentSamplingRate = samplingRate;
2933
}
3034

@@ -109,7 +113,7 @@ export class EXGFilter {
109113
}
110114

111115
process(input: number, type: number): number {
112-
if (!type) return input * this.yScale;
116+
if (!type) return input * this.yScale;
113117
let output = input;
114118
let chData = 0;
115119
switch (this.currentSamplingRate) {

0 commit comments

Comments
 (0)