v2.0.0
Loading...
Searching...
No Matches
mne_raw_data.cpp
Go to the documentation of this file.
1//=============================================================================================================
17
18//=============================================================================================================
19// INCLUDES
20//=============================================================================================================
21
22#include "mne_raw_data.h"
23
24#include <QFile>
25#include <QDebug>
26#include <QTextStream>
27
28#include <Eigen/Core>
29
30#define _USE_MATH_DEFINES
31#include <math.h>
32
33//=============================================================================================================
34// USED NAMESPACES
35//=============================================================================================================
36
37using namespace Eigen;
38using namespace FIFFLIB;
39using namespace MNELIB;
40
41constexpr int FAIL = -1;
42constexpr int OK = 0;
43
44#if defined(_WIN32) || defined(_WIN64)
45#define snprintf _snprintf
46#define vsnprintf _vsnprintf
47#define strcasecmp _stricmp
48#define strncasecmp _strnicmp
49#endif
50
51namespace MNELIB
52{
53
55using RowMajorMatrixXf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
56
65{
66 struct Entry {
68 };
69
70 std::vector<Entry> entries;
71 int next = 0;
72
73 explicit RingBuffer(int nslots)
74 : entries(static_cast<size_t>(nslots))
75 , next(0)
76 {}
77
79 void allocate(int nrow, int ncol, RowMajorMatrixXf *res)
80 {
81 if (next >= static_cast<int>(entries.size()))
82 next = 0;
83 Entry &e = entries[static_cast<size_t>(next++)];
84 if (e.user) // evict old occupant
85 e.user->resize(0, 0);
86 res->resize(nrow, ncol);
87 e.user = res;
88 }
89};
90
91}
92
93//============================= misc_util.c =============================
94
95//============================= mne_apply_filter.c =============================
96
97namespace MNELIB
98{
99
107{
108 std::vector<float> freq_resp;
109 std::vector<float> eog_freq_resp;
110 std::vector<float> precalc;
111
112 explicit FilterData(int resp_size)
113 : freq_resp(static_cast<size_t>(resp_size), 1.0f)
114 , eog_freq_resp(static_cast<size_t>(resp_size), 1.0f)
115 {}
116};
117
118}
119
121 const MNEFilterDef& f2)
122/*
123 * Return 0 if the two filter definitions are same, 1 otherwise
124 */
125{
126 if (f1.filter_on != f2.filter_on ||
127 std::fabs(f1.lowpass - f2.lowpass) > 0.1 ||
128 std::fabs(f1.lowpass_width - f2.lowpass_width) > 0.1 ||
129 std::fabs(f1.highpass - f2.highpass) > 0.1 ||
130 std::fabs(f1.highpass_width - f2.highpass_width) > 0.1 ||
131 std::fabs(f1.eog_lowpass - f2.eog_lowpass) > 0.1 ||
132 std::fabs(f1.eog_lowpass_width - f2.eog_lowpass_width) > 0.1 ||
133 std::fabs(f1.eog_highpass - f2.eog_highpass) > 0.1 ||
134 std::fabs(f1.eog_highpass_width - f2.eog_highpass_width) > 0.1)
135 return 1;
136 else
137 return 0;
138}
139
140//============================= mne_fft.c =============================
141
142void mne_fft_ana(float *data, int np, std::vector<float>& /*precalc*/)
143/*
144 * FFT analysis for real data
145 */
146{
147 Q_UNUSED(data);
148 Q_UNUSED(np);
149 qCritical("##################### DEBUG Error: FFT analysis needs to be implemented");
150 return;
151}
152
153void mne_fft_syn(float *data, int np, std::vector<float>& /*precalc*/)
154/*
155 * FFT synthesis for real data
156 */
157{
158 Q_UNUSED(data);
159 Q_UNUSED(np);
160 qCritical("##################### DEBUG Error: FFT synthesis needs to be implemented");
161 return;
162}
163
164int mne_apply_filter(const MNEFilterDef& filter, FilterData *d, float *data, int ns, int zero_pad, float dc_offset, int kind)
165/*
166 * Do the magick trick
167 */
168{
169 int k,p,n;
170 float *freq_resp;
171
172 if (ns != filter.size + 2*filter.taper_size) {
173 qCritical("Incorrect data length in apply_filter");
174 return FAIL;
175 }
176 /*
177 * Zero padding
178 */
179 if (zero_pad) {
180 for (k = 0; k < filter.taper_size; k++)
181 data[k] = 0.0;
182 for (k = filter.taper_size + filter.size; k < ns; k++)
183 data[k] = 0.0;
184 }
185 if (!filter.filter_on) /* Nothing else to do */
186 return OK;
187 /*
188 * Make things nice by compensating for the dc offset
189 */
190 if (dc_offset != 0.0) {
191 for (k = filter.taper_size; k < filter.taper_size + filter.size; k++)
192 data[k] = data[k] - dc_offset;
193 }
194 if (!d)
195 return OK;
196 if (d->freq_resp.empty())
197 return OK;
198 /*
199 * Next comes the FFT
200 */
201 mne_fft_ana(data,ns,d->precalc);
202 /*
203 * Multiply with the frequency response
204 * See FFTpack doc for details of the arrangement
205 */
206 n = ns % 2 == 0 ? ns/2 : (ns+1)/2;
207 p = 0;
208 /*
209 * No imaginary part for the DC component
210 */
211 if (kind == FIFFV_EOG_CH)
212 freq_resp = d->eog_freq_resp.data();
213 else
214 freq_resp = d->freq_resp.data();
215 data[p] = data[p]*freq_resp[0]; p++;
216 /*
217 * The other components
218 */
219 for (k = 1 ; k < n ; k++) {
220 data[p] = data[p]*freq_resp[k]; p++;
221 data[p] = data[p]*freq_resp[k]; p++;
222 }
223 /*
224 * Then the last value
225 */
226 if (ns % 2 == 0)
227 data[p] = data[p]*freq_resp[k];
228
229 mne_fft_syn(data,ns,d->precalc);
230
231 return OK;
232}
233
234std::unique_ptr<FilterData> mne_create_filter_response(const MNEFilterDef& filter,
235 float sfreq,
236 int *highpass_effective)
237/*
238 * Create a frequency response
239 */
240{
241 int resp_size;
242 int k,s,w,f;
243 int highpasss,lowpasss;
244 int highpass_widths,lowpass_widths;
245 float lowpass,highpass,lowpass_width,highpass_width;
246 float *freq_resp;
247 float pi4 = M_PI/4.0;
248 float mult,add,c;
249
250 resp_size = (filter.size + 2*filter.taper_size)/2 + 1;
251
252 auto filter_data = std::make_unique<FilterData>(resp_size);
253 *highpass_effective = false;
254
255 for (f = 0; f < 2; f++) {
256 highpass = f == 0 ? filter.highpass : filter.eog_highpass;
257 highpass_width = f == 0 ? filter.highpass_width : filter.eog_highpass_width;
258 lowpass = f == 0 ? filter.lowpass : filter.eog_lowpass;
259 lowpass_width = f == 0 ? filter.lowpass_width : filter.eog_lowpass_width;
260 freq_resp = f == 0 ? filter_data->freq_resp.data() : filter_data->eog_freq_resp.data();
261 /*
262 * Start simple first
263 */
264 highpasss = ((resp_size-1)*highpass)/(0.5*sfreq);
265 lowpasss = ((resp_size-1)*lowpass)/(0.5*sfreq);
266
267 lowpass_widths = ((resp_size-1)*lowpass_width)/(0.5*sfreq);
268 lowpass_widths = (lowpass_widths+1)/2; /* What user specified */
269
270 if (filter.highpass_width > 0.0) {
271 highpass_widths = ((resp_size-1)*highpass_width)/(0.5*sfreq);
272 highpass_widths = (highpass_widths+1)/2; /* What user specified */
273 }
274 else
275 highpass_widths = 3; /* Minimal */
276
277 if (filter.filter_on) {
278 qInfo("filter : %7.3f ... %6.1f Hz bins : %d ... %d of %d hpw : %d lpw : %d\n",
279 highpass,
280 lowpass,
281 highpasss,
282 lowpasss,
283 resp_size,
284 highpass_widths,
285 lowpass_widths);
286 }
287 if (highpasss > highpass_widths + 1) {
288 w = highpass_widths;
289 mult = 1.0/w;
290 add = 3.0;
291 for (k = 0; k < highpasss-w+1; k++)
292 freq_resp[k] = 0.0;
293 for (k = -w+1, s = highpasss-w+1; k < w; k++, s++) {
294 if (s >= 0 && s < resp_size) {
295 c = cos(pi4*(k*mult+add));
296 freq_resp[s] = freq_resp[s]*c*c;
297 }
298 }
299 *highpass_effective = true;
300 }
301 else
302 *highpass_effective = *highpass_effective || (filter.highpass == 0.0);
303
304 if (lowpass_widths > 0) {
305 w = lowpass_widths;
306 mult = 1.0/w;
307 add = 1.0;
308 for (k = -w+1, s = lowpasss-w+1; k < w; k++, s++) {
309 if (s >= 0 && s < resp_size) {
310 c = cos(pi4*(k*mult+add));
311 freq_resp[s] = freq_resp[s]*c*c;
312 }
313 }
314 for (k = s; k < resp_size; k++)
315 freq_resp[k] = 0.0;
316 }
317 else {
318 for (k = lowpasss; k < resp_size; k++)
319 freq_resp[k] = 0.0;
320 }
321 if (filter.filter_on) {
322 if (*highpass_effective)
323 qInfo("Highpass filter will work as specified.\n");
324 else
325 qWarning("NOTE: Highpass filter omitted due to a too low corner frequency.\n");
326 }
327 else
328 qWarning("NOTE: Filter is presently switched off.\n");
329 }
330 return filter_data;
331}
332
333//============================= mne_raw_routines.c =============================
334
335int mne_read_raw_buffer_t(//fiffFile in, /* Input file */
336 FiffStream::SPtr& stream,
337 const FiffDirEntry::SPtr& ent, /* The directory entry to read */
338 RowMajorMatrixXf& data, /* Matrix [npick x nsamp] to fill */
339 int nchan, /* Number of channels in the data */
340 int nsamp, /* Expected number of samples */
341 const QList<FIFFLIB::FiffChInfo>& chs, /* Channel info for ALL channels */
342 int *pickno, /* Which channels to pick */
343 int npick) /* How many */
344
345{
346 FiffTag::UPtr t_pTag;
347// fiffTagRec tag;
348 fiff_short_t *this_samples;
349 const fiff_float_t *this_samplef;
350 fiff_int_t *this_sample;
351
352 int s,c;
353 int do_all;
354
355// tag.data = NULL;
356
357 Eigen::VectorXi pickno_vec;
358 if (npick == 0) {
359 pickno_vec = Eigen::VectorXi::LinSpaced(nchan, 0, nchan - 1);
360 pickno = pickno_vec.data();
361 do_all = true;
362 npick = nchan;
363 }
364 else
365 do_all = false;
366
367 Eigen::VectorXf mult(npick);
368 for (c = 0; c < npick; c++)
369 mult[c] = chs[pickno[c]].cal*chs[pickno[c]].range;
370
371// if (fiff_read_this_tag(in->fd,ent->pos,&tag) == FIFF_FAIL)
372// goto bad;
373 if (!stream->read_tag(t_pTag,ent->pos))
374 return FAIL;
375
376 if (ent->type == FIFFT_FLOAT) {
377 if (static_cast<int>(t_pTag->size()/(sizeof(fiff_float_t)*nchan)) != nsamp) {
378 qCritical("Incorrect number of samples in buffer.");
379 return FAIL;
380 }
381 qDebug() << "ToDo: Check whether this_samplef contains the right stuff!!! - use VectorXf instead";
382 this_samplef = t_pTag->toFloat();
383 for (s = 0; s < nsamp; s++, this_samplef += nchan) {
384 for (c = 0; c < npick; c++)
385 data(c,s) = mult[c]*this_samplef[pickno[c]];
386 }
387 }
388 else if (ent->type == FIFFT_SHORT || ent->type == FIFFT_DAU_PACK16) {
389 if (static_cast<int>(t_pTag->size()/(sizeof(fiff_short_t)*nchan)) != nsamp) {
390 qCritical("Incorrect number of samples in buffer.");
391 return FAIL;
392 }
393 qDebug() << "ToDo: Check whether this_samples contains the right stuff!!! - use VectorXi instead";
394 this_samples = (fiff_short_t *)t_pTag->data();
395 for (s = 0; s < nsamp; s++, this_samples += nchan) {
396 for (c = 0; c < npick; c++)
397 data(c,s) = mult[c]*this_samples[pickno[c]];
398 }
399 }
400 else if (ent->type == FIFFT_INT) {
401 if (static_cast<int>(t_pTag->size()/(sizeof(fiff_int_t)*nchan)) != nsamp) {
402 qCritical("Incorrect number of samples in buffer.");
403 return FAIL;
404 }
405 qDebug() << "ToDo: Check whether this_sample contains the right stuff!!! - use VectorXi instead";
406 this_sample = t_pTag->toInt();
407 for (s = 0; s < nsamp; s++, this_sample += nchan) {
408 for (c = 0; c < npick; c++)
409 data(c,s) = mult[c]*this_sample[pickno[c]];
410 }
411 }
412 else {
413 qCritical("We are not prepared to handle raw data type: %d",ent->type);
414 return FAIL;
415 }
416 return OK;
417}
418
419//============================= mne_process_bads.c =============================
420
422 const FiffDirNode::SPtr& pNode, QStringList& listp, int& nlistp)
423{
424 FiffDirNode::SPtr node,bad;
425 QList<FiffDirNode::SPtr> temp;
426 QStringList list;
427 int nlist = 0;
428 FiffTag::UPtr t_pTag;
429 QString names;
430
431 if (pNode->isEmpty())
432 node = stream->dirtree();
433 else
434 node = pNode;
435
436 temp = node->dir_tree_find(FIFFB_MNE_BAD_CHANNELS);
437 if (temp.size() > 0) {
438 bad = temp[0];
439
440 bad->find_tag(stream, FIFF_MNE_CH_NAME_LIST, t_pTag);
441 if (t_pTag) {
442 names = t_pTag->toString();
443 list = FiffStream::split_name_list(names);
444 nlist = list.size();
445 }
446 }
447 listp = list;
448 nlistp = nlist;
449 return OK;
450}
451
452int mne_read_bad_channel_list(const QString& name, QStringList& listp, int& nlistp)
453
454{
455 QFile file(name);
456 FiffStream::SPtr stream(new FiffStream(&file));
457
458 int res;
459
460 if(!stream->open())
461 return FAIL;
462
463 res = mne_read_bad_channel_list_from_node(stream,stream->dirtree(),listp,nlistp);
464
465 stream->close();
466
467 return res;
468}
469
470int mne_sparse_vec_mult2(FiffSparseMatrix* mat, /* The sparse matrix */
471 float *vector, /* Vector to be multiplied */
472 float *res) /* Result of the multiplication */
473/*
474 * Multiply a vector by a sparse matrix using Eigen.
475 */
476{
477 Eigen::Map<const Eigen::VectorXf> vecIn(vector, mat->cols());
478 Eigen::Map<Eigen::VectorXf> vecOut(res, mat->rows());
479 vecOut = mat->eigen() * vecIn;
480 return 0;
481}
482
483int mne_sparse_mat_mult2(FiffSparseMatrix* mat, /* The sparse matrix */
484 const RowMajorMatrixXf& mult, /* Matrix to be multiplied */
485 int ncol, /* How many columns in the above */
486 RowMajorMatrixXf& res) /* Result of the multiplication */
487/*
488 * Multiply a dense matrix by a sparse matrix using Eigen.
489 */
490{
491 Q_UNUSED(ncol);
492 // mat->eigen() is column-major sparse, mult is row-major dense
493 // Result: res = sparse * mult (rows: mat->rows(), cols: mult.cols())
494 res = mat->eigen() * mult;
495 return 0;
496}
497
498#define APPROX_RING_BUF_SIZE (600*1024*1024)
499
500static int approx_ring_buf_size = APPROX_RING_BUF_SIZE;
501
502//=============================================================================================================
503// DEFINE MEMBER METHODS
504//=============================================================================================================
505
507:info(nullptr)
508,nbad(0)
509,first_samp(0)
510,omit_samp(0)
513,nsamp(0)
514,proj(nullptr)
515,sss(nullptr)
516,comp(nullptr)
519,max_event(0)
521,deriv(nullptr)
522,deriv_matched(nullptr)
523{
524}
525
526//=============================================================================================================
527
529{
530// fiff_close(this->file);
531 if (this->stream)
532 this->stream->close();
533 this->filename.clear();
534 this->ch_names.clear();
535
536 this->badlist.clear();
537
538 this->dig_trigger.clear();
539 this->event_list.reset();
540}
541
542//=============================================================================================================
543
544void MNERawData::add_filter_response(int *highpass_effective)
545/*
546 * Add the standard filter frequency response function
547 */
548{
549 /*
550 * Free the previous filter definition
551 */
552 filter_data.reset();
553 /*
554 * Nothing more to do if there is no filter
555 */
556 if (!filter)
557 return;
558 /*
559 * Create a new one
560 */
562 info->sfreq,
563 highpass_effective);
564}
565
566//=============================================================================================================
567
569/*
570 * These will hold the filtered data
571 */
572{
573 MNEFilterDef* filter = this->filter.get();
574 int nfilt_buf;
575 int k;
576 int firstsamp;
577 int nring_buf;
578 int highpass_effective;
579
580 this->filt_bufs.clear();
581 this->filt_ring.reset();
582
583 if (!this->filter || filter->size <= 0)
584 return;
585
586 for (nfilt_buf = 0, firstsamp = this->first_samp-filter->taper_size;
587 firstsamp < this->nsamp + this->first_samp;
588 firstsamp = firstsamp + filter->size)
589 nfilt_buf++;
590#ifdef DEBUG
591 qInfo("%d filter buffers needed\n",nfilt_buf);
592#endif
593 this->filt_bufs.resize(nfilt_buf);
594 for (k = 0, firstsamp = this->first_samp-filter->taper_size; k < nfilt_buf; k++,
595 firstsamp = firstsamp + filter->size) {
596 filt_bufs[k].ns = filter->size + 2*filter->taper_size;
597 filt_bufs[k].firsts = firstsamp;
598 filt_bufs[k].lasts = firstsamp + filt_bufs[k].ns - 1;
599 // bufs[k].ent = NULL;
600 filt_bufs[k].nchan = this->info->nchan;
601 filt_bufs[k].is_skip = false;
602 filt_bufs[k].valid = false;
603 filt_bufs[k].ch_filtered = Eigen::VectorXi::Zero(this->info->nchan);
604 filt_bufs[k].comp_status = MNE_CTFV_NOGRAD;
605 }
606 nring_buf = approx_ring_buf_size/((2*filter->taper_size+filter->size)*
607 static_cast<std::size_t>(this->info->nchan)*sizeof(float));
608 this->filt_ring = std::make_unique<RingBuffer>(nring_buf);
609 add_filter_response(&highpass_effective);
610
611 return;
612}
613
614//=============================================================================================================
615
617/*
618 * load just one
619 */
620{
621 if (buf->ent->kind == FIFF_DATA_SKIP) {
622 qCritical("Cannot load a skip");
623 return FAIL;
624 }
625 if (buf->vals.size() == 0) { /* The data space may have been reused */
626 buf->valid = false;
627 ring->allocate(buf->nchan,buf->ns,&buf->vals);
628 }
629 if (buf->valid)
630 return OK;
631
632#ifdef DEBUG
633 qDebug("Read buffer %d .. %d\n",buf->firsts,buf->lasts);
634#endif
635
637 buf->ent,
638 buf->vals,
639 buf->nchan,
640 buf->ns,
641 info->chInfo,
642 nullptr,0) != OK) {
643 buf->valid = false;
644 return FAIL;
645 }
646 buf->valid = true;
647 buf->comp_status = comp_file;
648 return OK;
649}
650
651//=============================================================================================================
652
654/*
655 * Apply compensation channels
656 */
657{
658
659 if (!comp)
660 return OK;
661 if (!comp->undo && !comp->current)
662 return OK;
663 if (buf->comp_status == comp_now)
664 return OK;
665 if (buf->vals.size() == 0)
666 return OK;
667 /*
668 * vals is now a RowMajorMatrixXf — wrap in a column-major MatrixXf for compensation
669 */
670 {
671 Eigen::MatrixXf dataMat = buf->vals; /* implicit copy/conversion */
672
673 if (comp->undo) {
674 std::swap(comp->current, comp->undo);
675 /*
676 * Undo the previous compensation
677 */
678 if (comp->apply_transpose(false, dataMat) != OK) {
679 std::swap(comp->current, comp->undo);
680 return FAIL;
681 }
682 std::swap(comp->current, comp->undo);
683 }
684 if (comp->current) {
685 /*
686 * Apply new compensation
687 */
688 if (comp->apply_transpose(true, dataMat) != OK)
689 return FAIL;
690 }
691 /*
692 * Copy result back to buf->vals
693 */
694 buf->vals = dataMat;
695 }
696 buf->comp_status = comp_now;
697 return OK;
698}
699
700//=============================================================================================================
701
702int MNERawData::pick_data(mneChSelection sel, int firsts, int ns, float **picked)
703/*
704 * Data from a selection of channels
705 */
706{
707 int k,s,p,start,c,fills;
708 int ns2,s2;
709 MNERawBufDef* this_buf;
710 float *values;
711 int need_some;
712
713 RowMajorMatrixXf deriv_vals;
714 int deriv_ns = 0;
715 int nderiv = 0;
716
717 if (firsts < first_samp) {
718 for (s = 0, p = firsts; p < first_samp; s++, p++) {
719 if (sel)
720 for (c = 0; c < sel->nchan; c++)
721 picked[c][s] = 0.0;
722 else
723 for (c = 0; c < info->nchan; c++)
724 picked[c][s] = 0.0;
725 }
726 ns = ns - s;
727 firsts = first_samp;
728 }
729 else
730 s = 0;
731 /*
732 * There is possibly nothing to do
733 */
734 if (sel) {
735 for (c = 0, need_some = false; c < sel->nchan; c++) {
736 if (sel->pick[c] >= 0 || sel->pick_deriv[c] >= 0) {
737 need_some = true;
738 break;
739 }
740 }
741 if (!need_some)
742 return OK;
743 }
744 /*
745 * Have to to the hard work
746 */
747 for (k = 0, this_buf = bufs.data(), s = 0; k < static_cast<int>(bufs.size()); k++, this_buf++) {
748 if (this_buf->lasts >= firsts) {
749 start = firsts - this_buf->firsts;
750 if (start < 0)
751 start = 0;
752 if (this_buf->is_skip) {
753 for (p = start; p < this_buf->ns && ns > 0; p++, ns--, s++) {
754 if (sel) {
755 for (c = 0; c < sel->nchan; c++)
756 if (sel->pick[c] >= 0)
757 picked[c][s] = 0.0;
758 }
759 else {
760 for (c = 0; c < info->nchan; c++)
761 picked[c][s] = 0.0;
762 }
763 }
764 }
765 else {
766 /*
767 * Load the buffer
768 */
769 if (load_one_buffer(this_buf) != OK)
770 return FAIL;
771 /*
772 * Apply compensation
773 */
774 if (compensate_buffer(this_buf) != OK)
775 return FAIL;
776 ns2 = s2 = 0;
777 if (sel) {
778 /*
779 * Do we need the derived channels?
780 */
781 if (sel->nderiv > 0 && deriv_matched) {
782 if (deriv_ns < this_buf->ns || nderiv != deriv_matched->deriv_data->nrow) {
783 deriv_vals.resize(deriv_matched->deriv_data->nrow, this_buf->ns);
784 nderiv = deriv_matched->deriv_data->nrow;
785 deriv_ns = this_buf->ns;
786 }
787 if (mne_sparse_mat_mult2(deriv_matched->deriv_data->data.get(),this_buf->vals,this_buf->ns,deriv_vals) == FAIL) {
788 return FAIL;
789 }
790 }
791 for (c = 0; c < sel->nchan; c++) {
792 /*
793 * First pick the ordinary channels...
794 */
795 if (sel->pick[c] >= 0) {
796 for (p = start, s2 = s, ns2 = ns; p < this_buf->ns && ns2 > 0; p++, ns2--, s2++)
797 picked[c][s2] = this_buf->vals(sel->pick[c], p);
798 }
799 /*
800 * ...then the derived ones
801 */
802 else if (sel->pick_deriv[c] >= 0 && deriv_matched) {
803 for (p = start, s2 = s, ns2 = ns; p < this_buf->ns && ns2 > 0; p++, ns2--, s2++)
804 picked[c][s2] = deriv_vals(sel->pick_deriv[c], p);
805 }
806 }
807 }
808 else {
809 for (c = 0; c < info->nchan; c++)
810 for (p = start, s2 = s, ns2 = ns; p < this_buf->ns && ns2 > 0; p++, ns2--, s2++)
811 picked[c][s2] = this_buf->vals(c, p);
812 }
813 s = s2;
814 ns = ns2;
815 }
816 if (ns == 0)
817 break;
818 }
819 }
820 /*
821 * Extend with the last available sample or zero if the request is beyond the data
822 */
823 if (s > 0) {
824 fills = s-1;
825 for (; ns > 0; ns--, s++) {
826 if (sel)
827 for (c = 0; c < sel->nchan; c++)
828 picked[c][s] = picked[c][fills];
829 else
830 for (c = 0; c < info->nchan; c++)
831 picked[c][s] = picked[c][fills];
832 }
833 }
834 else {
835 for (; ns > 0; ns--, s++) {
836 if (sel)
837 for (c = 0; c < sel->nchan; c++)
838 picked[c][s] = 0;
839 else
840 for (c = 0; c < info->nchan; c++)
841 picked[c][s] = 0;
842 }
843 }
844 return OK;
845}
846
847//=============================================================================================================
848
849int MNERawData::pick_data_proj(mneChSelection sel, int firsts, int ns, float **picked)
850/*
851 * Data from a set of channels, apply projection
852 */
853{
854 int k,s,p,start,c,fills;
855 MNERawBufDef* this_buf;
856 RowMajorMatrixXf *values;
857 Eigen::VectorXf deriv_pvalues_vec;
858
859 if (!proj || (sel && !proj->affect(sel->chspick,sel->nchan) && !proj->affect(sel->chspick_nospace,sel->nchan)))
860 return pick_data(sel,firsts,ns,picked);
861
862 if (firsts < first_samp) {
863 for (s = 0, p = firsts; p < first_samp; s++, p++) {
864 if (sel)
865 for (c = 0; c < sel->nchan; c++)
866 picked[c][s] = 0.0;
867 else
868 for (c = 0; c < info->nchan; c++)
869 picked[c][s] = 0.0;
870 }
871 ns = ns - s;
872 firsts = first_samp;
873 }
874 else
875 s = 0;
876 Eigen::VectorXf pvalues(info->nchan);
877 for (k = 0, this_buf = bufs.data(); k < static_cast<int>(bufs.size()); k++, this_buf++) {
878 if (this_buf->lasts >= firsts) {
879 start = firsts - this_buf->firsts;
880 if (start < 0)
881 start = 0;
882 if (this_buf->is_skip) {
883 for (p = start; p < this_buf->ns && ns > 0; p++, ns--, s++) {
884 if (sel) {
885 for (c = 0; c < sel->nchan; c++)
886 if (sel->pick[c] >= 0)
887 picked[c][s] = 0.0;
888 }
889 else {
890 for (c = 0; c < info->nchan; c++)
891 picked[c][s] = 0.0;
892 }
893 }
894 }
895 else {
896 /*
897 * Load the buffer
898 */
899 if (load_one_buffer(this_buf) != OK)
900 return FAIL;
901 /*
902 * Apply compensation
903 */
904 if (compensate_buffer(this_buf) != OK)
905 return FAIL;
906 /*
907 * Apply projection
908 */
909 values = &this_buf->vals;
910 if (sel && sel->nderiv > 0 && deriv_matched) {
911 deriv_pvalues_vec.resize(deriv_matched->deriv_data->nrow);
912 }
913 for (p = start; p < this_buf->ns && ns > 0; p++, ns--, s++) {
914 for (c = 0; c < info->nchan; c++)
915 pvalues[c] = (*values)(c,p);
916 if (proj->project_vector(pvalues,true) != OK)
917 qWarning()<<"Error";
918 if (sel) {
919 if (sel->nderiv > 0 && deriv_matched) {
920 if (mne_sparse_vec_mult2(deriv_matched->deriv_data->data.get(),pvalues.data(),deriv_pvalues_vec.data()) == FAIL)
921 return FAIL;
922 }
923 for (c = 0; c < sel->nchan; c++) {
924 /*
925 * First try the ordinary channels...
926 */
927 if (sel->pick[c] >= 0)
928 picked[c][s] = pvalues[sel->pick[c]];
929 /*
930 * ...then the derived ones
931 */
932 else if (sel->pick_deriv[c] >= 0 && deriv_matched)
933 picked[c][s] = deriv_pvalues_vec[sel->pick_deriv[c]];
934 }
935 }
936 else {
937 for (c = 0; c < info->nchan; c++) {
938 picked[c][s] = pvalues[c];
939 }
940 }
941 }
942 }
943 if (ns == 0)
944 break;
945 }
946 }
947
948 /*
949 * Extend with the last available sample or zero if the request is beyond the data
950 */
951 if (s > 0) {
952 fills = s-1;
953 for (; ns > 0; ns--, s++) {
954 if (sel)
955 for (c = 0; c < sel->nchan; c++)
956 picked[c][s] = picked[c][fills];
957 else
958 for (c = 0; c < info->nchan; c++)
959 picked[c][s] = picked[c][fills];
960 }
961 }
962 else {
963 for (; ns > 0; ns--, s++) {
964 if (sel)
965 for (c = 0; c < sel->nchan; c++)
966 picked[c][s] = 0;
967 else
968 for (c = 0; c < info->nchan; c++)
969 picked[c][s] = 0;
970 }
971 }
972 return OK;
973}
974
975//=============================================================================================================
976
978/*
979 * Load and filter one buffer
980 */
981{
982 int k;
983 int res;
984
985 if (buf->vals.size() == 0) {
986 buf->valid = false;
987 filt_ring->allocate(buf->nchan, buf->ns,&buf->vals);
988 }
989 if (buf->valid)
990 return OK;
991
992 std::vector<float*> vals_storage(buf->nchan);
993 float **vals = vals_storage.data();
994 for (k = 0; k < buf->nchan; k++) {
995 buf->ch_filtered[k] = false;
996 vals[k] = buf->vals.row(k).data() + filter->taper_size;
997 }
998
999 res = pick_data_proj(nullptr,buf->firsts + filter->taper_size,buf->ns - 2*filter->taper_size,vals);
1000
1001#ifdef DEBUG
1002 if (res == OK)
1003 qDebug("Loaded filtered buffer %d...%d %d %d last = %d\n",
1004 buf->firsts,buf->lasts,buf->lasts-buf->firsts+1,buf->ns,first_samp + nsamp);
1005#endif
1006 buf->valid = res == OK;
1007 return res;
1008}
1009
1010//=============================================================================================================
1011
1012int MNERawData::pick_data_filt(mneChSelection sel, int firsts, int ns, float **picked)
1013/*
1014 * Data for a selection (filtered and picked)
1015 */
1016{
1017 int k,s,bs,c;
1018 int bs1,bs2,s1,s2,lasts;
1019 MNERawBufDef* this_buf;
1020 float *values;
1021 RowMajorMatrixXf deriv_vals;
1022 Eigen::VectorXf dc;
1023 float dc_offset;
1024 int deriv_ns = 0;
1025 int nderiv = 0;
1026 int filter_was;
1027
1028 if (!filter->filter_on)
1029 return pick_data_proj(sel,firsts,ns,picked);
1030
1031 if (sel) {
1032 for (s = 0; s < ns; s++)
1033 for (c = 0; c < sel->nchan; c++)
1034 picked[c][s] = 0.0;
1035 }
1036 else {
1037 for (s = 0; s < ns; s++)
1038 for (c = 0; c < info->nchan; c++)
1039 picked[c][s] = 0.0;
1040 }
1041 lasts = firsts + ns - 1;
1042 /*
1043 * Take into account the initial dc offset (compensate and project)
1044 */
1045 if (first_sample_val.size() > 0) {
1046 dc = first_sample_val;
1047 /*
1048 * Is this correct??
1049 */
1050 if (comp && comp->current)
1051 if (comp->apply(true,dc) != OK)
1052 return FAIL;
1053 if (proj)
1054 if (proj->project_vector(dc,true) != OK)
1055 return FAIL;
1056 }
1057 filter_was = filter->filter_on;
1058 /*
1059 * Find the first buffer to consider
1060 */
1061 for (k = 0, this_buf = filt_bufs.data(); k < static_cast<int>(filt_bufs.size()); k++, this_buf++) {
1062 if (this_buf->lasts >= firsts)
1063 break;
1064 }
1065 for (; k < static_cast<int>(filt_bufs.size()) && this_buf->firsts <= lasts; k++, this_buf++) {
1066#ifdef DEBUG
1067 qDebug("this_buf (%d): %d..%d\n",k,this_buf->firsts,this_buf->lasts);
1068#endif
1069 /*
1070 * Load the buffer first and apply projection
1071 */
1072 if (load_one_filt_buf(this_buf) != OK)
1073 return FAIL;
1074 /*
1075 * Then filter all relevant channels (not stimuli)
1076 */
1077 if (sel) {
1078 for (c = 0; c < sel->nchan; c++) {
1079 if (sel->pick[c] >= 0) {
1080 if (!this_buf->ch_filtered[sel->pick[c]]) {
1081 /*
1082 * Do not filter stimulus channels
1083 */
1084 dc_offset = 0.0;
1085 if (info->chInfo[sel->pick[c]].kind == FIFFV_STIM_CH)
1086 filter->filter_on = false;
1087 else if (dc.size() > 0)
1088 dc_offset = dc[sel->pick[c]];
1089 if (mne_apply_filter(*filter,filter_data.get(),this_buf->vals.row(sel->pick[c]).data(),this_buf->ns,true,
1090 dc_offset,info->chInfo[sel->pick[c]].kind) != OK) {
1091 filter->filter_on = filter_was;
1092 return FAIL;
1093 }
1094 this_buf->ch_filtered[sel->pick[c]] = true;
1095 filter->filter_on = filter_was;
1096 }
1097 }
1098 }
1099 /*
1100 * Also check channels included in derivations if they are used
1101 */
1102 if (sel->nderiv > 0 && deriv_matched) {
1103 MNEDeriv* der = deriv_matched.get();
1104 for (c = 0; c < der->deriv_data->ncol; c++) {
1105 if (der->in_use[c] > 0 &&
1106 !this_buf->ch_filtered[c]) {
1107 /*
1108 * Do not filter stimulus channels
1109 */
1110 dc_offset = 0.0;
1111 if (info->chInfo[c].kind == FIFFV_STIM_CH)
1112 filter->filter_on = false;
1113 else if (dc.size() > 0)
1114 dc_offset = dc[c];
1115 if (mne_apply_filter(*filter,filter_data.get(),this_buf->vals.row(c).data(),this_buf->ns,true,
1116 dc_offset,info->chInfo[c].kind) != OK) {
1117 filter->filter_on = filter_was;
1118 return FAIL;
1119 }
1120 this_buf->ch_filtered[c] = true;
1121 filter->filter_on = filter_was;
1122 }
1123 }
1124 }
1125 }
1126 else {
1127 /*
1128 * Simply filter all channels if there is no selection
1129 */
1130 for (c = 0; c < info->nchan; c++) {
1131 if (!this_buf->ch_filtered[c]) {
1132 /*
1133 * Do not filter stimulus channels
1134 */
1135 dc_offset = 0.0;
1136 if (info->chInfo[c].kind == FIFFV_STIM_CH)
1137 filter->filter_on = false;
1138 else if (dc.size() > 0)
1139 dc_offset = dc[c];
1140 if (mne_apply_filter(*filter,filter_data.get(),this_buf->vals.row(c).data(),this_buf->ns,true,
1141 dc_offset,info->chInfo[c].kind) != OK) {
1142 filter->filter_on = filter_was;
1143 return FAIL;
1144 }
1145 this_buf->ch_filtered[c] = true;
1146 filter->filter_on = filter_was;
1147 }
1148 }
1149 }
1150 /*
1151 * Decide the picking limits
1152 */
1153 if (firsts >= this_buf->firsts) {
1154 bs1 = firsts - this_buf->firsts;
1155 s1 = 0;
1156 }
1157 else {
1158 bs1 = 0;
1159 s1 = this_buf->firsts - firsts;
1160 }
1161 if (lasts >= this_buf->lasts) {
1162 bs2 = this_buf->ns;
1163 s2 = this_buf->lasts - lasts + ns;
1164 }
1165 else {
1166 bs2 = lasts - this_buf->lasts + this_buf->ns;
1167 s2 = ns;
1168 }
1169#ifdef DEBUG
1170 qDebug("buf : %d..%d %d\n",bs1,bs2,bs2-bs1);
1171 qDebug("dest : %d..%d %d\n",s1,s2,s2-s1);
1172#endif
1173 /*
1174 * Then pick data from all relevant channels
1175 */
1176 if (sel) {
1177 if (sel->nderiv > 0 && deriv_matched) {
1178 /*
1179 * Compute derived data if we need it
1180 */
1181 if (deriv_ns < this_buf->ns || nderiv != deriv_matched->deriv_data->nrow) {
1182 deriv_vals.resize(deriv_matched->deriv_data->nrow, this_buf->ns);
1183 nderiv = deriv_matched->deriv_data->nrow;
1184 deriv_ns = this_buf->ns;
1185 }
1186 if (mne_sparse_mat_mult2(deriv_matched->deriv_data->data.get(),this_buf->vals,this_buf->ns,deriv_vals) == FAIL)
1187 return FAIL;
1188 }
1189 for (c = 0; c < sel->nchan; c++) {
1190 /*
1191 * First the ordinary channels
1192 */
1193 if (sel->pick[c] >= 0) {
1194 values = this_buf->vals.row(sel->pick[c]).data();
1195 for (s = s1, bs = bs1; s < s2; s++, bs++)
1196 picked[c][s] += values[bs];
1197 }
1198 else if (sel->pick_deriv[c] >= 0 && deriv_matched) {
1199 for (s = s1, bs = bs1; s < s2; s++, bs++)
1200 picked[c][s] += deriv_vals(sel->pick_deriv[c], bs);
1201 }
1202 }
1203 }
1204 else {
1205 for (c = 0; c < info->nchan; c++) {
1206 values = this_buf->vals.row(c).data();
1207 for (s = s1, bs = bs1; s < s2; s++, bs++)
1208 picked[c][s] += values[bs];
1209 }
1210 }
1211 }
1212 (void)bs2; // squash compiler warning, this is unused
1213 return OK;
1214}
1215
1216//=============================================================================================================
1217
1219 int omit_skip,
1220 int allow_maxshield,
1221 const MNEFilterDef& filter,
1222 int comp_set)
1223/*
1224 * Open a raw data file
1225 */
1226{
1227 std::unique_ptr<MNERawInfo> info;
1228 std::unique_ptr<MNERawData> data;
1229
1230 auto filePtr = std::make_unique<QFile>(name);
1231 FiffStream::SPtr stream(new FiffStream(filePtr.get()));
1232 // fiffFile in = NULL;
1233
1235 QList<FiffDirEntry::SPtr> dir0;
1236 // fiffTagRec tag;
1237 FiffTag::UPtr t_pTag;
1238 FiffChInfo ch;
1239 int k, b, nbuf, ndir;
1240 int current_dir0 = 0;
1241
1242 // tag.data = NULL;
1243
1244 if (MNERawInfo::load(name,allow_maxshield,info) == FAIL)
1245 return nullptr;
1246
1247 for (k = 0; k < info->nchan; k++) {
1248 ch = info->chInfo.at(k);
1249 if (QString::compare(ch.ch_name,MNE_DEFAULT_TRIGGER_CH) == 0) {
1250 if (std::fabs(1.0 - ch.range) > 1e-5) {
1251 ch.range = 1.0;
1252 qInfo("%s range set to %f\n",MNE_DEFAULT_TRIGGER_CH,ch.range);
1253 }
1254 }
1255 /*
1256 * Take care of the nonzero unit multiplier
1257 */
1258 if (ch.unit_mul != 0) {
1259 ch.cal = pow(10.0,static_cast<double>(ch.unit_mul))*ch.cal;
1260 qInfo("Ch %s unit multiplier %d -> 0\n",ch.ch_name.toLatin1().data(),ch.unit_mul);
1261 ch.unit_mul = 0;
1262 }
1263 }
1264 // if ((in = fiff_open(name)) == NULL)
1265 // goto bad;
1266 if(!stream->open())
1267 return nullptr;
1268
1269 data = std::make_unique<MNERawData>();
1270 data->filename = name;
1271 data->file = std::move(filePtr);
1272 data->stream = stream;
1273 data->info = std::move(info);
1274 /*
1275 * Add the channel name list
1276 */
1277 data->ch_names.clear();
1278 for (int i = 0; i < data->info->nchan; i++)
1279 data->ch_names.append(data->info->chInfo[i].ch_name);
1280 if (data->ch_names.size() != data->info->nchan) {
1281 qCritical("Channel names were not translated correctly into a name list");
1282 return nullptr;
1283 }
1284 /*
1285 * Compensation data
1286 */
1287 data->comp = MNECTFCompDataSet::read(data->filename);
1288 if (data->comp) {
1289 if (data->comp->ncomp > 0)
1290 qInfo("Read %d compensation data sets from %s\n",data->comp->ncomp,data->filename.toUtf8().constData());
1291 else
1292 qInfo("No compensation data in %s\n",data->filename.toUtf8().constData());
1293 }
1294 else
1295 qWarning() << "err_print_error()";
1296 if ((data->comp_file = MNECTFCompDataSet::get_comp(data->info->chInfo,data->info->nchan)) == FAIL)
1297 return nullptr;
1298 qInfo("Compensation in file : %s\n",MNECTFCompDataSet::explain_comp(MNECTFCompDataSet::map_comp_kind(data->comp_file)).toUtf8().constData());
1299 if (comp_set < 0)
1300 data->comp_now = data->comp_file;
1301 else
1302 data->comp_now = comp_set;
1303
1304 if (!data->comp) {
1305 if (data->comp_now != MNE_CTFV_NOGRAD) {
1306 qCritical("Cannot do compensation because compensation data are missing");
1307 return nullptr;
1308 }
1309 } else if (data->comp->set_compensation(data->comp_now,
1310 data->info->chInfo,
1311 data->info->nchan,
1312 QList<FIFFLIB::FiffChInfo>(),
1313 0) == FAIL)
1314 return nullptr;
1315 /*
1316 * SSS data
1317 */
1318 data->sss = MNESssData::read(data->filename);
1319 if (data->sss && data->sss->job != FIFFV_SSS_JOB_NOTHING && data->sss->comp_info.size() > 0) {
1320 qInfo("SSS data read from %s :\n",data->filename.toUtf8().constData());
1321 QTextStream errStream(stderr);
1322 data->sss->print(errStream);
1323 }
1324 else {
1325 qInfo("No SSS data in %s\n",data->filename.toUtf8().constData());
1326 data->sss.reset();
1327 }
1328 /*
1329 * Buffers
1330 */
1331 dir0 = data->info->rawDir;
1332 ndir = data->info->ndir;
1333 /*
1334 * Take into account the first sample
1335 */
1336 if (dir0[current_dir0]->kind == FIFF_FIRST_SAMPLE) {
1337 // if (fiff_read_this_tag(in->fd,dir0->pos,&tag) == FIFF_FAIL)
1338 // goto bad;
1339 if (!stream->read_tag(t_pTag,dir0[current_dir0]->pos))
1340 return nullptr;
1341 data->first_samp = *t_pTag->toInt();
1342 current_dir0++;
1343 ndir--;
1344 }
1345 if (dir0[current_dir0]->kind == FIFF_DATA_SKIP) {
1346 int nsamp_skip;
1347 // if (fiff_read_this_tag(in->fd,dir0->pos,&tag) == FIFF_FAIL)
1348 // goto bad;
1349 if (!stream->read_tag(t_pTag,dir0[current_dir0]->pos))
1350 return nullptr;
1351 nsamp_skip = data->info->buf_size*(*t_pTag->toInt());
1352 qInfo("Data skip of %d samples in the beginning\n",nsamp_skip);
1353 current_dir0++;
1354 ndir--;
1355 if (dir0[current_dir0]->kind == FIFF_FIRST_SAMPLE) {
1356 // if (fiff_read_this_tag(in->fd,dir0->pos,&tag) == FIFF_FAIL)
1357 // goto bad;
1358 if (!stream->read_tag(t_pTag,dir0[current_dir0]->pos))
1359 return nullptr;
1360 data->first_samp += *t_pTag->toInt();
1361 current_dir0++;
1362 ndir--;
1363 }
1364 if (omit_skip) {
1365 data->omit_samp = data->first_samp + nsamp_skip;
1366 data->omit_samp_old = nsamp_skip;
1367 data->first_samp = 0;
1368 }
1369 else {
1370 data->first_samp = data->first_samp + nsamp_skip;
1371 }
1372 }
1373 else if (omit_skip) {
1374 data->omit_samp = data->first_samp;
1375 data->first_samp = 0;
1376 }
1377#ifdef DEBUG
1378 qInfo("data->first_samp = %d\n",data->first_samp);
1379#endif
1380 /*
1381 * Figure out the buffers
1382 */
1383 // for (k = 0, dir = dir0, nbuf = 0; k < ndir; k++, dir++)
1384 for (k = 0, nbuf = 0; k < ndir; k++)
1385 if (dir0[k]->kind == FIFF_DATA_BUFFER ||
1386 dir0[k]->kind == FIFF_DATA_SKIP)
1387 nbuf++;
1388 data->bufs.resize(nbuf);
1389
1390 // for (k = 0, nbuf = 0, dir = dir0; k < ndir; k++, dir++)
1391 for (k = 0, nbuf = 0; k < ndir; k++)
1392 if (dir0[k]->kind == FIFF_DATA_BUFFER ||
1393 dir0[k]->kind == FIFF_DATA_SKIP) {
1394 data->bufs[nbuf].ns = 0;
1395 data->bufs[nbuf].ent = dir0[k];
1396 data->bufs[nbuf].nchan = data->info->nchan;
1397 data->bufs[nbuf].is_skip = dir0[k]->kind == FIFF_DATA_SKIP;
1398 data->bufs[nbuf].valid = false;
1399 data->bufs[nbuf].comp_status = data->comp_file;
1400 nbuf++;
1401 }
1402 data->nsamp = 0;
1403 for (k = 0; k < nbuf; k++) {
1404 dir = data->bufs[k].ent;
1405 if (dir->kind == FIFF_DATA_BUFFER) {
1406 if (dir->type == FIFFT_DAU_PACK16 || dir->type == FIFFT_SHORT)
1407 data->bufs[k].ns = dir->size/(data->info->nchan*sizeof(fiff_dau_pack16_t));
1408 else if (dir->type == FIFFT_FLOAT)
1409 data->bufs[k].ns = dir->size/(data->info->nchan*sizeof(fiff_float_t));
1410 else if (dir->type == FIFFT_INT)
1411 data->bufs[k].ns = dir->size/(data->info->nchan*sizeof(fiff_int_t));
1412 else {
1413 qCritical("We are not prepared to handle raw data type: %d",dir->type);
1414 return nullptr;
1415 }
1416 }
1417 else if (dir->kind == FIFF_DATA_SKIP) {
1418 // if (fiff_read_this_tag(in->fd,dir->pos,&tag) == FIFF_FAIL)
1419 // goto bad;
1420 if (!stream->read_tag(t_pTag,dir->pos))
1421 return nullptr;
1422 data->bufs[k].ns = data->info->buf_size*(*t_pTag->toInt());
1423 }
1424 data->bufs[k].firsts = k == 0 ? data->first_samp : data->bufs[k-1].lasts + 1;
1425 data->bufs[k].lasts = data->bufs[k].firsts + data->bufs[k].ns - 1;
1426 data->nsamp += data->bufs[k].ns;
1427 }
1428 // FREE_36(tag.data);
1429 /*
1430 * Set up the first sample values
1431 */
1432 data->bad = Eigen::VectorXi::Zero(data->info->nchan);
1433 data->offsets = Eigen::VectorXf::Zero(data->info->nchan);
1434 /*
1435 * Th bad channel stuff
1436 */
1437 {
1438 if (mne_read_bad_channel_list(name,data->badlist,data->nbad) == OK) {
1439 for (b = 0; b < data->nbad; b++) {
1440 for (k = 0; k < data->info->nchan; k++) {
1441 if (QString::compare(data->info->chInfo[k].ch_name,data->badlist[b],Qt::CaseInsensitive) == 0) {
1442 data->bad[k] = 1;
1443 break;
1444 }
1445 }
1446 }
1447 qInfo("%d bad channels read from %s%s",data->nbad,name.toUtf8().constData(),data->nbad > 0 ? ":\n" : "\n");
1448 if (data->nbad > 0) {
1449 qInfo("\t");
1450 for (k = 0; k < data->nbad; k++)
1451 qInfo("%s%c",data->badlist[k].toUtf8().constData(),k < data->nbad-1 ? ' ' : '\n');
1452 }
1453 }
1454 }
1455 /*
1456 * Initialize the raw data buffers
1457 */
1458 nbuf = approx_ring_buf_size/(data->info->buf_size*static_cast<std::size_t>(data->info->nchan)*sizeof(float));
1459 data->ring = std::make_unique<RingBuffer>(nbuf);
1460 /*
1461 * Initialize the filter buffers
1462 */
1463 data->filter = std::make_unique<MNEFilterDef>(filter);
1464 data->setup_filter_bufs();
1465
1466 {
1467 std::vector<float> vals_storage(data->info->nchan, 0.0f);
1468 std::vector<float*> vals_rows(data->info->nchan);
1469 for (int i = 0; i < data->info->nchan; i++)
1470 vals_rows[i] = &vals_storage[i];
1471 float **vals = vals_rows.data();
1472
1473 if (data->pick_data(nullptr,data->first_samp,1,vals) == FAIL)
1474 return nullptr;
1475 data->first_sample_val.resize(data->info->nchan);
1476 for (k = 0; k < data->info->nchan; k++)
1477 data->first_sample_val[k] = vals[k][0];
1478 qInfo("Initial dc offsets determined\n");
1479 }
1480 qInfo("Raw data file %s:\n",name.toUtf8().constData());
1481 qInfo("\tnchan = %d\n",data->info->nchan);
1482 qInfo("\tnsamp = %d\n",data->nsamp);
1483 qInfo("\tsfreq = %-8.3f Hz\n",data->info->sfreq);
1484 qInfo("\tlength = %-8.3f sec\n",data->nsamp/data->info->sfreq);
1485
1486 return data.release();
1487}
1488
1489//=============================================================================================================
1490
1491MNERawData *MNERawData::open_file(const QString& name, int omit_skip, int allow_maxshield, const MNEFilterDef& filter)
1492/*
1493 * Wrapper for open_file to work as before
1494 */
1495{
1496 return open_file_comp(name,omit_skip,allow_maxshield,filter,-1);
1497}
constexpr int FAIL
constexpr int OK
#define MNE_DEFAULT_TRIGGER_CH
Default digital trigger channel name.
Definition mne_types.h:126
#define MNE_CTFV_NOGRAD
Definition mne_types.h:108
void mne_fft_syn(float *data, int np, std::vector< float > &)
int mne_sparse_vec_mult2(FiffSparseMatrix *mat, float *vector, float *res)
int mne_read_raw_buffer_t(FiffStream::SPtr &stream, const FiffDirEntry::SPtr &ent, RowMajorMatrixXf &data, int nchan, int nsamp, const QList< FIFFLIB::FiffChInfo > &chs, int *pickno, int npick)
int mne_sparse_mat_mult2(FiffSparseMatrix *mat, const RowMajorMatrixXf &mult, int ncol, RowMajorMatrixXf &res)
int mne_apply_filter(const MNEFilterDef &filter, FilterData *d, float *data, int ns, int zero_pad, float dc_offset, int kind)
int mne_read_bad_channel_list(const QString &name, QStringList &listp, int &nlistp)
#define APPROX_RING_BUF_SIZE
int mne_read_bad_channel_list_from_node(FiffStream::SPtr &stream, const FiffDirNode::SPtr &pNode, QStringList &listp, int &nlistp)
int mne_compare_filters(const MNEFilterDef &f1, const MNEFilterDef &f2)
void mne_fft_ana(float *data, int np, std::vector< float > &)
std::unique_ptr< FilterData > mne_create_filter_response(const MNEFilterDef &filter, float sfreq, int *highpass_effective)
Legacy MNE-C raw-recording container with per-file buffer descriptors.
#define M_PI
#define FIFFV_EOG_CH
#define FIFF_MNE_CH_NAME_LIST
#define FIFFV_STIM_CH
#define FIFFB_MNE_BAD_CHANNELS
#define FIFF_DATA_BUFFER
Definition fiff_file.h:549
#define FIFFT_INT
Definition fiff_file.h:224
#define FIFFT_SHORT
Definition fiff_file.h:223
#define FIFF_FIRST_SAMPLE
Definition fiff_file.h:454
#define FIFFT_DAU_PACK16
Definition fiff_file.h:236
#define FIFFT_FLOAT
Definition fiff_file.h:225
#define FIFFV_SSS_JOB_NOTHING
Definition fiff_file.h:531
#define FIFF_DATA_SKIP
Definition fiff_file.h:550
Core MNE data structures (source spaces, source estimates, hemispheres).
MNEChSelection * mneChSelection
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > RowMajorMatrixXf
FIFF file I/O, in-memory data structures and high-level readers/writers.
Per-channel FIFF descriptor: identifiers, kind, calibration, coil type, channel-frame coil position a...
QSharedPointer< FiffDirEntry > SPtr
QSharedPointer< FiffDirNode > SPtr
Sparse FIFF matrix: CCS or RCS storage with the value / index / pointer triple as written by FiffStre...
Eigen::SparseMatrix< float > & eigen()
FIFF tag-stream reader/writer: wraps a QIODevice and exposes typed read_* / write_* methods for every...
QSharedPointer< FiffStream > SPtr
static QStringList split_name_list(QString p_sNameList)
std::unique_ptr< FiffTag > UPtr
Definition fiff_tag.h:164
Eigen::VectorXi pick_deriv
static std::unique_ptr< MNECTFCompDataSet > read(const QString &name)
static QString explain_comp(int kind)
static int get_comp(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
One item in a derivation data set.
Definition mne_deriv.h:61
std::unique_ptr< MNESparseNamedMatrix > deriv_data
Definition mne_deriv.h:81
Eigen::VectorXi in_use
Definition mne_deriv.h:82
Definition of one raw data buffer within a FIFF file.
FIFFLIB::FiffDirEntry::SPtr ent
Eigen::VectorXi ch_filtered
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > vals
void allocate(int nrow, int ncol, RowMajorMatrixXf *res)
std::vector< Entry > entries
RingBuffer(int nslots)
RowMajorMatrixXf * user
Pre-computed frequency-domain filter state used for FFT-based raw data filtering.
FilterData(int resp_size)
std::vector< float > eog_freq_resp
std::vector< float > freq_resp
std::vector< float > precalc
int load_one_filt_buf(MNERawBufDef *buf)
std::unique_ptr< MNELIB::MNEProjOp > proj
std::unique_ptr< MNELIB::MNECTFCompDataSet > comp
std::unique_ptr< FilterData > filter_data
void add_filter_response(int *highpass_effective)
int compensate_buffer(MNERawBufDef *buf)
int pick_data_proj(mneChSelection sel, int firsts, int ns, float **picked)
QStringList ch_names
std::unique_ptr< RingBuffer > filt_ring
std::unique_ptr< MNELIB::MNERawInfo > info
std::unique_ptr< MNELIB::MNEDeriv > deriv_matched
unsigned int dig_trigger_mask
QStringList badlist
std::vector< MNELIB::MNERawBufDef > filt_bufs
static MNERawData * open_file_comp(const QString &name, int omit_skip, int allow_maxshield, const MNEFilterDef &filter, int comp_set)
std::unique_ptr< MNEFilterDef > filter
int load_one_buffer(MNERawBufDef *buf)
Eigen::VectorXf first_sample_val
std::unique_ptr< MNEEventList > event_list
std::unique_ptr< MNELIB::MNEDerivSet > deriv
unsigned int max_event
std::vector< MNELIB::MNERawBufDef > bufs
int pick_data(mneChSelection sel, int firsts, int ns, float **picked)
FIFFLIB::FiffStream::SPtr stream
std::unique_ptr< MNELIB::MNESssData > sss
static MNERawData * open_file(const QString &name, int omit_skip, int allow_maxshield, const MNEFilterDef &filter)
int pick_data_filt(mneChSelection sel, int firsts, int ns, float **picked)
std::unique_ptr< RingBuffer > ring
static int load(const QString &name, int allow_maxshield, std::unique_ptr< MNERawInfo > &infop)
static std::unique_ptr< MNESssData > read(const QString &name)