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