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
1717class 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
291262public void bandPowerSmoothingDropdown (int n ) {
0 commit comments