Skip to content

Commit 916b941

Browse files
committed
Add the option to switch band power widget to linear scale #1139
1 parent c002eaf commit 916b941

5 files changed

Lines changed: 114 additions & 179 deletions

File tree

OpenBCI_GUI/BandPowerEnums.pde

Lines changed: 17 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11

2-
public enum BPAutoClean implements IndexingInterface
3-
{
4-
ON (0, "On"),
5-
OFF (1, "Off");
2+
public enum BPLogLin implements IndexingInterface {
3+
LOG (0, "Log"),
4+
LINEAR (1, "Linear");
65

76
private int index;
87
private String label;
98

10-
BPAutoClean(int _index, String _label) {
9+
BPLogLin(int _index, String _label) {
1110
this.index = _index;
1211
this.label = _label;
1312
}
@@ -23,62 +22,25 @@ public enum BPAutoClean implements IndexingInterface
2322
}
2423
}
2524

26-
public enum BPAutoCleanThreshold implements IndexingInterface
27-
{
28-
FORTY (0, 40f, "40 uV"),
29-
FIFTY (1, 50f, "50 uV"),
30-
SIXTY (2, 60f, "60 uV"),
31-
SEVENTY (3, 70f, "70 uV"),
32-
EIGHTY (4, 80f, "80 uV"),
33-
NINETY (5, 90f, "90 uV"),
34-
ONE_HUNDRED(6, 100f, "100 uV");
25+
public enum BPVerticalScale implements IndexingInterface {
26+
SCALE_10 (0, 10, "10 uV"),
27+
SCALE_50 (1, 50, "50 uV"),
28+
SCALE_100 (2, 100, "100 uV"),
29+
SCALE_500 (3, 500, "500 uV"),
30+
SCALE_1000 (4, 1000, "1000 uV"),
31+
SCALE_1500 (5, 1500, "1500 uV");
3532

3633
private int index;
37-
private float value;
34+
private final int value;
3835
private String label;
3936

40-
BPAutoCleanThreshold(int _index, float _value, String _label) {
41-
this.index = _index;
42-
this.value = _value;
43-
this.label = _label;
44-
}
45-
46-
public float getValue() {
47-
return value;
48-
}
49-
50-
@Override
51-
public String getString() {
52-
return label;
53-
}
54-
55-
@Override
56-
public int getIndex() {
57-
return index;
58-
}
59-
}
60-
61-
public enum BPAutoCleanTimer implements IndexingInterface
62-
{
63-
HALF_SECOND (0, 500, ".5 sec"),
64-
ONE_SECOND (1, 1000, "1 sec"),
65-
THREE_SECONDS (2, 2000, "3 sec"),
66-
FIVE_SECONDS (3, 5000, "5 sec"),
67-
TEN_SECONDS (4, 10000, "10 sec"),
68-
TWENTY_SECONDS (5, 20000, "20 sec"),
69-
THIRTY_SECONDS(6, 30000, "30 sec");
70-
71-
private int index;
72-
private float value;
73-
private String label;
74-
75-
BPAutoCleanTimer(int _index, float _value, String _label) {
76-
this.index = _index;
77-
this.value = _value;
78-
this.label = _label;
37+
BPVerticalScale(int index, int value, String label) {
38+
this.index = index;
39+
this.value = value;
40+
this.label = label;
7941
}
8042

81-
public float getValue() {
43+
public int getValue() {
8244
return value;
8345
}
8446

OpenBCI_GUI/FFTEnums.pde

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ public enum FFTVerticalScale implements IndexingInterface {
132132
SCALE_10 (0, 10, "10 uV"),
133133
SCALE_50 (1, 50, "50 uV"),
134134
SCALE_100 (2, 100, "100 uV"),
135-
SCALE_1000 (3, 1000, "1000 uV");
135+
SCALE_500 (3, 500, "500 uV"),
136+
SCALE_1000 (3, 1000, "1000 uV"),
137+
SCALE_1500 (4, 1500, "1500 uV");
136138

137139
private int index;
138140
private final int value;
@@ -159,14 +161,14 @@ public enum FFTVerticalScale implements IndexingInterface {
159161
}
160162
}
161163

162-
public enum FFTLogLin implements IndexingInterface {
164+
public enum GraphLogLin implements IndexingInterface {
163165
LOG (0, "Log"),
164166
LIN (1, "Linear");
165167

166168
private int index;
167169
private String label;
168170

169-
FFTLogLin(int index, String label) {
171+
GraphLogLin(int index, String label) {
170172
this.index = index;
171173
this.label = label;
172174
}

OpenBCI_GUI/W_BandPower.pde

Lines changed: 75 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@
1010
// //
1111
// Created by: Wangshu Sun, May 2017 //
1212
// Modified by: Richard Waltman, March 2022 //
13-
// Refactored by: Richard Waltman, March 2025 //
13+
// Refactored by: Richard Waltman, April 2025 //
1414
// //
1515
////////////////////////////////////////////////////////////////////////////////////////////////////////
1616

1717
class W_BandPower extends WidgetWithSettings {
18-
// indexes
1918
private final int DELTA = 0; // 1-4 Hz
2019
private final int THETA = 1; // 4-8 Hz
2120
private final int ALPHA = 2; // 8-13 Hz
@@ -32,24 +31,61 @@ class W_BandPower extends WidgetWithSettings {
3231

3332
private List<controlP5.Controller> cp5ElementsToCheck;
3433

35-
int[] autoCleanTimers;
36-
boolean[] previousThresholdCrossed;
37-
3834
W_BandPower() {
3935
super();
4036
widgetTitle = "Band Power";
4137

42-
autoCleanTimers = new int[currentBoard.getNumEXGChannels()];
43-
previousThresholdCrossed = new boolean[currentBoard.getNumEXGChannels()];
38+
createPlot();
39+
}
40+
41+
@Override
42+
protected void initWidgetSettings() {
43+
super.initWidgetSettings();
44+
widgetSettings.set(BPVerticalScale.class, BPVerticalScale.SCALE_100)
45+
.set(GraphLogLin.class, GraphLogLin.LOG)
46+
.set(FFTSmoothingFactor.class, globalFFTSettings.getSmoothingFactor())
47+
.set(FFTFilteredEnum.class, globalFFTSettings.getFilteredEnum());
48+
49+
initDropdown(BPVerticalScale.class, "bandPowerVerticalScaleDropdown", "Max uV");
50+
initDropdown(GraphLogLin.class, "bandPowerLogLinDropdown", "Log/Lin");
51+
initDropdown(FFTSmoothingFactor.class, "bandPowerSmoothingDropdown", "Smooth");
52+
initDropdown(FFTFilteredEnum.class, "bandPowerDataFilteringDropdown", "Filters");
4453

54+
bpChanSelect = new ExGChannelSelect(ourApplet, x, y, w, navH);
55+
bpChanSelect.activateAllButtons();
56+
cp5ElementsToCheck = new ArrayList<controlP5.Controller>();
57+
cp5ElementsToCheck.addAll(bpChanSelect.getCp5ElementsForOverlapCheck());
58+
saveActiveChannels(bpChanSelect.getActiveChannels());
59+
widgetSettings.saveDefaults();
60+
}
61+
62+
@Override
63+
protected void applySettings() {
64+
updateDropdownLabel(BPVerticalScale.class, "bandPowerVerticalScaleDropdown");
65+
updateDropdownLabel(GraphLogLin.class, "bandPowerLogLinDropdown");
66+
updateDropdownLabel(FFTSmoothingFactor.class, "bandPowerSmoothingDropdown");
67+
updateDropdownLabel(FFTFilteredEnum.class, "bandPowerDataFilteringDropdown");
68+
applyActiveChannels(bpChanSelect);
69+
applyVerticalScale();
70+
applyPlotLogScale();
71+
}
72+
73+
@Override
74+
protected void updateChannelSettings() {
75+
if (bpChanSelect != null) {
76+
saveActiveChannels(bpChanSelect.getActiveChannels());
77+
}
78+
}
79+
80+
private void createPlot() {
4581
// Setup for the BandPower plot
4682
bp_plot = new GPlot(ourApplet, x, y-NAV_HEIGHT, w, h+NAV_HEIGHT);
4783
// bp_plot.setPos(x, y+NAV_HEIGHT);
4884
bp_plot.setDim(w, h);
4985
bp_plot.setLogScale("y");
50-
bp_plot.setYLim(0.1, 100);
86+
bp_plot.setYLim(0.1, 100); // Lower limit must be > 0 for log scale
5187
bp_plot.setXLim(0, 5);
52-
bp_plot.getYAxis().setNTicks(9);
88+
bp_plot.getYAxis().setNTicks(4);
5389
bp_plot.getXAxis().setNTicks(0);
5490
bp_plot.getTitle().setTextAlignment(LEFT);
5591
bp_plot.getTitle().setRelativePos(0);
@@ -82,53 +118,11 @@ class W_BandPower extends WidgetWithSettings {
82118
);
83119
//setting color of text label for each histogram bar on the x axis
84120
bp_plot.getHistogram().setFontColor(OPENBCI_DARKBLUE);
85-
}
86-
87-
@Override
88-
protected void initWidgetSettings() {
89-
super.initWidgetSettings();
90-
widgetSettings.set(BPAutoClean.class, BPAutoClean.OFF)
91-
.set(BPAutoCleanThreshold.class, BPAutoCleanThreshold.FIFTY)
92-
.set(BPAutoCleanTimer.class, BPAutoCleanTimer.THREE_SECONDS)
93-
.set(FFTSmoothingFactor.class, globalFFTSettings.getSmoothingFactor())
94-
.set(FFTFilteredEnum.class, globalFFTSettings.getFilteredEnum());
95-
96-
initDropdown(BPAutoClean.class, "bandPowerAutoCleanDropdown", "Auto Clean");
97-
initDropdown(BPAutoCleanThreshold.class, "bandPowerAutoCleanThresholdDropdown", "Threshold");
98-
initDropdown(BPAutoCleanTimer.class, "bandPowerAutoCleanTimerDropdown", "Timer");
99-
initDropdown(FFTSmoothingFactor.class, "bandPowerSmoothingDropdown", "Smooth");
100-
initDropdown(FFTFilteredEnum.class, "bandPowerDataFilteringDropdown", "Filtered?");
101-
102-
bpChanSelect = new ExGChannelSelect(ourApplet, x, y, w, navH);
103-
bpChanSelect.activateAllButtons();
104-
cp5ElementsToCheck = new ArrayList<controlP5.Controller>();
105-
cp5ElementsToCheck.addAll(bpChanSelect.getCp5ElementsForOverlapCheck());
106-
saveActiveChannels(bpChanSelect.getActiveChannels());
107-
widgetSettings.saveDefaults();
108-
}
109-
110-
@Override
111-
protected void applySettings() {
112-
updateDropdownLabel(BPAutoClean.class, "bandPowerAutoCleanDropdown");
113-
updateDropdownLabel(BPAutoCleanThreshold.class, "bandPowerAutoCleanThresholdDropdown");
114-
updateDropdownLabel(BPAutoCleanTimer.class, "bandPowerAutoCleanTimerDropdown");
115-
updateDropdownLabel(FFTSmoothingFactor.class, "bandPowerSmoothingDropdown");
116-
updateDropdownLabel(FFTFilteredEnum.class, "bandPowerDataFilteringDropdown");
117-
applyActiveChannels(bpChanSelect);
118-
}
119-
120-
@Override
121-
protected void updateChannelSettings() {
122-
if (bpChanSelect != null) {
123-
saveActiveChannels(bpChanSelect.getActiveChannels());
124-
}
121+
applyPlotLogScale();
125122
}
126123

127124
public void update() {
128125
super.update();
129-
130-
// If enabled, automatically turn channels on or off in ExGChannelSelect for this widget
131-
autoCleanByEnableDisableChannels();
132126

133127
//Update channel checkboxes and active channels
134128
bpChanSelect.update(x, y, w);
@@ -202,50 +196,6 @@ class W_BandPower extends WidgetWithSettings {
202196
return normalizedBandPowers;
203197
}
204198

205-
private void autoCleanByEnableDisableChannels() {
206-
BPAutoClean autoClean = widgetSettings.get(BPAutoClean.class);
207-
BPAutoCleanThreshold autoCleanThreshold = widgetSettings.get(BPAutoCleanThreshold.class);
208-
BPAutoCleanTimer autoCleanTimer = widgetSettings.get(BPAutoCleanTimer.class);
209-
if (autoClean == BPAutoClean.OFF) {
210-
return;
211-
}
212-
213-
int numChannels = currentBoard.getNumEXGChannels();
214-
for (int i = 0; i < numChannels; i++) {
215-
float uvrms = dataProcessing.data_std_uV[i];
216-
boolean thresholdCrossed = uvrms > autoCleanThreshold.getValue();
217-
218-
int currentMillis = millis();
219-
220-
//Check for state change. Reset timer on either state.
221-
if (thresholdCrossed != previousThresholdCrossed[i]) {
222-
previousThresholdCrossed[i] = thresholdCrossed;
223-
autoCleanTimers[i] = currentMillis;
224-
}
225-
226-
//Auto-disable a channel if it's above the threshold and has been for the timer duration
227-
boolean timerDurationExceeded = currentMillis - autoCleanTimers[i] > autoCleanTimer.getValue();
228-
if (timerDurationExceeded) {
229-
boolean enableChannel = !thresholdCrossed;
230-
bpChanSelect.setToggleState(i, enableChannel);
231-
}
232-
}
233-
}
234-
235-
public void setAutoClean(int n) {
236-
widgetSettings.setByIndex(BPAutoClean.class, n);
237-
Arrays.fill(previousThresholdCrossed, false);
238-
Arrays.fill(autoCleanTimers, 0);
239-
}
240-
241-
public void setAutoCleanThreshold(int n) {
242-
widgetSettings.setByIndex(BPAutoCleanThreshold.class, n);
243-
}
244-
245-
public void setAutoCleanTimer(int n) {
246-
widgetSettings.setByIndex(BPAutoCleanTimer.class, n);
247-
}
248-
249199
//Called in DataProcessing.pde to update data even if widget is closed
250200
public void updateBandPowerWidgetData() {
251201
float normalizingSum = 0;
@@ -265,6 +215,31 @@ class W_BandPower extends WidgetWithSettings {
265215
}
266216
}
267217

218+
public void setVerticalScale(int n) {
219+
widgetSettings.setByIndex(BPVerticalScale.class, n);
220+
applyVerticalScale();
221+
}
222+
223+
public void setLogLin(int n) {
224+
widgetSettings.setByIndex(GraphLogLin.class, n);
225+
applyPlotLogScale();
226+
}
227+
228+
private void applyVerticalScale() {
229+
BPVerticalScale scale = widgetSettings.get(BPVerticalScale.class);
230+
int scaleValue = scale.getValue();
231+
bp_plot.setYLim(0.1, scaleValue); // Lower limit must be > 0 for log scale
232+
}
233+
234+
private void applyPlotLogScale() {
235+
GraphLogLin logLin = widgetSettings.get(GraphLogLin.class);
236+
if (logLin == GraphLogLin.LOG) {
237+
bp_plot.setLogScale("y");
238+
} else {
239+
bp_plot.setLogScale("");
240+
}
241+
}
242+
268243
public void setSmoothingDropdownFrontend(FFTSmoothingFactor _smoothingFactor) {
269244
widgetSettings.set(FFTSmoothingFactor.class, _smoothingFactor);
270245
updateDropdownLabel(FFTSmoothingFactor.class, "bandPowerSmoothingDropdown");
@@ -276,16 +251,12 @@ class W_BandPower extends WidgetWithSettings {
276251
}
277252
};
278253

279-
public void bandPowerAutoCleanDropdown(int n) {
280-
((W_BandPower) widgetManager.getWidget("W_BandPower")).setAutoClean(n);
281-
}
282-
283-
public void bandPowerAutoCleanThresholdDropdown(int n) {
284-
((W_BandPower) widgetManager.getWidget("W_BandPower")).setAutoCleanThreshold(n);
254+
public void bandPowerVerticalScaleDropdown(int n) {
255+
((W_BandPower) widgetManager.getWidget("W_BandPower")).setVerticalScale(n);
285256
}
286257

287-
public void bandPowerAutoCleanTimerDropdown(int n) {
288-
((W_BandPower) widgetManager.getWidget("W_BandPower")).setAutoCleanTimer(n);
258+
public void bandPowerLogLinDropdown(int n) {
259+
((W_BandPower) widgetManager.getWidget("W_BandPower")).setLogLin(n);
289260
}
290261

291262
public void bandPowerSmoothingDropdown(int n) {

0 commit comments

Comments
 (0)