Looking to create a custom Heart Rate and HRV widget

nushaabnushaab Toronto, ON
edited June 20 in OpenBCI_GUI

Hello,
I am looking to create a custom Heart Rate and HRV widget that simply displays these values in real-time, based on a 3-lead ECG electrode set up, where two leads are attached to Cyton channel N6P, and one lead is grounded on BIAS.
I was wondering how I could go about accessing the live, incoming data from the channel? I've attached the code I have right now for reference.
Thanks!

import controlP5.*;
import processing.core.PApplet;

class W_HeartRate extends Widget {

    ControlP5 localCP5;
    double hr = 72, hrv = 0;
    long instance1 = 0, timer;
    int value = 0, count = 0;
    boolean flag = false;

    W_HeartRate(PApplet _parent) {
        super(_parent);

        localCP5 = new ControlP5(ourApplet);
        localCP5.setGraphics(ourApplet, 0, 0);
        localCP5.setAutoDraw(false);

        // Initialize timer
        timer = millis();
    }

    public void update() {
        super.update();

        // Fetch data from channel 6
        float[] ecgData = getLiveECGData(6); // Channel 6 data

        // Process data to update heart rate and HRV
        processECGData(ecgData);
    }

    private float[] getLiveECGData(int channelIndex) {
        // Get the live ECG data for the specified channel
        // Replace this with actual logic to fetch data from OpenBCI board
        int nPoints = 100; // Number of data points to fetch
        float[] data = new float[nPoints];
        for (int i = 0; i < nPoints; i++) {
            data[i] = dataProcessingFilteredBuffer[channelIndex][i];
        }
        return data;
    }

    private void processECGData(float[] ecgData) {
        int threshold = 100;
        int timerValue = 10000; // 10 seconds in milliseconds

        for (int i = 0; i < ecgData.length; i++) {
            value = (int) map(ecgData[i], 250, 400, 0, 100); // Flatten the ECG values

            if (value > threshold && !flag) {
                count++;
                flag = true;
                long now = millis();
                long interval = now - instance1; // RR interval in milliseconds
                instance1 = now;

                if (interval > 0) {
                    hrv = hr / 60.0 - interval / 1000.0;
                }
            } else if (value < threshold) {
                flag = false;
            }

            if ((millis() - timer) > timerValue) {
                hr = count * 6;
                timer = millis();
                count = 0;
            }
        }
    }

    public void draw() {
        super.draw();
        drawHeartRate();
        localCP5.draw();
    }

    private void drawHeartRate() {
        pushStyle();
        fill(50);
        textFont(createFont("Arial", 20));
        fill(255, 0, 0); // Red color for heart rate text
        textAlign(LEFT, CENTER);
        text("Heart Rate: " + (int) hr + " BPM", x + 20, y + 20);
        text("HRV: " + hrv, x + 20, y + 50);
        popStyle();
    }

    public void screenResized() {
        super.screenResized();
        localCP5.setGraphics(ourApplet, 0, 0);
    }

    public void mousePressed() {
        super.mousePressed();
    }

    public void mouseReleased() {
        super.mouseReleased();
    }
}

Comments

  • wjcroftwjcroft Mount Shasta, CA

    Hi Nushaab,

    It appears you have found the Widget tutorial,

    https://docs.openbci.com/Software/OpenBCISoftware/GUIWidgets/#custom-widget

    Which suggests:

    • To see how to access global data structures like FFT data and Time Series data, check out how the other widgets are accessing data in their update() functions

    So your best bet is to look over other widget source code files (filenames beginning with 'W_xxx') in the Github:

    https://github.com/OpenBCI/OpenBCI_GUI/tree/master/OpenBCI_GUI

    There is no specific API or global structures descriptions on the GUI data access techniques. You just have to find a 'similar' widget to what you are doing and see how it grabbed the data.

    Richard @retiutut may have some tips if you have questions as you dive into the code.

    On the other hand, you would probably have a much easier time writing your program, if you just called Brainflow data stream functions directly. Numerous examples on this page:

    https://brainflow.org/
    https://brainflow.readthedocs.io/en/stable/Examples.html

    William

  • IffatIqbalIffatIqbal Toronto, ON

    Hi! I am trying to make a widget for ECG that just simply shows the Heart Rate and HRV (variability). If I am using a 3-lead ecg system connected to AGND and top and bottom of N6P how do I gather the data--from which class in the OPENBCI_GUI do I grab this data from? Alternately, is there any custom widget for this purpose?

    I can clearly see the EKG in the time series but I don't know what threshold to use for the R-peaks so I used standard deviation.

  • wjcroftwjcroft Mount Shasta, CA

    Hi @IffatIqbal,

    I merged your new thread into this existing thread. See some of the previous comments.

    By the way AGND is NOT used for the ground connection. You want to use the Bias/Ground pin instead.

    https://docs.openbci.com/GettingStarted/Biosensing-Setups/ECGSetup/

    William

Sign In or Register to comment.