v2.0.0
Loading...
Searching...
No Matches
fiff_info.cpp
Go to the documentation of this file.
1//=============================================================================================================
21
22//=============================================================================================================
23// INCLUDES
24//=============================================================================================================
25
26#include "fiff_info.h"
27#include "fiff_stream.h"
28#include "fiff_file.h"
29
30#include <utils/ioutils.h>
31#include <iostream>
32#include <QDebug>
33
34//=============================================================================================================
35// USED NAMESPACES
36//=============================================================================================================
37
38using namespace FIFFLIB;
39using namespace UTILSLIB;
40using namespace Eigen;
41
42//=============================================================================================================
43// DEFINE MEMBER METHODS
44//=============================================================================================================
45
47: FiffInfoBase()//nchan(-1)
48, sfreq(-1.0)
49, linefreq(-1.0)
50, highpass(-1.0)
51, lowpass(-1.0)
52, gantry_angle(-1)
53, acq_pars("")
54, acq_stim("")
55{
56 meas_date[0] = -1;
57}
58
59//=============================================================================================================
60
61FiffInfo::FiffInfo(const FiffInfo& p_FiffInfo)
62: FiffInfoBase(p_FiffInfo)
63, file_id(p_FiffInfo.file_id)
64, sfreq(p_FiffInfo.sfreq)
65, linefreq(p_FiffInfo.linefreq)
66, highpass(p_FiffInfo.highpass)
67, lowpass(p_FiffInfo.lowpass)
68, proj_id(p_FiffInfo.proj_id)
69, proj_name(p_FiffInfo.proj_name)
71, experimenter(p_FiffInfo.experimenter)
72, description(p_FiffInfo.description)
73, utc_offset(p_FiffInfo.utc_offset)
74, gantry_angle(p_FiffInfo.gantry_angle)
75, dev_ctf_t(p_FiffInfo.dev_ctf_t)
76, dig(p_FiffInfo.dig)
77, dig_trans(p_FiffInfo.dig_trans)
78, projs(p_FiffInfo.projs)
79, comps(p_FiffInfo.comps)
80, acq_pars(p_FiffInfo.acq_pars)
81, acq_stim(p_FiffInfo.acq_stim)
82{
83 meas_date[0] = p_FiffInfo.meas_date[0];
84 meas_date[1] = p_FiffInfo.meas_date[1];
85}
86
87//=============================================================================================================
88
92
93//=============================================================================================================
94
96{
98 file_id = FiffId();
99 meas_date[0] = -1;
100 sfreq = -1.0;
101 linefreq = -1.0;
102 highpass = -1.0;
103 lowpass = -1.0;
104 proj_id = -1;
105 proj_name = "";
106 xplotter_layout = "";
107 experimenter = "";
108 description = "";
109 utc_offset = "";
110 gantry_angle = -1;
111 dev_ctf_t.clear();
112 dig.clear();
113 dig_trans.clear();
114 projs.clear();
115 comps.clear();
116 acq_pars = "";
117 acq_stim = "";
118}
119
120//=============================================================================================================
121
123{
124 qint32 comp = 0;
125 qint32 first_comp = -1;
126
127 qint32 k = 0;
128 for (k = 0; k < this->nchan; ++k)
129 {
130 if (this->chs[k].kind == FIFFV_MEG_CH)
131 {
132 comp = this->chs[k].chpos.coil_type >> 16;
133 if (first_comp < 0)
134 first_comp = comp;
135 else if (comp != first_comp)
136 qWarning("Compensation is not set equally on all MEG channels");
137 }
138 }
139 return comp;
140}
141
142//=============================================================================================================
143
144bool FiffInfo::make_compensator(fiff_int_t from, fiff_int_t to, FiffCtfComp& ctf_comp, bool exclude_comp_chs) const
145{
146 MatrixXd C1, C2, comp_tmp;
147
148// if(ctf_comp.data)
149// delete ctf_comp.data;
150 ctf_comp.data->clear();
151
152 if (from == to)
153 {
154 ctf_comp.data->data = MatrixXd::Identity(this->nchan, this->nchan);
155 return false;
156 }
157
158 if (from == 0)
159 C1 = MatrixXd::Zero(this->nchan,this->nchan);
160 else
161 {
162 if (!this->make_compensator(from, C1))
163 {
164 qWarning("Cannot create compensator C1\n");
165 qWarning("Desired compensation matrix (kind = %d) not found\n",from);
166 return false;
167 }
168 }
169
170 if (to == 0)
171 C2 = MatrixXd::Zero(this->nchan,this->nchan);
172 else
173 {
174 if (!this->make_compensator(to, C2))
175 {
176 qWarning("Cannot create compensator C2\n");
177 qWarning("Desired compensation matrix (kind = %d) not found\n",to);
178 return false;
179 }
180 }
181 //
182 // s_orig = s_from + C1*s_from = (I + C1)*s_from
183 // s_to = s_orig - C2*s_orig = (I - C2)*s_orig
184 // s_to = (I - C2)*(I + C1)*s_from = (I + C1 - C2 - C2*C1)*s_from
185 //
186 comp_tmp = MatrixXd::Identity(this->nchan,this->nchan) + C1 - C2 - C2*C1;
187
188 qint32 k;
189 if (exclude_comp_chs)
190 {
191 VectorXi pick = MatrixXi::Zero(1,this->nchan);
192 qint32 npick = 0;
193 for (k = 0; k < this->nchan; ++k)
194 {
195 if (this->chs[k].kind != FIFFV_REF_MEG_CH)
196 {
197 pick(npick) = k;
198 ++npick;
199 }
200 }
201 if (npick == 0)
202 {
203 qWarning("Nothing remains after excluding the compensation channels\n");
204 return false;
205 }
206
207 ctf_comp.data->data.resize(npick,this->nchan);
208 for (k = 0; k < npick; ++k)
209 ctf_comp.data->data.row(k) = comp_tmp.block(pick(k), 0, 1, this->nchan);
210 } else {
211 ctf_comp.data->data = comp_tmp;
212 }
213
214 return true;
215}
216
217//=============================================================================================================
218
219bool FiffInfo::make_compensator(fiff_int_t kind, MatrixXd& this_comp) const//private method
220{
221 FiffNamedMatrix::SDPtr this_data;
222 MatrixXd presel, postsel;
223 qint32 k, col, c, ch=0, row, row_ch=0, channelAvailable;
224
225 for (k = 0; k < this->comps.size(); ++k)
226 {
227 if (this->comps[k].kind == kind)
228 {
229 this_data = this->comps[k].data;
230
231 //
232 // Create the preselector
233 //
234 presel = MatrixXd::Zero(this_data->ncol,this->nchan);
235
236 for(col = 0; col < this_data->ncol; ++col)
237 {
238 channelAvailable = 0;
239 for (c = 0; c < this->ch_names.size(); ++c)
240 {
241 if (QString::compare(this_data->col_names.at(col),this->ch_names.at(c)) == 0)
242 {
243 ++channelAvailable;
244 ch = c;
245 }
246 }
247 if (channelAvailable == 0)
248 {
249 qWarning("Channel %s is not available in data\n",this_data->col_names.at(col).toUtf8().constData());
250 return false;
251 }
252 else if (channelAvailable > 1)
253 {
254 qWarning("Ambiguous channel %s",this_data->col_names.at(col).toUtf8().constData());
255 return false;
256 }
257 presel(col,ch) = 1.0;
258 }
259 //
260 // Create the postselector
261 //
262 postsel = MatrixXd::Zero(this->nchan,this_data->nrow);
263
264 for (c = 0; c < this->nchan; ++c)
265 {
266 channelAvailable = 0;
267 for (row = 0; row < this_data->row_names.size(); ++row)
268 {
269 if (QString::compare(this->ch_names.at(c),this_data->row_names.at(row)) == 0)
270 {
271 ++channelAvailable;
272 row_ch = row;
273 }
274 }
275 if (channelAvailable > 1)
276 {
277 qWarning("Ambiguous channel %s", this->ch_names.at(c).toUtf8().constData());
278 return false;
279 }
280 else if (channelAvailable == 1)
281 {
282 postsel(c,row_ch) = 1.0;
283 }
284 }
285 this_comp = postsel*this_data->data*presel;
286 return true;
287 }
288 }
289 this_comp = defaultMatrixXd;
290 return false;
291}
292
293//=============================================================================================================
294
295FiffInfo FiffInfo::pick_info(const RowVectorXi &sel) const
296{
297 FiffInfo res = *this;//new FiffInfo(this);
298 if (sel.size() == 0)
299 return res;
300
301 //ToDo when pointer List do delation
302 res.chs.clear();
303 res.ch_names.clear();
304
305 qint32 idx;
306 for(qint32 i = 0; i < sel.size(); ++i)
307 {
308 idx = sel[i];
309 res.chs.append(this->chs[idx]);
310 res.ch_names.append(this->ch_names[idx]);
311 }
312 res.nchan = static_cast<int>(sel.size());
313
314 return res;
315}
316
317//=============================================================================================================
318
319QList<FiffChInfo> FiffInfo::set_current_comp(QList<FiffChInfo>& listFiffChInfo, fiff_int_t value)
320{
321 QList<FiffChInfo> newList;
322 qint32 k;
323 fiff_int_t coil_type;
324
325 for(k = 0; k < listFiffChInfo.size(); ++k)
326 newList.append(listFiffChInfo[k]);
327
328 qint32 lower_half = 65535;// hex2dec('FFFF');
329 for (k = 0; k < listFiffChInfo.size(); ++k)
330 {
331 if (listFiffChInfo[k].kind == FIFFV_MEG_CH)
332 {
333 coil_type = listFiffChInfo[k].chpos.coil_type & lower_half;
334 newList[k].chpos.coil_type = (coil_type | (value << 16));
335 }
336 }
337 return newList;
338}
339
340//=============================================================================================================
341
342bool FiffInfo::readMegEegChannels(const QString& name,
343 bool do_meg,
344 bool do_eeg,
345 const QStringList& bads,
346 QList<FiffChInfo>& chsp,
347 int& nmegp,
348 int& neegp)
349{
350 QFile file(name);
351 FiffStream::SPtr stream(new FiffStream(&file));
352
353 if (!stream->open())
354 return false;
355
356 FiffInfo info;
357 FiffDirNode::SPtr infoNode;
358 if (!stream->read_meas_info(stream->dirtree(), info, infoNode)) {
359 qCritical("%s : could not read measurement info", name.toUtf8().data());
360 stream->close();
361 return false;
362 }
363 stream->close();
364
365 QList<FiffChInfo> meg;
366 QList<FiffChInfo> eeg;
367
368 for (int k = 0; k < info.chs.size(); k++) {
369 if (bads.contains(info.chs[k].ch_name))
370 continue;
371 if (do_meg && info.chs[k].kind == FIFFV_MEG_CH)
372 meg.append(info.chs[k]);
373 else if (do_eeg && info.chs[k].isValidEeg())
374 eeg.append(info.chs[k]);
375 }
376
377 chsp.clear();
378 chsp.reserve(meg.size() + eeg.size());
379 chsp.append(meg);
380 chsp.append(eeg);
381
382 nmegp = meg.size();
383 neegp = eeg.size();
384 return true;
385}
386
387//=============================================================================================================
388
390{
391 //
392 // We will always write floats
393 //
394 fiff_int_t data_type = 4;
395 qint32 k;
396 QList<FiffChInfo> chs;
397
398 for(k = 0; k < this->nchan; ++k)
399 chs << this->chs[k];
400
401 fiff_int_t nchan = chs.size();
402
403 //
404 // write the essentials
405 //
406 p_pStream->start_block(FIFFB_MEAS);//4
407 p_pStream->write_id(FIFF_BLOCK_ID);//5
408 if(this->meas_id.version != -1)
409 {
410 p_pStream->write_id(FIFF_PARENT_BLOCK_ID,this->meas_id);//6
411 }
412 //
413 // Measurement info
414 //
415 p_pStream->start_block(FIFFB_MEAS_INFO);//7
416
417 //
418 // Blocks from the original -> skip this
419 //
420// QList<fiff_int_t> blocks;
421// blocks << FIFFB_SUBJECT << FIFFB_HPI_MEAS << FIFFB_HPI_RESULT << FIFFB_ISOTRAK << FIFFB_PROCESSING_HISTORY;
422 bool have_hpi_result = false;
423 bool have_isotrak = false;
424 //
425 // megacq parameters
426 //
427 if (!this->acq_pars.isEmpty() || !this->acq_stim.isEmpty())
428 {
429 p_pStream->start_block(FIFFB_DACQ_PARS);
430 if (!this->acq_pars.isEmpty())
431 p_pStream->write_string(FIFF_DACQ_PARS, this->acq_pars);
432
433 if (!this->acq_stim.isEmpty())
434 p_pStream->write_string(FIFF_DACQ_STIM, this->acq_stim);
435
436 p_pStream->end_block(FIFFB_DACQ_PARS);
437 }
438 //
439 // Coordinate transformations if the HPI result block was not there
440 //
441 if (!have_hpi_result)
442 {
443 if (!this->dev_head_t.isEmpty())
444 p_pStream->write_coord_trans(this->dev_head_t);
445
446 if (!this->ctf_head_t.isEmpty())
447 p_pStream->write_coord_trans(this->ctf_head_t);
448 }
449 //
450 // Polhemus data
451 //
452 if (this->dig.size() > 0 && !have_isotrak)
453 {
454 p_pStream->start_block(FIFFB_ISOTRAK);
455 for (qint32 k = 0; k < this->dig.size(); ++k)
456 p_pStream->write_dig_point(this->dig[k]);
457
458 p_pStream->end_block(FIFFB_ISOTRAK);
459 }
460 //
461 // Projectors
462 //
463 p_pStream->write_proj(this->projs);
464 //
465 // CTF compensation info
466 //
467 p_pStream->write_ctf_comp(this->comps);
468 //
469 // Bad channels
470 //
471 if (this->bads.size() > 0)
472 {
476 }
477 //
478 // General
479 //
480 p_pStream->write_float(FIFF_SFREQ,&this->sfreq);
481 p_pStream->write_float(FIFF_LINE_FREQ,&this->linefreq);
482 p_pStream->write_float(FIFF_HIGHPASS,&this->highpass);
483 p_pStream->write_float(FIFF_LOWPASS,&this->lowpass);
485 p_pStream->write_string(FIFF_DESCRIPTION,this->description);
486 p_pStream->write_string(FIFF_UNIT_C,this->utc_offset);
487 p_pStream->write_string(FIFF_PROJ_NAME,this->proj_name);
488 p_pStream->write_int(FIFF_PROJ_ID,&this->proj_id);
489 p_pStream->write_int(FIFF_GANTRY_ANGLE,&this->gantry_angle);
490 p_pStream->write_int(FIFF_NCHAN,&nchan);
491 p_pStream->write_int(FIFF_DATA_PACK,&data_type);
492 if (this->meas_date[0] != -1)
493 p_pStream->write_int(FIFF_MEAS_DATE,this->meas_date, 2);
494 //
495 // Channel info
496 //
497 MatrixXd cals(1,nchan);
498
499 for(k = 0; k < nchan; ++k)
500 {
501 //
502 // Scan numbers may have been messed up
503 //
504 chs[k].scanNo = k+1;//+1 because
505// chs[k].range = 1.0f;//Why? -> cause its already calibrated through reading
506 cals(0,k) = static_cast<double>(chs[k].cal); //ToDo whats going on with cals?
507 p_pStream->write_ch_info(chs[k]);
508 }
509 //
510 //
511 p_pStream->end_block(FIFFB_MEAS_INFO);
512}
513
514//=============================================================================================================
515
516void FiffInfo::print() const
517{
518 std::cout << "Sample frequency: " << sfreq << "\n";
519 std::cout << "LineFreq: " << linefreq << " | Highpass: " << highpass << " | Lowpass: " << lowpass << "\n";
520 std::cout << "Number of digitizer points: " << dig.size() << "\n";
521 for (auto& point : dig){
522 if (point.kind == FIFFV_POINT_HPI){
523 std::cout << "HPI Point " << point.ident << " - " << point.r[0] << ", " << point.r[1] << ", " << point.r[2] << "\n";
524 }
525 }
526}
Header-only Eigen matrix text I/O — round-trips dense matrices to whitespace-separated ASCII for cros...
#define FIFF_UNIT_C
#define FIFFV_REF_MEG_CH
#define FIFFV_MEG_CH
#define FIFF_MNE_CH_NAME_LIST
#define FIFFB_MNE_BAD_CHANNELS
#define FIFFV_POINT_HPI
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
FIFF tag-kind, block-kind and type-code numerical definitions, authoritative for FIFFLIB.
#define FIFF_GANTRY_ANGLE
Definition fiff_file.h:548
#define FIFF_DACQ_STIM
Definition fiff_file.h:344
#define FIFF_PARENT_BLOCK_ID
Definition fiff_file.h:326
#define FIFF_NCHAN
Definition fiff_file.h:446
#define FIFF_PROJ_ID
Definition fiff_file.h:568
#define FIFFB_ISOTRAK
Definition fiff_file.h:363
#define FIFF_HIGHPASS
Definition fiff_file.h:469
#define FIFF_EXPERIMENTER
Definition fiff_file.h:458
#define FIFF_PROJ_NAME
Definition fiff_file.h:569
#define FIFF_DATA_PACK
Definition fiff_file.h:448
#define FIFF_DESCRIPTION
Definition fiff_file.h:479
#define FIFF_LINE_FREQ
Definition fiff_file.h:482
#define FIFFB_MEAS
Definition fiff_file.h:355
#define FIFFB_DACQ_PARS
Definition fiff_file.h:372
#define FIFF_BLOCK_ID
Definition fiff_file.h:319
#define FIFF_DACQ_PARS
Definition fiff_file.h:343
#define FIFF_MEAS_DATE
Definition fiff_file.h:450
#define FIFF_LOWPASS
Definition fiff_file.h:465
#define FIFFB_MEAS_INFO
Definition fiff_file.h:356
#define FIFF_SFREQ
Definition fiff_file.h:447
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
FIFF file I/O, in-memory data structures and high-level readers/writers.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
One CTF software-gradient compensation matrix: grade kind, calibration flag and the gradiometer × ref...
QSharedPointer< FiffDirNode > SPtr
128-bit FIFF identifier: hardware machine ID plus creation time, stamped on every file and block.
Definition fiff_id.h:66
FiffInfo pick_info(const Eigen::RowVectorXi &sel=defaultVectorXi) const
void set_current_comp(fiff_int_t value)
Definition fiff_info.h:301
void print() const
static bool readMegEegChannels(const QString &name, bool do_meg, bool do_eeg, const QStringList &bads, QList< FiffChInfo > &chsp, int &nmegp, int &neegp)
QString description
Definition fiff_info.h:271
FiffCoordTrans dev_ctf_t
Definition fiff_info.h:274
fiff_int_t gantry_angle
Definition fiff_info.h:273
void writeToStream(FiffStream *p_pStream) const
FiffCoordTrans dig_trans
Definition fiff_info.h:276
QList< FiffCtfComp > comps
Definition fiff_info.h:278
qint32 get_current_comp()
QString xplotter_layout
Definition fiff_info.h:269
fiff_int_t meas_date[2]
Definition fiff_info.h:262
bool make_compensator(fiff_int_t from, fiff_int_t to, FiffCtfComp &ctf_comp, bool exclude_comp_chs=false) const
QList< FiffDigPoint > dig
Definition fiff_info.h:275
QString experimenter
Definition fiff_info.h:270
QList< FiffProj > projs
Definition fiff_info.h:277
QList< FiffChInfo > chs
FiffCoordTrans ctf_head_t
FiffCoordTrans dev_head_t
QSharedDataPointer< FiffNamedMatrix > SDPtr
FIFF tag-stream reader/writer: wraps a QIODevice and exposes typed read_* / write_* methods for every...
fiff_long_t start_block(fiff_int_t kind)
fiff_long_t write_proj(const QList< FiffProj > &projs)
QSharedPointer< FiffStream > SPtr
fiff_long_t write_dig_point(const FiffDigPoint &dig)
fiff_long_t write_int(fiff_int_t kind, const fiff_int_t *data, fiff_int_t nel=1, fiff_int_t next=FIFFV_NEXT_SEQ)
fiff_long_t write_float(fiff_int_t kind, const float *data, fiff_int_t nel=1)
fiff_long_t write_id(fiff_int_t kind, const FiffId &id=FiffId::getDefault())
fiff_long_t write_coord_trans(const FiffCoordTrans &trans)
fiff_long_t write_name_list(fiff_int_t kind, const QStringList &data)
fiff_long_t write_string(fiff_int_t kind, const QString &data)
fiff_long_t end_block(fiff_int_t kind, fiff_int_t next=FIFFV_NEXT_SEQ)
fiff_long_t write_ch_info(const FiffChInfo &ch)
fiff_long_t write_ctf_comp(const QList< FiffCtfComp > &comps)