v2.0.0
Loading...
Searching...
No Matches
filterdesignview.cpp
Go to the documentation of this file.
1//=============================================================================================================
36
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "filterdesignview.h"
42#include "ui_filterdesignview.h"
43
45
46#include <dsp/filterio.h>
47
48#include <fiff/fiff_info.h>
49
50//=============================================================================================================
51// QT INCLUDES
52//=============================================================================================================
53
54#include <QDate>
55#include <QFileDialog>
56#include <QStandardPaths>
57#include <QSvgGenerator>
58#include <QCheckBox>
59#include <QSettings>
60#include <QApplication>
61#include <QKeyEvent>
62#include <QScreen>
63
64//=============================================================================================================
65// EIGEN INCLUDES
66//=============================================================================================================
67
68//=============================================================================================================
69// USED NAMESPACES
70//=============================================================================================================
71
72using namespace DISPLIB;
73using namespace FIFFLIB;
74using namespace UTILSLIB;
75
76//=============================================================================================================
77// DEFINE MEMBER METHODS
78//=============================================================================================================
79
80FilterDesignView::FilterDesignView(const QString& sSettingsPath,
81 QWidget *parent,
82 Qt::WindowFlags f)
83: AbstractView(parent, f)
84, m_pUi(new Ui::FilterDesignViewWidget)
85, m_iFilterTaps(512)
86, m_dSFreq(600)
87{
88 m_sSettingsPath = sSettingsPath;
89 m_pUi->setupUi(this);
90
95
98}
99
100//=============================================================================================================
101
103{
104 saveSettings();
105
106 delete m_pUi;
107}
108
109//=============================================================================================================
110
111void FilterDesignView::setMaxAllowedFilterTaps(int iMaxNumberFilterTaps)
112{
113 if(iMaxNumberFilterTaps%2 != 0) {
114 iMaxNumberFilterTaps--;
115 }
116
117 m_pUi->m_spinBox_filterTaps->setMaximum(iMaxNumberFilterTaps);
118 m_pUi->m_spinBox_filterTaps->setMinimum(16);
119
120 //Update filter depending on new window size
122}
123
124//=============================================================================================================
125
127{
128 return m_pUi->m_spinBox_filterTaps->value();
129}
130
131//=============================================================================================================
132
133void FilterDesignView::setSamplingRate(double dSamplingRate)
134{
135 if(dSamplingRate <= 0) {
136 qWarning() << "[FilterDesignView::setSamplingRate] Sampling frequency is <= 0. Returning.";
137 }
138
139 m_dSFreq = dSamplingRate;
140
141 //Update min max of spin boxes to nyquist
142 double nyquistFrequency = m_dSFreq/2;
143
144 m_pUi->m_doubleSpinBox_to->setMaximum(nyquistFrequency);
145 m_pUi->m_doubleSpinBox_from->setMaximum(nyquistFrequency);
146
147 if(m_pUi->m_doubleSpinBox_to->value()>m_dSFreq/2) {
148 m_pUi->m_doubleSpinBox_to->setValue(m_dSFreq/2);
149 }
150
151 if(m_pUi->m_doubleSpinBox_from->value()>m_dSFreq/2) {
152 m_pUi->m_doubleSpinBox_from->setValue(m_dSFreq/2);
153 }
154
156
158}
159
160//=============================================================================================================
161
163{
164 m_pUi->m_doubleSpinBox_from->setValue(dFrom);
166}
167
168//=============================================================================================================
169
171{
172 m_pUi->m_doubleSpinBox_to->setValue(dTo);
174}
175
176//=============================================================================================================
177
182
183//=============================================================================================================
184
186{
187 return m_pUi->m_comboBox_filterApplyTo->currentText();
188}
189
190//=============================================================================================================
191
192void FilterDesignView::setChannelType(const QString& sType)
193{
194 m_pUi->m_comboBox_filterApplyTo->setCurrentText(sType);
195 saveSettings();
196}
197
198//=============================================================================================================
199
201{
202 if(m_sSettingsPath.isEmpty()) {
203 return;
204 }
205
206 QSettings settings("MNECPP");
207
208 settings.setValue(m_sSettingsPath + QString("/FilterDesignView/filterFrom"), m_filterKernel.getHighpassFreq());
209 settings.setValue(m_sSettingsPath + QString("/FilterDesignView/filterTo"), m_filterKernel.getLowpassFreq());
210 settings.setValue(m_sSettingsPath + QString("/FilterDesignView/filterOrder"), m_filterKernel.getFilterOrder());
211 settings.setValue(m_sSettingsPath + QString("/FilterDesignView/filterDesignMethod"), FilterKernel::m_designMethods.indexOf(m_filterKernel.getDesignMethod()));
212 settings.setValue(m_sSettingsPath + QString("/FilterDesignView/filterTransition"), m_filterKernel.getParksWidth()*(m_filterKernel.getSamplingFrequency()/2));
213 settings.setValue(m_sSettingsPath + QString("/FilterDesignView/filterChannelType"), getChannelType());
214 settings.setValue(m_sSettingsPath + QString("/FilterDesignView/Position"), this->pos());
215}
216
217//=============================================================================================================
218
220{
221 if(m_sSettingsPath.isEmpty()) {
222 return;
223 }
224
225 QSettings settings("MNECPP");
226
227 //Set stored filter settings from last session
228 m_pUi->m_doubleSpinBox_to->setValue(settings.value(m_sSettingsPath + QString("/FilterDesignView/filterTo"), 40.0).toDouble());
229 m_pUi->m_doubleSpinBox_from->setValue(settings.value(m_sSettingsPath + QString("/FilterDesignView/filterFrom"), 1.0).toDouble());
230 m_pUi->m_spinBox_filterTaps->setValue(settings.value(m_sSettingsPath + QString("/FilterDesignView/filterOrder"), 128).toInt());
231 m_pUi->m_comboBox_designMethod->setCurrentIndex(settings.value(m_sSettingsPath + QString("/FilterDesignView/filterDesignMethod"), FilterKernel::m_designMethods.indexOf(FilterParameter("Cosine"))).toInt());
232 m_pUi->m_doubleSpinBox_transitionband->setValue(settings.value(m_sSettingsPath + QString("/FilterDesignView/filterTransition"), 0.1).toDouble());
233 m_pUi->m_comboBox_filterApplyTo->setCurrentText(settings.value(m_sSettingsPath + QString("/FilterDesignView/filterChannelType"), "All").toString());
234
235 QPoint pos = settings.value(m_sSettingsPath + QString("/FilterDesignView/Position"), QPoint(100,100)).toPoint();
236
237 QRect screenRect = QApplication::primaryScreen()->geometry();
238 if(!screenRect.contains(pos) && QGuiApplication::screens().size() == 1) {
239 move(QPoint(100,100));
240 } else {
241 move(pos);
242 }
243}
244
245//=============================================================================================================
246
248{
249 switch(mode) {
251 break;
252 default: // default is research mode
253 break;
254 }
255}
256
257//=============================================================================================================
258
260{
261 switch(mode) {
263 break;
264 default: // default is realtime mode
265 break;
266 }
267}
268
269//=============================================================================================================
270
272{
273 connect(m_pUi->m_doubleSpinBox_from, &QDoubleSpinBox::editingFinished,
275
276 connect(m_pUi->m_doubleSpinBox_to, &QDoubleSpinBox::editingFinished,
278
279 connect(m_pUi->m_doubleSpinBox_transitionband, &QDoubleSpinBox::editingFinished,
281
282 connect(m_pUi->m_spinBox_filterTaps, &QSpinBox::editingFinished,
284
285 //Intercept events from the spin boxes to get control over key events
286 m_pUi->m_doubleSpinBox_from->installEventFilter(this);
287 m_pUi->m_doubleSpinBox_to->installEventFilter(this);
288 m_pUi->m_doubleSpinBox_transitionband->installEventFilter(this);
289}
290
291//=============================================================================================================
292
294{
295 connect(m_pUi->m_pushButton_exportPlot,&QPushButton::released,
297
298 connect(m_pUi->m_pushButton_exportFilter,&QPushButton::released,
300
301 connect(m_pUi->m_pushButton_loadFilter,&QPushButton::released,
303}
304
305//=============================================================================================================
306
308{
310 m_pUi->m_comboBox_designMethod->addItem(filterMethod.getName());
311 }
312
313 connect(m_pUi->m_comboBox_designMethod,static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
315
316 //Initial selection is a bandpass and Cosine design method
317 m_pUi->m_doubleSpinBox_from->setVisible(true);
318 m_pUi->m_label_lowpass->setVisible(true);
319
320 m_pUi->m_doubleSpinBox_to->setVisible(true);
321 m_pUi->m_label_highpass->setVisible(true);
322
323 m_pUi->m_spinBox_filterTaps->setVisible(true);
324 m_pUi->m_label_filterTaps->setVisible(true);
325
326 connect(m_pUi->m_comboBox_filterApplyTo, &QComboBox::currentTextChanged,
328}
329
330//=============================================================================================================
331
333{
334 m_pFilterPlotScene = new FilterPlotScene(m_pUi->m_graphicsView_filterPlot, this);
335
336 m_pUi->m_graphicsView_filterPlot->setScene(m_pFilterPlotScene);
337 m_pUi->m_graphicsView_filterPlot->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
338 m_pUi->m_graphicsView_filterPlot->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
339
341}
342
343//=============================================================================================================
344
345void FilterDesignView::resizeEvent(QResizeEvent* event)
346{
347 Q_UNUSED(event);
348 m_pUi->m_graphicsView_filterPlot->fitInView(m_pFilterPlotScene->itemsBoundingRect(), Qt::KeepAspectRatio);
349}
350
351//=============================================================================================================
352
353void FilterDesignView::keyPressEvent(QKeyEvent * event)
354{
355 if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
356 emit filterChannelTypeChanged(m_pUi->m_comboBox_filterApplyTo->currentText());
357 }
358
359 if((event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Z) || event->key() == Qt::Key_Delete) {
360 emit filterChannelTypeChanged(m_pUi->m_comboBox_filterApplyTo->currentText());
361 }
362}
363
364//=============================================================================================================
365
367{
368 //Update the filter of the scene
370 m_filterKernel.getSamplingFrequency(), //Pass the filters sampling frequency, not the one from the fiff info. Reason: sFreq from a loaded filter could be different
371 m_pUi->m_doubleSpinBox_from->value(),
372 m_pUi->m_doubleSpinBox_to->value());
373
374 m_pUi->m_graphicsView_filterPlot->fitInView(m_pFilterPlotScene->itemsBoundingRect(), Qt::KeepAspectRatio);
375}
376
377//=============================================================================================================
378
380{
381 Q_UNUSED(currentIndex);
382
383 //Change visibility of filter tap spin boxes depending on filter design method
384 switch(m_pUi->m_comboBox_designMethod->currentIndex()) {
385 case 0: //Cosine
386// m_pUi->m_spinBox_filterTaps->setVisible(false);
387// m_pUi->m_label_filterTaps->setVisible(false);
388 m_pUi->m_spinBox_filterTaps->setVisible(true);
389 m_pUi->m_label_filterTaps->setVisible(true);
390 break;
391
392 case 1: //Tschebyscheff
393 m_pUi->m_spinBox_filterTaps->setVisible(true);
394 m_pUi->m_label_filterTaps->setVisible(true);
395 break;
396 }
397
399}
400
401//=============================================================================================================
402
404{
405 emit updateFilterFrom(m_pUi->m_doubleSpinBox_from->value());
406 emit updateFilterTo(m_pUi->m_doubleSpinBox_to->value());
407
408 //User defined filter parameters
409 double from = m_pUi->m_doubleSpinBox_from->value();
410 double to = m_pUi->m_doubleSpinBox_to->value();
411
412 double trans_width = m_pUi->m_doubleSpinBox_transitionband->value();
413
414 double bw = to-from;
415 double center = from+bw/2;
416
417 double nyquistFrequency = m_dSFreq/2;
418
419 //Calculate the needed fft length
420 m_iFilterTaps = m_pUi->m_spinBox_filterTaps->value();
421 if(m_pUi->m_spinBox_filterTaps->value()%2 != 0) {
423 }
424
425 //set maximum and minimum for cut off frequency spin boxes
426 m_pUi->m_doubleSpinBox_to->setMaximum(nyquistFrequency);
427 m_pUi->m_doubleSpinBox_from->setMaximum(nyquistFrequency);
428 m_pUi->m_doubleSpinBox_to->setMinimum(0);
429 m_pUi->m_doubleSpinBox_from->setMinimum(0);
430
431 if((m_pUi->m_doubleSpinBox_to->value() < m_pUi->m_doubleSpinBox_from->value())) {
432 m_pUi->m_doubleSpinBox_to->setValue(m_pUi->m_doubleSpinBox_from->value() + 1);
433 }
434
435 m_pUi->m_doubleSpinBox_to->setMinimum(m_pUi->m_doubleSpinBox_from->value());
436 m_pUi->m_doubleSpinBox_from->setMaximum(m_pUi->m_doubleSpinBox_to->value());
437
438 int iMethod = FilterKernel::m_designMethods.indexOf(FilterParameter(m_pUi->m_comboBox_designMethod->currentText()));
439
440 //Generate filters
441 m_filterKernel = FilterKernel("Designed Filter",
444 (double)center/nyquistFrequency,
445 (double)bw/nyquistFrequency,
446 (double)trans_width/nyquistFrequency,
447 m_dSFreq,
448 iMethod);
449
451
452 //update filter plot
454
455 saveSettings();
456}
457
458//=============================================================================================================
459
460void FilterDesignView::onSpinBoxFilterChannelType(const QString& channelType)
461{
462 emit filterChannelTypeChanged(channelType);
463}
464
465//=============================================================================================================
466
468{
469 // Open file dialog
470 QDate date;
471 QString fileName = QFileDialog::getSaveFileName(this,
472 "Save filter plot",
473 QString("%1/%2_%3_%4_FilterPlot").arg(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).arg(date.currentDate().year()).arg(date.currentDate().month()).arg(date.currentDate().day()),
474 tr("Vector graphic(*.svg);;Images (*.png)"));
475
476 if(!fileName.isEmpty()) {
477 // Generate screenshot
478 if(fileName.contains(".svg")) {
479 QSvgGenerator svgGen;
480
481 svgGen.setFileName(fileName);
482 QRectF rect = m_pFilterPlotScene->itemsBoundingRect();
483 svgGen.setSize(QSize(rect.width(), rect.height()));
484 //svgGen.setViewBox(QRect(0, 0, rect.width(), rect.height()));
485
486 QPainter painter(&svgGen);
487 m_pFilterPlotScene->render(&painter);
488 }
489
490 if(fileName.contains(".png")) {
491 m_pFilterPlotScene->setSceneRect(m_pFilterPlotScene->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
492 QImage image(m_pFilterPlotScene->sceneRect().size().toSize(), QImage::Format_ARGB32); // Create the image with the exact size of the shrunk scene
493 image.fill(Qt::transparent); // Start all pixels transparent
494
495 QPainter painter(&image);
496 m_pFilterPlotScene->render(&painter);
497 image.save(fileName);
498 }
499 }
500}
501
502//=============================================================================================================
503
505{
506 //Generate appropriate name for the filter to be saved
507 QString filtername;
508
509 filtername = QString("%1_%2_%3_Fs%4").arg(m_filterKernel.getFilterType().getName()).arg((int)m_filterKernel.getHighpassFreq()).arg((int)m_filterKernel.getLowpassFreq()).arg((int)m_filterKernel.getSamplingFrequency());
510
511 //Do not pass m_filterKernel because this is most likely the User Defined filter which name should not change due to the filter model implementation. Hence use temporal copy of m_filterKernel.
512 FilterKernel filterWriteTemp = m_filterKernel;
513 filterWriteTemp.getName() = filtername;
514
515 QString fileName = QFileDialog::getSaveFileName(this,
516 "Save filter coefficients",
517 QString("%1/%2").arg(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).arg(filtername),
518 tr("Text file(*.txt)"));
519
520 FilterIO::writeFilter(fileName, filterWriteTemp);
521}
522
523//=============================================================================================================
524
526{
527 QString path = QFileDialog::getOpenFileName(this,
528 QString("Load filter"),
529 QString("./"),
530 tr("txt files (*.txt)"));
531
532 if(!path.isEmpty()) {
533 //Replace old with new filter operator
534 FilterKernel filterLoadTemp;
535
536 if(!FilterIO::readFilter(path, filterLoadTemp)) {
537 return;
538 }
539 updateGuiFromFilter(filterLoadTemp);
540
542
544
545 } else {
546 qDebug()<<"Could not load filter.";
547 }
548}
549
550//=============================================================================================================
551
553{
554
555}
556
557//=============================================================================================================
558
560{
561 return m_pUi->m_doubleSpinBox_from->value();
562}
563
564//=============================================================================================================
565
567{
568 return m_pUi->m_doubleSpinBox_to->value();
569}
570
571//=============================================================================================================
572
574{
575 m_pUi->m_doubleSpinBox_from->setValue(filter.getHighpassFreq());
576 m_pUi->m_doubleSpinBox_to->setValue(filter.getLowpassFreq());
577 m_pUi->m_spinBox_filterTaps->setValue(filter.getFilterOrder());
578 m_pUi->m_doubleSpinBox_transitionband->setValue(filter.getParksWidth()*(filter.getSamplingFrequency()/2));
579
580 m_pUi->m_comboBox_designMethod->setCurrentIndex(FilterKernel::m_designMethods.indexOf(filter.getDesignMethod()));
581}
582
583//=============================================================================================================
584
Contains the declaration of the FilterDesignView class.
Contains the declaration of the FilterPlotScene class.
FiffInfo class declaration.
FilterIO class declaration.
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
2-D display widgets and visualisation helpers (charts, topography, colour maps).
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
AbstractView(QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void setMaxAllowedFilterTaps(int iMaxNumberFilterTaps)
void changeStateSpinBoxes(int currentIndex)
void updateFilterFrom(double dFrom)
void updateGuiMode(GuiMode mode)
void setSamplingRate(double dSamplingRate)
void updateFilterTo(double dTo)
QPointer< FilterPlotScene > m_pFilterPlotScene
void resizeEvent(QResizeEvent *event)
virtual void keyPressEvent(QKeyEvent *event)
UTILSLIB::FilterKernel m_filterKernel
void guiStyleChanged(DISPLIB::AbstractView::StyleMode style)
UTILSLIB::FilterKernel getCurrentFilter()
void setChannelType(const QString &sType)
Ui::FilterDesignViewWidget * m_pUi
void updateProcessingMode(ProcessingMode mode)
void onSpinBoxFilterChannelType(const QString &channelType)
void filterChannelTypeChanged(const QString &channelType)
void updateGuiFromFilter(const UTILSLIB::FilterKernel &filter)
FilterDesignView(const QString &sSettingsPath, QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void filterChanged(const UTILSLIB::FilterKernel &activeFilter)
The FilterPlotScene class provides the scene where a filter response can be plotted.
static bool readFilter(QString path, FilterKernel &filter)
Definition filterio.cpp:68
static bool writeFilter(const QString &path, const FilterKernel &filter)
Definition filterio.cpp:153
Named filter-design parameter descriptor holding a human-readable name and description (e....
The FilterKernel class provides methods to create/design a FIR filter kernel.
double getParksWidth() const
double getSamplingFrequency() const
QString getName() const
static QVector< FilterParameter > m_designMethods
static QVector< FilterParameter > m_filterTypes
double getLowpassFreq() const
double getHighpassFreq() const
FilterParameter getDesignMethod() const