-
-
-
-
+ {isRecordingRef.current && (
+
+
- {/* Display (Play/Pause) button with tooltip */}
- {isConnected && (
+ {/* Center-aligned buttons */}
+
+ {/* Connection button with tooltip */}
-
- {isDisplay ? (
-
+
+ {isConnected ? (
+ <>
+ Disconnect
+
+ >
) : (
-
+ <>
+ Connect
+
+ >
)}
-
- {isDisplay ? "Pause Data Display" : "Resume Data Display"}
-
+ {isConnected ? "Disconnect Device" : "Connect Device"}
- )}
+ {/* Autoscale/Bit selection */}
+ {isConnected && (
+
+
+
+ {/* Decrease Canvas Button */}
+
+
+
+
+
+
+
+ {Zoom === 1 ? "We can't shrinkage" : "Decrease Zoom"}
+
+
- {/* Record button with tooltip */}
- {isConnected && (
-
-
-
-
- {isRecordingRef.current ? (
-
- ) : (
-
- )}
-
-
-
-
- {!isRecordingRef.current
- ? "Start Recording"
- : "Stop Recording"}
-
-
-
-
- )}
+
- {/* Save/Delete data buttons with tooltip */}
- {isConnected && (
-
-
- {hasData && datasets.length === 1 && (
-
-
-
-
-
-
-
- Save Data as CSV
-
-
- )}
+ {/* Toggle All Channels Button */}
+
+
+
+ {Zoom}x
+
+
+
+ {FullZoom ? "Remove Full Zoom" : "Full Zoom"}
+
+
+
+
-
+ {/* Increase Canvas Button */}
+
+
+
+
+
+
+
+
+ {Zoom >= 10 ? "Maximum Zoom Reached" : "Increase Zoom"}
+
+
+
+
+
+
+ )}
+ {/* Display (Play/Pause) button with tooltip */}
+ {isConnected && (
+
-
-
+
+ {isDisplay ? (
+
+ ) : (
+
+ )}
- Save Recording
+
+ {isDisplay ? "Pause Data Display" : "Resume Data Display"}
+
+
+ )}
+ {/* Record button with tooltip */}
+ {isConnected && (
+
-
+ {isRecordingRef.current ? (
+
+ ) : (
+
+ )}
- Delete Recording
+
+ {!isRecordingRef.current
+ ? "Start Recording"
+ : "Stop Recording"}
+
-
-
- )}
-
- {/* Canvas control buttons with tooltip */}
- {isConnected && (
-
-
-
- {/* Decrease Canvas Button */}
-
-
-
-
-
-
-
-
- {canvasCount === 1
- ? "At Least One Canvas Required"
- : "Decrease Channel"}
-
-
-
+
+ )}
+
+ {/* Save/Delete data buttons with tooltip */}
+ {isConnected && (
+
+
+ {hasData && datasets.length === 1 && (
+
+
+
+
+
+
+
+ Save Data as CSV
+
+
+ )}
- {/* Toggle All Channels Button */}
- CH
+
-
- {showAllChannels
- ? "Hide All Channels"
- : "Show All Channels"}
-
+ Save Recording
-
-
- {/* Increase Canvas Button */}
= 6 || !isDisplay || recData}
+ onClick={deleteDataFromIndexedDB}
+ disabled={!hasData}
>
-
+
-
- {canvasCount >= 6
- ? "Maximum Channels Reached"
- : "Increase Channel"}
-
+ Delete Recording
-
-
- )}
+
+ )}
+ {isConnected && (
+
+
+
+ Filter
+
+
+
+
+
+ {/* Filter Name */}
+
+ {/* Buttons */}
+
+ removeFilterFromAllChannels([0, 1, 2, 3, 4, 5])}
+ className={
+ Object.keys(appliedFiltersRef.current).length === 0
+ ? "bg-red-700 hover:bg-white-500 text-white hover:text-white" // Disabled background
+ : "bg-white-500" // Active background
+ }
+ >
+
+
+ applyFilterToAllChannels([0, 1, 2, 3, 4, 5], 1)}
+ className={
+ Object.keys(appliedFiltersRef.current).length === 6 && Object.values(appliedFiltersRef.current).every((value) => value === 1)
+ ? "bg-green-700 hover:bg-white-500 text-white hover:text-white" // Disabled background
+ : "bg-white-500" // Active background
+ }
+ >
+ 50Hz
+
+ applyFilterToAllChannels([0, 1, 2, 3, 4, 5], 2)}
+ className={
+ Object.keys(appliedFiltersRef.current).length === 6 && Object.values(appliedFiltersRef.current).every((value) => value === 2)
+ ? "bg-green-700 hover:bg-white-500 text-white hover:text-white" // Disabled background
+ : "bg-white-500" // Active background
+ }
+ >
+ 60Hz
+
+
+
+
+ {["CH1", "CH2", "CH3", "CH4", "CH5", "CH6"].map((filterName, index) => (
+
+ {/* Filter Name */}
+
{filterName}
+
+ {/* Buttons */}
+
+ removeFilter(index)}
+ className={
+ appliedFiltersRef.current[index] === undefined
+ ? "bg-red-700 hover:bg-white-500 text-white hover:text-white" // Disabled background
+ : "bg-white-500" // Active background
+ }
+ >
+
+
+ handleFrequencySelection(index, 1)}
+ className={
+ appliedFiltersRef.current[index] === 1
+ ? "bg-green-700 hover:bg-white-500 text-white hover:text-white" // Disabled background
+ : "bg-white-500" // Active background
+ }
+ >
+ 50Hz
+
+ handleFrequencySelection(index, 2)}
+ className={
+ appliedFiltersRef.current[index] === 2
+ ? "bg-green-700 hover:bg-white-500 text-white hover:text-white" // Disabled background
+ : "bg-white-500" // Active background
+ }
+ >
+ 60Hz
+
+
+
+ ))}
+
+
+
+
+
+ )}
+
+
+ {/* Canvas control buttons with tooltip */}
+ {isConnected && (
+
+
+
+ {/* Decrease Canvas Button */}
+
+
+
+
+
+
+
+
+ {canvasCount === 1
+ ? "At Least One Canvas Required"
+ : "Decrease Channel"}
+
+
+
+
+
+
+ {/* Toggle All Channels Button */}
+
+
+
+ CH
+
+
+
+
+ {showAllChannels
+ ? "Hide All Channels"
+ : "Show All Channels"}
+
+
+
+
+
+
+ {/* Increase Canvas Button */}
+
+
+ = 6 || !isDisplay || recData}
+ >
+
+
+
+
+
+ {canvasCount >= 6
+ ? "Maximum Channels Reached"
+ : "Increase Channel"}
+
+
+
+
+
+
+ )}
+
-
);
};
diff --git a/src/components/LandingComp/TechStack.tsx b/src/components/LandingComp/TechStack.tsx
index e4e131b..65b2d3e 100644
--- a/src/components/LandingComp/TechStack.tsx
+++ b/src/components/LandingComp/TechStack.tsx
@@ -43,8 +43,8 @@ const Stack = () => {
name: "Web Serial API",
logo:
theme === "light"
- ? "./assets/dark/favicon.ico"
- : "./assets/light/favicon.ico",
+ ? "./assets/dark/Webserialdark.svg"
+ : "./assets/light/serialdevicelight.svg",
url: "https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API",
description: "For connecting to the serial port of the device.",
},
@@ -52,8 +52,8 @@ const Stack = () => {
name: "IndexedDB API",
logo:
theme === "light"
- ? "./assets/dark/favicon.ico"
- : "./assets/light/favicon.ico",
+ ? "./assets/dark/indexDBdark.svg"
+ : "./assets/light/indexDBlight.svg",
url: "https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API",
description: "IndexedDB is a low-level API for client-side storage.",
},
@@ -124,4 +124,4 @@ const Stack = () => {
);
};
-export default Stack;
+export default Stack;
\ No newline at end of file
diff --git a/src/components/filters.tsx b/src/components/filters.tsx
new file mode 100644
index 0000000..6def59c
--- /dev/null
+++ b/src/components/filters.tsx
@@ -0,0 +1,111 @@
+// TypeScript filter classes for Chords
+// Made with <3 at Upside Down labs
+// Author: Aman Maheshwari
+//
+// Reference:
+// https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.butter.html
+// https://courses.ideate.cmu.edu/16-223/f2020/Arduino/FilterDemos/filter_gen.py
+//
+// Note:
+// filter_gen.py provides C/C++ type functions which we have converted to TS
+
+//Notch Filter 50Hz/60Hz
+export class Notch {
+ // Properties to hold the state of the filter sections
+ private z1_1: number;
+ private z2_1: number;
+
+ private z1_2: number;
+ private z2_2: number;
+
+ private x_1: number;
+ private x_2: number;
+
+ constructor() {
+ // Initialize state variables for both filter sections
+ this.z1_1 = 0;
+ this.z2_1 = 0;
+
+ this.z1_2 = 0;
+ this.z2_2 = 0;
+
+ this.x_1 = 0;
+ this.x_2 = 0;
+ }
+
+ // Method to apply the filter
+ process(input: number, type: number, sample: number): number {
+ if(!type) return input;
+ let output = input;
+ switch (sample) {
+ case 1: // 500Hz
+ switch (type) {
+ case 1: // Notch Sampling rate: 500.0 Hz, frequency: [48.0, 52.0] Hz.
+ this.x_1 = output - (-1.56858163 * this.z1_1) - (0.96424138 * this.z2_1);
+ output = 0.96508099 * this.x_1 + -1.56202714 * this.z1_1 + 0.96508099 * this.z2_1;
+ this.z2_1 = this.z1_1;
+ this.z1_1 = this.x_1;
+
+ // Second filter section
+ this.x_2 = output - (-1.61100358 * this.z1_2) - (0.96592171 * this.z2_2);
+ output = 1.0 * this.x_2 + -1.61854514 * this.z1_2 + 1.0 * this.z2_2;
+ this.z2_2 = this.z1_2;
+ this.z1_2 = this.x_2;
+ break;
+ case 2: // Notch Sampling rate: 500.0 Hz, frequency: [58.0, 62.0] Hz.
+ this.x_1 = output - (-1.40810535 * this.z1_1) - (0.96443153 * this.z2_1);
+ output = 0.96508099 * this.x_1 + (-1.40747202 * this.z1_1) + (0.96508099 * this.z2_1);
+ this.z2_1 = this.z1_1;
+ this.z1_1 = this.x_1;
+
+ // Second filter section
+ this.x_2 = output - (-1.45687509 * this.z1_2) - (0.96573127 * this.z2_2);
+ output = 1.00000000 * this.x_2 + (-1.45839783 * this.z1_2) + (1.00000000 * this.z2_2);
+ this.z2_2 = this.z1_2;
+ this.z1_2 = this.x_2;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case 2: // 250Hz
+ switch (type) {
+ case 1: // Notch Sampling rate: 250.0 Hz, frequency: [48.0, 52.0] Hz.
+ this.x_1 = output - (-0.53127491 * this.z1_1) - (0.93061518 * this.z2_1);
+ output = 0.93137886 * this.x_1 + (-0.57635175 * this.z1_1) + 0.93137886 * this.z2_1;
+ this.z2_1 = this.z1_1;
+ this.z1_1 = this.x_1;
+
+ // Second filter section
+ this.x_2 = output - (-0.66243374 * this.z1_2) - (0.93214913 * this.z2_2);
+ output = 1.00000000 * this.x_2 + (-0.61881558 * this.z1_2) + 1.00000000 * this.z2_2;
+ this.z2_2 = this.z1_2;
+ this.z1_2 = this.x_2;
+ break;
+
+ case 2: // Notch Sampling rate: 250.0 Hz, frequency: [58.0, 62.0] Hz.
+ this.x_1 = output - (-0.05269865 * this.z1_1) - (0.93123336 * this.z2_1);
+ output = 0.93137886 * this.x_1 + (-0.11711144 * this.z1_1) + 0.93137886 * this.z2_1;
+ this.z2_1 = this.z1_1;
+ this.z1_1 = this.x_1;
+
+ // Second filter section
+ this.x_2 = output - (-0.18985625 * this.z1_2) - (0.93153034 * this.z2_2);
+ output = 1.00000000 * this.x_2 + (-0.12573985 * this.z1_2) + 1.00000000 * this.z2_2;
+ this.z2_2 = this.z1_2;
+ this.z1_2 = this.x_2;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return output;
+ }
+}
\ No newline at end of file