Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Band Power Widget and Add Average Band Power data type to Networking #1034

Merged
merged 2 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### Bug Fixes
* Stop data stream when no data received after 5 seconds #1011
* Revisit Ganglion Impedance widget so it behaves like new Cyton Impedance Widget #1021
* Fix dropdown backgrounds in Networking Widget

### Improvements
* Update to Processing 4 #674 #1025
Expand All @@ -12,6 +13,7 @@
* Clarify Cyton Smoothing feature #1027
* Set Cyton Smoothing on by default and increase communication with a popup and additional Help button #1026
* Update help text for various buttons across the GUI to help new and existing users
* Update Band Power widget and add Average Band Power data type to Networking Widget

# v5.0.9

Expand Down
2 changes: 1 addition & 1 deletion OpenBCI_GUI/OpenBCI_GUI.pde
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import http.requests.*;
// Global Variables & Instances
//------------------------------------------------------------------------
//Used to check GUI version in TopNav.pde and displayed on the splash screen on startup
String localGUIVersionString = "v5.1.0-alpha.4";
String localGUIVersionString = "v5.1.0-alpha.5";
String localGUIVersionDate = "March 2022";
String guiLatestVersionGithubAPI = "https://api.github.com/repos/OpenBCI/OpenBCI_GUI/releases/latest";
String guiLatestReleaseLocation = "https://github.com/OpenBCI/OpenBCI_GUI/releases/latest";
Expand Down
5 changes: 4 additions & 1 deletion OpenBCI_GUI/SessionSettings.pde
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class SessionSettings {

//Used to set text in dropdown menus when loading Networking settings
String[] nwProtocolArray = {"Serial", "LSL", "UDP", "OSC"};
String[] nwDataTypesArray = {"None", "TimeSeries", "Focus", "EMG", "BandPower", "Accel/Aux", "FFT", "Pulse"};
String[] nwDataTypesArray = {"None", "Focus", "EMG", "AvgBandPower", "BandPower", "TimeSeries", "Accel/Aux", "FFT", "Pulse"};
String[] nwBaudRatesArray = {"57600", "115200", "250000", "500000"};

//Used to set text in dropdown menus when loading Analog Read settings
Expand Down Expand Up @@ -267,6 +267,8 @@ class SessionSettings {
dropdownColors.setCaptionLabel((int)color(1, 18, 41)); //color of text in primary box
// dropdownColors.setValueLabel((int)color(1, 18, 41)); //color of text in all dropdown boxes
dropdownColors.setValueLabel((int)color(100)); //color of text in all dropdown boxes

setLogFileDurationChoice(defaultOBCIMaxFileSize);
}

///////////////////////////////////
Expand Down Expand Up @@ -305,6 +307,7 @@ class SessionSettings {
}

public String getSessionPath() {
//println("SESSIONPATH==",sessionPath, millis());
return sessionPath;
}

Expand Down
2 changes: 1 addition & 1 deletion OpenBCI_GUI/TopNav.pde
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,6 @@ class TutorialSelector {
toggleVisibility(); //shut layoutSelector if something is selected
}
});
openbciForum.setDescription("Here you can alter the overall layout of the GUI, allowing for different container configurations with more or less widgets.");
openbciForum.setDescription("Click here to view information on how to lower the Cyton Dongle latency for your current operating system.");
}
}
46 changes: 36 additions & 10 deletions OpenBCI_GUI/W_BandPower.pde
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@
// Averaged over all channels
//
// Created by: Wangshu Sun, May 2017
// Modified by: Richard Waltman, March 2022
//
////////////////////////////////////////////////////////////////////////////////////////////////////////



