58 throw std::runtime_error(
"Error during fiff setup raw read");
70 throw std::runtime_error(
"Error during fiff setup raw read");
101 cals = RowVectorXd();
108#include <QElapsedTimer>
114 const RowVectorXi& sel,
117 bool projAvailable =
true;
119 if (this->
proj.size() == 0) {
121 projAvailable =
false;
132 from = this->first_samp;
137 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);
143 qint32 nchan = this->
info.nchan;
147 using T = Eigen::Triplet<double>;
148 std::vector<T> tripletList;
149 tripletList.reserve(nchan);
150 for (i = 0; i < nchan; ++i)
151 tripletList.push_back(T(i, i, this->
cals[i]));
153 SparseMatrix<double> cal(nchan, nchan);
154 cal.setFromTriplets(tripletList.begin(), tripletList.end());
159 if (sel.size() == 0) {
160 data = MatrixXd(nchan, to - from + 1);
162 if (projAvailable || this->
comp.kind != -1) {
164 mult_full = this->
comp.data->data * cal;
165 else if (this->
comp.kind == -1)
166 mult_full = this->
proj * cal;
168 mult_full = this->
proj * this->
comp.data->data * cal;
171 data = MatrixXd(sel.size(), to - from + 1);
174 MatrixXd selVect(sel.size(), nchan);
178 if (!projAvailable && this->
comp.kind == -1) {
180 tripletList.reserve(sel.size());
181 for (i = 0; i < sel.size(); ++i)
182 tripletList.push_back(T(i, i, this->
cals[sel[i]]));
183 cal = SparseMatrix<double>(sel.size(), sel.size());
184 cal.setFromTriplets(tripletList.begin(), tripletList.end());
186 if (!projAvailable) {
187 for (i = 0; i < sel.size(); ++i)
188 selVect.row(i) = this->
comp.data->data.block(sel[i], 0, 1, nchan);
189 mult_full = selVect * cal;
190 }
else if (this->
comp.kind == -1) {
191 for (i = 0; i < sel.size(); ++i)
192 selVect.row(i) = this->
proj.block(sel[i], 0, 1, nchan);
194 mult_full = selVect * cal;
196 for (i = 0; i < sel.size(); ++i)
197 selVect.row(i) = this->
proj.block(sel[i], 0, 1, nchan);
199 mult_full = selVect * this->
comp.data->data * cal;
208 tripletList.reserve(mult_full.rows() * mult_full.cols());
209 for (i = 0; i < mult_full.rows(); ++i)
210 for (k = 0; k < mult_full.cols(); ++k)
211 if (mult_full(i, k) != 0)
212 tripletList.push_back(T(i, k, mult_full(i, k)));
214 SparseMatrix<double> mult(mult_full.rows(), mult_full.cols());
215 if (tripletList.size() > 0)
216 mult.setFromTriplets(tripletList.begin(), tripletList.end());
220 if (!this->
file->device()->isOpen()) {
221 if (!this->
file->device()->open(QIODevice::ReadOnly)) {
222 qWarning(
"Cannot open file %s", this->
info.filename.toUtf8().constData());
229 MatrixXd one, newData, tmp_data;
230 FiffRawDir thisRawDir;
233 for (k = 0; k < this->
rawdir.size(); ++k) {
234 thisRawDir = this->
rawdir[k];
238 if (thisRawDir.
last > from) {
239 if (thisRawDir.
ent->kind == -1) {
246 one.resize(nchan, thisRawDir.
nsamp);
248 one.resize(sel.cols(), thisRawDir.
nsamp);
252 fid->read_tag(t_pTag, thisRawDir.
ent->pos);
257 if (mult.cols() == 0) {
258 if (sel.cols() == 0) {
260 one = cal * (Map<const MatrixDau16>(t_pTag->toDauPack16(), nchan, thisRawDir.
nsamp)).cast<double>();
262 one = cal * (Map<const MatrixXi>(t_pTag->toInt(), nchan, thisRawDir.
nsamp)).cast<double>();
264 one = cal * (Map<const MatrixXf>(t_pTag->toFloat(), nchan, thisRawDir.
nsamp)).cast<double>();
266 one = cal * (Map<const MatrixShort>(t_pTag->toShort(), nchan, thisRawDir.
nsamp)).cast<double>();
268 one = cal * Map<const MatrixXd>(t_pTag->toDouble(), nchan, thisRawDir.
nsamp);
270 qWarning(
"Data Storage Format not known yet [1]!! Type: %d\n", t_pTag->type);
271 this->
file->device()->close();
276 newData.resize(sel.cols(), thisRawDir.
nsamp);
279 tmp_data = (Map<const MatrixDau16>(t_pTag->toDauPack16(), nchan, thisRawDir.
nsamp)).cast<double>();
281 for (r = 0; r < sel.size(); ++r)
282 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
284 tmp_data = (Map<const MatrixXi>(t_pTag->toInt(), nchan, thisRawDir.
nsamp)).cast<double>();
286 for (r = 0; r < sel.size(); ++r)
287 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
289 tmp_data = (Map<const MatrixXf>(t_pTag->toFloat(), nchan, thisRawDir.
nsamp)).cast<double>();
291 for (r = 0; r < sel.size(); ++r)
292 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
294 tmp_data = (Map<const MatrixShort>(t_pTag->toShort(), nchan, thisRawDir.
nsamp)).cast<double>();
296 for (r = 0; r < sel.size(); ++r)
297 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
299 tmp_data = Map<const MatrixXd>(t_pTag->toDouble(), nchan, thisRawDir.
nsamp);
301 for (r = 0; r < sel.size(); ++r)
302 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
304 qWarning(
"Data Storage Format not known yet [2]!! Type: %d\n", t_pTag->type);
305 this->
file->device()->close();
313 one = mult * (Map<const MatrixDau16>(t_pTag->toDauPack16(), nchan, thisRawDir.
nsamp)).cast<double>();
315 one = mult * (Map<const MatrixXi>(t_pTag->toInt(), nchan, thisRawDir.
nsamp)).cast<double>();
317 one = mult * (Map<const MatrixXf>(t_pTag->toFloat(), nchan, thisRawDir.
nsamp)).cast<double>();
319 one = mult * (Map<const MatrixShort>(t_pTag->toShort(), nchan, thisRawDir.
nsamp)).cast<double>();
321 one = mult * Map<const MatrixXd>(t_pTag->toDouble(), nchan, thisRawDir.
nsamp);
323 qWarning(
"Data Storage Format not known yet [3]!! Type: %d\n", t_pTag->type);
324 this->
file->device()->close();
332 if (to >= thisRawDir.
last && from <= thisRawDir.
first) {
337 last_pick = thisRawDir.
nsamp - 1;
340 }
else if (from > thisRawDir.
first) {
341 first_pick = from - thisRawDir.
first;
342 if (to < thisRawDir.
last) {
347 last_pick = thisRawDir.
nsamp + to - thisRawDir.
last - 1;
354 last_pick = thisRawDir.
nsamp - 1;
363 last_pick = to - thisRawDir.
first;
370 picksamp = last_pick - first_pick + 1;
373 qDebug() <<
"first_pick: " << first_pick;
374 qDebug() <<
"last_pick: " << last_pick;
375 qDebug() <<
"picksamp: " << picksamp;
382 data.block(0, dest, data.rows(), picksamp) = one.block(0, first_pick, data.rows(), picksamp);
390 if (thisRawDir.
last >= to) {
396 if (!this->
file->device()->isOpen()) {
397 this->
file->device()->close();
400 times = MatrixXd(1, to - from + 1);
402 for (i = 0; i < times.cols(); ++i)
403 times(0, i) =
static_cast<float>(from + i) / this->
info.sfreq;
412 SparseMatrix<double>& multSegment,
415 const RowVectorXi& sel,
418 bool projAvailable =
true;
420 if (this->
proj.size() == 0) {
422 projAvailable =
false;
438 qWarning(
"No data in this range");
444 qint32 nchan = this->
info.nchan;
448 using T = Eigen::Triplet<double>;
449 std::vector<T> tripletList;
450 tripletList.reserve(nchan);
451 for (i = 0; i < nchan; ++i)
452 tripletList.push_back(T(i, i, this->
cals[i]));
454 SparseMatrix<double> cal(nchan, nchan);
455 cal.setFromTriplets(tripletList.begin(), tripletList.end());
460 if (sel.size() == 0) {
461 data = MatrixXd(nchan, to - from + 1);
463 if (projAvailable || this->
comp.kind != -1) {
465 mult_full = this->
comp.data->data * cal;
466 else if (this->
comp.kind == -1)
467 mult_full = this->
proj * cal;
469 mult_full = this->
proj * this->
comp.data->data * cal;
472 data = MatrixXd(sel.size(), to - from + 1);
475 MatrixXd selVect(sel.size(), nchan);
479 if (!projAvailable && this->
comp.kind == -1) {
481 tripletList.reserve(sel.size());
482 for (i = 0; i < sel.size(); ++i)
483 tripletList.push_back(T(i, i, this->
cals[sel[i]]));
484 cal = SparseMatrix<double>(sel.size(), sel.size());
485 cal.setFromTriplets(tripletList.begin(), tripletList.end());
487 if (!projAvailable) {
488 for (i = 0; i < sel.size(); ++i)
489 selVect.row(i) = this->
comp.data->data.block(sel[i], 0, 1, nchan);
490 mult_full = selVect * cal;
491 }
else if (this->
comp.kind == -1) {
492 for (i = 0; i < sel.size(); ++i)
493 selVect.row(i) = this->
proj.block(sel[i], 0, 1, nchan);
495 mult_full = selVect * cal;
497 for (i = 0; i < sel.size(); ++i)
498 selVect.row(i) = this->
proj.block(sel[i], 0, 1, nchan);
500 mult_full = selVect * this->
comp.data->data * cal;
509 tripletList.reserve(mult_full.rows() * mult_full.cols());
510 for (i = 0; i < mult_full.rows(); ++i)
511 for (k = 0; k < mult_full.cols(); ++k)
512 if (mult_full(i, k) != 0)
513 tripletList.push_back(T(i, k, mult_full(i, k)));
515 SparseMatrix<double> mult(mult_full.rows(), mult_full.cols());
516 if (tripletList.size() > 0)
517 mult.setFromTriplets(tripletList.begin(), tripletList.end());
523 if (!this->
file->device()->isOpen()) {
524 if (!this->
file->device()->open(QIODevice::ReadOnly)) {
525 qWarning(
"Cannot open file %s", this->
info.filename.toUtf8().constData());
534 for (k = 0; k < this->
rawdir.size(); ++k) {
535 FiffRawDir thisRawDir = this->
rawdir[k];
539 if (thisRawDir.
last > from) {
540 if (thisRawDir.
ent->kind == -1) {
547 one.resize(nchan, thisRawDir.
nsamp);
549 one.resize(sel.cols(), thisRawDir.
nsamp);
554 fid->read_tag(t_pTag, thisRawDir.
ent->pos);
559 if (mult.cols() == 0) {
560 if (sel.cols() == 0) {
562 one = cal * (Map<const MatrixDau16>(t_pTag->toDauPack16(), nchan, thisRawDir.
nsamp)).cast<double>();
564 one = cal * (Map<const MatrixXi>(t_pTag->toInt(), nchan, thisRawDir.
nsamp)).cast<double>();
566 one = cal * (Map<const MatrixXf>(t_pTag->toFloat(), nchan, thisRawDir.
nsamp)).cast<double>();
568 one = cal * (Map<const MatrixShort>(t_pTag->toShort(), nchan, thisRawDir.
nsamp)).cast<double>();
570 one = cal * Map<const MatrixXd>(t_pTag->toDouble(), nchan, thisRawDir.
nsamp);
572 qWarning(
"Data Storage Format not known yet [1]!! Type: %d\n", t_pTag->type);
573 this->
file->device()->close();
578 MatrixXd newData(sel.cols(), thisRawDir.
nsamp);
581 MatrixXd tmp_data = (Map<const MatrixDau16>(t_pTag->toDauPack16(), nchan, thisRawDir.
nsamp)).cast<double>();
583 for (r = 0; r < sel.size(); ++r)
584 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
586 MatrixXd tmp_data = (Map<const MatrixXi>(t_pTag->toInt(), nchan, thisRawDir.
nsamp)).cast<double>();
588 for (r = 0; r < sel.size(); ++r)
589 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
591 MatrixXd tmp_data = (Map<const MatrixXf>(t_pTag->toFloat(), nchan, thisRawDir.
nsamp)).cast<double>();
593 for (r = 0; r < sel.size(); ++r)
594 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
596 MatrixXd tmp_data = (Map<const MatrixShort>(t_pTag->toShort(), nchan, thisRawDir.
nsamp)).cast<double>();
598 for (r = 0; r < sel.size(); ++r)
599 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
601 MatrixXd tmp_data = Map<const MatrixXd>(t_pTag->toDouble(), nchan, thisRawDir.
nsamp);
603 for (r = 0; r < sel.size(); ++r)
604 newData.block(r, 0, 1, thisRawDir.
nsamp) = tmp_data.block(sel[r], 0, 1, thisRawDir.
nsamp);
606 qWarning(
"Data Storage Format not known yet [2]!! Type: %d\n", t_pTag->type);
607 this->
file->device()->close();
615 one = mult * (Map<const MatrixDau16>(t_pTag->toDauPack16(), nchan, thisRawDir.
nsamp)).cast<double>();
617 one = mult * (Map<const MatrixXi>(t_pTag->toInt(), nchan, thisRawDir.
nsamp)).cast<double>();
619 one = mult * (Map<const MatrixXf>(t_pTag->toFloat(), nchan, thisRawDir.
nsamp)).cast<double>();
621 one = mult * (Map<const MatrixShort>(t_pTag->toShort(), nchan, thisRawDir.
nsamp)).cast<double>();
623 one = mult * Map<const MatrixXd>(t_pTag->toDouble(), nchan, thisRawDir.
nsamp);
625 qWarning(
"Data Storage Format not known yet [3]!! Type: %d\n", t_pTag->type);
626 this->
file->device()->close();
634 if (to >= thisRawDir.
last && from <= thisRawDir.
first) {
639 last_pick = thisRawDir.
nsamp - 1;
642 }
else if (from > thisRawDir.
first) {
643 first_pick = from - thisRawDir.
first;
644 if (to < thisRawDir.
last) {
649 last_pick = thisRawDir.
nsamp + to - thisRawDir.
last - 1;
656 last_pick = thisRawDir.
nsamp - 1;
665 last_pick = to - thisRawDir.
first;
672 picksamp = last_pick - first_pick + 1;
675 qDebug() <<
"first_pick: " << first_pick;
676 qDebug() <<
"last_pick: " << last_pick;
677 qDebug() <<
"picksamp: " << picksamp;
684 data.block(0, dest, data.rows(), picksamp) = one.block(0, first_pick, data.rows(), picksamp);
692 if (thisRawDir.
last >= to) {
698 if (mult.cols() == 0)
703 if (!this->
file->device()->isOpen()) {
704 this->
file->device()->close();
707 times = MatrixXd(1, to - from + 1);
709 for (i = 0; i < times.cols(); ++i)
710 times(0, i) =
static_cast<float>(from + i) / this->
info.sfreq;
721 const RowVectorXi& sel)
const
726 from = floor(
static_cast<double>(from) * this->
info.sfreq);
727 to = ceil(
static_cast<double>(to) * this->
info.sfreq);
731 return this->
read_raw_segment(data, times,
static_cast<qint32
>(from),
static_cast<qint32
>(to), sel);
737 const RowVectorXi& picks,
745 int firstSamp = (from >= 0) ? from :
first_samp;
746 int lastSamp = (to >= 0) ? to :
last_samp;
748 if (firstSamp > lastSamp) {
749 qWarning() <<
"[FiffRawData::save] Invalid sample range.";
758 outInfo.
sfreq =
info.sfreq /
static_cast<float>(decim);
765 qWarning() <<
"[FiffRawData::save] Cannot start writing raw file.";
770 int firstOut = firstSamp / decim;
774 const int blockSize = 2000;
775 int blockSamples = decim * blockSize;
777 for (
int samp = firstSamp; samp <= lastSamp; samp += blockSamples) {
778 int nsamp = qMin(blockSamples, lastSamp - samp + 1);
783 qWarning() <<
"[FiffRawData::save] Error reading data at sample" << samp;
784 pStream->finish_writing_raw();
790 int nOut = (nsamp + decim - 1) / decim;
791 MatrixXd decimData(segData.rows(), nOut);
792 for (
int s = 0, idx = 0; s < nsamp && idx < nOut; s += decim, ++idx) {
793 decimData.col(idx) = segData.col(s);
798 pStream->write_raw_buffer(segData, calsOut);
801 pStream->finish_writing_raw();
803 qInfo() <<
"[FiffRawData::save] Saved raw data from sample" << firstSamp
804 <<
"to" << lastSamp <<
"(decim=" << decim <<
")";
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,...
constexpr auto FIFFT_DOUBLE
constexpr auto FIFFT_DAU_PACK16
constexpr auto FIFF_FIRST_SAMPLE
constexpr auto FIFFT_SHORT
constexpr auto FIFFT_FLOAT
Stim-channel event list (sample, previous value, new value triples) with FIFF read/write helpers.
FIFF continuous raw recording: FiffInfo plus a directory of FIFF_DATA_BUFFER tags for random-access s...
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,...
bool read_raw_segment(Eigen::MatrixXd &data, Eigen::MatrixXd ×, fiff_int_t from=-1, fiff_int_t to=-1, const Eigen::RowVectorXi &sel=defaultRowVectorXi, bool do_debug=false) const
bool save(QIODevice &p_IODevice, const Eigen::RowVectorXi &picks=Eigen::RowVectorXi(), int decim=1, int from=-1, int to=-1) const
bool read_raw_segment_times(Eigen::MatrixXd &data, Eigen::MatrixXd ×, float from, float to, const Eigen::RowVectorXi &sel=defaultRowVectorXi) const
QList< FiffRawDir > rawdir
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