Skip to content

Commit 8e181d3

Browse files
author
Ritika Mishra
committed
updated autoscaling and overriding logic
1 parent 11118d1 commit 8e181d3

File tree

1 file changed

+62
-66
lines changed

1 file changed

+62
-66
lines changed

src/app/serial-plotter/page.tsx

Lines changed: 62 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const SerialPlotter = () => {
3434
const bitsref = useRef<number>(10);
3535
const channelsref = useRef<number>(1);
3636
const sweepPositions = useRef<number[]>(new Array(channelsref.current).fill(0)); // Array for sweep positions
37-
37+
const currentScaleRef = useRef({ yMin: -1, yMax: 1 });
3838
const dataRef = useRef<DataPoint[]>([]);
3939

4040
useEffect(() => {
@@ -67,7 +67,7 @@ const SerialPlotter = () => {
6767
});
6868

6969
wglp.update();
70-
}, [selectedChannels]); // ✅ Runs when channels are detected
70+
}, [selectedChannels]);
7171

7272
useEffect(() => {
7373
if (!canvasRef.current) return;
@@ -88,31 +88,53 @@ const SerialPlotter = () => {
8888
});
8989
// You can call wglp.update() here once for the initial setup.
9090
wglp.update();
91-
}, [selectedChannels, viewMode, isConnected]); // Remove data from dependencies if you handle data updates elsewhere
91+
}, [selectedChannels, viewMode, isConnected]);
9292

9393
useEffect(() => {
94-
if (data.length === 0) return;
95-
96-
// Calculate autoscale on the entire data state
97-
const allValues = data.flatMap(dp => dp.values);
98-
const MIN_POINTS_FOR_SCALING = 10;
99-
let yMin, yMax;
100-
101-
if (allValues.length < MIN_POINTS_FOR_SCALING) {
102-
yMin = -1;
103-
yMax = 1;
104-
} else {
105-
yMin = Math.min(...allValues);
106-
yMax = Math.max(...allValues);
107-
}
108-
const yRange = yMax - yMin || 1;
94+
const smoothingFactor = 0.5; // Adjust this between 0 (no change) and 1 (immediate change)
95+
// Update frequently for a continuous effect (e.g., every 50ms)
96+
const interval = setInterval(() => {
97+
if (!wglpRef.current || linesRef.current.length === 0 || dataRef.current.length === 0) return;
98+
99+
// Compute the new autoscale parameters from the full data window
100+
const allValues = dataRef.current.flatMap(dp => dp.values);
101+
const MIN_POINTS_FOR_SCALING = 10;
102+
let newYMin = -1, newYMax = 1;
103+
if (allValues.length >= MIN_POINTS_FOR_SCALING) {
104+
newYMin = Math.min(...allValues);
105+
newYMax = Math.max(...allValues);
106+
}
109107

110-
// Optionally, update all current lines with the new scale
111-
linesRef.current.forEach((line, i) => {
108+
// Smoothly interpolate between the current scale and the new scale
109+
currentScaleRef.current.yMin += smoothingFactor * (newYMin - currentScaleRef.current.yMin);
110+
currentScaleRef.current.yMax += smoothingFactor * (newYMax - currentScaleRef.current.yMax);
111+
112+
const currentYMin = currentScaleRef.current.yMin;
113+
const currentYMax = currentScaleRef.current.yMax;
114+
const yRange = currentYMax - currentYMin || 1;
115+
116+
// Update every point in the buffer using the smoothed scale
117+
linesRef.current.forEach((line, channelIndex) => {
118+
const numPoints = dataRef.current.length;
119+
for (let j = 0; j < numPoints; j++) {
120+
const value = dataRef.current[j].values[channelIndex];
121+
if (value === undefined) continue;
122+
const scaledY = ((value - currentYMin) / yRange) * 2 - 1;
123+
try {
124+
line.setY(j, scaledY);
125+
} catch (e) {
126+
console.error(`Error autoscaling channel ${channelIndex} at point ${j}:`, e);
127+
}
128+
}
129+
});
112130

113-
});
114-
}, [data]);
131+
if (wglpRef.current) {
132+
wglpRef.current.update();
133+
}
134+
}, 10); // Update every 50ms for a continuous, smooth effect
115135