class W_BandPower extends Widget {

// indexes
final int DELTA = 0; // 1-4 Hz
final int THETA = 1; // 4-8 Hz
final int ALPHA = 2; // 8-13 Hz
final int BETA = 3; // 13-30 Hz
final int GAMMA = 4; // 30-55 Hz

private final int NUM_BANDS = 5;
private float[] activePower = new float[NUM_BANDS];
private float[] normalizedBandPowers = new float[NUM_BANDS];

GPlot bp_plot;
public ChannelSelect bpChanSelect;
boolean prevChanSelectIsVisible = false;
Expand Down Expand Up @@ -56,26 +69,35 @@ class W_BandPower extends Widget {

//setting bg colors of histogram bars to match the color scheme of the channel colors w/ an opacity of 150/255
bp_plot.getHistogram().setBgColors(new color[] {
color((int)channelColors[2], 150), color((int)channelColors[1], 150),
color((int)channelColors[3], 150), color((int)channelColors[4], 150), color((int)channelColors[6], 150)

color((int)channelColors[6], 150),
color((int)channelColors[4], 150),
color((int)channelColors[3], 150),
color((int)channelColors[2], 150),
color((int)channelColors[1], 150),
}
);
} //end of constructor

void update() {
super.update(); //calls the parent update() method of Widget (DON'T REMOVE)

float[] activePower = new float[NUM_BANDS];
float normalizingSum = 0;

for (int i = 0; i < NUM_BANDS; i++) {
float sum = 0;

for (int j = 0; j < bpChanSelect.activeChan.size(); j++) {
int chan = bpChanSelect.activeChan.get(j);
sum += dataProcessing.avgPowerInBins[chan][i];
activePower[i] = sum / bpChanSelect.activeChan.size();
}

activePower[i] = sum / bpChanSelect.activeChan.size();

normalizingSum += activePower[i];
}

for (int i = 0; i < NUM_BANDS; i++) {
normalizedBandPowers[i] = activePower[i] / normalizingSum;
}

//Update channel checkboxes and active channels
Expand Down Expand Up @@ -137,11 +159,15 @@ class W_BandPower extends Widget {

void flexGPlotSizeAndPosition() {
if (bpChanSelect.isVisible()) {
bp_plot.setPos(x, y);
bp_plot.setOuterDim(w, h);
bp_plot.setPos(x, y + bpChanSelect.getHeight() - navH);
bp_plot.setOuterDim(w, h - bpChanSelect.getHeight() + navH);
} else {
bp_plot.setPos(x, y - navHeight);
bp_plot.setOuterDim(w, h + navHeight);
bp_plot.setPos(x, y - navH);
bp_plot.setOuterDim(w, h + navH);
}
}

public float[] getNormalizedBPSelectedChannels() {
return normalizedBandPowers;
}
};
4 changes: 4 additions & 0 deletions OpenBCI_GUI/W_HeadPlot.pde
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,10 @@ class HeadPlot {

public void draw() {

if (!hardCalcsDone) {
return;
}

pushStyle();
smooth();
//draw head parts
Expand Down
91 changes: 82 additions & 9 deletions OpenBCI_GUI/W_Networking.pde
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ class W_Networking extends Widget {
}
defaultBaud = "57600";
baudRates = Arrays.asList(settings.nwBaudRatesArray);
protocolMode = "Serial"; //default to Serial
protocolMode = "UDP"; //Set Default to UDP
protocolIndex = 2; //Set Default to UDP
addDropdown("Protocol", "Protocol", Arrays.asList(settings.nwProtocolArray), protocolIndex);
comPorts = new ArrayList<String>(Arrays.asList(processing.serial.Serial.list()));
verbosePrint("comPorts = " + comPorts);
Expand Down Expand Up @@ -220,8 +221,10 @@ class W_Networking extends Widget {
checkTopNovEvents();

//ignore top left button interaction when widgetSelector dropdown is active
lockElementOnOverlapCheck(guideButton);
lockElementOnOverlapCheck(dataOutputsButton);
List<controlP5.Controller> cp5ElementsToCheck = new ArrayList<controlP5.Controller>();
cp5ElementsToCheck.add((controlP5.Controller)guideButton);
cp5ElementsToCheck.add((controlP5.Controller)dataOutputsButton);
lockElementsOnOverlapCheck(cp5ElementsToCheck);
filterButtonsCheck();

if (dataDropdownsShouldBeClosed) { //this if takes care of the scenario where you select the same widget that is active...
Expand Down Expand Up @@ -596,7 +599,7 @@ class W_Networking extends Widget {

ScrollableList scrollList = new CustomScrollableList(cp5_networking_dropdowns, name)
.setOpen(false)

.setBackgroundColor(color(0))
.setColorBackground(color(31,69,110)) // text field bg color
.setColorValueLabel(color(255)) // text color
.setColorCaptionLabel(color(255))
Expand Down Expand Up @@ -744,8 +747,17 @@ class W_Networking extends Widget {
cp5_networking_baudRate.setGraphics(pApplet, 0,0);
cp5_networking_portName.setGraphics(pApplet, 0,0);

//scale the item width of all elements in the networking widget
itemWidth = int(map(width, 1024, 1920, 100, 120)) - 4;

column0 = x+w/22-12;
int widthd = 46;//This value has been fine-tuned to look proper in windowed mode 1024*768 and fullscreen on 1920x1080

if (protocolMode.equals("UDP") || protocolMode.equals("LSL")) {
widthd = 38;
itemWidth = int(map(width, 1024, 1920, 120, 140)) - 4;
}

column1 = x+12*w/widthd-25;//This value has been fine-tuned to look proper in windowed mode 1024*768 and fullscreen on 1920x1080
column2 = x+(12+9*1)*w/widthd-25;
column3 = x+(12+9*2)*w/widthd-25;
Expand All @@ -766,11 +778,8 @@ class W_Networking extends Widget {
guideButton.setPosition(x0 + 2, y0 + navH + 2);
dataOutputsButton.setPosition(x0 + 2*2 + guideButton.getWidth() , y0 + navH + 2);

//scale the item width of all elements in the networking widget
itemWidth = int(map(width, 1024, 1920, 100, 120)) - 4;

int dropdownsItemsToShow = int((this.h0 * datatypeDropdownScaling) / (this.navH - 4));
int dropdownHeight = (dropdownsItemsToShow + 1) * (this.navH - 4);
int dropdownHeight = (dropdownsItemsToShow) * (this.navH - 4);
int maxDropdownHeight = (settings.nwDataTypesArray.length + 1) * (this.navH - 4);
if (dropdownHeight > maxDropdownHeight) dropdownHeight = maxDropdownHeight;

Expand Down Expand Up @@ -1059,6 +1068,8 @@ class W_Networking extends Widget {
return 125;
} else if (dataType.equals("EMG")) {
return currentBoard.getNumEXGChannels();
} else if (dataType.equals("AvgBandPower")) {
return 1;
} else if (dataType.equals("BandPower")) {
return 5;
} else if (dataType.equals("Pulse")) {
Expand Down Expand Up @@ -1411,6 +1422,8 @@ class Stream extends Thread {
sendFFTData();
} else if (this.dataType.equals("EMG")) {
sendEMGData();
} else if (this.dataType.equals("AvgBandPower")) {
sendNormalizedPowerBandData();
} else if (this.dataType.equals("BandPower")) {
sendPowerBandData();
} else if (this.dataType.equals("Accel/Aux")) {
Expand Down Expand Up @@ -1766,6 +1779,66 @@ class Stream extends Thread {
}
}

void sendNormalizedPowerBandData() {
// UNFILTERED & FILTERED ... influenced globally by the FFT filters dropdown ... just like the FFT data
int numBandPower = 5; //DELTA, THETA, ALPHA, BETA, GAMMA

if (this.filter==false || this.filter==true) {
// OSC
if (this.protocol.equals("OSC")) {
msg.clearArguments();
for (int i = 0; i < numBandPower; i++) {
msg.add(w_bandPower.getNormalizedBPSelectedChannels()[i]); // [CHAN][BAND]
}
try {
this.osc.send(msg,this.netaddress);
} catch (Exception e) {
println(e.getMessage());
}
// UDP
} else if (this.protocol.equals("UDP")) {
// DELTA, THETA, ALPHA, BETA, GAMMA
StringBuilder outputter = new StringBuilder("{\"type\":\"averageBandPower\",\"data\":[");
for (int i = 0; i < numBandPower; i++) {
outputter.append(str(w_bandPower.getNormalizedBPSelectedChannels()[i]));
if (i != numBandPower - 1) {
outputter.append(",");
} else {
outputter.append("]}\r\n");
}
}
//println(outputter.toString());
try {
this.udp.send(outputter.toString(), this.ip, this.port);
} catch (Exception e) {
println(e.getMessage());
}
// LSL
} else if (this.protocol.equals("LSL")) {
// DELTA, THETA, ALPHA, BETA, GAMMA
float[] avgPowerLSL = w_bandPower.getNormalizedBPSelectedChannels();
outlet_data.push_sample(avgPowerLSL);
} else if (this.protocol.equals("Serial")) {
serialMessage = "[";
for (int i = 0; i < numBandPower; i++) {
float power_band = w_bandPower.getNormalizedBPSelectedChannels()[i];
String power_band_3dec = String.format("%.3f", power_band);
serialMessage += power_band_3dec;
if (i < numBandPower - 1) {
serialMessage += ","; //add a comma to serialMessage to separate chan values, as long as it isn't last value...
}
}
serialMessage += "]";
try {
// println(serialMessage);
this.serial_networking.write(serialMessage);
} catch (Exception e) {
println(e.getMessage());
}
}
}
}

void sendEMGData() {
// UNFILTERED & FILTERED ... influenced globally by the FFT filters dropdown ... just like the FFT data
if (this.filter==false || this.filter==true) {
Expand Down Expand Up @@ -1945,7 +2018,7 @@ class Stream extends Thread {
// Add timestamp to LSL Stream
outlet_data.push_sample(dataToSend);
} else if (this.protocol.equals("Serial")) {
// Data Format: 0001,0002,0003\n or 0001,0002\n depending if Wifi Shield is used
// Data Format: 0001,0002,0003\n or 0001,0002\n depending if Wi-Fi Shield is used
// 5 chars per pin, including \n char for Z
serialMessage = "";
for (int i = 0; i < NUM_ANALOG_READS; i++) {
Expand Down
Loading