Exemple #1
0
void UI_ECGExport::Export_RR_intervals()
{
  int i,
      len,
      signal_nr,
      type=-1,
      beat_cnt,
      samples_cnt,
      progress_steps,
      datarecords,
      whole_recording=0,
      import_as_annots=0,
      filenum=0;

  char path[MAX_PATH_LENGTH],
       str[2048];

  double *beat_interval_list,
         *buf;

  long long *beat_onset_list,
            datrecs,
            smpls_left,
            l_time=0LL;

  struct signalcompblock *signalcomp;


  FILE *outputfile;

  QList<QListWidgetItem *> selectedlist;

  struct annotationblock *annotation;


  selectedlist = list->selectedItems();

  if(selectedlist.size() < 1)
  {
    QMessageBox messagewindow(QMessageBox::Critical, "Error", "Select a signal first.");
    messagewindow.exec();
    return;
  }

  signal_nr = selectedlist.at(0)->data(Qt::UserRole).toInt();

  if((signal_nr < 0) || (signal_nr >= mainwindow->signalcomps))
  {
    QMessageBox messagewindow(QMessageBox::Critical, "Error", "Invalid signalcomp number");
    messagewindow.exec();
    return;
  }

  signalcomp = mainwindow->signalcomp[signal_nr];

  if(signalcomp->ecg_filter == NULL)
  {
    QMessageBox messagewindow(QMessageBox::Critical, "Error", "Heart Rate detection is not activated for the selected signal.");
    messagewindow.exec();
    return;
  }

  if(checkBox2->checkState() == Qt::Checked)
  {
    import_as_annots = 1;
  }

  if(checkBox1->checkState() == Qt::Checked)
  {
    whole_recording = 1;

    class FilteredBlockReadClass blockrd;

    buf = blockrd.init_signalcomp(signalcomp, 1, 0);
    if(buf == NULL)
    {
      QMessageBox messagewindow(QMessageBox::Critical, "Error", "Error, can not initialize FilteredBlockReadClass.");
      messagewindow.exec();
      return;
    }

    samples_cnt = blockrd.samples_in_buf();
    if(samples_cnt < 1)
    {
      QMessageBox messagewindow(QMessageBox::Critical, "Error", "Error, samples_cnt is < 1.");
      messagewindow.exec();
      return;
    }

    filenum = signalcomp->filenum;

    reset_ecg_filter(signalcomp->ecg_filter);

    datarecords = signalcomp->edfhdr->datarecords;

    QProgressDialog progress("Processing file...", "Abort", 0, datarecords);
    progress.setWindowModality(Qt::WindowModal);
    progress.setMinimumDuration(200);

    progress_steps = datarecords / 100;
    if(progress_steps < 1)
    {
      progress_steps = 1;
    }

    for(i=0; i<signalcomp->edfhdr->datarecords; i++)
    {
      if(!(i%progress_steps))
      {
        progress.setValue(i);

        qApp->processEvents();

        if(progress.wasCanceled() == TRUE)
        {
          return;
        }
      }

      if(blockrd.process_signalcomp(i) != 0)
      {
        progress.reset();
        QMessageBox messagewindow(QMessageBox::Critical, "Error", "Error while reading file.");
        messagewindow.exec();
        return;
      }
    }

    progress.reset();
  }

  beat_cnt = ecg_filter_get_beat_cnt(signalcomp->ecg_filter);

  beat_onset_list = ecg_filter_get_onset_beatlist(signalcomp->ecg_filter);

  beat_interval_list = ecg_filter_get_interval_beatlist(signalcomp->ecg_filter);

  if(beat_cnt < 4)
  {
    QMessageBox messagewindow(QMessageBox::Critical, "Error", "Error, not enough beats.");
    messagewindow.exec();
    return;
  }

  if(import_as_annots)
  {
    for(i=0; i<beat_cnt; i++)
    {
      if(whole_recording)
      {
        l_time = 0LL;
      }
      else
      {
        l_time = signalcomp->edfhdr->viewtime;
      }

      if(l_time < 0LL)
      {
        l_time = 0LL;
      }

      datrecs = beat_onset_list[i] / signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].smp_per_record;

      smpls_left = beat_onset_list[i] % signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].smp_per_record;

      l_time += (datrecs * signalcomp->edfhdr->long_data_record_duration);

      l_time += ((smpls_left * signalcomp->edfhdr->long_data_record_duration) / signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].smp_per_record);

      if(!whole_recording)
      {
        l_time += (mainwindow->edfheaderlist[mainwindow->sel_viewtime]->viewtime - signalcomp->edfhdr->viewtime);
      }

      annotation = (struct annotationblock *)calloc(1, sizeof(struct annotationblock));
      if(annotation == NULL)
      {
        QMessageBox messagewindow(QMessageBox::Critical, "Error", "A memory allocation error occurred (annotation).");
        messagewindow.exec();
        return;
      }
      annotation->onset = l_time;
      strncpy(annotation->annotation, "R-onset", MAX_ANNOTATION_LEN);
      annotation->annotation[MAX_ANNOTATION_LEN] = 0;
      edfplus_annotation_add_item(&mainwindow->annotationlist[filenum], annotation);
    }

    if(mainwindow->annotations_dock[signalcomp->filenum] == NULL)
    {
      mainwindow->annotations_dock[filenum] = new UI_Annotationswindow(filenum, mainwindow);

      mainwindow->addDockWidget(Qt::RightDockWidgetArea, mainwindow->annotations_dock[filenum]->docklist, Qt::Vertical);

      if(!mainwindow->annotationlist[filenum])
      {
        mainwindow->annotations_dock[filenum]->docklist->hide();
      }
    }

    if(mainwindow->annotationlist[filenum])
    {
      mainwindow->annotations_dock[filenum]->docklist->show();

      mainwindow->annotations_edited = 1;

      mainwindow->annotations_dock[filenum]->updateList();

      mainwindow->save_act->setEnabled(TRUE);
    }
  }
  else
  {
    path[0] = 0;
    if(mainwindow->recent_savedir[0]!=0)
    {
      strcpy(path, mainwindow->recent_savedir);
      strcat(path, "/");
    }
    len = strlen(path);
    get_filename_from_path(path + len, signalcomp->edfhdr->filename, MAX_PATH_LENGTH - len);
    remove_extension_from_filename(path);
    strcat(path, "_RR_interval.txt");

    strcpy(path, QFileDialog::getSaveFileName(0, "Export RR-interval to ASCII", QString::fromLocal8Bit(path), "Text files (*.txt *.TXT)").toLocal8Bit().data());

    if(!strcmp(path, ""))
    {
      return;
    }

    get_directory_from_path(mainwindow->recent_savedir, path, MAX_PATH_LENGTH);

    outputfile = fopeno(path, "wb");
    if(outputfile==NULL)
    {
      QMessageBox messagewindow(QMessageBox::Critical, "Error", "Error, can not open outputfile for writing.");
      messagewindow.exec();
      return;
    }

    if(radioButton1->isChecked() == TRUE)
    {
      type = 1;
    }

    if(radioButton2->isChecked() == TRUE)
    {
      type = 2;
    }

    if(radioButton3->isChecked() == TRUE)
    {
      type = 3;
    }

    if(type == 1)
    {
      for(i=0; i<beat_cnt; i++)
      {
        fprintf(outputfile, "%.4f\n", beat_interval_list[i]);
      }
    }

    if((type == 2) || (type == 3))
    {
      for(i=0; i<beat_cnt; i++)
      {
        if(whole_recording)
        {
          l_time = 0LL;
        }
        else
        {
          l_time = signalcomp->edfhdr->viewtime;
        }

        if(l_time < 0LL)
        {
          l_time = 0LL;
        }

        datrecs = beat_onset_list[i] / signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].smp_per_record;

        smpls_left = beat_onset_list[i] % signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].smp_per_record;

        l_time += (datrecs * signalcomp->edfhdr->long_data_record_duration);

        l_time += ((smpls_left * signalcomp->edfhdr->long_data_record_duration) / signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].smp_per_record);

        if(!whole_recording)
        {
          l_time += (mainwindow->edfheaderlist[mainwindow->sel_viewtime]->viewtime - signalcomp->edfhdr->viewtime);
        }

        if(type == 2)
        {
          fprintf(outputfile, "%.4f\t%.4f\n", ((double)l_time) / TIME_DIMENSION, beat_interval_list[i]);
        }

        if(type == 3)
        {
          fprintf(outputfile, "%.4f\n", ((double)l_time) / TIME_DIMENSION);
        }
      }
    }

    fclose(outputfile);
  }

  myobjectDialog->close();

  if(!import_as_annots)
  {
    sprintf(str, "Done. The R-onsets and/or RR-intervals are exported to:\n\n%s", path);
    QMessageBox messagewindow(QMessageBox::Information, "Ready", str);
    messagewindow.setIconPixmap(QPixmap(":/images/ok.png"));
    messagewindow.exec();
  }

  reset_ecg_filter(signalcomp->ecg_filter);

  mainwindow->setup_viewbuf();
}
UI_StatisticWindow::UI_StatisticWindow(struct signalcompblock *signalcomp, long long pagetime)
{
  int i,
      tmp,
      NN50,
      pNN50;

  char stat_str[2048];

  double d_tmp,
         average_bpm,
         average_rr,
         sdnn_bpm,
         sdnn_rr,
         *buf_bpm,
         rmssd_rr,
         *beat_interval_list;

  StatDialog = new QDialog;
  StatDialog->setWindowTitle("Statistics");
  StatDialog->setModal(true);
  StatDialog->setAttribute(Qt::WA_DeleteOnClose, true);
  StatDialog->setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
  StatDialog->setWindowIcon(QIcon(":/images/edf.png"));

  if(signalcomp->ecg_filter != NULL)
  {
    StatDialog->setMinimumSize(600, 400);
    StatDialog->setSizeGripEnabled(true);

    startSlider = new QSlider;
    startSlider->setOrientation(Qt::Horizontal);
    startSlider->setMinimum(0);
    startSlider->setMaximum(295);
    startSlider->setValue(0);

    stopSlider = new QSlider;
    stopSlider->setOrientation(Qt::Horizontal);
    stopSlider->setMinimum(5);
    stopSlider->setMaximum(300);
    stopSlider->setValue(300);

    curve1 = new SignalCurve(StatDialog);
    curve1->setSignalColor(Qt::darkGreen);
    curve1->setBackgroundColor(Qt::black);
    curve1->setRasterColor(Qt::gray);
    curve1->setTraceWidth(0);
    curve1->setH_label(signalcomp->physdimension);
    curve1->setLowerLabel("HR (beats/min)");
    curve1->setDashBoardEnabled(false);
    curve1->setUpperLabel1("Distribution");
    curve1->setFillSurfaceEnabled(true);

    vlayout2_1 = new QVBoxLayout;
    vlayout2_1->setSpacing(20);
    vlayout2_1->addWidget(curve1);
    vlayout2_1->addWidget(startSlider);
    vlayout2_1->addWidget(stopSlider);
  }
  else
  {
    StatDialog->setMinimumSize(300, 400);
    StatDialog->setMaximumSize(300, 400);
  }

  Label1 = new QLabel(StatDialog);
  Label1->setAlignment(Qt::AlignLeft | Qt::AlignTop);

  pushButton1 = new QPushButton(StatDialog);
  pushButton1->setMinimumSize(100, 25);
  pushButton1->setText("&Close");

  hlayout1_1_1 = new QHBoxLayout;
  hlayout1_1_1->addWidget(pushButton1);
  hlayout1_1_1->addStretch(100);

  vlayout1_1 = new QVBoxLayout;
  vlayout1_1->setSpacing(20);
  vlayout1_1->addWidget(Label1);
  vlayout1_1->addStretch(100);
  vlayout1_1->addLayout(hlayout1_1_1);

  hlayout1 = new QHBoxLayout;
  hlayout1->addLayout(vlayout1_1, 1);
  if(signalcomp->ecg_filter != NULL)
  {
    hlayout1->addLayout(vlayout2_1, 100);
  }

  StatDialog->setLayout(hlayout1);

  QObject::connect(pushButton1, SIGNAL(clicked()), StatDialog, SLOT(close()));

  for(i=0; i<300; i++)
  {
    bpm_distribution[i] = 0;
  }

  if(signalcomp->ecg_filter == NULL)
  {
    if((signalcomp->stat_cnt < 1) || (pagetime < 10LL))
    {
      if(signalcomp->alias[0] != 0)
      {
        sprintf(stat_str, "Signal:  %s\n\nSamples:   0\n\nSum:       0 %s\n\nMean:      0 %s\n\nRMS:       0 %s\n\nMRS:       0 %s\n\nZero crossings:  0\n\nFrequency:  0 Hz",
                signalcomp->alias,
                signalcomp->physdimension,
                signalcomp->physdimension,
                signalcomp->physdimension,
                signalcomp->physdimension);
      }
      else
      {
        sprintf(stat_str, "Signal:  %s\n\nSamples:   0\n\nSum:       0 %s\n\nMean:      0 %s\n\nRMS:       0 %s\n\nMRS:       0 %s\n\nZero crossings:  0\n\nFrequency:  0 Hz",
                signalcomp->signallabel,
                signalcomp->physdimension,
                signalcomp->physdimension,
                signalcomp->physdimension,
                signalcomp->physdimension);
      }
    }
    else
    {
      if(signalcomp->alias[0] != 0)
      {
        sprintf(stat_str, "Signal:  %s\n\nSamples:   %i\n\nSum:       %f %s\n\nMean:      %f %s\n\nRMS:       %f %s\n\nMRS:       %f %s\n\nZero crossings:  %i\n\nFrequency:  %f Hz",
                signalcomp->alias,
                signalcomp->stat_cnt,
                signalcomp->stat_sum * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue,
                signalcomp->physdimension,
                (signalcomp->stat_sum * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue) / signalcomp->stat_cnt,
                signalcomp->physdimension,
                sqrt(signalcomp->stat_sum_sqr / signalcomp->stat_cnt) * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue,
                signalcomp->physdimension,
                (signalcomp->stat_sum_rectified / signalcomp->stat_cnt) * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue,
                signalcomp->physdimension,
                signalcomp->stat_zero_crossing_cnt,
                (((double)signalcomp->stat_zero_crossing_cnt / 2.0)) / ((double)pagetime / (double)TIME_DIMENSION)
              );
      }
      else
      {
        sprintf(stat_str, "Signal:  %s\n\nSamples:   %i\n\nSum:       %f %s\n\nMean:      %f %s\n\nRMS:       %f %s\n\nMRS:       %f %s\n\nZero crossings:  %i\n\nFrequency:  %f Hz",
                signalcomp->signallabel,
                signalcomp->stat_cnt,
                signalcomp->stat_sum * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue,
                signalcomp->physdimension,
                (signalcomp->stat_sum * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue) / signalcomp->stat_cnt,
                signalcomp->physdimension,
                sqrt(signalcomp->stat_sum_sqr / signalcomp->stat_cnt) * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue,
                signalcomp->physdimension,
                (signalcomp->stat_sum_rectified / signalcomp->stat_cnt) * signalcomp->edfhdr->edfparam[signalcomp->edfsignal[0]].bitvalue,
                signalcomp->physdimension,
                signalcomp->stat_zero_crossing_cnt,
                (((double)signalcomp->stat_zero_crossing_cnt / 2.0)) / ((double)pagetime / (double)TIME_DIMENSION)
              );
      }
    }
  }
  else
  {
    beat_cnt = ecg_filter_get_beat_cnt(signalcomp->ecg_filter);

    beat_interval_list = ecg_filter_get_interval_beatlist(signalcomp->ecg_filter);

    if(beat_cnt < 3)
    {
      sprintf(stat_str, "Not enough beats.");
    }
    else
    {
      average_bpm = 0.0;
      average_rr = 0.0;
      sdnn_bpm = 0.0;
      sdnn_rr = 0.0;
      rmssd_rr = 0.0;
      NN50 = 0;

      buf_bpm = (double *)malloc(sizeof(double) * beat_cnt);
      if(buf_bpm == NULL)
      {
        QMessageBox messagewindow(QMessageBox::Critical, "Error", "The system was not able to provide enough resources (memory) to perform the requested action.");
        messagewindow.exec();
        return;
      }

      for(i=0; i<beat_cnt; i++)
      {
        buf_bpm[i] = 60.0 / beat_interval_list[i];

        average_bpm += buf_bpm[i];
        average_rr += beat_interval_list[i];

        if(i < (beat_cnt - 1))
        {
          d_tmp = (beat_interval_list[i] - beat_interval_list[i + 1]) * 1000.0;

          rmssd_rr += (d_tmp * d_tmp);

          if(((beat_interval_list[i] - beat_interval_list[i + 1]) > 0.05 ) || ((beat_interval_list[i + 1] - beat_interval_list[i]) > 0.05 ))
          {
            NN50++;
          }
        }
      }

      average_bpm /= beat_cnt;
      average_rr /= beat_cnt;
      rmssd_rr /= beat_cnt;
      rmssd_rr = sqrt(rmssd_rr);

      pNN50 = (NN50 * 100) / (beat_cnt - 1);

      for(i=0; i<beat_cnt; i++)
      {
        sdnn_bpm += (buf_bpm[i] - average_bpm) * (buf_bpm[i] - average_bpm);
        sdnn_rr += (beat_interval_list[i] - average_rr) * (beat_interval_list[i] - average_rr);
      }

      sdnn_bpm = sqrt(sdnn_bpm / beat_cnt);
      sdnn_rr = sqrt(sdnn_rr / beat_cnt);

      sprintf(stat_str,
              "Heart Rate\n\n"
              "Beats:    %3i\n\n"
              "Mean RR:  %3i ms\n\n"
              "SDNN RR:  %3i ms\n\n"
              "RMSSD RR: %3i ms\n\n"
              "Mean HR:  %3.3f bpm\n\n"
              "SDNN HR:  %3.3f bpm\n\n"
              "NN50:     %3i\n\n"
              "pNN50:    %3i %%\n\n",
              beat_cnt,
              (int)(average_rr * 1000.0),
              (int)(sdnn_rr * 1000.0),
              (int)rmssd_rr,
              average_bpm,
              sdnn_bpm,
              NN50,
              pNN50);

      free(buf_bpm);

      for(i=0; i<beat_cnt; i++)
      {
        tmp = 60.0 / beat_interval_list[i];

        if((tmp > 0) && (tmp < 301))
        {
          bpm_distribution[tmp-1]++;
        }
      }

      max_val = 1;

      for(i=0; i<300; i++)
      {
        if(bpm_distribution[i] > max_val)
        {
          max_val = bpm_distribution[i];
        }
      }

      for(i=0; i<300; i++)
      {
        if(bpm_distribution[i] > (max_val / 70))
        {
          start_ruler = i;

          break;
        }
      }

      for(i=299; i>=0; i--)
      {
        if(bpm_distribution[i] > (max_val / 70))
        {
          end_ruler = i + 1;

          if(end_ruler > 300)
          {
            end_ruler = 300;
          }

          break;
        }
      }

      if(start_ruler >= end_ruler)
      {
        start_ruler = 0;

        end_ruler = 300;
      }

      startSlider->setValue(start_ruler);
      stopSlider->setValue(end_ruler);

      curve1->setH_RulerValues(start_ruler + 1, end_ruler + 1);

      curve1->drawCurve(bpm_distribution + start_ruler, end_ruler - start_ruler, (int)(max_val * 1.1) + 1, 0.0);

      QObject::connect(startSlider, SIGNAL(valueChanged(int)), this, SLOT(startSliderMoved(int)));
      QObject::connect(stopSlider,  SIGNAL(valueChanged(int)), this, SLOT(stopSliderMoved(int)));
    }
  }

  Label1->setText(stat_str);

  StatDialog->exec();
}