136+
return () => clearInterval(interval);
137+
}, []);
116138

117139

118140
const getLineColor = (index: number): ColorRGBA => {
@@ -141,18 +163,13 @@ const SerialPlotter = () => {
141163
selectedChannelsRef.current = [];
142164
readSerialData(selectedPort);
143165

144-
145166
setTimeout(() => {
146167
sweepPositions.current = new Array(6).fill(0);
147-
148168
}, 6000);
149-
150-
151169
} catch (err) {
152170
console.error("Error connecting to serial:", err);
153171
}
154-
}, [baudRateref.current, setPort, setIsConnected, setRawData, wglpRef, linesRef]);
155-
172+
}, [baudRateref.current, setPort, setIsConnected, setRawData]);
156173

157174
const readSerialData = async (serialPort: SerialPort) => {
158175
try {
@@ -204,7 +221,6 @@ const SerialPlotter = () => {
204221
if (prevChannels.length !== values.length) {
205222
return Array.from({ length: values.length }, (_, i) => i);
206223
}
207-
208224
return prevChannels;
209225
});
210226
}
@@ -216,7 +232,6 @@ const SerialPlotter = () => {
216232
updateWebGLPlot(newData, dataRef.current);
217233
setData(dataRef.current);
218234
}
219-
220235
}
221236
}
222237
serialReader.releaseLock();
@@ -265,37 +280,22 @@ const SerialPlotter = () => {
265280
const updateWebGLPlot = (newData: DataPoint[], windowData: DataPoint[]) => {
266281
if (!wglpRef.current || linesRef.current.length === 0 || newData.length === 0) return;
267282

268-
// Use the entire window for autoscaling
269-
const allValues = windowData.flatMap(dp => dp.values);
270-
const MIN_POINTS_FOR_SCALING = 10;
271-
let yMin, yMax;
272-
273-
if (allValues.length < MIN_POINTS_FOR_SCALING) {
274-
yMin = -1;
275-
yMax = 1;
276-
} else {
277-
yMin = Math.min(...allValues);
278-
yMax = Math.max(...allValues);
279-
}
283+
// Use the smoothed scale from currentScaleRef for the new data
284+
const { yMin, yMax } = currentScaleRef.current;
280285
const yRange = yMax - yMin || 1;
281286

282287
newData.forEach((dataPoint) => {
283-
linesRef.current.forEach((line, i) => {
284-
if (i >= dataPoint.values.length) return;
285-
const yValue = ((dataPoint.values[i] - yMin) / yRange) * 2 - 1;
286-
const currentPos = sweepPositions.current[i] % line.numPoints;
288+
linesRef.current.forEach((line, channelIndex) => {
289+
if (channelIndex >= dataPoint.values.length) return;
290+
const yValue = ((dataPoint.values[channelIndex] - yMin) / yRange) * 2 - 1;
291+
const currentPos = sweepPositions.current[channelIndex] % line.numPoints;
287292
try {
288293
line.setY(currentPos, yValue);
289294
} catch (error) {
290-
console.error(`Error plotting data for line ${i} at position ${currentPos}:`, error);
291-
}
292-
const clearPosition = Math.ceil((currentPos + maxPoints / 100) % line.numPoints);
293-
try {
294-
line.setY(clearPosition, NaN);
295-
} catch (error) {
296-
console.error(`Error clearing data at position ${clearPosition} for line ${i}:`, error);
295+
console.error(`Error plotting data for line ${channelIndex} at pos ${currentPos}:`, error);
297296
}
298-
sweepPositions.current[i] = (currentPos + 1) % line.numPoints;
297+
// Advance the circular buffer pointer
298+
sweepPositions.current[channelIndex] = (currentPos + 1) % line.numPoints;
299299
});
300300
});
301301

@@ -305,6 +305,7 @@ const SerialPlotter = () => {
305305
};
306306

307307

308+
308309
const disconnectSerial = async () => {
309310
if (reader) {
310311
await reader.cancel();
@@ -342,7 +343,6 @@ const SerialPlotter = () => {
342343
const writer = port.writable.getWriter(); // Get writer
343344
await writer.write(new TextEncoder().encode(command + "\n"));
344345
writer.releaseLock(); // Release writer after writing
345-
346346
} catch (err) {
347347
console.error("Error sending command:", err);
348348
}
@@ -371,7 +371,7 @@ const SerialPlotter = () => {
371371
ref={rawDataRef}
372372
className="w-full border rounded-xl shadow-lg bg-[#1a1a2e] text-white overflow-auto flex flex-col"
373373
style={{
374-
height: viewMode === "monitor" ? "calc(100vh - 100px)" : "35vh", // Adjust height when only monitor is shown
374+
height: viewMode === "monitor" ? "calc(100vh - 100px)" : "35vh",
375375
maxHeight: viewMode === "monitor" ? "calc(100vh - 100px)" : "35vh",
376376
minHeight: "35vh",
377377
}}
@@ -385,29 +385,28 @@ const SerialPlotter = () => {
385385
onChange={(e) => setCommand(e.target.value)}
386386
placeholder="Enter command"
387387
className="w-full p-2 text-xs font-semibold rounded bg-gray-800 text-white border border-gray-600"
388-
style={{ height: '36px' }} // Ensure the height is consistent with buttons
388+
style={{ height: '36px' }}
389389
/>
390390

391391
{/* Buttons (Shifted Left) */}
392392
<div className="flex items-center space-x-2 mr-auto">
393393
<Button
394394
onClick={sendCommand}
395395
className="px-4 py-2 text-xs font-semibold bg-gray-500 rounded shadow-md hover:bg-gray-500 transition ml-2"
396-
style={{ height: '36px' }} // Set height equal to the input box
396+
style={{ height: '36px' }}
397397
>
398398
Send
399399
</Button>
400400
<button
401401
onClick={() => setRawData("")}
402402
className="px-4 py-2 text-xs bg-red-600 text-white rounded shadow-md hover:bg-red-700 transition"
403-
style={{ height: '36px' }} // Set height equal to the input box
403+
style={{ height: '36px' }}
404404
>
405405
Clear
406406
</button>
407407
</div>
408408
</div>
409409

410-
411410
{/* Data Display */}
412411
<pre className="text-xs whitespace-pre-wrap break-words px-4 pb-4 flex-grow overflow-auto rounded-xl">
413412
{rawData}
@@ -418,7 +417,6 @@ const SerialPlotter = () => {
418417

419418
{/* Footer Section */}
420419
<footer className="flex flex-col gap-2 sm:flex-row py-2 m-2 w-full shrink-0 items-center justify-center px-2 md:px-4">
421-
422420
{/* Connection Button */}
423421
<div className="flex justify-center">
424422
<Button
@@ -437,8 +435,8 @@ const SerialPlotter = () => {
437435
onClick={() => setViewMode(mode)}
438436
className={`px-4 py-2 text-sm transition font-semibold
439437
${viewMode === mode
440-
? "bg-primary text-white dark:text-gray-900 shadow-md" // Active state
441-
: "bg-gray-500 text-gray-900 hover:bg-gray-300"} // Inactive state (lighter shade)
438+
? "bg-primary text-white dark:text-gray-900 shadow-md"
439+
: "bg-gray-500 text-gray-900 hover:bg-gray-300"}
442440
${index === 0 ? "rounded-xl rounded-r-none" : ""}
443441
${index === arr.length - 1 ? "rounded-xl rounded-l-none" : ""}
444442
${index !== 0 && index !== arr.length - 1 ? "rounded-none" : ""}`}
@@ -448,7 +446,6 @@ const SerialPlotter = () => {
448446
))}
449447
</div>
450448

451-
452449
{/* Baud Rate Selector */}
453450
<div className="flex items-center space-x-2">
454451
<label className="text-sm font-semibold">Baud Rate:</label>
@@ -463,9 +460,8 @@ const SerialPlotter = () => {
463460
</select>
464461
</div>
465462
</footer>
466-
467463
</div>
468464
);
469465
};
470466

471-
export default SerialPlotter;
467+
export default SerialPlotter;

0 commit comments

Comments
 (0)