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