CEBL  2.1
FilterConfig.cpp
Go to the documentation of this file.
1 
10 #include "FilterConfig.hpp"
11 #include "../CEBLModel.hpp"
12 #include "../cppR/cppR.hpp"
13 #include "DataProcess.hpp"
14 
15 //----------------------------------------------------------------------
16 // CONSTRUCTORS / DESTRUCTORS
17 
18 
20 {
21  this->model = model;
22  this->plugin_loader = new PluginLoader<Filter>;
23  this->num_lags = 0;
24  this->selected_components_string = "(not set)";
25  this->selected_components_valid = false;
26  this->num_components = 0;
27  this->num_expected_channels = 0;
28  this->num_expected_lags = 0;
29  this->num_channels = 0;
30  this->trained = false;
31 
32  std::vector<string> paths = model->preferencesGetPaths();
33  for(unsigned int i=0; i<paths.size();i++)
34  {
35  string path = paths[i] + "plugins/filters/";
36  try
37  {
38  plugin_loader->loadDir(path.c_str());
39  } catch(FileException & e)
40  {
41  //cerr << e.what() << "\n";
42  //if there were exceptions, just continue
43  continue;
44  }
45  }
46 }
47 
48 //------------------------------
49 
51 {
52  delete plugin_loader;
53 }
54 
55 //----------------------------------------------------------------------
56 //GETTING OPERATIONS
57 
58 
59 //------------------------------
60 
61 std::vector<string> FilterConfig::getNameList()
62 {
63  return plugin_loader->getNames();
64 }
65 
66 //------------------------------
67 
68 std::vector<string> FilterConfig::getPathList()
69 {
70  return plugin_loader->getPaths();
71 }
72 
73 //------------------------------
74 
76 {
77  if(selected_filter == "")
78  {
79  return false;
80  }
81  return plugin_loader->getPlugin(selected_filter)->isTrained() && this->trained;
82 }
83 
84 //------------------------------
85 
87 {
88  return num_lags;
89 }
90 
91 //------------------------------
92 
94 {
95  return selected_components;
96 }
97 
98 //------------------------------
99 
101 {
102  this->num_channels = data.size1();
103  EEGData ret;
104 
105  string filter = this->selected_filter;
106  if(filter == "")
107  {
108  throw PluginException("Extracting filtering components: No filter selected.");
109  }
110  if(data.nrow() == 0 || data.ncol() == 0)
111  {
112  throw DataException("Extracting filtering components: No data recorded in EEG data buffer.");
113  }
114 
115  //lag the data
116  data = model->getDataProcess()->process(data,true,true,false);
117  data = cppR::Lag(data.getMatrix(), num_lags);
118  this->num_components = ublas::matrix<double>(data).size1();
119 
120  try
121  {
122  ret = plugin_loader->getPlugin(filter)->extract(data);
123  }
124  catch(...)
125  {
126  throw PluginException("Failed to extract components using filter: " + filter);
127  }
128 
129  return ret;
130 }
131 
132 //------------------------------
133 
135 {
136  return selected_components_string;
137 }
138 
139 //------------------------------
140 
142 {
143  return selected_components_valid;
144 }
145 
146 
147 //------------------------------
148 
149 
151 {
152  if(!this->isTrained())
153  {
154  throw PluginException("Filter has not been trained.");
155  }
156  if(data.size1() != this->num_expected_channels)
157  {
158  throw PluginException("Filter cannot be applied because the number of channels does not match the filter.");
159  }
160 
161  if(num_lags != this->num_expected_lags)
162  {
163  throw PluginException("Filter cannot be applied because the number of lags has changed.");
164  }
165  ublas::matrix<double> filtered = cppR::Lag(data.getMatrix(), num_lags);
166  filtered = plugin_loader->getPlugin(this->selected_filter)->apply(filtered);
167  //select just the first N rows
168  ublas::matrix<double> ret = cppR::submatrix(filtered,
169  0, data.size1() - 1,
170  0,0);
171  return ret;
172 }
173 
174 //------------------------------
175 
176 //get the number of channels that the filter was trained on
178 {
179  return num_expected_channels;
180 }
181 
182 
183 //------------------------------
184 ublas::matrix<double> FilterConfig::getFilterMatrix()
185 {
186  if(!this->isTrained())
187  {
188  throw PluginException("Filter has not been trained.");
189  }
190  return plugin_loader->getPlugin(this->selected_filter)->getFilterMatrix();
191 }
192 
193 //----------------------------------------------------------------------
194 //SETTING OPERATIONS
195 
196 
197 //------------------------------
198 
200 {
201  num_lags = lags;
202 }
203 
204 //------------------------------
205 
207 {
208  this->selected_filter = filter;
209 }
210 
211 //------------------------------
212 
213 void FilterConfig::train(EEGData training_data, string filter)
214 {
215  this->trained = false;
216  std::vector<int> selected_components = this->selected_components;
217  for(unsigned int i=0; i<selected_components.size();i++)
218  {
219  selected_components[i]--;
220  }
221 
222  if(selected_components[selected_components.size()-1] > num_components
223  || selected_components[0] < 0)
224  {
225  throw PluginException("Training filter failed because selected components are out of range.");
226  }
227 
228  training_data = model->getDataProcess()->process(training_data,true,true,false);
229  this->num_expected_channels = training_data.size1();
230  this->num_expected_lags = num_lags;
231  training_data = cppR::Lag(training_data.getMatrix(), num_lags);
232 
233  if(filter == "")
234  filter = this->selected_filter;
235 
236  plugin_loader->getPlugin(filter)->make(training_data, selected_components);
237  this->trained = true;
238 }
239 
240 //------------------------------
241 
243 {
244  const char * components = comp_string.c_str();
245  std::vector<int> comp;
246  int MAX_VALUE = num_channels * (this->num_lags+1);
247  num_components = MAX_VALUE;
248  int MIN_VALUE = 0;
249  int state = 0;
250  int location = 0;
251  int buffer_loc = 0;
252  bool cont = true; //is the string still valid?
253  bool end = false; //have we reached end of string?
254  char buffer[25] = "";
255  char current;
256  int colon_start = 0;
257 
258  while(cont && !end)
259  {
260  //what state are we in?
261  switch(state)
262  {
263  //init state - after a comma or at the beginning of string
264  //----------------------------------------
265  case 0:
266  current = components[location++];
267  //ignore whitespace
268  if(current == ' ')
269  break;
270 
271 
272  if(current >= '0' && current <= '9')
273  {
274  buffer[buffer_loc++] = current;
275  //we are in integer reading state now
276  state = 1;
277  }
278  else
279  {
280  cont = false;//failed
281 
282  }
283  break;
284 
285  //----------------------------------------
286  // reading integer
287  case 1:
288  //consume a character
289  current = components[location++];
290  if(current == ' ')
291  break;
292 
293  //if current character is an integer add it to the buffer
294  //and go back to integer state
295  if(current >= '0' && current <= '9')
296  {
297  buffer[buffer_loc++] = current;
298  //we are in integer reading state now
299  state = 1;
300  }
301  else if(current == ',')
302  {
303  buffer[buffer_loc] = '\0';
304  int val = atoi(buffer);
305  if(val > MAX_VALUE || val < MIN_VALUE)
306  {
307  cont = false;
308  break;
309  }
310  comp.push_back(val);
311  buffer_loc = 0;
312  state = 0;
313  }
314  else if(current == ':')
315  {
316  colon_start = atoi(buffer);
317  if(colon_start > MAX_VALUE || colon_start < MIN_VALUE)
318  {
319  cont = false;
320  break;
321  }
322  buffer_loc = 0;
323  state = 2;
324  }
325  else if(current == '\0')
326  {
327  buffer[buffer_loc] = '\0';
328  int val = atoi(buffer);
329  if(val > MAX_VALUE || val < MIN_VALUE)
330  {
331  cont = false;
332  break;
333  }
334  comp.push_back(val);
335  buffer_loc = 0;
336  end = true;
337  }
338  else
339  {
340  cont = false;//failed
341  }
342  break;
343  //----------------------------------------
344  //reading a ':'
345  case 2:
346  //consume a character
347  current = components[location++];
348  //ignore whitespace
349  if(current == ' ')
350  break;
351 
352  //must read an integer from here
353  if(current >= '0' && current <= '9')
354  {
355  buffer[buffer_loc++] = current;
356  //put us in the :integer state
357  state = 3;
358  }
359  else
360  {
361  cont = false;//nothing other than an integer can follow a colon
362  }
363  break;
364  //reading integer after colon
365  case 3:
366  //consume a character
367  current = components[location++];
368  //ignore whitespace
369  if(current == ' ')
370  break;
371 
372  //if current character is an integer add it to the buffer
373  //and go back to integer state
374  if(current >= '0' && current <= '9')
375  {
376  buffer[buffer_loc++] = current;
377  //we are in integer reading state now
378  state = 3;
379  }
380  else if(current == ',')
381  {
382  buffer[buffer_loc] = '\0';
383  int val = atoi(buffer);
384  if(val > MAX_VALUE || val < MIN_VALUE )
385  {
386  cont = false;
387  break;
388  }
389  if(val > colon_start)
390  for(int i=colon_start; i<= val; i++)
391  comp.push_back(i);
392  else
393  for(int i=val; i<= colon_start; i++)
394  comp.push_back(i);
395  buffer_loc = 0;
396  state = 0;
397  }
398  else if(current == '\0')
399  {
400  buffer[buffer_loc] = '\0';
401  int val = atoi(buffer);
402  if(val > MAX_VALUE || val < MIN_VALUE)
403  {
404  cont = false;
405  break;
406  }
407  if(val > colon_start)
408  for(int i=colon_start; i<= val; i++)
409  comp.push_back(i);
410  else
411  for(int i=val; i<= colon_start; i++)
412  comp.push_back(i);
413  buffer_loc = 0;
414  end = true;
415  }
416  else
417  {
418  cont = false;//failed
419  }
420  break;
421  default:
422  cont = false;
423  break;
424  }
425  }
426 
427  //save the resulting list of integers
428 
429  if(cont)
430  {
431 
432  //sort and pick unique components
433  std::sort(comp.begin(), comp.end());
434  std::vector<int>::iterator new_end =
435  std::unique(comp.begin(), comp.end());
436  comp.erase(new_end, comp.end());
437 
438  //create a string for the components
439  stringstream s;
440  this->selected_components.clear();
441  for(unsigned int i=0; i < comp.size()-1; i++)
442  {
443  this->selected_components.push_back(comp[i]);
444  s << comp[i] << ", ";
445  }
446  this->selected_components.push_back(comp[comp.size()-1]);
447  s << comp[comp.size()-1];
448 
449  //check that there are an okay number of selected components
450  bool comp_num_okay = false;
451  if(this->selected_components.size() <= unsigned(MAX_VALUE)
452  && this->selected_components.size() > 0)
453  {
454  if(this->selected_components[0] > 0
455  && this->selected_components[0] <= MAX_VALUE
456  && this->selected_components[this->selected_components.size()-1] > 0
457  && this->selected_components[this->selected_components.size()-1] <= MAX_VALUE)
458  {
459  comp_num_okay = true;
460  }
461  }
462  this->selected_components_valid = comp_num_okay;
463  if(comp_num_okay)
464  {
465  this->selected_components_string = s.str();
466  }
467  else
468  {
469  this->selected_components_string = "(value out of range)";
470  }
471  }
472  else
473  {
474  this->selected_components_valid = false;
475  this->selected_components_string = "(error parsing input)";
476  }
477 }