CEBL  2.1
PassBand.cpp
Go to the documentation of this file.
1 #include "PassBand.hpp"
2 #include "WidgetUtils.hpp"
3 #include <iostream>
4 #include <fftw3.h>
5 
6 
7 using namespace std;
8 using namespace cppR;
9 typedef ublas::matrix<double> Matrix;
10 
11 
12 
13 /**************************************************/
14 
15 double const pi = M_PI;
16 
17 template <typename T>
18 double logb(int base, T value)
19 {
20  return log(value)/log(base);
21 }
22 template <typename T>
23 double log2(T value)
24 {
25  return logb(2,value);
26 }
27 
28 /**************************************************/
29 
30 namespace CEBL
31 {
32 
33  //----------------------------------------
34  //constructor
35 
36  PassBand::PassBand()
37  {
38  trained = false;
39  gamma = .99;
40  plugin_name = "Pass Band";
41  //InitGUI();
42  };
43 
44 
45 
46 
47  //----------------------------------------
49  ublas::matrix<double> PassBand::use(const ublas::matrix<double> &data)
50  {
51  //if filter has not been trained, just return the data
52  if(!trained)
53  {
54  return data;
55  }
56  //create variables for return of data
57  int nfeatures = nrow(data);
58  ublas::matrix<double> ret = createMatrix(0,0,0);
59  ublas::matrix<double> var_ret = createMatrix(0,0,data.size2());
60  bool ret_set = false;
61 
62  for(int i=0;i<num_bands;i++)
63  {
64  //make sure we have a filter made
65 
66 
67  //create a state
68  if(states.size() <= i)
69  {
70  FilterState new_state;
71  new_state.empty = true;
72  states.push_back(new_state);
73  }
74 
75  //create means and vars for this band
76  if(means.size() <= i)
77  {
78  vector<double> temp;
79  vars.push_back(temp);
80  means.push_back(temp);
81  }
82  //filter data
83  FilterResult temp = filter(filters[i], data, states[i]);
84  states[i] = temp.state;
85  //initially resize ret if it hasn't been set yet
86  if(!ret_set)
87  {
88  ret = temp.filtered;
89  ret_set = true;
90  }
91  else
92  {
93  //bind result onto return matrix
94  ret = rbind(ret,temp.filtered);
95  }
96 
97  //now calulate variance
98 
99  //matrix to return vars
100  Matrix var_matrix;
101  var_matrix.resize(data.size1(),data.size2());
102  //loop through features
103  for(int feature=0;feature<data.size1();feature++)
104  {
105 
106  //create means and vars for this feature
107  if(means[i].size() <= feature)
108  {
109  vars[i].push_back(0);
110  means[i].push_back(0);
111  }
112  ublas::vector<double> row = ublas::row(temp.filtered,feature);
113  //calculate new means and vars
114  for(int col=0; col<data.size2(); col++)
115  {
116  means[i][feature] = gamma * means[i][feature]
117  + (1.0-gamma)*(row[col]);
118  vars[i][feature] = gamma * vars[i][feature]
119  + (1.0-gamma)*(pow(row[col]-means[i][feature],2));
120 
121  var_matrix(feature,col) = vars[i][feature];
122  }
123  }
124  var_ret = rbind(var_ret,var_matrix);
125 
126 
127  }
128 
129  bool use_variance = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_variance));
130  if(use_variance)
131  return var_ret;
132  else
133  return ret;
134  }
135 
136 
137 
138 
139 
140 
141  //** function called from CEBL to load gui interface */
142  GtkWidget *PassBand::getGuiInterface()
143  {
144  return gui_container;
145  }
146 
147 
148 
149 
150 
151 
153  void PassBand::save(boost::archive::text_oarchive &ar, const unsigned int &version) const
154  {
155  ar & trained;
156  ar & num_bands;
157  ar & gamma;
158 
159  }
160  void PassBand::load(boost::archive::text_iarchive &ar, const unsigned int &version)
161  {
162  }
163 
164 
165 
166 
167 
168 
170  void PassBand::train()
171  {
172 
173  for(int i=0;i<num_bands;i++)
174  {
175  ConfigRow row = config_rows[i];
176  int pass = int((row.low + row.high) / 2.0);
177  //check if we have already made a filter for this configuration
178  if(configurations.count(sample_rate) == 0
179  || configurations[sample_rate].count(row.low) == 0
180  || configurations[sample_rate][row.low].count(row.high) == 0)
181  {
182  //we have not made this filter yet. make it now
183  configurations[sample_rate][row.low][row.high]
184  = makePassband(151,8,sample_rate,row.low, pass, row.high);
185 
186  }
187  //set current filter for this row to the right one
188  filters[i] = configurations[sample_rate][row.low][row.high];
189  }
190  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_trained),true);
191  trained = true;
192 
193  //clear the state buffers
194  states.resize(0);
195  vars.resize(0);
196  means.resize(0);
197  }
198 
199 
200 
201 
202 
203 
204 
205 
206  void PassBand::ChangeOptions(int pos)
207  {
208  bool new_config = false;
209  for(int i=0; i<num_bands; i++)
210  {
211 
212  //first go through and make sure all spin_lows are less than spin_high
213  int low = int(gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget_rows[i].spin_low)));
214  int high = int(gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget_rows[i].spin_high)));
215 
216  //save this config for easy access
217  if(i < config_rows.size())
218  {
219  config_rows[i].low = low;
220  config_rows[i].high = high;
221  }
222  else
223  {
224  ConfigRow temp;
225  temp.low = low;
226  temp.high = high;
227  config_rows.push_back(temp);
228  }
229 
230  //if bounds are wrong
231  if(low >= high)
232  {
233  //low is changing
234  if(pos==0)
235  {
236  gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget_rows[i].spin_low),high-1);
237  low = high-1;
238  }
239  //high is changing
240  if(pos==2)
241  {
242  gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget_rows[i].spin_high),low+1);
243  high = low+1;
244  }
245  }
246 
247  //now check if this is a new configuration
248  if(configurations.count(sample_rate) == 0
249  || configurations[sample_rate].count(low) == 0
250  || configurations[sample_rate][low].count(high) == 0)
251  {
252  new_config = true;
253  }
254  else
255  {
256 
257  //filter[i] = configurations[low][high];
258  }
259  }
260  if(new_config)
261  {
262  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_trained),false);
263  trained = false;
264  }
265  else
266  {
267  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_trained),true);
268  trained = true;
269  }
270  }
271 
272 
273 
274 
275 
276 
277  //--------------------------------------------------
278  //gui functions
279 
280 
281 
282  //initialize gui widgets and structure
283  void PassBand::InitGUI()
284  {
285  //initialize values
286  num_bands = 0;
287 
288  //create main interface container
289  gui_container = gtk_vbox_new(false,0);
290 
291  //first row is a box containing a label and button for number of bands
292  GtkWidget *hbox_row1 = gtk_hbox_new(false,0);
293 
294  gtk_box_pack_start(GTK_BOX(gui_container),hbox_row1, false, false, 0);
295 
296  //------------------------------
297  //create spin button for number of bands
298 
299  //spin button for num bands
300  spin_bands = gtk_spin_button_new_with_range(1,50,1);
301  gtk_widget_set_size_request(spin_bands, 40, 18);
302  g_signal_connect(G_OBJECT(spin_bands),
303  "value-changed",
304  G_CALLBACK(CB_ChangeNumBands),
305  (gpointer)this);
306  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_bands),1);
307  gtk_box_pack_start(GTK_BOX(hbox_row1), gtk_label_new("Number of Bands: "), false, false,0);
308  gtk_box_pack_start(GTK_BOX(hbox_row1), spin_bands, false, false,0);
309 
310  spin_gamma = gtk_spin_button_new_with_range(0,1,0.001);
311  gtk_widget_set_size_request(spin_gamma, 80, 18);
312  g_signal_connect(G_OBJECT(spin_gamma),
313  "value-changed",
314  G_CALLBACK(CB_ChangeGamma),
315  (gpointer)this);
316  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_gamma),gamma);
317  gtk_box_pack_start(GTK_BOX(hbox_row1), gtk_label_new("Gamma: "), false, false,0);
318  gtk_box_pack_start(GTK_BOX(hbox_row1), spin_gamma, false, false,0);
319 
320  //--------------------------------------------------
321  //create a check box to set whether to return variance
322  // or straight output from the filter
323 
324  check_variance = gtk_check_button_new_with_label("Use Variance");
325  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_variance),true);
326  gtk_box_pack_end(GTK_BOX(hbox_row1), check_variance, false, false, 0);
327 
328  //----------------------------------------
329  //create check box to show trained status
330 
331  check_trained = gtk_check_button_new_with_label("Trained");
332  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_trained), false);
333  gtk_widget_set_sensitive(check_trained,false);
334 
335  gtk_box_pack_end(GTK_BOX(hbox_row1), check_trained, false, false, 0);
336 
337 
338  //----------------------------------------
339  //create table for bands
340 
341 
342  table_bands = gtk_table_new(2,2, true);
343  gtk_table_set_row_spacings(GTK_TABLE(table_bands),4);
344  gtk_table_set_col_spacings(GTK_TABLE(table_bands),4);
345 
346  gtk_table_attach_defaults(GTK_TABLE(table_bands),
347  gtk_label_new("Lower (Hz)"),
348  0, 1,
349  0, 1);
350  gtk_table_attach_defaults(GTK_TABLE(table_bands),
351  gtk_label_new("Upper (Hz)"),
352  1, 2,
353  0, 1);
354  gtk_box_pack_start(GTK_BOX(gui_container),table_bands, false, false, 4);
355 
356  //create initial row of values
357  ChangeNumBands(1);
358 
359 
360  //show container
361  gtk_widget_show_all(gui_container);
362 
363 
364  }
365 
366 
367 
368 
369 
370 
371  //CB functions
372  void PassBand::ChangeNumBands(int force_bands)
373  {
374  //find out how many bands there are now
375 
376  int new_bands;
377  if(force_bands==-1)
378  new_bands = int(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin_bands)));
379  else
380  new_bands = force_bands;
381 
382  if(new_bands == num_bands)
383  return;
384 
385  gtk_widget_show_all(table_bands);
386 
387  //remove rows
388  for(int i=0;i<widget_rows.size();i++)
389  {
390  gtk_widget_hide(widget_rows[i].spin_low);
391  gtk_widget_hide(widget_rows[i].spin_high);
392  }
393 
394  //assign member variable to new band number
395  num_bands = new_bands;
396 
397  //resize table accordingly
398  if(num_bands > widget_rows.size())
399  gtk_table_resize(GTK_TABLE(table_bands),num_bands+1,2);
400 
401 
402  //add the rows to the table
403  for(int i=0;i<num_bands;i++)
404  {
405 
406  //create new widgets as necessary
407  if(i >= widget_rows.size())
408  {
409  PassBandGUIRow temp;
410  //low
411  temp.spin_low = gtk_spin_button_new_with_range(0,1000,1);
412  gtk_spin_button_set_value(GTK_SPIN_BUTTON(temp.spin_low),20);
413  g_signal_connect(G_OBJECT(temp.spin_low),
414  "value-changed",
415  G_CALLBACK(CB_ChangeOptionsLow),
416  (gpointer)this);
417 
418 
419 
420  //high
421  temp.spin_high = gtk_spin_button_new_with_range(1,1000,1);
422  gtk_spin_button_set_value(GTK_SPIN_BUTTON(temp.spin_high),30);
423  g_signal_connect(G_OBJECT(temp.spin_high),
424  "value-changed",
425  G_CALLBACK(CB_ChangeOptionsHigh),
426  (gpointer)this);
427  widget_rows.push_back(temp);
428  //attach new widget
429  gtk_table_attach_defaults(GTK_TABLE(table_bands),
430  widget_rows[i].spin_low,
431  0, 1,
432  i+1, i+2);
433  gtk_table_attach_defaults(GTK_TABLE(table_bands),
434  widget_rows[i].spin_high,
435  1, 2,
436  i+1, i+2);
437 
438  gtk_widget_show(widget_rows[i].spin_low);
439  gtk_widget_show(widget_rows[i].spin_high);
440  }
441  else
442  {
443  gtk_widget_show(widget_rows[i].spin_low);
444  gtk_widget_show(widget_rows[i].spin_high);
445  }
446  }
447 
448  //notify a change in options
449  ChangeOptions();
450 
451  }
452 
453 
454 
455 
456 
457 
458 
459 
460  //CALLBACKS
461  void PassBand::CB_ChangeNumBands(GtkWidget *spin, gpointer data)
462  {
463  ((PassBand*)data)->ChangeNumBands();
464  }
465  void PassBand::CB_ChangeGamma(GtkWidget *spin, gpointer data)
466  {
467  ((PassBand*)data)->gamma = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
468  }
469  void PassBand::CB_ChangeOptionsLow(GtkWidget *spin, gpointer data)
470  {
471  ((PassBand*)data)->ChangeOptions(0);
472  }
473  void PassBand::CB_ChangeOptionsHigh(GtkWidget *spin, gpointer data)
474  {
475  ((PassBand*)data)->ChangeOptions(2);
476  }
477 }//end of namespace
478 
479 
480 
481 /************************************************************/
482 //DYNAMIC LOADING
483 
485 {
486  printf("Shared Library Says: Creating a Lag object.\n");
487  return new CEBL::PassBand;
488 }
489 
490 extern "C" void ObjectDestroy(CEBL::Feature* p)
491 {
492  delete p;
493 }