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
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 fiff_short_t* this_samples;
373 const fiff_float_t* this_samplef;
374 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 = (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
522#define 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 * load just one
641 */
642{
643 if (buf->ent->kind == FIFF_DATA_SKIP) {
644 qCritical("Cannot load a skip");
645 return FAIL;
646 }
647 if (buf->vals.size() == 0) { /* The data space may have been reused */
648 buf->valid = false;
649 ring->allocate(buf->nchan, buf->ns, &buf->vals);
650 }
651 if (buf->valid)
652 return OK;
653
654#ifdef DEBUG
655 qDebug("Read buffer %d .. %d\n", buf->firsts, buf->lasts);
656#endif
657
659 buf->ent,
660 buf->vals,
661 buf->nchan,
662 buf->ns,
663 info->chInfo,
664 nullptr, 0) != OK) {
665 buf->valid = false;
666 return FAIL;
667 }
668 buf->valid = true;
669 buf->comp_status = comp_file;
670 return OK;
671}
672
673//=============================================================================================================
674
676/*
677 * Apply compensation channels
678 */
679{
680 if (!comp)
681 return OK;
682 if (!comp->undo && !comp->current)
683 return OK;
684 if (buf->comp_status == comp_now)
685 return OK;
686 if (buf->vals.size() == 0)
687 return OK;
688 /*
689 * vals is now a RowMajorMatrixXf — wrap in a column-major MatrixXf for compensation
690 */
691 {
692 Eigen::MatrixXf dataMat = buf->vals; /* implicit copy/conversion */
693
694 if (comp->undo) {
695 std::swap(comp->current, comp->undo);
696 /*
697 * Undo the previous compensation
698 */
699 if (comp->apply_transpose(false, dataMat) != OK) {
700 std::swap(comp->current, comp->undo);
701 return FAIL;
702 }
703 std::swap(comp->current, comp->undo);
704 }
705 if (comp->current) {
706 /*
707 * Apply new compensation
708 */
709 if (comp->apply_transpose(true, dataMat) != OK)
710 return FAIL;
711 }
712 /*
713 * Copy result back to buf->vals
714 */
715 buf->vals = dataMat;
716 }
717 buf->comp_status = comp_now;
718 return OK;
719}
720
721//=============================================================================================================
722
723int MNERawData::pick_data(mneChSelection sel, int firsts, int ns, float** picked)
724/*
725 * Data from a selection of channels
726 */
727{
728 int k, s, p, start, c, fills;
729 int ns2, s2;
730 MNERawBufDef* this_buf;
731 int need_some;
732
733 RowMajorMatrixXf deriv_vals;
734 int deriv_ns = 0;
735 int nderiv = 0;
736
737 if (firsts < first_samp) {
738 for (s = 0, p = firsts; p < first_samp; s++, p++) {
739 if (sel)
740 for (c = 0; c < sel->nchan; c++)
741 picked[c][s] = 0.0;
742 else
743 for (c = 0; c < info->nchan; c++)
744 picked[c][s] = 0.0;
745 }
746 ns = ns - s;
747 firsts = first_samp;
748 } else
749 s = 0;
750 /*
751 * There is possibly nothing to do
752 */
753 if (sel) {
754 for (c = 0, need_some = false; c < sel->nchan; c++) {
755 if (sel->pick[c] >= 0 || sel->pick_deriv[c] >= 0) {
756 need_some = true;
757 break;
758 }
759 }
760 if (!need_some)
761 return OK;
762 }
763 /*
764 * Have to to the hard work
765 */
766 // s continues after any leading zero padding (MNE-C reset it here and overwrote the padding).
767 for (k = 0, this_buf = bufs.data(); k < static_cast<int>(bufs.size()); k++, this_buf++) {
768 if (this_buf->lasts >= firsts) {
769 start = firsts - this_buf->firsts;
770 if (start < 0)
771 start = 0;
772 if (this_buf->is_skip) {
773 for (p = start; p < this_buf->ns && ns > 0; p++, ns--, s++) {
774 if (sel) {
775 for (c = 0; c < sel->nchan; c++)
776 if (sel->pick[c] >= 0)
777 picked[c][s] = 0.0;
778 } else {
779 for (c = 0; c < info->nchan; c++)
780 picked[c][s] = 0.0;
781 }
782 }
783 } else {
784 /*
785 * Load the buffer
786 */
787 if (load_one_buffer(this_buf) != OK)
788 return FAIL;
789 /*
790 * Apply compensation
791 */
792 if (compensate_buffer(this_buf) != OK)
793 return FAIL;
794 ns2 = s2 = 0;
795 if (sel) {
796 /*
797 * Do we need the derived channels?
798 */
799 if (sel->nderiv > 0 && deriv_matched) {
800 if (deriv_ns < this_buf->ns || nderiv != deriv_matched->deriv_data->nrow) {
801 deriv_vals.resize(deriv_matched->deriv_data->nrow, this_buf->ns);
802 nderiv = deriv_matched->deriv_data->nrow;
803 deriv_ns = this_buf->ns;
804 }
805 if (mne_sparse_mat_mult2(deriv_matched->deriv_data->data.get(), this_buf->vals, this_buf->ns, deriv_vals) == FAIL) {
806 return FAIL;
807 }
808 }
809 for (c = 0; c < sel->nchan; c++) {
810 /*
811 * First pick the ordinary channels...
812 */
813 if (sel->pick[c] >= 0) {
814 for (p = start, s2 = s, ns2 = ns; p < this_buf->ns && ns2 > 0; p++, ns2--, s2++)
815 picked[c][s2] = this_buf->vals(sel->pick[c], p);
816 }
817 /*
818 * ...then the derived ones
819 */
820 else if (sel->pick_deriv[c] >= 0 && deriv_matched) {
821 for (p = start, s2 = s, ns2 = ns; p < this_buf->ns && ns2 > 0; p++, ns2--, s2++)
822 picked[c][s2] = deriv_vals(sel->pick_deriv[c], p);
823 }
824 }
825 } else {
826 for (c = 0; c < info->nchan; c++)
827 for (p = start, s2 = s, ns2 = ns; p < this_buf->ns && ns2 > 0; p++, ns2--, s2++)
828 picked[c][s2] = this_buf->vals(c, p);
829 }
830 s = s2;
831 ns = ns2;
832 }
833 if (ns == 0)
834 break;
835 }
836 }
837 /*
838 * Extend with the last available sample or zero if the request is beyond the data
839 */
840 if (s > 0) {
841 fills = s - 1;
842 for (; ns > 0; ns--, s++) {
843 if (sel)
844 for (c = 0; c < sel->nchan; c++)
845 picked[c][s] = picked[c][fills];
846 else
847 for (c = 0; c < info->nchan; c++)
848 picked[c][s] = picked[c][fills];
849 }
850 } else {
851 for (; ns > 0; ns--, s++) {
852 if (sel)
853 for (c = 0; c < sel->nchan; c++)
854 picked[c][s] = 0;
855 else
856 for (c = 0; c < info->nchan; c++)
857 picked[c][s] = 0;
858 }
859 }
860 return OK;
861}
862
863//=============================================================================================================
864
865int MNERawData::pick_data_proj(mneChSelection sel, int firsts, int ns, float** picked)
866/*
867 * Data from a set of channels, apply projection
868 */
869{
870 int k, s, p, start, c, fills;
871 MNERawBufDef* this_buf;
872 RowMajorMatrixXf* values;
873 Eigen::VectorXf deriv_pvalues_vec;
874
875 if (!proj || (sel && !proj->affect(sel->chspick, sel->nchan) && !proj->affect(sel->chspick_nospace, sel->nchan)))
876 return pick_data(sel, firsts, ns, picked);
877
878 if (firsts < first_samp) {
879 for (s = 0, p = firsts; p < first_samp; s++, p++) {
880 if (sel)
881 for (c = 0; c < sel->nchan; c++)
882 picked[c][s] = 0.0;
883 else
884 for (c = 0; c < info->nchan; c++)
885 picked[c][s] = 0.0;
886 }
887 ns = ns - s;
888 firsts = first_samp;
889 } else
890 s = 0;
891 Eigen::VectorXf pvalues(info->nchan);
892 for (k = 0, this_buf = bufs.data(); k < static_cast<int>(bufs.size()); k++, this_buf++) {
893 if (this_buf->lasts >= firsts) {
894 start = firsts - this_buf->firsts;
895 if (start < 0)
896 start = 0;
897 if (this_buf->is_skip) {
898 for (p = start; p < this_buf->ns && ns > 0; p++, ns--, s++) {
899 if (sel) {
900 for (c = 0; c < sel->nchan; c++)
901 if (sel->pick[c] >= 0)
902 picked[c][s] = 0.0;
903 } else {
904 for (c = 0; c < info->nchan; c++)
905 picked[c][s] = 0.0;
906 }
907 }
908 } else {
909 /*
910 * Load the buffer
911 */
912 if (load_one_buffer(this_buf) != OK)
913 return FAIL;
914 /*
915 * Apply compensation
916 */
917 if (compensate_buffer(this_buf) != OK)
918 return FAIL;
919 /*
920 * Apply projection
921 */
922 values = &this_buf->vals;
923 if (sel && sel->nderiv > 0 && deriv_matched) {
924 deriv_pvalues_vec.resize(deriv_matched->deriv_data->nrow);
925 }
926 for (p = start; p < this_buf->ns && ns > 0; p++, ns--, s++) {
927 for (c = 0; c < info->nchan; c++)
928 pvalues[c] = (*values)(c, p);
929 if (proj->project_vector(pvalues, true) != OK)
930 qWarning() << "Error";
931 if (sel) {
932 if (sel->nderiv > 0 && deriv_matched) {
933 if (mne_sparse_vec_mult2(deriv_matched->deriv_data->data.get(), pvalues.data(), deriv_pvalues_vec.data()) == FAIL)
934 return FAIL;
935 }
936 for (c = 0; c < sel->nchan; c++) {
937 /*
938 * First try the ordinary channels...
939 */
940 if (sel->pick[c] >= 0)
941 picked[c][s] = pvalues[sel->pick[c]];
942 /*
943 * ...then the derived ones
944 */
945 else if (sel->pick_deriv[c] >= 0 && deriv_matched)
946 picked[c][s] = deriv_pvalues_vec[sel->pick_deriv[c]];
947 }
948 } else {
949 for (c = 0; c < info->nchan; c++) {
950 picked[c][s] = pvalues[c];
951 }
952 }
953 }
954 }
955 if (ns == 0)
956 break;
957 }
958 }
959
960 /*
961 * Extend with the last available sample or zero if the request is beyond the data
962 */
963 if (s > 0) {
964 fills = s - 1;
965 for (; ns > 0; ns--, s++) {
966 if (sel)
967 for (c = 0; c < sel->nchan; c++)
968 picked[c][s] = picked[c][fills];
969 else
970 for (c = 0; c < info->nchan; c++)
971 picked[c][s] = picked[c][fills];
972 }
973 } else {
974 for (; ns > 0; ns--, s++) {
975 if (sel)
976 for (c = 0; c < sel->nchan; c++)
977 picked[c][s] = 0;
978 else
979 for (c = 0; c < info->nchan; c++)
980 picked[c][s] = 0;
981 }
982 }
983 return OK;
984}
985
986//=============================================================================================================
987
989/*
990 * Load and filter one buffer
991 */
992{
993 int k;
994 int res;
995
996 if (buf->vals.size() == 0) {
997 buf->valid = false;
998 filt_ring->allocate(buf->nchan, buf->ns, &buf->vals);
999 }
1000 if (buf->valid)
1001 return OK;
1002
1003 std::vector<float*> vals_storage(buf->nchan);
1004 float** vals = vals_storage.data();
1005 for (k = 0; k < buf->nchan; k++) {
1006 buf->ch_filtered[k] = false;
1007 vals[k] = buf->vals.row(k).data() + filter->taper_size;
1008 }
1009
1010 res = pick_data_proj(nullptr, buf->firsts + filter->taper_size, buf->ns - 2 * filter->taper_size, vals);
1011
1012#ifdef DEBUG
1013 if (res == OK)
1014 qDebug("Loaded filtered buffer %d...%d %d %d last = %d\n",
1015 buf->firsts, buf->lasts, buf->lasts - buf->firsts + 1, buf->ns, first_samp + nsamp);
1016#endif
1017 buf->valid = res == OK;
1018 return res;
1019}
1020
1021//=============================================================================================================
1022
1023int MNERawData::pick_data_filt(mneChSelection sel, int firsts, int ns, float** picked)
1024/*
1025 * Data for a selection (filtered and picked)
1026 */
1027{
1028 int k, s, bs, c;
1029 int bs1, bs2, s1, s2, lasts;
1030 MNERawBufDef* this_buf;
1031 float* values;
1032 RowMajorMatrixXf deriv_vals;
1033 Eigen::VectorXf dc;
1034 float dc_offset;
1035 int deriv_ns = 0;
1036 int nderiv = 0;
1037 int filter_was;
1038
1039 if (!filter->filter_on)
1040 return pick_data_proj(sel, firsts, ns, picked);
1041
1042 if (sel) {
1043 for (s = 0; s < ns; s++)
1044 for (c = 0; c < sel->nchan; c++)
1045 picked[c][s] = 0.0;
1046 } else {
1047 for (s = 0; s < ns; s++)
1048 for (c = 0; c < info->nchan; c++)
1049 picked[c][s] = 0.0;
1050 }
1051 lasts = firsts + ns - 1;
1052 /*
1053 * Take into account the initial dc offset (compensate and project)
1054 */
1055 if (first_sample_val.size() > 0) {
1056 dc = first_sample_val;
1057 /*
1058 * Is this correct??
1059 */
1060 if (comp && comp->current)
1061 if (comp->apply(true, dc) != OK)
1062 return FAIL;
1063 if (proj)
1064 if (proj->project_vector(dc, true) != OK)
1065 return FAIL;
1066 }
1067 filter_was = filter->filter_on;
1068 /*
1069 * Find the first buffer to consider
1070 */
1071 for (k = 0, this_buf = filt_bufs.data(); k < static_cast<int>(filt_bufs.size()); k++, this_buf++) {
1072 if (this_buf->lasts >= firsts)
1073 break;
1074 }
1075 for (; k < static_cast<int>(filt_bufs.size()) && this_buf->firsts <= lasts; k++, this_buf++) {
1076#ifdef DEBUG
1077 qDebug("this_buf (%d): %d..%d\n", k, this_buf->firsts, this_buf->lasts);
1078#endif
1079 /*
1080 * Load the buffer first and apply projection
1081 */
1082 if (load_one_filt_buf(this_buf) != OK)
1083 return FAIL;
1084 /*
1085 * Then filter all relevant channels (not stimuli)
1086 */
1087 if (sel) {
1088 for (c = 0; c < sel->nchan; c++) {
1089 if (sel->pick[c] >= 0) {
1090 if (!this_buf->ch_filtered[sel->pick[c]]) {
1091 /*
1092 * Do not filter stimulus channels
1093 */
1094 dc_offset = 0.0;
1095 if (info->chInfo[sel->pick[c]].kind == FIFFV_STIM_CH)
1096 filter->filter_on = false;
1097 else if (dc.size() > 0)
1098 dc_offset = dc[sel->pick[c]];
1099 if (mne_apply_filter(*filter, filter_data.get(), this_buf->vals.row(sel->pick[c]).data(), this_buf->ns, true,
1100 dc_offset, info->chInfo[sel->pick[c]].kind) != OK) {
1101 filter->filter_on = filter_was;
1102 return FAIL;
1103 }
1104 this_buf->ch_filtered[sel->pick[c]] = true;
1105 filter->filter_on = filter_was;
1106 }
1107 }
1108 }
1109 /*
1110 * Also check channels included in derivations if they are used
1111 */
1112 if (sel->nderiv > 0 && deriv_matched) {
1113 MNEDeriv* der = deriv_matched.get();
1114 for (c = 0; c < der->deriv_data->ncol; c++) {
1115 if (der->in_use[c] > 0 &&
1116 !this_buf->ch_filtered[c]) {
1117 /*
1118 * Do not filter stimulus channels
1119 */
1120 dc_offset = 0.0;
1121 if (info->chInfo[c].kind == FIFFV_STIM_CH)
1122 filter->filter_on = false;
1123 else if (dc.size() > 0)
1124 dc_offset = dc[c];
1125 if (mne_apply_filter(*filter, filter_data.get(), this_buf->vals.row(c).data(), this_buf->ns, true,
1126 dc_offset, info->chInfo[c].kind) != OK) {
1127 filter->filter_on = filter_was;
1128 return FAIL;
1129 }
1130 this_buf->ch_filtered[c] = true;
1131 filter->filter_on = filter_was;
1132 }
1133 }
1134 }
1135 } else {
1136 /*
1137 * Simply filter all channels if there is no selection
1138 */
1139 for (c = 0; c < info->nchan; c++) {
1140 if (!this_buf->ch_filtered[c]) {
1141 /*
1142 * Do not filter stimulus channels
1143 */
1144 dc_offset = 0.0;
1145 if (info->chInfo[c].kind == FIFFV_STIM_CH)
1146 filter->filter_on = false;
1147 else if (dc.size() > 0)
1148 dc_offset = dc[c];
1149 if (mne_apply_filter(*filter, filter_data.get(), this_buf->vals.row(c).data(), this_buf->ns, true,
1150 dc_offset, info->chInfo[c].kind) != OK) {
1151 filter->filter_on = filter_was;
1152 return FAIL;
1153 }
1154 this_buf->ch_filtered[c] = true;
1155 filter->filter_on = filter_was;
1156 }
1157 }
1158 }
1159 /*
1160 * Decide the picking limits
1161 */
1162 if (firsts >= this_buf->firsts) {
1163 bs1 = firsts - this_buf->firsts;
1164 s1 = 0;
1165 } else {
1166 bs1 = 0;
1167 s1 = this_buf->firsts - firsts;
1168 }
1169 if (lasts >= this_buf->lasts) {
1170 bs2 = this_buf->ns;
1171 s2 = this_buf->lasts - lasts + ns;
1172 } else {
1173 bs2 = lasts - this_buf->lasts + this_buf->ns;
1174 s2 = ns;
1175 }
1176#ifdef DEBUG
1177 qDebug("buf : %d..%d %d\n", bs1, bs2, bs2 - bs1);
1178 qDebug("dest : %d..%d %d\n", s1, s2, s2 - s1);
1179#endif
1180 /*
1181 * Then pick data from all relevant channels
1182 */
1183 if (sel) {
1184 if (sel->nderiv > 0 && deriv_matched) {
1185 /*
1186 * Compute derived data if we need it
1187 */
1188 if (deriv_ns < this_buf->ns || nderiv != deriv_matched->deriv_data->nrow) {
1189 deriv_vals.resize(deriv_matched->deriv_data->nrow, this_buf->ns);
1190 nderiv = deriv_matched->deriv_data->nrow;
1191 deriv_ns = this_buf->ns;
1192 }
1193 if (mne_sparse_mat_mult2(deriv_matched->deriv_data->data.get(), this_buf->vals, this_buf->ns, deriv_vals) == FAIL)
1194 return FAIL;
1195 }
1196 for (c = 0; c < sel->nchan; c++) {
1197 /*
1198 * First the ordinary channels
1199 */
1200 if (sel->pick[c] >= 0) {
1201 values = this_buf->vals.row(sel->pick[c]).data();
1202 for (s = s1, bs = bs1; s < s2; s++, bs++)
1203 picked[c][s] += values[bs];
1204 } else if (sel->pick_deriv[c] >= 0 && deriv_matched) {
1205 for (s = s1, bs = bs1; s < s2; s++, bs++)
1206 picked[c][s] += deriv_vals(sel->pick_deriv[c], bs);
1207 }
1208 }
1209 } else {
1210 for (c = 0; c < info->nchan; c++) {
1211 values = this_buf->vals.row(c).data();
1212 for (s = s1, bs = bs1; s < s2; s++, bs++)
1213 picked[c][s] += values[bs];
1214 }
1215 }
1216 }
1217 (void)bs2; // squash compiler warning, this is unused
1218 return OK;
1219}
1220
1221//=============================================================================================================
1222
1224 int omit_skip,
1225 int allow_maxshield,
1226 const MNEFilterDef& filter,
1227 int comp_set)
1228/*
1229 * Open a raw data file
1230 */
1231{
1232 std::unique_ptr<MNERawInfo> info;
1233 std::unique_ptr<MNERawData> data;
1234
1235 auto filePtr = std::make_unique<QFile>(name);
1236 FiffStream::SPtr stream(new FiffStream(filePtr.get()));
1237 // fiffFile in = NULL;
1238
1240 QList<FiffDirEntry::SPtr> dir0;
1241 // fiffTagRec tag;
1242 FiffTag::UPtr t_pTag;
1243 int k, b, nbuf, ndir;
1244 int current_dir0 = 0;
1245
1246 // tag.data = NULL;
1247
1248 if (MNERawInfo::load(name, allow_maxshield, info) == FAIL)
1249 return nullptr;
1250
1251 for (k = 0; k < info->nchan; k++) {
1252 FiffChInfo& ch = info->chInfo[k];
1253 // FiffTag::toChInfo strips the spaces from channel names.
1254 if (QString(ch.ch_name).remove(' ') == QString(MNE_DEFAULT_TRIGGER_CH).remove(' ')) {
1255 if (std::fabs(1.0 - ch.range) > 1e-5) {
1256 ch.range = 1.0;
1257 qInfo("%s range set to %f\n", MNE_DEFAULT_TRIGGER_CH, ch.range);
1258 }
1259 }
1260 /*
1261 * Take care of the nonzero unit multiplier
1262 */
1263 if (ch.unit_mul != 0) {
1264 ch.cal = pow(10.0, static_cast<double>(ch.unit_mul)) * ch.cal;
1265 qInfo("Ch %s unit multiplier %d -> 0\n", ch.ch_name.toLatin1().data(), ch.unit_mul);
1266 ch.unit_mul = 0;
1267 }
1268 }
1269 // if ((in = fiff_open(name)) == NULL)
1270 // goto bad;
1271 if (!stream->open())
1272 return nullptr;
1273
1274 data = std::make_unique<MNERawData>();
1275 data->filename = name;
1276 data->file = std::move(filePtr);
1277 data->stream = stream;
1278 data->info = std::move(info);
1279 /*
1280 * Add the channel name list
1281 */
1282 data->ch_names.clear();
1283 for (int i = 0; i < data->info->nchan; i++)
1284 data->ch_names.append(data->info->chInfo[i].ch_name);
1285 if (data->ch_names.size() != data->info->nchan) {
1286 qCritical("Channel names were not translated correctly into a name list");
1287 return nullptr;
1288 }
1289 /*
1290 * Compensation data
1291 */
1292 data->comp = MNECTFCompDataSet::read(data->filename);
1293 if (data->comp) {
1294 if (data->comp->ncomp > 0)
1295 qInfo("Read %d compensation data sets from %s\n", data->comp->ncomp, data->filename.toUtf8().constData());
1296 else
1297 qInfo("No compensation data in %s\n", data->filename.toUtf8().constData());
1298 } else
1299 qWarning() << "err_print_error()";
1300 if ((data->comp_file = MNECTFCompDataSet::get_comp(data->info->chInfo, data->info->nchan)) == FAIL)
1301 return nullptr;
1302 qInfo("Compensation in file : %s\n", MNECTFCompDataSet::explain_comp(MNECTFCompDataSet::map_comp_kind(data->comp_file)).toUtf8().constData());
1303 if (comp_set < 0)
1304 data->comp_now = data->comp_file;
1305 else
1306 data->comp_now = comp_set;
1307
1308 if (!data->comp) {
1309 if (data->comp_now != MNE_CTFV_NOGRAD) {
1310 qCritical("Cannot do compensation because compensation data are missing");
1311 return nullptr;
1312 }
1313 } else if (data->comp->set_compensation(data->comp_now,
1314 data->info->chInfo,
1315 data->info->nchan,
1316 QList<FIFFLIB::FiffChInfo>(),
1317 0) == FAIL)
1318 return nullptr;
1319 /*
1320 * SSS data
1321 */
1322 data->sss = MNESssData::read(data->filename);
1323 if (data->sss && data->sss->job != FIFFV_SSS_JOB_NOTHING && data->sss->comp_info.size() > 0) {
1324 qInfo("SSS data read from %s :\n", data->filename.toUtf8().constData());
1325 QTextStream errStream(stderr);
1326 data->sss->print(errStream);
1327 } else {
1328 qInfo("No SSS data in %s\n", data->filename.toUtf8().constData());
1329 data->sss.reset();
1330 }
1331 /*
1332 * Buffers
1333 */
1334 dir0 = data->info->rawDir;
1335 ndir = data->info->ndir;
1336 /*
1337 * Take into account the first sample
1338 */
1339 if (dir0[current_dir0]->kind == FIFF_FIRST_SAMPLE) {
1340 // if (fiff_read_this_tag(in->fd,dir0->pos,&tag) == FIFF_FAIL)
1341 // goto bad;
1342 if (!stream->read_tag(t_pTag, dir0[current_dir0]->pos))
1343 return nullptr;
1344 data->first_samp = *t_pTag->toInt();
1345 current_dir0++;
1346 ndir--;
1347 }
1348 if (dir0[current_dir0]->kind == FIFF_DATA_SKIP) {
1349 int nsamp_skip;
1350 // if (fiff_read_this_tag(in->fd,dir0->pos,&tag) == FIFF_FAIL)
1351 // goto bad;
1352 if (!stream->read_tag(t_pTag, dir0[current_dir0]->pos))
1353 return nullptr;
1354 nsamp_skip = data->info->buf_size * (*t_pTag->toInt());
1355 qInfo("Data skip of %d samples in the beginning\n", nsamp_skip);
1356 current_dir0++;
1357 ndir--;
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 (omit_skip) {
1368 data->omit_samp = data->first_samp + nsamp_skip;
1369 data->omit_samp_old = nsamp_skip;
1370 data->first_samp = 0;
1371 } else {
1372 data->first_samp = data->first_samp + nsamp_skip;
1373 }
1374 } else if (omit_skip) {
1375 data->omit_samp = data->first_samp;
1376 data->first_samp = 0;
1377 }
1378#ifdef DEBUG
1379 qInfo("data->first_samp = %d\n", data->first_samp);
1380#endif
1381 /*
1382 * Figure out the buffers
1383 */
1384 // ndir counts the entries after the consumed leading ones (MNE-C advances dir0 instead).
1385 for (k = current_dir0, nbuf = 0; k < current_dir0 + ndir; k++)
1386 if (dir0[k]->kind == FIFF_DATA_BUFFER ||
1387 dir0[k]->kind == FIFF_DATA_SKIP)
1388 nbuf++;
1389 data->bufs.resize(nbuf);
1390
1391 for (k = current_dir0, nbuf = 0; k < current_dir0 + 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 if (dir->type == FIFFT_DOUBLE)
1413 data->bufs[k].ns = dir->size / (data->info->nchan * sizeof(double));
1414 else {
1415 qCritical("We are not prepared to handle raw data type: %d", dir->type);
1416 return nullptr;
1417 }
1418 } else if (dir->kind == FIFF_DATA_SKIP) {
1419 // if (fiff_read_this_tag(in->fd,dir->pos,&tag) == FIFF_FAIL)
1420 // goto bad;
1421 if (!stream->read_tag(t_pTag, dir->pos))
1422 return nullptr;
1423 data->bufs[k].ns = data->info->buf_size * (*t_pTag->toInt());
1424 }
1425 data->bufs[k].firsts = k == 0 ? data->first_samp : data->bufs[k - 1].lasts + 1;
1426 data->bufs[k].lasts = data->bufs[k].firsts + data->bufs[k].ns - 1;
1427 data->nsamp += data->bufs[k].ns;
1428 }
1429 // FREE_36(tag.data);
1430 /*
1431 * Set up the first sample values
1432 */
1433 data->bad = Eigen::VectorXi::Zero(data->info->nchan);
1434 data->offsets = Eigen::VectorXf::Zero(data->info->nchan);
1435 /*
1436 * Th bad channel stuff
1437 */
1438 {
1439 if (mne_read_bad_channel_list(name, data->badlist, data->nbad) == OK) {
1440 for (b = 0; b < data->nbad; b++) {
1441 for (k = 0; k < data->info->nchan; k++) {
1442 if (QString::compare(data->info->chInfo[k].ch_name, data->badlist[b], Qt::CaseInsensitive) == 0) {
1443 data->bad[k] = 1;
1444 break;
1445 }
1446 }
1447 }
1448 qInfo("%d bad channels read from %s%s", data->nbad, name.toUtf8().constData(), data->nbad > 0 ? ":\n" : "\n");
1449 if (data->nbad > 0) {
1450 qInfo("\t");
1451 for (k = 0; k < data->nbad; k++)
1452 qInfo("%s%c", data->badlist[k].toUtf8().constData(), k < data->nbad - 1 ? ' ' : '\n');
1453 }
1454 }
1455 }
1456 /*
1457 * Initialize the raw data buffers
1458 */
1459 nbuf = approx_ring_buf_size / (data->info->buf_size * static_cast<std::size_t>(data->info->nchan) * sizeof(float));
1460 data->ring = std::make_unique<RingBuffer>(nbuf);
1461 /*
1462 * Initialize the filter buffers
1463 */
1464 data->filter = std::make_unique<MNEFilterDef>(filter);
1465 data->setup_filter_bufs();
1466
1467 {
1468 std::vector<float> vals_storage(data->info->nchan, 0.0f);
1469 std::vector<float*> vals_rows(data->info->nchan);
1470 for (int i = 0; i < data->info->nchan; i++)
1471 vals_rows[i] = &vals_storage[i];
1472 float** vals = vals_rows.data();
1473
1474 if (data->pick_data(nullptr, data->first_samp, 1, vals) == FAIL)
1475 return nullptr;
1476 data->first_sample_val.resize(data->info->nchan);
1477 for (k = 0; k < data->info->nchan; k++)
1478 data->first_sample_val[k] = vals[k][0];
1479 qInfo("Initial dc offsets determined\n");
1480 }
1481 qInfo("Raw data file %s:\n", name.toUtf8().constData());
1482 qInfo("\tnchan = %d\n", data->info->nchan);
1483 qInfo("\tnsamp = %d\n", data->nsamp);
1484 qInfo("\tsfreq = %-8.3f Hz\n", data->info->sfreq);
1485 qInfo("\tlength = %-8.3f sec\n", data->nsamp / data->info->sfreq);
1486
1487 return data.release();
1488}
1489
1490//=============================================================================================================
1491
1492MNERawData* MNERawData::open_file(const QString& name, int omit_skip, int allow_maxshield, const MNEFilterDef& filter)
1493/*
1494 * Wrapper for open_file to work as before
1495 */
1496{
1497 return open_file_comp(name, omit_skip, allow_maxshield, filter, -1);
1498}
1499
1500//=============================================================================================================
1501
1502int MNERawData::attachDerivations(const MNEDerivSet& derivations, bool keepPrevious)
1503{
1504 if (!keepPrevious || !deriv) {
1505 deriv = std::make_unique<MNEDerivSet>();
1506 }
1507 deriv->append(derivations);
1508 deriv_matched = deriv->match(ch_names);
1509 if (!deriv_matched) {
1510 qInfo("No derivations are valid for these raw data.");
1511 return 0;
1512 }
1513 const int nvalid = deriv_matched->validate(info->chInfo);
1514 qInfo("%d of %d of the matched derivations are valid for these raw data.", nvalid, deriv_matched->deriv_data->nrow);
1515 return nvalid;
1516}
#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_DOUBLE
Definition fiff_file.h:226
#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
#define M_PI
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)
#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)
#define MNE_DEFAULT_TRIGGER_CH
Default digital trigger channel name.
Definition mne_types.h:127
#define MNE_CTFV_NOGRAD
Definition mne_types.h:109
Legacy MNE-C raw-recording container with per-file buffer descriptors.
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.
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
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)