I have ECG, Pulse rate, Respiratory Rate and NIBP to show in LightningChart JS
Medical Dashboard
which used a global sampling rate which is common to all channels [ecg,pulseRate,respRate,nibp]
. But the sampling rate would change for each channel. ECG and Pulse Rate will have 256, and Respiratory rate will have 128.
I tried below but didn't work, as it now becomes 128 samples/second to all the channels.
Code:
const SAMPLE_RATE = 256;
const SAMPLE_RATE_NEW = 128;
Below is the function i used with my changes.
let tSamplePos = window.performance.now();
let tSamplePosNew = window.performance.now();
let iSampleX = 0;
const addData = () => {
const tNow = window.performance.now();
const seriesNewPoints = seriesList.map((_) => []);
while (tNow > tSamplePos) {
const x = tSamplePos;
const xNew = tSamplePosNew;
for (let i = 0; i < seriesList.length; i += 1) {
const channel = channels[i];
const dataSet = channel.dataSet;
const sample = dataSet[iSampleX % dataSet.length];
if (i !== 2) {
// @ts-ignore
seriesNewPoints[i].push({ x, y: sample });
} else {
// @ts-ignore
seriesNewPoints[i].push({ xNew, y: sample });
}
// // @ts-ignore
//seriesNewPoints[i].push({ x, y: sample });
if (channel.name === "Electrocardiogram") {
updateBpm(sample);
}
}
tSamplePos += 1000 / SAMPLE_RATE;
tSamplePosNew += 1000 / SAMPLE_RATE_NEW;
iSampleX += 1;
}
seriesList.forEach((series, i) => series.add(seriesNewPoints[i]));
channelIncomingDataPointsCount += seriesNewPoints[0].length;
requestAnimationFrame(addData);
Setting the sampling rate:
let channelIncomingDataPointsCount = 0;
let channelIncomingDataPointsLastUpdate = window.performance.now();
setInterval(() => {
const tNow = window.performance.now();
const chDataPointsPerSecond = Math.round(
(channelIncomingDataPointsCount * 1000) /
(tNow - channelIncomingDataPointsLastUpdate)
);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const bpm = (beatsCount * 60 * 1000) / (tNow - tStart);
uiList.forEach((ui, i) => {
ui.labelSampleRate.setText(`${chDataPointsPerSecond} samples / second`);
});
channelIncomingDataPointsCount = 0;
channelIncomingDataPointsLastUpdate = tNow;
}, 2000);
How do i get different sampling rates in different channel? I am using this medical dashboard Online Medical Dashboard
Entire code is above.
I have tried multiple different solution but none of them worked. Need guidance on how to do it.
I tried using different sampling rate and push the data inside array, but i am not getting different sampling rates. Why I want this? The charts formed are different in different devices (laptop/desktop).
Since you are asking how to get different sample rates, I assume your data source doesn't include timestamps (X). Here's one way of achieving this:
The key here is preconfigured stream rate for each channel (128/256), which is supplied to PointLineAreaSet.appendSamples
method as step
parameter. Only incoming yValues
are specified, leaving X coordinates filled in automatically.
As long as the incoming data matches the configuration (e.g. ECG indeed receives 2x as many Y values as "NIPB"), then this works wonderfully.
Zoom in to confirm that ECG & Pulse rate channels indeed have more data points than the other channels.
const {
AxisScrollStrategies,
AxisTickStrategies,
emptyFill,
emptyLine,
lightningChart,
Themes,
} = lcjs
const chart = lightningChart().ChartXY({ theme: Themes.light, defaultAxisX: { type: 'linear-highPrecision' } })
.setTitle('')
.setCursorMode('show-all-interpolated')
chart.axisX
.setTickStrategy(AxisTickStrategies.Time)
.setScrollStrategy(AxisScrollStrategies.progressive)
.setDefaultInterval((state) => ({
end: state.dataMax ?? 0,
start: (state.dataMax ?? 0) - 10_000,
stopAxisAfter: false,
}))
chart.axisY.dispose()
const channels = [
{ name: 'ECG', rate: 256 },
{ name: 'Pulse rate', rate: 256 },
{ name: 'Resp rate', rate: 128 },
{ name: 'NIBP', rate: 128 },
].map((info, i) => {
const axisY = chart.addAxisY({iStack: i})
.setTitle(info.name)
.setTitleRotation(0)
.setChartInteractionZoomByWheel(false)
const series = chart.addPointLineAreaSeries({ dataPattern: 'ProgressiveX', axisY })
.setAreaFillStyle(emptyFill)
.setStrokeStyle(stroke => stroke.setThickness(1))
.setMaxSampleCount(100_000)
return { ...info, axisY, series }
})
// Incoming data Y's only. X's automatically indexed according to known channel sample rate
const handleIncomingSamples = (allYs) => {
channels.forEach((ch, i) => {
const ys = allYs[i]
ch.series.appendSamples({ yValues: ys, step: 1000 / ch.rate })
})
}
// NOTE: This demo code WILL run out of sync (time axis will progress slower/faster than actual time)
// This is because `setInterval` may happen more or less frequently than requested.
setInterval(() => {
const allYs = channels.map((ch) => {
const sampleCount = ch.rate / 128
return new Array(sampleCount).fill(0).map(_ => performance.now() % 1000 + 100 * Math.random())
})
handleIncomingSamples(allYs)
}, 1000/128)
<script src="https://cdn.jsdelivr.net/npm/@lightningchart/lcjs@6.0.3/dist/lcjs.iife.js"></script>