v2.0.0
Loading...
Searching...
No Matches
fiff_raw_data.cpp
Go to the documentation of this file.
1//=============================================================================================================
21
22//=============================================================================================================
23// INCLUDES
24//=============================================================================================================
25
26#include "fiff_raw_data.h"
27#include "fiff_events.h"
28#include "fiff_tag.h"
29#include "fiff_stream.h"
30#include "cstdlib"
31
32#include <stdexcept>
33//=============================================================================================================
34// USED NAMESPACES
35//=============================================================================================================
36
37using namespace FIFFLIB;
38using namespace Eigen;
39
40//=============================================================================================================
41// DEFINE MEMBER METHODS
42//=============================================================================================================
43
49
50//=============================================================================================================
51
52FiffRawData::FiffRawData(QIODevice &p_IODevice)
53: first_samp(-1)
54, last_samp(-1)
55{
56 //setup FiffRawData object
57 if(!FiffStream::setup_read_raw(p_IODevice, *this))
58 {
59 throw std::runtime_error("Error during fiff setup raw read");
60 }
61}
62
63//=============================================================================================================
64
65FiffRawData::FiffRawData(QIODevice &p_IODevice, bool b_littleEndian)
66: first_samp(-1)
67, last_samp(-1)
68{
69 //setup FiffRawData object
70 if(!FiffStream::setup_read_raw(p_IODevice, *this, false, b_littleEndian))
71 {
72 throw std::runtime_error("Error during fiff setup raw read");
73 }
74}
75
76//=============================================================================================================
77
79: file(p_FiffRawData.file)
80, info(p_FiffRawData.info)
81, first_samp(p_FiffRawData.first_samp)
82, last_samp(p_FiffRawData.last_samp)
83, cals(p_FiffRawData.cals)
84, rawdir(p_FiffRawData.rawdir)
85, proj(p_FiffRawData.proj)
86, comp(p_FiffRawData.comp)
87{
88}
89
90//=============================================================================================================
91
95
96//=============================================================================================================
97
99{
100 info.clear();
101 first_samp = -1;
102 last_samp = -1;
103 cals = RowVectorXd();
104 rawdir.clear();
105 proj = MatrixXd();
106 comp.clear();
107}
108
109//=============================================================================================================
110#include <QElapsedTimer>
111#include <QDebug>
112bool FiffRawData::read_raw_segment(MatrixXd& data,
113 MatrixXd& times,
114 fiff_int_t from,
115 fiff_int_t to,
116 const RowVectorXi& sel,
117 bool do_debug) const
118{
119 bool projAvailable = true;
120
121 if (this->proj.size() == 0) {
122 //qDebug() << "FiffRawData::read_raw_segment - No projectors setup. Consider calling MNE::setup_compensators.";
123 projAvailable = false;
124 }
125
126 if(from == -1)
127 from = this->first_samp;
128 if(to == -1)
129 to = this->last_samp;
130 //
131 // Initial checks
132 //
133 if(from < this->first_samp)
134 from = this->first_samp;
135 if(to > this->last_samp)
136 to = this->last_samp;
137 //
138 if(from > to)
139 {
140 qWarning("No data in this range %d ... %d = %9.3f ... %9.3f secs...", from, to, (static_cast<float>(from))/this->info.sfreq, (static_cast<float>(to))/this->info.sfreq);
141 return false;
142 }
143 //printf("Reading %d ... %d = %9.3f ... %9.3f secs...", from, to, (static_cast<float>(from))/this->info.sfreq, (static_cast<float>(to))/this->info.sfreq);
144 //
145 // Initialize the data and calibration vector
146 //
147 qint32 nchan = this->info.nchan;
148 qint32 dest = 0;//1;
149 qint32 i, k, r;
150
151 using T = Eigen::Triplet<double>;
152 std::vector<T> tripletList;
153 tripletList.reserve(nchan);
154 for(i = 0; i < nchan; ++i)
155 tripletList.push_back(T(i, i, this->cals[i]));
156
157 SparseMatrix<double> cal(nchan, nchan);
158 cal.setFromTriplets(tripletList.begin(), tripletList.end());
159// cal.makeCompressed();
160
161 MatrixXd mult_full;
162 //
163 if (sel.size() == 0)
164 {
165 data = MatrixXd(nchan, to-from+1);
166// data->setZero();
167 if (projAvailable || this->comp.kind != -1)
168 {
169 if (!projAvailable)
170 mult_full = this->comp.data->data*cal;
171 else if (this->comp.kind == -1)
172 mult_full = this->proj*cal;
173 else
174 mult_full = this->proj*this->comp.data->data*cal;
175 }
176 }
177 else
178 {
179 data = MatrixXd(sel.size(),to-from+1);
180// data->setZero();
181
182 MatrixXd selVect(sel.size(), nchan);
183
184 selVect.setZero();
185
186 if (!projAvailable && this->comp.kind == -1)
187 {
188 tripletList.clear();
189 tripletList.reserve(sel.size());
190 for(i = 0; i < sel.size(); ++i)
191 tripletList.push_back(T(i, i, this->cals[sel[i]]));
192 cal = SparseMatrix<double>(sel.size(), sel.size());
193 cal.setFromTriplets(tripletList.begin(), tripletList.end());
194 }
195 else
196 {
197 if (!projAvailable)
198 {
199 qDebug() << "This has to be debugged! #1";
200 for( i = 0; i < sel.size(); ++i)
201 selVect.row(i) = this->comp.data->data.block(sel[i],0,1,nchan);
202 mult_full = selVect*cal;
203 }
204 else if (this->comp.kind == -1)
205 {
206 for( i = 0; i < sel.size(); ++i)
207 selVect.row(i) = this->proj.block(sel[i],0,1,nchan);
208
209 mult_full = selVect*cal;
210 }
211 else
212 {
213 qDebug() << "This has to be debugged! #3";
214 for( i = 0; i < sel.size(); ++i)
215 selVect.row(i) = this->proj.block(sel[i],0,1,nchan);
216
217 mult_full = selVect*this->comp.data->data*cal;
218 }
219 }
220 }
221
222 //
223 // Make mult sparse
224 //
225 tripletList.clear();
226 tripletList.reserve(mult_full.rows()*mult_full.cols());
227 for(i = 0; i < mult_full.rows(); ++i)
228 for(k = 0; k < mult_full.cols(); ++k)
229 if(mult_full(i,k) != 0)
230 tripletList.push_back(T(i, k, mult_full(i,k)));
231
232 SparseMatrix<double> mult(mult_full.rows(),mult_full.cols());
233 if(tripletList.size() > 0)
234 mult.setFromTriplets(tripletList.begin(), tripletList.end());
235// mult.makeCompressed();
236
238 if (!this->file->device()->isOpen())
239 {
240 if (!this->file->device()->open(QIODevice::ReadOnly))
241 {
242 qWarning("Cannot open file %s",this->info.filename.toUtf8().constData());
243 }
244 fid = this->file;
245 }
246 else
247 {
248 fid = this->file;
249 }
250
251 MatrixXd one, newData, tmp_data;
252 FiffRawDir thisRawDir;
253 FiffTag::UPtr t_pTag;
254 fiff_int_t first_pick, last_pick, picksamp;
255 for(k = 0; k < this->rawdir.size(); ++k)
256 {
257 thisRawDir = this->rawdir[k];
258 //
259 // Do we need this buffer
260 //
261 if (thisRawDir.last > from)
262 {
263 if (thisRawDir.ent->kind == -1)
264 {
265 //
266 // Take the easy route: skip is translated to zeros
267 //
268 if(do_debug)
269 qDebug("S");
270 if (sel.cols() <= 0)
271 one.resize(nchan,thisRawDir.nsamp);
272 else
273 one.resize(sel.cols(),thisRawDir.nsamp);
274
275 one.setZero();
276 }
277 else
278 {
279 fid->read_tag(t_pTag, thisRawDir.ent->pos);
280 //
281 // Depending on the state of the projection and selection
282 // we proceed a little bit differently
283 //
284 if (mult.cols() == 0)
285 {
286 if (sel.cols() == 0)
287 {
288 if (t_pTag->type == FIFFT_DAU_PACK16)
289 one = cal*(Map< MatrixDau16 >( t_pTag->toDauPack16(),nchan, thisRawDir.nsamp)).cast<double>();
290 else if(t_pTag->type == FIFFT_INT)
291 one = cal*(Map< MatrixXi >( t_pTag->toInt(),nchan, thisRawDir.nsamp)).cast<double>();
292 else if(t_pTag->type == FIFFT_FLOAT)
293 one = cal*(Map<const MatrixXf>(t_pTag->toFloat(),nchan, thisRawDir.nsamp)).cast<double>();
294 else if(t_pTag->type == FIFFT_SHORT)
295 one = cal*(Map< MatrixShort >( t_pTag->toShort(),nchan, thisRawDir.nsamp)).cast<double>();
296 else
297 qWarning("Data Storage Format not known yet [1]!! Type: %d\n", t_pTag->type);
298 }
299 else
300 {
301 //ToDo find a faster solution for this!! --> make cal and mul sparse like in MATLAB
302 newData.resize(sel.cols(), thisRawDir.nsamp); //ToDo this can be done much faster, without newData
303
304 if (t_pTag->type == FIFFT_DAU_PACK16)
305 {
306 tmp_data = (Map< MatrixDau16 > ( t_pTag->toDauPack16(),nchan, thisRawDir.nsamp)).cast<double>();
307
308 for(r = 0; r < sel.size(); ++r)
309 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
310 }
311 else if(t_pTag->type == FIFFT_INT)
312 {
313 tmp_data = (Map< MatrixXi >( t_pTag->toInt(),nchan, thisRawDir.nsamp)).cast<double>();
314
315 for(r = 0; r < sel.size(); ++r)
316 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
317 }
318 else if(t_pTag->type == FIFFT_FLOAT)
319 {
320 tmp_data = (Map<const MatrixXf>(t_pTag->toFloat(),nchan, thisRawDir.nsamp)).cast<double>();
321
322 for(r = 0; r < sel.size(); ++r)
323 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
324 }
325 else if(t_pTag->type == FIFFT_SHORT)
326 {
327 tmp_data = (Map< MatrixShort > ( t_pTag->toShort(),nchan, thisRawDir.nsamp)).cast<double>();
328
329 for(r = 0; r < sel.size(); ++r)
330 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
331 }
332 else
333 {
334 qWarning("Data Storage Format not known yet [2]!! Type: %d\n", t_pTag->type);
335 }
336
337 one = cal*newData;
338 }
339 }
340 else
341 {
342 if (t_pTag->type == FIFFT_DAU_PACK16)
343 one = mult*(Map< MatrixDau16 >( t_pTag->toDauPack16(),nchan, thisRawDir.nsamp)).cast<double>();
344 else if(t_pTag->type == FIFFT_INT)
345 one = mult*(Map< MatrixXi >( t_pTag->toInt(),nchan, thisRawDir.nsamp)).cast<double>();
346 else if(t_pTag->type == FIFFT_FLOAT)
347 one = mult*(Map<const MatrixXf>(t_pTag->toFloat(),nchan, thisRawDir.nsamp)).cast<double>();
348 else
349 qWarning("Data Storage Format not known yet [3]!! Type: %d\n", t_pTag->type);
350 }
351 }
352 //
353 // The picking logic is a bit complicated
354 //
355 if (to >= thisRawDir.last && from <= thisRawDir.first)
356 {
357 //
358 // We need the whole buffer
359 //
360 first_pick = 0;//1;
361 last_pick = thisRawDir.nsamp - 1;
362 if (do_debug)
363 qDebug("W");
364 }
365 else if (from > thisRawDir.first)
366 {
367 first_pick = from - thisRawDir.first;// + 1;
368 if(to < thisRawDir.last)
369 {
370 //
371 // Something from the middle
372 //
373// qDebug() << "This needs to be debugged!";
374 last_pick = thisRawDir.nsamp + to - thisRawDir.last - 1;//is this alright?
375 if (do_debug)
376 qDebug("M");
377 }
378 else
379 {
380 //
381 // From the middle to the end
382 //
383 last_pick = thisRawDir.nsamp - 1;
384 if (do_debug)
385 qDebug("E");
386 }
387 }
388 else
389 {
390 //
391 // From the beginning to the middle
392 //
393 first_pick = 0;//1;
394 last_pick = to - thisRawDir.first;// + 1;
395 if (do_debug)
396 qDebug("B");
397 }
398 //
399 // Now we are ready to pick
400 //
401 picksamp = last_pick - first_pick + 1;
402
403 if(do_debug)
404 {
405 qDebug() << "first_pick: " << first_pick;
406 qDebug() << "last_pick: " << last_pick;
407 qDebug() << "picksamp: " << picksamp;
408 }
409
410 if (picksamp > 0)
411 {
412// for(r = 0; r < data->rows(); ++r)
413// for(c = 0; c < picksamp; ++c)
414// (*data)(r,dest + c) = one(r,first_pick + c);
415 data.block(0,dest,data.rows(),picksamp) = one.block(0, first_pick, data.rows(), picksamp);
416
417 dest += picksamp;
418 }
419 }
420 //
421 // Done?
422 //
423 if (thisRawDir.last >= to)
424 {
425 //printf(" [done]\n");
426 break;
427 }
428 }
429
430 if (!this->file->device()->isOpen()) {
431 this->file->device()->close();
432 }
433
434 times = MatrixXd(1, to-from+1);
435
436 for (i = 0; i < times.cols(); ++i)
437 times(0, i) = static_cast<float>(from+i) / this->info.sfreq;
438
439 return true;
440}
441
442//=============================================================================================================
443
444bool FiffRawData::read_raw_segment(MatrixXd& data,
445 MatrixXd& times,
446 SparseMatrix<double>& multSegment,
447 fiff_int_t from,
448 fiff_int_t to,
449 const RowVectorXi& sel,
450 bool do_debug) const
451{
452 bool projAvailable = true;
453
454 if (this->proj.size() == 0) {
455 //qInfo() << "FiffRawData::read_raw_segment - No projectors setup. Consider calling MNE::setup_compensators.";
456 projAvailable = false;
457 }
458
459 if(from == -1)
460 from = this->first_samp;
461 if(to == -1)
462 to = this->last_samp;
463 //
464 // Initial checks
465 //
466 if(from < this->first_samp)
467 from = this->first_samp;
468 if(to > this->last_samp)
469 to = this->last_samp;
470 //
471 if(from > to)
472 {
473 qWarning("No data in this range\n");
474 return false;
475 }
476 //printf("Reading %d ... %d = %9.3f ... %9.3f secs...", from, to, (static_cast<float>(from))/this->info.sfreq, (static_cast<float>(to))/this->info.sfreq);
477 //
478 // Initialize the data and calibration vector
479 //
480 qint32 nchan = this->info.nchan;
481 qint32 dest = 0;//1;
482 qint32 i, k, r;
483
484 using T = Eigen::Triplet<double>;
485 std::vector<T> tripletList;
486 tripletList.reserve(nchan);
487 for(i = 0; i < nchan; ++i)
488 tripletList.push_back(T(i, i, this->cals[i]));
489
490 SparseMatrix<double> cal(nchan, nchan);
491 cal.setFromTriplets(tripletList.begin(), tripletList.end());
492// cal.makeCompressed();
493
494 MatrixXd mult_full;
495 //
496 if (sel.size() == 0)
497 {
498 data = MatrixXd(nchan, to-from+1);
499// data->setZero();
500 if (projAvailable || this->comp.kind != -1)
501 {
502 if (!projAvailable)
503 mult_full = this->comp.data->data*cal;
504 else if (this->comp.kind == -1)
505 mult_full = this->proj*cal;
506 else
507 mult_full = this->proj*this->comp.data->data*cal;
508 }
509 }
510 else
511 {
512 data = MatrixXd(sel.size(),to-from+1);
513// data->setZero();
514
515 MatrixXd selVect(sel.size(), nchan);
516
517 selVect.setZero();
518
519 if (!projAvailable && this->comp.kind == -1)
520 {
521 tripletList.clear();
522 tripletList.reserve(sel.size());
523 for(i = 0; i < sel.size(); ++i)
524 tripletList.push_back(T(i, i, this->cals[sel[i]]));
525 cal = SparseMatrix<double>(sel.size(), sel.size());
526 cal.setFromTriplets(tripletList.begin(), tripletList.end());
527 }
528 else
529 {
530 if (!projAvailable)
531 {
532 qDebug() << "This has to be debugged! #1";
533 for( i = 0; i < sel.size(); ++i)
534 selVect.row(i) = this->comp.data->data.block(sel[i],0,1,nchan);
535 mult_full = selVect*cal;
536 }
537 else if (this->comp.kind == -1)
538 {
539 for( i = 0; i < sel.size(); ++i)
540 selVect.row(i) = this->proj.block(sel[i],0,1,nchan);
541
542 mult_full = selVect*cal;
543 }
544 else
545 {
546 qDebug() << "This has to be debugged! #3";
547 for( i = 0; i < sel.size(); ++i)
548 selVect.row(i) = this->proj.block(sel[i],0,1,nchan);
549
550 mult_full = selVect*this->comp.data->data*cal;
551 }
552 }
553 }
554
555 //
556 // Make mult sparse
557 //
558 tripletList.clear();
559 tripletList.reserve(mult_full.rows()*mult_full.cols());
560 for(i = 0; i < mult_full.rows(); ++i)
561 for(k = 0; k < mult_full.cols(); ++k)
562 if(mult_full(i,k) != 0)
563 tripletList.push_back(T(i, k, mult_full(i,k)));
564
565 SparseMatrix<double> mult(mult_full.rows(),mult_full.cols());
566 if(tripletList.size() > 0)
567 mult.setFromTriplets(tripletList.begin(), tripletList.end());
568// mult.makeCompressed();
569
570 //
571
573 if (!this->file->device()->isOpen())
574 {
575 if (!this->file->device()->open(QIODevice::ReadOnly))
576 {
577 qWarning("Cannot open file %s",this->info.filename.toUtf8().constData());
578 }
579 fid = this->file;
580 }
581 else
582 {
583 fid = this->file;
584 }
585
586 MatrixXd one;
587 fiff_int_t first_pick, last_pick, picksamp;
588 for(k = 0; k < this->rawdir.size(); ++k)
589 {
590 FiffRawDir thisRawDir = this->rawdir[k];
591 //
592 // Do we need this buffer
593 //
594 if (thisRawDir.last > from)
595 {
596 if (thisRawDir.ent->kind == -1)
597 {
598 //
599 // Take the easy route: skip is translated to zeros
600 //
601 if(do_debug)
602 qDebug("S");
603 if (sel.cols() <= 0)
604 one.resize(nchan,thisRawDir.nsamp);
605 else
606 one.resize(sel.cols(),thisRawDir.nsamp);
607
608 one.setZero();
609 }
610 else
611 {
612 FiffTag::UPtr t_pTag;
613 fid->read_tag(t_pTag, thisRawDir.ent->pos);
614 //
615 // Depending on the state of the projection and selection
616 // we proceed a little bit differently
617 //
618 if (mult.cols() == 0)
619 {
620 if (sel.cols() == 0)
621 {
622 if (t_pTag->type == FIFFT_DAU_PACK16)
623 one = cal*(Map< MatrixDau16 >( t_pTag->toDauPack16(),nchan, thisRawDir.nsamp)).cast<double>();
624 else if(t_pTag->type == FIFFT_INT)
625 one = cal*(Map< MatrixXi >( t_pTag->toInt(),nchan, thisRawDir.nsamp)).cast<double>();
626 else if(t_pTag->type == FIFFT_FLOAT)
627 one = cal*(Map<const MatrixXf>(t_pTag->toFloat(),nchan, thisRawDir.nsamp)).cast<double>();
628 else if(t_pTag->type == FIFFT_SHORT)
629 one = cal*(Map< MatrixShort >( t_pTag->toShort(),nchan, thisRawDir.nsamp)).cast<double>();
630 else
631 qWarning("Data Storage Format not known yet [1]!! Type: %d\n", t_pTag->type);
632 }
633 else
634 {
635
636 //ToDo find a faster solution for this!! --> make cal and mul sparse like in MATLAB
637 MatrixXd newData(sel.cols(), thisRawDir.nsamp); //ToDo this can be done much faster, without newData
638
639 if (t_pTag->type == FIFFT_DAU_PACK16)
640 {
641 MatrixXd tmp_data = (Map< MatrixDau16 > ( t_pTag->toDauPack16(),nchan, thisRawDir.nsamp)).cast<double>();
642
643 for(r = 0; r < sel.size(); ++r)
644 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
645 }
646 else if(t_pTag->type == FIFFT_INT)
647 {
648 MatrixXd tmp_data = (Map< MatrixXi >( t_pTag->toInt(),nchan, thisRawDir.nsamp)).cast<double>();
649
650 for(r = 0; r < sel.size(); ++r)
651 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
652 }
653 else if(t_pTag->type == FIFFT_FLOAT)
654 {
655 MatrixXd tmp_data = (Map<const MatrixXf>(t_pTag->toFloat(),nchan, thisRawDir.nsamp)).cast<double>();
656
657 for(r = 0; r < sel.size(); ++r)
658 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
659 }
660 else if(t_pTag->type == FIFFT_SHORT)
661 {
662 MatrixXd tmp_data = (Map< MatrixShort > ( t_pTag->toShort(),nchan, thisRawDir.nsamp)).cast<double>();
663
664 for(r = 0; r < sel.size(); ++r)
665 newData.block(r,0,1,thisRawDir.nsamp) = tmp_data.block(sel[r],0,1,thisRawDir.nsamp);
666 }
667 else
668 {
669 qWarning("Data Storage Format not known yet [2]!! Type: %d\n", t_pTag->type);
670 }
671
672 one = cal*newData;
673 }
674 }
675 else
676 {
677 if (t_pTag->type == FIFFT_DAU_PACK16)
678 one = mult*(Map< MatrixDau16 >( t_pTag->toDauPack16(),nchan, thisRawDir.nsamp)).cast<double>();
679 else if(t_pTag->type == FIFFT_INT)
680 one = mult*(Map< MatrixXi >( t_pTag->toInt(),nchan, thisRawDir.nsamp)).cast<double>();
681 else if(t_pTag->type == FIFFT_FLOAT)
682 one = mult*(Map<const MatrixXf>(t_pTag->toFloat(),nchan, thisRawDir.nsamp)).cast<double>();
683 else
684 qWarning("Data Storage Format not known yet [3]!! Type: %d\n", t_pTag->type);
685 }
686 }
687 //
688 // The picking logic is a bit complicated
689 //
690 if (to >= thisRawDir.last && from <= thisRawDir.first)
691 {
692 //
693 // We need the whole buffer
694 //
695 first_pick = 0;//1;
696 last_pick = thisRawDir.nsamp - 1;
697 if (do_debug)
698 qDebug("W");
699 }
700 else if (from > thisRawDir.first)
701 {
702 first_pick = from - thisRawDir.first;// + 1;
703 if(to < thisRawDir.last)
704 {
705 //
706 // Something from the middle
707 //
708// qDebug() << "This needs to be debugged!";
709 last_pick = thisRawDir.nsamp + to - thisRawDir.last - 1;//is this alright?
710 if (do_debug)
711 qDebug("M");
712 }
713 else
714 {
715 //
716 // From the middle to the end
717 //
718 last_pick = thisRawDir.nsamp - 1;
719 if (do_debug)
720 qDebug("E");
721 }
722 }
723 else
724 {
725 //
726 // From the beginning to the middle
727 //
728 first_pick = 0;//1;
729 last_pick = to - thisRawDir.first;// + 1;
730 if (do_debug)
731 qDebug("B");
732 }
733 //
734 // Now we are ready to pick
735 //
736 picksamp = last_pick - first_pick + 1;
737
738 if(do_debug)
739 {
740 qDebug() << "first_pick: " << first_pick;
741 qDebug() << "last_pick: " << last_pick;
742 qDebug() << "picksamp: " << picksamp;
743 }
744
745 if (picksamp > 0)
746 {
747// for(r = 0; r < data->rows(); ++r)
748// for(c = 0; c < picksamp; ++c)
749// (*data)(r,dest + c) = one(r,first_pick + c);
750 data.block(0,dest,data.rows(),picksamp) = one.block(0, first_pick, data.rows(), picksamp);
751
752 dest += picksamp;
753 }
754 }
755 //
756 // Done?
757 //
758 if (thisRawDir.last >= to)
759 {
760 //printf(" [done]\n");
761 break;
762 }
763 }
764
765 if(mult.cols()==0)
766 multSegment = cal;
767 else
768 multSegment = mult;
769
770 if (!this->file->device()->isOpen()) {
771 this->file->device()->close();
772 }
773
774 times = MatrixXd(1, to-from+1);
775
776 for (i = 0; i < times.cols(); ++i)
777 times(0, i) = static_cast<float>(from+i) / this->info.sfreq;
778
779 return true;
780}
781
782//=============================================================================================================
783
785 MatrixXd& times,
786 float from,
787 float to,
788 const RowVectorXi& sel) const
789{
790 //
791 // Convert to samples
792 //
793 from = floor(static_cast<double>(from)*this->info.sfreq);
794 to = ceil(static_cast<double>(to)*this->info.sfreq);
795 //
796 // Read it
797 //
798 return this->read_raw_segment(data, times, (qint32)from, (qint32)to, sel);
799}
800
801//=============================================================================================================
802
803bool FiffRawData::save(QIODevice &p_IODevice,
804 const RowVectorXi &picks,
805 int decim,
806 int from,
807 int to) const
808{
809 if (decim < 1) decim = 1;
810
811 int firstSamp = (from >= 0) ? from : first_samp;
812 int lastSamp = (to >= 0) ? to : last_samp;
813
814 if (firstSamp > lastSamp) {
815 qWarning() << "[FiffRawData::save] Invalid sample range.";
816 return false;
817 }
818
819 // Prepare output info
820 FiffInfo outInfo;
821 if (picks.size() > 0) {
822 outInfo = info.pick_info(picks);
823 } else {
824 outInfo = info;
825 }
826
827 // Adjust sampling frequency for decimation
828 if (decim > 1) {
829 outInfo.sfreq = info.sfreq / static_cast<float>(decim);
830 }
831
832 // Use the standard start_writing_raw pipeline
833 RowVectorXd calsOut;
834 FiffStream::SPtr pStream = FiffStream::start_writing_raw(p_IODevice, outInfo, calsOut, picks);
835 if (!pStream) {
836 qWarning() << "[FiffRawData::save] Cannot start writing raw file.";
837 return false;
838 }
839
840 // Write data in blocks
841 const int blockSize = 2000;
842 int blockSamples = decim * blockSize;
843
844 for (int samp = firstSamp; samp <= lastSamp; samp += blockSamples) {
845 int nsamp = qMin(blockSamples, lastSamp - samp + 1);
846
847 MatrixXd segData;
848 MatrixXd segTimes;
849 if (!read_raw_segment(segData, segTimes, samp, samp + nsamp - 1, picks)) {
850 qWarning() << "[FiffRawData::save] Error reading data at sample" << samp;
851 pStream->finish_writing_raw();
852 return false;
853 }
854
855 // Decimate if needed
856 if (decim > 1) {
857 int nOut = (nsamp + decim - 1) / decim;
858 MatrixXd decimData(segData.rows(), nOut);
859 for (int s = 0, idx = 0; s < nsamp && idx < nOut; s += decim, ++idx) {
860 decimData.col(idx) = segData.col(s);
861 }
862 segData = decimData;
863 }
864
865 pStream->write_raw_buffer(segData, calsOut);
866 }
867
868 pStream->finish_writing_raw();
869
870 qInfo() << "[FiffRawData::save] Saved raw data from sample" << firstSamp
871 << "to" << lastSamp << "(decim=" << decim << ")";
872 return true;
873}
FIFF continuous raw recording: FiffInfo plus a directory of FIFF_DATA_BUFFER tags for random-access s...
Stim-channel event list (sample, previous value, new value triples) with FIFF read/write helpers.
#define FIFFT_INT
Definition fiff_file.h:224
#define FIFFT_SHORT
Definition fiff_file.h:223
#define FIFFT_DAU_PACK16
Definition fiff_file.h:236
#define FIFFT_FLOAT
Definition fiff_file.h:225
FIFF tag: the 16-byte tag header (kind, type, size, next) plus its decoded payload.
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.
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Definition fiff_info.h:88
FiffCtfComp comp
bool save(QIODevice &p_IODevice, const Eigen::RowVectorXi &picks=Eigen::RowVectorXi(), int decim=1, int from=-1, int to=-1) const
fiff_int_t first_samp
bool read_raw_segment_times(Eigen::MatrixXd &data, Eigen::MatrixXd &times, float from, float to, const Eigen::RowVectorXi &sel=defaultRowVectorXi) const
Eigen::RowVectorXd cals
fiff_int_t last_samp
Eigen::MatrixXd proj
FiffInfo info
FiffStream::SPtr file
bool read_raw_segment(Eigen::MatrixXd &data, Eigen::MatrixXd &times, fiff_int_t from=-1, fiff_int_t to=-1, const Eigen::RowVectorXi &sel=defaultRowVectorXi, bool do_debug=false) const
QList< FiffRawDir > rawdir
FiffDirEntry::SPtr ent
QSharedPointer< FiffStream > SPtr
static bool setup_read_raw(QIODevice &p_IODevice, FiffRawData &data, bool allow_maxshield=true, bool is_littleEndian=false)
static FiffStream::SPtr start_writing_raw(QIODevice &p_IODevice, const FiffInfo &info, Eigen::RowVectorXd &cals, Eigen::MatrixXi sel=defaultMatrixXi, bool bResetRange=true)
std::unique_ptr< FiffTag > UPtr
Definition fiff_tag.h:164