v2.0.0
Loading...
Searching...
No Matches
mne_meas_data.cpp
Go to the documentation of this file.
1//=============================================================================================================
36
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "mne_meas_data.h"
42#include "mne_meas_data_set.h"
44
45#include <mne/mne_types.h>
47
48#include <fiff/fiff_types.h>
50
51#include <time.h>
52
53#include <QFile>
54#include <QTextStream>
55
56//=============================================================================================================
57// USED NAMESPACES
58//=============================================================================================================
59
60using namespace Eigen;
61using namespace FIFFLIB;
62using namespace MNELIB;
63using namespace INVERSELIB;
64
65#ifndef TRUE
66#define TRUE 1
67#endif
68
69#ifndef FALSE
70#define FALSE 0
71#endif
72
73#ifndef FAIL
74#define FAIL -1
75#endif
76
77#ifndef OK
78#define OK 0
79#endif
80
81#if defined(_WIN32) || defined(_WIN64)
82#define snprintf _snprintf
83#define vsnprintf _vsnprintf
84#define strcasecmp _stricmp
85#define strncasecmp _strnicmp
86#endif
87
88#define MIN(a,b) ((a) < (b) ? (a) : (b))
89#define MAX(a,b) ((a) > (b) ? (a) : (b))
90
91#define MALLOC_9(x,t) (t *)malloc((x)*sizeof(t))
92#define REALLOC_9(x,y,t) (t *)((x == NULL) ? malloc((y)*sizeof(t)) : realloc((x),(y)*sizeof(t)))
93
94#define FREE_9(x) if ((char *)(x) != NULL) free((char *)(x))
95
96#define ALLOC_CMATRIX_9(x,y) mne_cmatrix_9((x),(y))
97
98#define FREE_CMATRIX_9(m) mne_free_cmatrix_9((m))
99
100void fromFloatEigenMatrix_9(const Eigen::MatrixXf& from_mat, float **& to_mat, const int m, const int n)
101{
102 for ( int i = 0; i < m; ++i)
103 for ( int j = 0; j < n; ++j)
104 to_mat[i][j] = from_mat(i,j);
105}
106
107void fromFloatEigenMatrix_9(const Eigen::MatrixXf& from_mat, float **& to_mat)
108{
109 fromFloatEigenMatrix_9(from_mat, to_mat, from_mat.rows(), from_mat.cols());
110}
111
112void mne_free_cmatrix_9 (float **m)
113{
114 if (m) {
115 FREE_9(*m);
116 FREE_9(m);
117 }
118}
119
120static void matrix_error_9(int kind, int nr, int nc)
121
122{
123 if (kind == 1)
124 printf("Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
125 else if (kind == 2)
126 printf("Failed to allocate memory for a %d x %d matrix\n",nr,nc);
127 else
128 printf("Allocation error for a %d x %d matrix\n",nr,nc);
129 if (sizeof(void *) == 4) {
130 printf("This is probably because you seem to be using a computer with 32-bit architecture.\n");
131 printf("Please consider moving to a 64-bit platform.");
132 }
133 printf("Cannot continue. Sorry.\n");
134 exit(1);
135}
136
137float **mne_cmatrix_9(int nr,int nc)
138
139{
140 int i;
141 float **m;
142 float *whole;
143
144 m = MALLOC_9(nr,float *);
145 if (!m) matrix_error_9(1,nr,nc);
146 whole = MALLOC_9(nr*nc,float);
147 if (!whole) matrix_error_9(2,nr,nc);
148
149 for(i=0;i<nr;i++)
150 m[i] = whole + i*nc;
151 return m;
152}
153
154namespace INVERSELIB
155{
156
160typedef struct {
161 int size; /* Size of this buffer in floats */
162 float *data; /* The allocated buffer */
163 float ***datap; /* The matrix which uses this */
165
174
175}
176
177void mne_free_ring_buffer_9(void *thisp)
178
179{
180 int k;
181 ringBuf_9 this_buf = (ringBuf_9)thisp;
182
183 if (!this_buf)
184 return;
185
186 for (k = 0; k < this_buf->nbuf; k++)
187 FREE_9(this_buf->bufs[k]->data);
188 FREE_9(this_buf->bufs);
189 FREE_9(this_buf);
190 return;
191}
192
193//============================= mne_raw_routines.c =============================
194
196
197{
198 if (!s)
199 return;
200 s->name.clear();
201 s->chspick.clear();
202 s->chspick_nospace.clear();
203 s->chdef.clear();
204 delete s;
205 return;
206}
207
208void mne_string_to_name_list_9(const QString& s, QStringList& listp,int &nlistp)
209/*
210 * Convert a colon-separated list into a string array
211 */
212{
213 QStringList list;
214
215 if (!s.isEmpty() && s.size() > 0) {
217 //list = s.split(":");
218 }
219 listp = list;
220 nlistp = list.size();
221 return;
222}
223
224QString mne_name_list_to_string_9(const QStringList& list)
225/*
226 * Convert a string array to a colon-separated string
227 */
228{
229 int nlist = list.size();
230 QString res;
231 if (nlist == 0 || list.isEmpty())
232 return res;
233 // res[0] = '\0';
234 for (int k = 0; k < nlist-1; k++) {
235 res += list[k];
236 res += ":";
237 }
238 res += list[nlist-1];
239 return res;
240}
241
242QString mne_channel_names_to_string_9(const QList<FIFFLIB::FiffChInfo>& chs,
243 int nch)
244/*
245 * Make a colon-separated string out of channel names
246 */
247{
248 QStringList names;
249 QString res;
250 if (nch <= 0)
251 return res;
252 for (int k = 0; k < nch; k++)
253 names.append(chs[k].ch_name);
254 res = mne_name_list_to_string_9(names);
255 return res;
256}
257
258void mne_channel_names_to_name_list_9(const QList<FIFFLIB::FiffChInfo>& chs,
259 int nch,
260 QStringList& listp,
261 int &nlistp)
262
263{
264 QString s = mne_channel_names_to_string_9(chs,nch);
265
266 mne_string_to_name_list_9(s,listp,nlistp);
267 return;
268}
269
270//============================= read_ch_info.c =============================
271
272static FiffDirNode::SPtr find_meas_9 (const FiffDirNode::SPtr& node)
273/*
274 * Find corresponding meas node
275 */
276{
277 FiffDirNode::SPtr empty_node;
278 FiffDirNode::SPtr tmp_node = node;
279
280 while (tmp_node->type != FIFFB_MEAS) {
281 if (tmp_node->parent == NULL)
282 return empty_node;//(NULL);
283 tmp_node = tmp_node->parent;
284 }
285 return (tmp_node);
286}
287
288static FiffDirNode::SPtr find_meas_info_9 (const FiffDirNode::SPtr& node)
289/*
290 * Find corresponding meas info node
291 */
292{
293 int k;
294 FiffDirNode::SPtr empty_node;
295 FiffDirNode::SPtr tmp_node = node;
296
297 while (tmp_node->type != FIFFB_MEAS) {
298 if (tmp_node->parent == NULL)
299 return empty_node;
300 tmp_node = tmp_node->parent;
301 }
302 for (k = 0; k < tmp_node->nchild(); k++)
303 if (tmp_node->children[k]->type == FIFFB_MEAS_INFO)
304 return (tmp_node->children[k]);
305 return empty_node;
306}
307
308//============================= mne_read_evoked.c =============================
309
310#define MAXDATE 100
311
312static FiffDirNode::SPtr find_evoked (const FiffDirNode::SPtr& node)
313/*
314 * Find corresponding FIFFB_EVOKED node
315 */
316{
317 FiffDirNode::SPtr empty_node;
318 FiffDirNode::SPtr tmp_node = node;
319 while (tmp_node->type != FIFFB_EVOKED) {
320 if (tmp_node->parent == NULL)
321 return empty_node;
322 tmp_node = tmp_node->parent;
323 }
324 return (tmp_node);
325}
326
327static QString get_comment ( FiffStream::SPtr& stream,
328 const FiffDirNode::SPtr& start)
329
330{
331 int k;
332 FiffTag::SPtr t_pTag;
333 QList<FiffDirEntry::SPtr> ent = start->dir;
334 for (k = 0; k < start->nent(); k++)
335 if (ent[k]->kind == FIFF_COMMENT) {
336 if (stream->read_tag(t_pTag,ent[k]->pos)) {
337 return t_pTag->toString();
338 }
339 }
340 return QString("No comment");
341}
342
343static void get_aspect_name_type( FiffStream::SPtr& stream,
344 const FiffDirNode::SPtr& start,
345 QString& namep, int *typep)
346
347{
348 int k;
349 FiffTag::SPtr t_pTag;
350 QList<FiffDirEntry::SPtr> ent = start->dir;
351 QString res = "unknown";
352 int type = -1;
353
354 for (k = 0; k < start->nent(); k++)
355 if (ent[k]->kind == FIFF_ASPECT_KIND) {
356 if (stream->read_tag(t_pTag,ent[k]->pos)) {
357 type = *t_pTag->toInt();
358 switch (type) {
360 res = "average";
361 break;
363 res = "std.error";
364 break;
366 res = "single trace";
367 break;
369 res = "sample";
370 break;
372 res = "subaverage";
373 break;
375 res = "alt. average";
376 break;
378 res = "power density spectrum";
379 break;
381 res = "dipole amplitudes";
382 break;
383 }
384 }
385 break;
386 }
387 // if (namep)
388 namep = res;
389 if (typep)
390 *typep = type;
391 return;
392}
393
394static char *get_meas_date ( FiffStream::SPtr& stream,const FiffDirNode::SPtr& node )
395{
396 int k;
397 FiffTag::SPtr t_pTag;
398 char *res = NULL;
399 fiff_int_t kind, pos;
400 FiffDirNode::SPtr meas_info;
401
402 if (!(meas_info = find_meas_info_9(node))) {
403 return res;
404 }
405 for (k = 0; k < meas_info->nent();k++) {
406 kind = meas_info->dir[k]->kind;
407 pos = meas_info->dir[k]->pos;
408 if (kind == FIFF_MEAS_DATE)
409 {
410 if (stream->read_tag(t_pTag,pos)) {
411 FiffTime* meas_date = (FiffTime*)t_pTag->data();
412 time_t time = meas_date->secs;
413 struct tm *ltime;
414
415 ltime = localtime(&time);
416 res = MALLOC_9(MAXDATE,char);
417 (void)strftime(res,MAXDATE,"%x %X",ltime);
418 break;
419 }
420 }
421 }
422 return res;
423}
424
425static int get_meas_info ( FiffStream::SPtr& stream, /* The stream we are reading */
426 const FiffDirNode::SPtr& node, /* The directory node containing our data */
427 fiffId *id, /* The block id from the nearest FIFFB_MEAS parent */
428 FiffTime* *meas_date, /* Measurement date */
429 int *nchan, /* Number of channels */
430 float *sfreq, /* Sampling frequency */
431 float *highpass, /* Highpass filter setting */
432 float *lowpass, /* Lowpass filter setting */
433 QList<FIFFLIB::FiffChInfo>& chp, /* Channel descriptions */
434 FiffCoordTrans *trans) /* Coordinate transformation (head <-> device) */
435/*
436 * Find channel information from
437 * nearest FIFFB_MEAS_INFO parent of
438 * node.
439 */
440{
441 QList<FIFFLIB::FiffChInfo> ch;
442 FIFFLIB::FiffChInfo this_ch;
444 int j,k;
445 int to_find = 4;
446 QList<FiffDirNode::SPtr> hpi;
448 FiffDirNode::SPtr meas_info;
449 fiff_int_t kind, pos;
450 FiffTag::SPtr t_pTag;
451
452 *trans = FiffCoordTrans();
453 *id = NULL;
454 /*
455 * Find desired parents
456 */
457 if (!(meas = find_meas_9(node))) {
458 printf ("Meas. block not found!");
459 goto bad;
460 }
461 if (!(meas_info = find_meas_info_9(node))) {
462 printf ("Meas. info not found!");
463 goto bad;
464 }
465 /*
466 * Is there a block id is in the FIFFB_MEAS node?
467 */
468 if (!meas->id.isEmpty()) {
469 *id = MALLOC_9(1,fiffIdRec);
470 (*id)->version = meas->id.version;
471 (*id)->machid[0] = meas->id.machid[0];
472 (*id)->machid[1] = meas->id.machid[1];
473 (*id)->time = meas->id.time;
474 }
475 /*
476 * Others from FIFFB_MEAS_INFO
477 */
478 *lowpass = -1;
479 *highpass = -1;
480 for (k = 0; k < meas_info->nent(); k++) {
481 kind = meas_info->dir[k]->kind;
482 pos = meas_info->dir[k]->pos;
483 switch (kind) {
484
485 case FIFF_NCHAN :
486 if (!stream->read_tag(t_pTag,pos))
487 goto bad;
488 *nchan = *t_pTag->toInt();
489
490 for (j = 0; j < *nchan; j++) {
491 ch.append(FiffChInfo());
492 ch[j].scanNo = -1;
493 }
494 to_find = to_find + *nchan - 1;
495 break;
496
497 case FIFF_SFREQ :
498 if (!stream->read_tag(t_pTag,pos))
499 goto bad;
500 *sfreq = *t_pTag->toFloat();
501 to_find--;
502 break;
503
504 case FIFF_MEAS_DATE :
505 if (!stream->read_tag(t_pTag,pos))
506 goto bad;
507 if (*meas_date)
508 FREE_9(*meas_date);
509 *meas_date = MALLOC_9(1,FiffTime);
510 **meas_date = *(FiffTime*)t_pTag->data();
511 break;
512
513 case FIFF_LOWPASS :
514 if (!stream->read_tag(t_pTag,pos))
515 goto bad;
516 *lowpass = *t_pTag->toFloat();
517 to_find--;
518 break;
519
520 case FIFF_HIGHPASS :
521 if (!stream->read_tag(t_pTag,pos))
522 goto bad;
523 *highpass = *t_pTag->toFloat();
524 to_find--;
525 break;
526
527 case FIFF_CH_INFO : /* Information about one channel */
528
529 if (!stream->read_tag(t_pTag,pos))
530 goto bad;
531
532 this_ch = t_pTag->toChInfo();
533 if (this_ch.scanNo <= 0 || this_ch.scanNo > *nchan) {
534 qCritical ("FIFF_CH_INFO : scan # out of range!");
535 goto bad;
536 }
537 else
538 ch[this_ch.scanNo-1] = this_ch;
539 to_find--;
540 break;
541
542 case FIFF_COORD_TRANS :
543 if (!stream->read_tag(t_pTag,pos))
544 goto bad;
545 t = FiffCoordTrans::readFromTag( t_pTag );
546 /*
547 * Require this particular transform!
548 */
549 if (t.from == FIFFV_COORD_DEVICE && t.to == FIFFV_COORD_HEAD) {
550 *trans = t;
551 break;
552 }
553 }
554 }
555 /*
556 * Search for the coordinate transformation from
557 * HPI_RESULT block if it was not previously found
558 */
559
560 hpi = meas_info->dir_tree_find(FIFFB_HPI_RESULT);
561
562 if (hpi.size() > 0 && trans->isEmpty())
563 for (k = 0; k < hpi[0]->nent(); k++)
564 if (hpi[0]->dir[k]->kind == FIFF_COORD_TRANS) {
565 if (!stream->read_tag(t_pTag,hpi[0]->dir[k]->pos))
566 goto bad;
567 t = FiffCoordTrans::readFromTag( t_pTag );
568
569 /*
570 * Require this particular transform!
571 */
572 if (t.from == FIFFV_COORD_DEVICE && t.to == FIFFV_COORD_HEAD) {
573 *trans = t;
574 break;
575 }
576 }
577 if (*lowpass < 0) {
578 *lowpass = *sfreq/2.0;
579 to_find--;
580 }
581 if (*highpass < 0) {
582 *highpass = 0.0;
583 to_find--;
584 }
585 if (to_find != 0) {
586 printf ("Not all essential tags were found!");
587 goto bad;
588 }
589
590 chp = ch;
591 return (0);
592
593bad : {
594 return (-1);
595 }
596}
597
598static int find_between ( FiffStream::SPtr& stream,
599 const FiffDirNode::SPtr& low_node,
600 const FiffDirNode::SPtr& high_node,
601 int kind,
602 fiff_byte_t **data)
603{
604 FiffTag::SPtr t_pTag;
606 fiffDirEntry dir;
607 fiff_int_t kind_1, pos;
608 int k;
609
610 *data = NULL;
611 node = low_node;
612 while (node != NULL) {
613 for (k = 0; k < node->nent(); k++)
614 {
615 kind_1 = node->dir[k]->kind;
616 pos = node->dir[k]->pos;
617 if (kind_1 == kind) {
618 FREE_9(*data);
619 if (!stream->read_tag(t_pTag,pos)) {
620 return (FIFF_FAIL);
621 }
622 else {
623 fiff_byte_t* tmp = MALLOC_9(t_pTag->size(),fiff_byte_t);
624 fiff_byte_t* tmp_current = (fiff_byte_t *)t_pTag->data();
625
626 for( int k = 0; k < t_pTag->size(); ++k )
627 tmp[k] = tmp_current[k];
628
629 *data = tmp;
630 return (FIFF_OK);
631 }
632 }
633 }
634 if (node == high_node)
635 break;
636 node = node->parent;
637 }
638 return (FIFF_OK);
639}
640
641static int get_evoked_essentials (FiffStream::SPtr& stream, /* This is our file */
642 const FiffDirNode::SPtr& node, /* The interesting node */
643 float& sfreq, /* Sampling frequency
644 * The value pointed by this is not
645 * modified if individual sampling
646 * frequency is found */
647 float& tmin, /* Time scale minimum */
648 int& nsamp, /* Number of samples */
649 int& nave, /* Number of averaged responses */
650 int& akind, /* Aspect type */
651 int *& artefs, /* Artefact removal parameters */
652 int& nartef)
653/*
654 * Get the essential info for
655 * given evoked response data
656 */
657{
658 FiffTag::SPtr t_pTag;
659 int k;
660 int to_find = 2;
661 int first = -1;
662 int last = -1;
663 int my_nsamp = -1;
664 float my_tmin = -1;
665 int res = -1;
666 fiff_int_t kind, pos;
667
668 fiff_byte_t *tempb;
669
670 FiffDirNode::SPtr tmp_node = node;
671
672 /*
673 * This is rather difficult...
674 */
675 if (find_between (stream,tmp_node,tmp_node->parent,FIFF_NAVE,&tempb) == FIFF_FAIL)
676 return res;
677 if (tempb)
678 nave = *(int *)tempb;
679 FREE_9(tempb);
680 if (find_between (stream,tmp_node,tmp_node->parent,
681 FIFF_SFREQ,&tempb) == FIFF_FAIL)
682 return res;
683 if (tempb)
684 sfreq = *(float *)tempb;
685 FREE_9(tempb);
686
687 if (find_between (stream,tmp_node,tmp_node->parent,
688 FIFF_ASPECT_KIND,&tempb) == FIFF_FAIL)
689 return res;
690 if (tempb)
691 akind = *(int *)tempb;
692 else
693 akind = FIFFV_ASPECT_AVERAGE; /* Just a guess */
694 FREE_9(tempb);
695 /*
696 * Find evoked response descriptive data
697 */
698 tmp_node = tmp_node->parent;
699
700 // tag.data = NULL;
701 for (k = 0; k < tmp_node->dir_tree.size(); k++) {
702 kind = tmp_node->dir_tree[k]->kind;
703 pos = tmp_node->dir_tree[k]->pos;
704 switch (kind) {
705
706 case FIFF_FIRST_SAMPLE :
707 if (!stream->read_tag(t_pTag,pos))
708 goto out;
709 first = *t_pTag->toInt(); to_find--;
710 break;
711
712 case FIFF_LAST_SAMPLE :
713 if (!stream->read_tag(t_pTag,pos))
714 goto out;
715 last = *t_pTag->toInt(); to_find--;
716 break;
717
718 case FIFF_NO_SAMPLES :
719 if (!stream->read_tag(t_pTag,pos))
720 goto out;
721 my_nsamp = *t_pTag->toInt(); to_find--;
722 break;
723
724 case FIFF_FIRST_TIME :
725 if (!stream->read_tag(t_pTag,pos))
726 goto out;
727 my_tmin = *t_pTag->toFloat(); to_find--;
728 break;
729 case FIFF_ARTEF_REMOVAL :
730 if (!stream->read_tag(t_pTag,pos))
731 goto out;
732 qDebug() << "TODO: check whether artefs contains the right stuff -> use MatrixXi instead";
733 artefs = t_pTag->toInt();
734 nartef = t_pTag->size()/(3*sizeof(int));
735 break;
736 }
737 }
738 if (to_find > 0) {
739 printf ("Not all essential tags were found!");
740 goto out;
741 }
742 if (first != -1 && last != -1) {
743 nsamp = (last)-(first)+1;
744 tmin = (first)/(sfreq);
745 }
746 else if (my_tmin != -1 && my_nsamp != -1) {
747 tmin = my_tmin;
748 nsamp = my_nsamp;
749 }
750 else {
751 printf("Not enough data for time scale definition!");
752 goto out;
753 }
754 res = 0;
755
756out : {
757 return res;
758 }
759}
760
761static int get_evoked_optional( FiffStream::SPtr& stream,
762 const FiffDirNode::SPtr& node, /* The directory node containing our data */
763 int *nchan, /* Number of channels */
764 QList<FiffChInfo>& chp) /* Channel descriptions */
765/*
766 * The channel info may have been modified
767 */
768{
769 int res = FIFF_FAIL;
770 QList<FiffChInfo> new_ch;
771 int new_nchan = *nchan;
772 int k,to_find;
773 FiffTag::SPtr t_pTag;
774 fiff_int_t kind, pos;
775 FiffChInfo this_ch;
776 FiffDirNode::SPtr evoked_node;
777
778 if (!(evoked_node = find_evoked(node))) {
779 res = FIFF_OK;
780 goto out;
781 }
782
783 to_find = 0;
784 if(evoked_node->find_tag(stream, FIFF_NCHAN, t_pTag))
785 new_nchan = *t_pTag->toInt();
786 else
787 new_nchan = *nchan;
788
789 for (k = 0; k < evoked_node->nent(); k++) {
790 kind = evoked_node->dir[k]->kind;
791 pos = evoked_node->dir[k]->pos;
792 if (kind == FIFF_CH_INFO) { /* Information about one channel */
793 if (new_ch.isEmpty()) {
794 to_find = new_nchan;
795 for (int i = 0; i < to_find; i++) {
796 new_ch.append(FiffChInfo());
797 }
798 }
799 if (!stream->read_tag(t_pTag,pos))
800 goto out;
801
802 this_ch = t_pTag->toChInfo();
803 if (this_ch.scanNo <= 0 || this_ch.scanNo > new_nchan) {
804 printf ("FIFF_CH_INFO : scan # out of range!");
805 goto out;
806 }
807 else
808 new_ch[this_ch.scanNo-1] = this_ch;
809 to_find--;
810 }
811 }
812 if (to_find != 0) {
813 printf("All channels were not specified "
814 "at the FIFFB_EVOKED level.");
815 goto out;
816 }
817 res = FIFF_OK;
818 goto out;
819
820out : {
821 if (res == FIFF_OK) {
822 *nchan = new_nchan;
823 if (!new_ch.isEmpty()) {
824 chp = new_ch;
825 }
826 }
827 return res;
828 }
829}
830
831static void unpack_data(double offset,
832 double scale,
833 short *packed,
834 int nsamp,
835 float *orig)
836{
837 int k;
838 for (k = 0; k < nsamp; k++)
839 orig[k] = scale * packed[k] + offset;
840 return;
841}
842
843static float **get_epochs ( FiffStream::SPtr& stream, /* This is our file */
844 const FiffDirNode::SPtr& node, /* The interesting node */
845 int nchan, int nsamp) /* Number of channels and number of samples to be expected */
846/*
847 * Get the evoked response epochs
848 */
849{
850 fiff_int_t kind, pos;
851 FiffTag::SPtr t_pTag;
852 int k;
853 int ch;
854 float **epochs = NULL;
855 float offset,scale;
856 short *packed;
857
858 for (k = 0, ch = 0; k < node->nent() && ch < nchan; k++) {
859 kind = node->dir[k]->kind;
860 pos = node->dir[k]->pos;
861 if (kind == FIFF_EPOCH) {
862 if (!stream->read_tag(t_pTag,pos))
863 goto bad;
864 if (t_pTag->type & FIFFT_MATRIX) {
865 if ((t_pTag->type & ~FIFFT_MATRIX) != FIFFT_FLOAT) {
866 printf("Epochs in matrix should be floats!");
867 goto bad;
868 }
869
870 qint32 ndim;
871 QVector<qint32> dims;
872 t_pTag->getMatrixDimensions(ndim, dims);
873
874 if (ndim != 2) {
875 printf("Data matrix dimension should be two!");
876 goto bad;
877 }
878 if (dims[0] != nsamp) {
879 printf("Incorrect number of samples in data matrix!");
880 goto bad;
881 }
882 if (dims[1] != nchan) {
883 printf("Incorrect number of channels in data matrix!");
884 goto bad;
885 }
886 MatrixXf tmp_epochs = t_pTag->toFloatMatrix().transpose();
887 epochs = ALLOC_CMATRIX_9(tmp_epochs.rows(),tmp_epochs.cols());
888 fromFloatEigenMatrix_9(tmp_epochs, epochs);
889 ch = nchan;
890 break; /* We have the data */
891 }
892 else { /* Individual epochs */
893 if (epochs == NULL)
894 epochs = ALLOC_CMATRIX_9(nchan,nsamp);
895 if (t_pTag->type == FIFFT_OLD_PACK) {
896 offset = ((float *)t_pTag->data())[0];
897 scale = ((float *)t_pTag->data())[1];
898 packed = (short *)(((float *)t_pTag->data())+2);
899 unpack_data(offset,scale,packed,nsamp,epochs[ch++]);
900 }
901 else if (t_pTag->type == FIFFT_FLOAT)
902 memcpy(epochs[ch++],t_pTag->data(),nsamp*sizeof(float));
903 else {
904 printf ("Unknown data packing type!");
905 FREE_CMATRIX_9(epochs);
906 return (NULL);
907 }
908 }
909 if (ch == nchan)
910 return (epochs);
911 }
912 }
913 if (ch < nchan) {
914 printf ("All epochs were not found!");
915 goto bad;
916 }
917 return (epochs);
918
919bad : {
920 FREE_CMATRIX_9(epochs);
921 return (NULL);
922 }
923}
924
926 QList<FiffDirNode::SPtr>& nodesp,
927 int **aspect_typesp,
928 QStringList* commentsp)
929/*
930 * Find all data we are able to process
931 */
932{
933 QList<FiffDirNode::SPtr> evoked;
934 QList<FiffDirNode::SPtr> meas;
935 QList<FiffDirNode::SPtr> nodes;
936 int evoked_count,count;
937 QString part,type,meas_date;
938 QStringList comments;
939 int *types = NULL;
940 int j,k,p;
941
942 if (stream == NULL)
943 return 0;
944 /*
945 * First find all measurements
946 */
947 meas = stream->dirtree()->dir_tree_find(FIFFB_MEAS);
948 /*
949 * Process each measurement
950 */
951 for (count = 0,p = 0; p < meas.size(); p++) {
952 evoked = meas[p]->dir_tree_find(FIFFB_EVOKED);
953 /*
954 * Count the entries
955 */
956 for (evoked_count = 0, j = 0; j < evoked.size(); j++) {
957 for (k = 0; k < evoked[j]->nchild(); k++) {
958 if (evoked[j]->children[k]->type == FIFFB_ASPECT) {
959 evoked_count++;
960 }
961 }
962 }
963 /*
964 * Enlarge tables
965 */
966 types = REALLOC_9(types,count+evoked_count+1,int);
967 /*
968 * Insert node references and compile associated comments...
969 */
970 for (j = 0; j < evoked.size(); j++) /* Evoked data */
971 for (k = 0; k < evoked[j]->nchild(); k++)
972 if (evoked[j]->children[k]->type == FIFFB_ASPECT) {
973 meas_date = get_meas_date(stream,evoked[j]);
974 part = get_comment(stream,evoked[j]);
975 get_aspect_name_type(stream,evoked[j]->children[k],type,types+count);
976 if (!meas_date.isEmpty()) {
977 comments.append(QString("%1>%2>%3").arg(meas_date).arg(part).arg(type));
978 }
979 else {
980 comments.append(QString("%1>%2").arg(part).arg(type));
981 }
982 nodes.append(evoked[j]->children[k]);
983 count++;
984 }
985 }
986 if (count == 0) { /* Nothing to report */
987 comments.clear();
988 nodesp.clear();
989 if (commentsp)
990 *commentsp = comments;
991 if (aspect_typesp)
992 *aspect_typesp = NULL;
993 return 0;
994 }
995 else { /* Return the appropriate variables */
996// comments[count] = NULL;
997 types[count] = -1;
998 nodesp = nodes;
999 if (commentsp)
1000 *commentsp = comments;
1001 else
1002 comments.clear();
1003 if (aspect_typesp)
1004 *aspect_typesp = types;
1005 else
1006 FREE_9(types);
1007 return count;
1008 }
1009}
1010
1011QList<FiffDirNode::SPtr> mne_find_evoked ( FiffStream::SPtr& stream, QStringList* commentsp)
1012/* Optionally return the compiled comments here */
1013{
1014 QList<FiffDirNode::SPtr> evoked;
1015 mne_find_evoked_types_comments(stream,evoked,NULL,commentsp);
1016 return evoked;
1017}
1018
1019static void remove_artefacts (float *resp,
1020 int nsamp,
1021 int *artefs,
1022 int nartef)
1023/*
1024 * Apply the artefact removal
1025 */
1026{
1027 int start,end;
1028 int j,k;
1029 float a,b;
1030 int remove_jump;
1031
1032 for (k = 0; k < nartef; k++) {
1033 if (artefs[3*k] == FIFFV_ARTEF_NONE || artefs[3*k] == FIFFV_ARTEF_KEEP)
1034 continue;
1035 remove_jump = (artefs[3*k] == FIFFV_ARTEF_NOJUMP);
1036 /*
1037 * Find out the indices for the start and end times
1038 */
1039 start = artefs[3*k+1];
1040 end = artefs[3*k+2];
1041 start = MAX(0,MIN(start,nsamp));
1042 end = MAX(0,MIN(end,nsamp));
1043 /*
1044 * Replace the artefact region with a straight line
1045 */
1046 if (start < end) {
1047 if (remove_jump) { /* Remove jump... */
1048 a = resp[end] - resp[start];
1049 for (j = 0; j <=start; j++)
1050 resp[j] = resp[j] + a;
1051 for (j = start+1 ; j < end; j++)
1052 resp[j] = resp[end];
1053 }
1054 else { /* Just connect... */
1055 a = (resp[end]-resp[start])/(end-start);
1056 b = (resp[start]*end - resp[end]*start)/(end-start);
1057 for (j = start+1 ; j < end; j++)
1058 resp[j] = a*j+b;
1059 }
1060 }
1061 }
1062 return;
1063}
1064
1065int mne_read_evoked(const QString& name, /* Name of the file */
1066 int setno, /* Which data set */
1067 int *nchanp, /* How many channels */
1068 int *nsampp, /* Number of time points */
1069 float *tminp, /* First time point */
1070 float *sfreqp, /* Sampling frequency */
1071 QList<FiffChInfo>& chsp, /* Channel info (this is now optional as well) */
1072 float ***epochsp, /* Data, channel by channel */
1073 /*
1074 * Optional items follow
1075 */
1076 QString* commentp, /* Comment for these data */
1077 float *highpassp, /* Highpass frequency */
1078 float *lowpassp, /* Lowpass frequency */
1079 int *navep, /* How many averages */
1080 int *aspect_kindp, /* What kind of an evoked data */
1081 FiffCoordTrans *transp, /* Coordinate transformation */
1082 fiffId *idp, /* Measurement id */
1083 FiffTime* *meas_datep) /* Measurement date */
1084/*
1085 * Load evoked-response data from a fif file
1086 */
1087{
1088 QFile file(name);
1089 FiffStream::SPtr stream(new FiffStream(&file));
1090
1091 QList<FiffDirNode::SPtr> evoked; /* The evoked data nodes */
1092 int nset = 0;
1093 int nchan = 0; /* How many channels */
1094 QStringList comments; /* The associated comments */
1095 float sfreq = 0.0; /* What sampling frequency */
1096 FiffDirNode::SPtr start;
1097 QList<FiffChInfo> chs; /* Channel info */
1098 int *artefs = NULL; /* Artefact limits */
1099 int nartef = 0; /* How many */
1100 float **epochs = NULL; /* The averaged epochs */
1101 FiffCoordTrans trans; /* The coordinate transformation */
1102 fiffId id = NULL; /* Measurement id */
1103 FiffTime* meas_date = NULL; /* Measurement date */
1104 int nave = 1; /* Number of averaged responses */
1105 float tmin = 0; /* Time scale minimum */
1106 float lowpass; /* Lowpass filter frequency */
1107 float highpass = 0.0; /* Highpass filter frequency */
1108 int nsamp = 0; /* Samples in epoch */
1109 int aspect_kind; /* What kind of data */
1110 int res = FAIL; /* A little bit of pessimism */
1111
1112 float *epoch;
1113 int j,k;
1114
1115 if (setno < 0) {
1116 printf ("Evoked response selector must be positive!");
1117 goto out;
1118 }
1119
1120 if(!stream->open())
1121 goto out;
1122
1123 /*
1124 * Select correct data set
1125 */
1126 evoked = mne_find_evoked(stream,(commentp == NULL) ? NULL : &comments);
1127 if (!evoked.size()) {
1128 printf ("No evoked response data available here");
1129 goto out;
1130 }
1131
1132 nset = evoked.size();
1133
1134 if (setno < nset) {
1135 start = evoked[setno];
1136 }
1137 else {
1138 printf ("Too few evoked response data sets (how come?)");
1139 goto out;
1140 }
1141 /*
1142 * Get various things...
1143 */
1144 if (get_meas_info (stream,
1145 start,
1146 &id,
1147 &meas_date,
1148 &nchan,
1149 &sfreq,
1150 &highpass,
1151 &lowpass,
1152 chs,
1153 &trans) == -1)
1154 goto out;
1155
1156 /*
1157 * sfreq is listed here again because
1158 * there might be an individual one in the
1159 * evoked-response data
1160 */
1161 if (get_evoked_essentials(stream,start,sfreq,
1162 tmin,nsamp,nave,aspect_kind,
1163 artefs,nartef) == -1)
1164 goto out;
1165 /*
1166 * Some things may be redefined at a lower level
1167 */
1168 if (get_evoked_optional(stream,
1169 start,
1170 &nchan,
1171 chs) == -1)
1172 goto out;
1173 /*
1174 * Omit nonmagnetic channels
1175 */
1176 if ((epochs = get_epochs(stream,start,nchan,nsamp)) == NULL)
1177 goto out;
1178 /*
1179 * Change artefact limits to start from 0
1180 */
1181 for (k = 0; k < nartef; k++) {
1182 qDebug() << "TODO: Artefact Vectors do not contain the right stuff!";
1183 artefs[2*k+1] = artefs[2*k+1] - sfreq*tmin;
1184 artefs[2*k+2] = artefs[2*k+2] - sfreq*tmin;
1185 }
1186 for (k = 0; k < nchan; k++) {
1187 epoch = epochs[k];
1188 for (j = 0; j < nsamp; j++)
1189 epoch[j] = chs[k].cal*epoch[j];
1190 remove_artefacts(epoch,nsamp,artefs,nartef);
1191 }
1192 /*
1193 * Ready to go
1194 */
1195 chsp = chs;
1196 *tminp = tmin;
1197 *nchanp = nchan;
1198 *nsampp = nsamp;
1199 *sfreqp = sfreq;
1200 *epochsp = epochs; epochs = NULL;
1201 /*
1202 * Fill in the optional data
1203 */
1204 if (commentp) {
1205 *commentp = comments[setno];
1206 comments[setno] = "";
1207 }
1208 if (highpassp)
1209 *highpassp = highpass;
1210 if (lowpassp)
1211 *lowpassp = lowpass;
1212 if (transp) {
1213 *transp = trans;
1214 trans = FiffCoordTrans();
1215 }
1216 if (navep)
1217 *navep = nave;
1218 if (aspect_kindp)
1219 *aspect_kindp = aspect_kind;
1220 if (idp) {
1221 *idp = id;
1222 id = NULL;
1223 }
1224 if (meas_datep) {
1225 *meas_datep = meas_date;
1226 meas_date = NULL;
1227 }
1228 res = OK;
1229 /*
1230 * FREE all allocated data on exit
1231 */
1232out : {
1233 comments.clear();
1234 FREE_9(artefs);
1235 FREE_9(id);
1236 FREE_9(meas_date);
1237 FREE_CMATRIX_9(epochs);
1238 stream->close();
1239 return res;
1240 }
1241}
1242
1243//============================= mne_inverse_io.c =============================
1244
1245#define MAXBUF 200
1246
1248
1249{
1250 char buf[MAXBUF];
1251 static char s[300];
1252 struct tm *ltime;
1253 time_t secs;
1254
1255 secs = id->time.secs;
1256 ltime = localtime(&secs);
1257 (void)strftime(buf,MAXBUF,"%c",ltime);
1258
1259 snprintf(s,sizeof(s),"%d.%d 0x%x%x %s",id->version>>16,id->version & 0xFFFF,id->machid[0],id->machid[1],buf);
1260 return s;
1261}
1262
1263int mne_read_meg_comp_eeg_ch_info_9(const QString& name,
1264 QList<FiffChInfo>& megp, /* MEG channels */
1265 int *nmegp,
1266 QList<FiffChInfo>& meg_compp,
1267 int *nmeg_compp,
1268 QList<FiffChInfo>& eegp, /* EEG channels */
1269 int *neegp,
1270 FiffCoordTrans *meg_head_t,
1271 fiffId *idp) /* The measurement ID */
1272/*
1273 * Read the channel information and split it into three arrays,
1274 * one for MEG, one for MEG compensation channels, and one for EEG
1275 */
1276{
1277 QFile file(name);
1278 FiffStream::SPtr stream(new FiffStream(&file));
1279
1280 QList<FiffChInfo> chs;
1281 int nchan = 0;
1282 QList<FiffChInfo> meg;
1283 int nmeg = 0;
1284 QList<FiffChInfo> meg_comp;
1285 int nmeg_comp = 0;
1286 QList<FiffChInfo> eeg;
1287 int neeg = 0;
1288 fiffId id = NULL;
1289 QList<FiffDirNode::SPtr> nodes;
1290 FiffDirNode::SPtr info;
1291 FiffTag::SPtr t_pTag;
1292 FiffChInfo this_ch;
1294 fiff_int_t kind, pos;
1295 int j,k,to_find;
1296
1297 if(!stream->open())
1298 goto bad;
1299
1300 nodes = stream->dirtree()->dir_tree_find(FIFFB_MNE_PARENT_MEAS_FILE);
1301
1302 if (nodes.size() == 0) {
1303 nodes = stream->dirtree()->dir_tree_find(FIFFB_MEAS_INFO);
1304 if (nodes.size() == 0) {
1305 qCritical ("Could not find the channel information.");
1306 goto bad;
1307 }
1308 }
1309 info = nodes[0];
1310 to_find = 0;
1311 for (k = 0; k < info->nent(); k++) {
1312 kind = info->dir[k]->kind;
1313 pos = info->dir[k]->pos;
1314 switch (kind) {
1315 case FIFF_NCHAN :
1316 if (!stream->read_tag(t_pTag,pos))
1317 goto bad;
1318 nchan = *t_pTag->toInt();
1319
1320 for (j = 0; j < nchan; j++) {
1321 chs.append(FiffChInfo());
1322 chs[j].scanNo = -1;
1323 }
1324 to_find = nchan;
1325 break;
1326
1328 if(!stream->read_tag(t_pTag, pos))
1329 goto bad;
1330 // id = t_pTag->toFiffID();
1331 *id = *(fiffId)t_pTag->data();
1332 break;
1333
1334 case FIFF_COORD_TRANS :
1335 if(!stream->read_tag(t_pTag, pos))
1336 goto bad;
1337 // t = t_pTag->toCoordTrans();
1338 t = FiffCoordTrans::readFromTag( t_pTag );
1339 if (t.from != FIFFV_COORD_DEVICE || t.to != FIFFV_COORD_HEAD)
1340 t = FiffCoordTrans();
1341 break;
1342
1343 case FIFF_CH_INFO : /* Information about one channel */
1344 if(!stream->read_tag(t_pTag, pos))
1345 goto bad;
1346
1347 this_ch = t_pTag->toChInfo();
1348 if (this_ch.scanNo <= 0 || this_ch.scanNo > nchan) {
1349 printf ("FIFF_CH_INFO : scan # out of range %d (%d)!",this_ch.scanNo,nchan);
1350 goto bad;
1351 }
1352 else
1353 chs[this_ch.scanNo-1] = this_ch;
1354 to_find--;
1355 break;
1356 }
1357 }
1358 if (to_find != 0) {
1359 qCritical("Some of the channel information was missing.");
1360 goto bad;
1361 }
1362 if (t.isEmpty() && meg_head_t != NULL) {
1363 /*
1364 * Try again in a more general fashion
1365 */
1367 if (t.isEmpty()) {
1368 qCritical("MEG -> head coordinate transformation not found.");
1369 goto bad;
1370 }
1371 }
1372 /*
1373 * Sort out the channels
1374 */
1375 for (k = 0; k < nchan; k++) {
1376 if (chs[k].kind == FIFFV_MEG_CH) {
1377 meg.append(chs[k]);
1378 nmeg++;
1379 } else if (chs[k].kind == FIFFV_REF_MEG_CH) {
1380 meg_comp.append(chs[k]);
1381 nmeg_comp++;
1382 } else if (chs[k].kind == FIFFV_EEG_CH) {
1383 eeg.append(chs[k]);
1384 neeg++;
1385 }
1386 }
1387 // fiff_close(in);
1388 stream->close();
1389
1390 megp = meg;
1391 if(nmegp) {
1392 *nmegp = nmeg;
1393 }
1394
1395 meg_compp = meg_comp;
1396 if(nmeg_compp) {
1397 *nmeg_compp = nmeg_comp;
1398 }
1399 eegp = eeg;
1400 if(neegp) {
1401 *neegp = neeg;
1402 }
1403
1404 if (idp == NULL) {
1405 FREE_9(id);
1406 }
1407 else
1408 *idp = id;
1409 if (meg_head_t == NULL) {
1410 ; // value type, no cleanup needed
1411 }
1412 else
1413 *meg_head_t = t;
1414
1415 return FIFF_OK;
1416
1417bad : {
1418 // fiff_close(in);
1419 stream->close();
1420 FREE_9(id);
1421 // FREE(tag.data);
1422 return FIFF_FAIL;
1423 }
1424}
1425
1427 const FiffDirNode::SPtr& pNode, QStringList& listp, int& nlistp)
1428{
1429 FiffDirNode::SPtr node,bad;
1430 QList<FiffDirNode::SPtr> temp;
1431 QStringList list;
1432 int nlist = 0;
1433 FiffTag::SPtr t_pTag;
1434 QString names;
1435
1436 if (pNode->isEmpty())
1437 node = stream->dirtree();
1438 else
1439 node = pNode;
1440
1441 temp = node->dir_tree_find(FIFFB_MNE_BAD_CHANNELS);
1442 if (temp.size() > 0) {
1443 bad = temp[0];
1444
1445 bad->find_tag(stream, FIFF_MNE_CH_NAME_LIST, t_pTag);
1446 if (t_pTag) {
1447 names = t_pTag->toString();
1448 mne_string_to_name_list_9(names,list,nlist);
1449 }
1450 }
1451 listp = list;
1452 nlistp = nlist;
1453 return OK;
1454}
1455
1456int mne_read_bad_channel_list_9(const QString& name, QStringList& listp, int& nlistp)
1457
1458{
1459 QFile file(name);
1460 FiffStream::SPtr stream(new FiffStream(&file));
1461
1462 int res;
1463
1464 if(!stream->open())
1465 return FAIL;
1466
1467 res = mne_read_bad_channel_list_from_node_9(stream,stream->dirtree(),listp,nlistp);
1468
1469 stream->close();
1470
1471 return res;
1472}
1473
1474//=============================================================================================================
1475// DEFINE MEMBER METHODS
1476//=============================================================================================================
1477
1479 :meas_id (NULL)
1480 ,current (NULL)
1481 ,ch_major (FALSE)
1482 ,nset (0)
1483 ,nchan (0)
1484 ,op (NULL)
1485 ,fwd (NULL)
1486 ,proj (NULL)
1487 ,comp (nullptr)
1488 ,raw (NULL)
1489 ,chsel (NULL)
1490 ,bad (NULL)
1491 ,nbad (0)
1492 ,badlist (NULL)
1493{
1494 meas_date.secs = 0;
1495 meas_date.usecs = 0;
1496}
1497
1498//=============================================================================================================
1499
1501{
1502 int k;
1503
1504 filename.clear();
1505 FREE_9(meas_id);
1506 if(proj)
1507 delete proj;
1508 comp.reset();
1509 FREE_9(bad);
1510 badlist.clear();
1511
1512 for (k = 0; k < nset; k++)
1513 delete sets[k];
1514
1515 if(raw)
1516 delete raw;
1518
1519 return;
1520}
1521
1522//=============================================================================================================
1523
1524void MNEMeasData::adjust_baselines(float bmin, float bmax)
1525{
1526 int b1,b2;
1527 float sfreq,tmin,tmax;
1528 float **data;
1529 float ave;
1530 int s,c;
1531
1532 if (!this->current)
1533 return;
1534
1535 sfreq = 1.0/ this->current->tstep;
1536 tmin = this->current->tmin;
1537 tmax = this->current->tmin + ( this->current->np-1)/sfreq;
1538
1539 if (bmin < tmin)
1540 b1 = 0;
1541 else if (bmin > tmax)
1542 b1 = this->current->np;
1543 else {
1544 for (b1 = 0; b1/sfreq + tmin < bmin; b1++)
1545 ;
1546 if (b1 < 0)
1547 b1 = 0;
1548 else if (b1 > this->current->np)
1549 b1 = this->current->np;
1550 }
1551 if (bmax < tmin)
1552 b2 = 0;
1553 else if (bmax > tmax)
1554 b2 = this->current->np;
1555 else {
1556 for (b2 = this->current->np; b2/sfreq + tmin > bmax; b2--)
1557 ;
1558 if (b2 < 0)
1559 b2 = 0;
1560 else if (b2 > this->current->np)
1561 b2 = this->current->np;
1562 }
1563 data = this->current->data;
1564 if (b2 > b1) {
1565 for (c = 0; c < this->nchan; c++) {
1566 for (s = b1, ave = 0.0; s < b2; s++)
1567 ave += data[s][c];
1568 ave = ave/(b2-b1);
1569 this->current->baselines[c] += ave;
1570 for (s = 0; s < this->current->np; s++)
1571 data[s][c] = data[s][c] - ave;
1572 }
1573 qDebug() << "TODO: Check comments content";
1574 printf("\t%s : using baseline %7.1f ... %7.1f ms\n",
1575 this->current->comment.toUtf8().constData() ? this->current->comment.toUtf8().constData() : "unknown",
1576 1000*(tmin+b1/sfreq),
1577 1000*(tmin+b2/sfreq));
1578 }
1579 return;
1580}
1581
1582//=============================================================================================================
1583
1585 int set,
1588 const QStringList& namesp,
1589 int nnamesp,
1590 MNEMeasData *add_to) /* Add to this */
1591/*
1592 * Read an evoked-response data file
1593 */
1594{
1595 /*
1596 * Data read from the file
1597 */
1598 QList<FiffChInfo> chs;
1599 int nchan_file,nsamp;
1600 float dtmin,dtmax,sfreq;
1601 QString comment;
1602 float **data = NULL;
1603 float lowpass,highpass;
1604 int nave;
1605 int aspect_kind;
1606 fiffId id = NULL;
1608 FiffTime* meas_date = NULL;
1609 QString stim14_name;
1610 /*
1611 * Desired channels
1612 */
1613 QStringList names;
1614 int nchan = 0;
1615 /*
1616 * Selected channels
1617 */
1618 int *sel = NULL;
1619 int stim14 = -1;
1620 /*
1621 * Other stuff
1622 */
1623 float *source,tmin,tmax;
1624 int k,p,c,np,n1,n2;
1625 MNEMeasData* res = NULL;
1626 MNEMeasData* new_data = add_to;
1627 MNEMeasDataSet* dataset = NULL;
1628
1629 stim14_name = getenv(MNE_ENV_TRIGGER_CH);
1630 if (stim14_name.isEmpty() || stim14_name.size() == 0)
1631 stim14_name = MNE_DEFAULT_TRIGGER_CH;
1632
1633 if (add_to)
1634 mne_channel_names_to_name_list_9(add_to->chs,add_to->nchan,names,nchan);
1635 else {
1636 if (op) {
1637 names = op->eigen_fields->collist;
1638 nchan = op->nchan;
1639 }
1640 else if (fwd) {
1641 names = fwd->collist;
1642 nchan = fwd->ncol;
1643 }
1644 else {
1645 names = namesp;
1646 nchan = nnamesp;
1647 }
1648 if (names.isEmpty())
1649 nchan = 0;
1650 }
1651 /*
1652 * Read the evoked data file
1653 */
1654 if (mne_read_evoked(name,set-1,
1655 &nchan_file,
1656 &nsamp,
1657 &dtmin,
1658 &sfreq,
1659 chs,
1660 &data,
1661 &comment,
1662 &highpass,
1663 &lowpass,
1664 &nave,
1665 &aspect_kind,
1666 &t,
1667 &id,
1668 &meas_date) == FAIL)
1669 goto out;
1670
1671 if (id)
1672 printf("\tMeasurement file id: %s\n",mne_format_file_id(id));
1673
1674#ifdef FOO
1675 if (add_to) { /* Should add consistency check here */
1676 printf("\tWarning: data set consistency check is still in the works.\n");
1677 }
1678#endif
1679 /*
1680 * Pick out the necessary channels
1681 */
1682 if (nchan > 0) {
1683 sel = MALLOC_9(nchan,int);
1684 for (k = 0; k < nchan; k++)
1685 sel[k] = -1;
1686 for (c = 0; c < nchan_file; c++) {
1687 for (k = 0; k < nchan; k++) {
1688 if (sel[k] == -1 && QString::compare(chs[c].ch_name,names[k]) == 0) {
1689 sel[k] = c;
1690 break;
1691 }
1692 }
1693 if (QString::compare(stim14_name,chs[c].ch_name) == 0) {
1694 stim14 = c;
1695 }
1696 }
1697 for (k = 0; k < nchan; k++)
1698 if (sel[k] == -1) {
1699 printf("All channels needed were not in the MEG/EEG data file "
1700 "(first missing: %s).",names[k].toUtf8().constData());
1701 goto out;
1702 }
1703 }
1704 else { /* Load all channels */
1705 sel = MALLOC_9(nchan_file,int);
1706 for (c = 0, nchan = 0; c < nchan_file; c++) {
1707 if (chs[c].kind == FIFFV_MEG_CH || chs[c].kind == FIFFV_EEG_CH) {
1708 sel[nchan] = c;
1709 nchan++;
1710 }
1711 if (QString::compare(stim14_name,chs[c].ch_name) == 0) {
1712 stim14 = c;
1713 }
1714 }
1715 }
1716 /*
1717 * Cut the data to the analysis time range
1718 */
1719 n1 = 0;
1720 n2 = nsamp;
1721 np = n2 - n1;
1722 dtmax = dtmin + (np-1)/sfreq;
1723 /*
1724 * Then the analysis time range
1725 */
1726 tmin = dtmin;
1727 tmax = dtmax;
1728 printf("\tData time range: %8.1f ... %8.1f ms\n",1000*tmin,1000*tmax);
1729 /*
1730 * Just put it together
1731 */
1732 if (!new_data) { /* We need a new meas data structure */
1733 new_data = new MNEMeasData;
1734 new_data->filename = name;
1735 new_data->meas_id = id; id = NULL;
1736 /*
1737 * Getting starting time from measurement ID is not too accurate...
1738 */
1739 if (meas_date)
1740 new_data->meas_date = *meas_date;
1741 else {
1742 if (new_data->meas_id)
1743 new_data->meas_date = new_data->meas_id->time;
1744 else {
1745 new_data->meas_date.secs = 0;
1746 new_data->meas_date.usecs = 0;
1747 }
1748 }
1749 new_data->lowpass = lowpass;
1750 new_data->highpass = highpass;
1751 new_data->nchan = nchan;
1752 new_data->sfreq = sfreq;
1753
1754 if (!t.isEmpty()) {
1755 new_data->meg_head_t = std::make_unique<FiffCoordTrans>(t);
1756 t = FiffCoordTrans();
1757 printf("\tUsing MEG <-> head transform from the present data set\n");
1758 }
1759 if (op != NULL && op->mri_head_t && !op->mri_head_t->isEmpty()) { /* Copy if available */
1760 new_data->mri_head_t = std::make_unique<FiffCoordTrans>(*op->mri_head_t);
1761 printf("\tPicked MRI <-> head transform from the inverse operator\n");
1762 }
1763 /*
1764 * Channel list
1765 */
1766 for (k = 0; k < nchan; k++) {
1767 new_data->chs.append(FiffChInfo());
1768 new_data->chs[k] = chs[sel[k]];
1769 }
1770
1771 new_data->op = op; /* Attach inverse operator */
1772 new_data->fwd = fwd; /* ...or a fwd operator */
1773 if (op) /* Attach the projection operator and CTF compensation info to the data, too */
1774 new_data->proj = op->proj->dup();
1775 else {
1776 new_data->proj = MNEProjOp::read(name);
1777 if (new_data->proj && new_data->proj->nitems > 0) {
1778 printf("\tLoaded projection from %s:\n",name.toUtf8().data());
1779 QTextStream errStream(stderr);
1780 new_data->proj->report(errStream,"\t\t");
1781 }
1782 new_data->comp = MNECTFCompDataSet::read(name);
1783 if (!new_data->comp)
1784 goto out;
1785 if (new_data->comp->ncomp > 0)
1786 printf("\tRead %d compensation data sets from %s\n",new_data->comp->ncomp,name.toUtf8().data());
1787 }
1788 /*
1789 * Th bad channel stuff
1790 */
1791 {
1792 int b;
1793
1794 new_data->bad = MALLOC_9(new_data->nchan,int);
1795 for (k = 0; k < new_data->nchan; k++)
1796 new_data->bad[k] = FALSE;
1797
1798 if (mne_read_bad_channel_list_9(name,new_data->badlist,new_data->nbad) == OK) {
1799 for (b = 0; b < new_data->nbad; b++) {
1800 for (k = 0; k < new_data->nchan; k++) {
1801 if (QString::compare(new_data->chs[k].ch_name,new_data->badlist[b],Qt::CaseInsensitive) == 0) {
1802 new_data->bad[k] = TRUE;
1803 break;
1804 }
1805 }
1806 }
1807 printf("\t%d bad channels read from %s%s",new_data->nbad,name.toUtf8().data(),new_data->nbad > 0 ? ":\n" : "\n");
1808 if (new_data->nbad > 0) {
1809 printf("\t\t");
1810 for (k = 0; k < new_data->nbad; k++)
1811 printf("%s%c",new_data->badlist[k].toUtf8().constData(),k < new_data->nbad-1 ? ' ' : '\n');
1812 }
1813 }
1814 }
1815 }
1816 /*
1817 * New data set is created anyway
1818 */
1819 dataset = new MNEMeasDataSet;
1820 dataset->tmin = tmin;
1821 dataset->tstep = 1.0/sfreq;
1822 dataset->first = n1;
1823 dataset->np = np;
1824 dataset->nave = nave;
1825 dataset->kind = aspect_kind;
1826 dataset->data = ALLOC_CMATRIX_9(np,nchan);
1827 dataset->comment = comment; comment.clear();
1828 dataset->baselines = MALLOC_9(nchan,float);
1829 /*
1830 * Pick data from all channels
1831 */
1832 for (k = 0; k < nchan; k++) {
1833 source = data[sel[k]];
1834 /*
1835 * Shift the response
1836 */
1837 for (p = 0; p < np; p++)
1838 dataset->data[p][k] = source[p+n1];
1839 dataset->baselines[k] = 0.0;
1840 }
1841 /*
1842 * Pick the digital trigger channel, too
1843 */
1844 if (stim14 >= 0) {
1845 dataset->stim14 = MALLOC_9(np,float);
1846 source = data[stim14];
1847 for (p = 0; p < np; p++) /* Copy the data and correct for the possible non-unit calibration */
1848 dataset->stim14[p] = source[p+n1]/chs[stim14].cal;
1849 }
1850 new_data->sets.append(dataset); dataset = NULL;
1851 new_data->nset++;
1852 if (!add_to)
1853 new_data->current = new_data->sets[0];
1854 res = new_data;
1855 printf("\t%s dataset %s from %s\n",
1856 add_to ? "Added" : "Loaded",
1857 new_data->sets[new_data->nset-1]->comment.toUtf8().constData() ? new_data->sets[new_data->nset-1]->comment.toUtf8().constData() : "unknown",name.toUtf8().data());
1858
1859out : {
1860 FREE_9(sel);
1861 comment.clear();
1862 FREE_CMATRIX_9(data);
1863 FREE_9(id);
1864 if (res == NULL && !add_to)
1865 delete new_data;
1866 if (add_to)
1867 names.clear();
1868 return res;
1869 }
1870}
1871
1872//=============================================================================================================
1873
1875 int set,
1878 const QStringList& namesp,
1879 int nnamesp)
1880
1881{
1882 return mne_read_meas_data_add(name,set,op,fwd,namesp,nnamesp,NULL);
1883}
#define FIFFV_EEG_CH
#define FIFF_OK
#define FIFFV_COORD_DEVICE
#define FIFFV_ARTEF_NONE
#define FIFF_FAIL
#define FIFFV_REF_MEG_CH
#define FIFFV_MEG_CH
#define FIFFV_COORD_HEAD
#define FIFF_MNE_CH_NAME_LIST
#define FIFFB_MNE_PARENT_MEAS_FILE
#define FIFFV_ARTEF_KEEP
#define FIFFB_MNE_BAD_CHANNELS
#define FIFFV_ARTEF_NOJUMP
#define FIFF_PARENT_BLOCK_ID
Definition fiff_file.h:333
#define FIFF_FIRST_TIME
Definition fiff_file.h:482
#define FIFF_NCHAN
Definition fiff_file.h:453
#define FIFF_HIGHPASS
Definition fiff_file.h:476
#define FIFFT_MATRIX
Definition fiff_file.h:272
#define FIFFT_OLD_PACK
Definition fiff_file.h:246
#define FIFFB_ASPECT
Definition fiff_file.h:368
#define FIFF_FIRST_SAMPLE
Definition fiff_file.h:461
#define FIFFV_ASPECT_AVERAGE
Definition fiff_file.h:438
#define FIFFB_MEAS
Definition fiff_file.h:362
#define FIFF_NAVE
Definition fiff_file.h:460
#define FIFF_COMMENT
Definition fiff_file.h:459
#define FIFFV_ASPECT_DIPOLE_WAVE
Definition fiff_file.h:445
#define FIFFV_ASPECT_SUBAVERAGE
Definition fiff_file.h:441
#define FIFF_ASPECT_KIND
Definition fiff_file.h:463
#define FIFFV_ASPECT_SAMPLE
Definition fiff_file.h:443
#define FIFFV_ASPECT_STD_ERR
Definition fiff_file.h:439
#define FIFF_COORD_TRANS
Definition fiff_file.h:475
#define FIFF_EPOCH
Definition fiff_file.h:558
#define FIFFT_FLOAT
Definition fiff_file.h:232
#define FIFF_MEAS_DATE
Definition fiff_file.h:457
#define FIFFB_EVOKED
Definition fiff_file.h:366
#define FIFF_LAST_SAMPLE
Definition fiff_file.h:462
#define FIFF_ARTEF_REMOVAL
Definition fiff_file.h:474
#define FIFF_NO_SAMPLES
Definition fiff_file.h:481
#define FIFF_CH_INFO
Definition fiff_file.h:456
#define FIFFV_ASPECT_ALTAVERAGE
Definition fiff_file.h:442
#define FIFFV_ASPECT_POWER_DENSITY
Definition fiff_file.h:444
#define FIFFB_HPI_RESULT
Definition fiff_file.h:372
#define FIFF_LOWPASS
Definition fiff_file.h:472
#define FIFFB_MEAS_INFO
Definition fiff_file.h:363
#define FIFFV_ASPECT_SINGLE
Definition fiff_file.h:440
#define FIFF_SFREQ
Definition fiff_file.h:454
Old fiff_type declarations - replace them.
FiffCoordTrans class declaration.
Legacy MNE-C constants and common typedefs.
#define MNE_ENV_TRIGGER_CH
Environment variable overriding the trigger channel name.
Definition mne_types.h:152
#define MNE_DEFAULT_TRIGGER_CH
Default digital trigger channel name.
Definition mne_types.h:149
MNENamedMatrix class declaration.
#define TRUE
#define FALSE
#define OK
#define FAIL
MNE Meas Data Set (MNEMeasDataSet) class declaration.
MNE Meas Data (MNEMeasData) class declaration.
int mne_read_meg_comp_eeg_ch_info_9(const QString &name, QList< FiffChInfo > &megp, int *nmegp, QList< FiffChInfo > &meg_compp, int *nmeg_compp, QList< FiffChInfo > &eegp, int *neegp, FiffCoordTrans *meg_head_t, fiffId *idp)
int mne_find_evoked_types_comments(FiffStream::SPtr &stream, QList< FiffDirNode::SPtr > &nodesp, int **aspect_typesp, QStringList *commentsp)
#define FREE_9(x)
#define MIN(a, b)
#define REALLOC_9(x, y, t)
#define MAXDATE
int mne_read_bad_channel_list_from_node_9(FiffStream::SPtr &stream, const FiffDirNode::SPtr &pNode, QStringList &listp, int &nlistp)
void mne_free_cmatrix_9(float **m)
QString mne_channel_names_to_string_9(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
#define FREE_CMATRIX_9(m)
char * mne_format_file_id(fiffId id)
#define MALLOC_9(x, t)
void mne_channel_names_to_name_list_9(const QList< FIFFLIB::FiffChInfo > &chs, int nch, QStringList &listp, int &nlistp)
void fromFloatEigenMatrix_9(const Eigen::MatrixXf &from_mat, float **&to_mat, const int m, const int n)
#define ALLOC_CMATRIX_9(x, y)
QList< FiffDirNode::SPtr > mne_find_evoked(FiffStream::SPtr &stream, QStringList *commentsp)
void mne_ch_selection_free_9(mneChSelection s)
int mne_read_bad_channel_list_9(const QString &name, QStringList &listp, int &nlistp)
void mne_free_ring_buffer_9(void *thisp)
float ** mne_cmatrix_9(int nr, int nc)
#define MAXBUF
int mne_read_evoked(const QString &name, int setno, int *nchanp, int *nsampp, float *tminp, float *sfreqp, QList< FiffChInfo > &chsp, float ***epochsp, QString *commentp, float *highpassp, float *lowpassp, int *navep, int *aspect_kindp, FiffCoordTrans *transp, fiffId *idp, FiffTime **meas_datep)
QString mne_name_list_to_string_9(const QStringList &list)
#define MAX(a, b)
void mne_string_to_name_list_9(const QString &s, QStringList &listp, int &nlistp)
Core MNE data structures (source spaces, source estimates, hemispheres).
MNEChSelection * mneChSelection
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
qint32 fiff_int_t
Definition fiff_types.h:89
FiffId * fiffId
Backward-compatible pointer typedef for the old fiffId pointer.
Definition fiff_types.h:130
FiffDirEntry * fiffDirEntry
Backward-compatible pointer typedef for the old fiffDirEntry pointer.
Definition fiff_types.h:144
FiffId fiffIdRec
Backward-compatible typedef for the old fiffIdRec struct.
Definition fiff_types.h:126
unsigned char fiff_byte_t
Definition fiff_types.h:85
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
struct INVERSELIB::ringBufBuf_9 ringBufBufRec_9
struct INVERSELIB::ringBuf_9 ringBufRec_9
Channel info descriptor.
Coordinate transformation description.
QSharedPointer< FiffDirNode > SPtr
fiff_int_t machid[2]
Definition fiff_id.h:167
FiffTime time
Definition fiff_id.h:168
fiff_int_t version
Definition fiff_id.h:166
FIFF File I/O routines.
static QStringList split_name_list(QString p_sNameList)
QSharedPointer< FiffStream > SPtr
QSharedPointer< FiffTag > SPtr
Definition fiff_tag.h:155
Time stamp record storing seconds and microseconds since epoch.
Definition fiff_time.h:61
MNE inverse operator combining noise covariance, forward solution, and source covariance for source e...
Single ring buffer entry holding a float array and a pointer to its matrix view.
Circular buffer managing a fixed-size pool of ringBufBuf_9 entries for streaming data reuse.
FIFFLIB::fiffId meas_id
MNELIB::MNERawData * raw
static MNEMeasData * mne_read_meas_data_add(const QString &name, int set, MNEInverseOperator *op, MNELIB::MNENamedMatrix *fwd, const QStringList &namesp, int nnamesp, MNEMeasData *add_to)
std::unique_ptr< FIFFLIB::FiffCoordTrans > mri_head_t
void adjust_baselines(float bmin, float bmax)
QList< FIFFLIB::FiffChInfo > chs
MNELIB::MNEProjOp * proj
MNEInverseOperator * op
MNELIB::MNENamedMatrix * fwd
FIFFLIB::FiffTime meas_date
QList< MNEMeasDataSet * > sets
static MNEMeasData * mne_read_meas_data(const QString &name, int set, MNEInverseOperator *op, MNELIB::MNENamedMatrix *fwd, const QStringList &namesp, int nnamesp)
std::unique_ptr< MNELIB::MNECTFCompDataSet > comp
std::unique_ptr< FIFFLIB::FiffCoordTrans > meg_head_t
MNELIB::mneChSelection chsel
MNEMeasDataSet * current
Single measurement epoch or average within MNEMeasData, including data matrix and projectors.
static std::unique_ptr< MNECTFCompDataSet > read(const QString &name)
A dense matrix with named rows and columns.
static MNEProjOp * read(const QString &name)
void report(QTextStream &out, const char *tag)
static FiffCoordTrans readMeasTransform(const QString &name)
static FiffCoordTrans readFromTag(const QSharedPointer< FiffTag > &tag)
MNE Inverse Operator (MNEInverseOperator) class declaration.