// file: $(NEDC_NFC)/class/cpp/Edf/edf_03.cc // // This file contains get methods. // // Revision History: // // 20240307 (JP): refactored code to expand set/get methods // // 20240305 (JP): removed the set_signal_dimensions method // // 20240130 (JP): updated the deidentify process by adding more steps // // 20180205 (JM): removed "pad_whitespace" functions from deidentify // // 20170103 (SL): added set_start_date method // // 20150701 (FG): apply_montage method modified to update the header labels // regarding the values parsed for the montage specified in the // parameter file // // 20150630 (FG): interpolation moved to Edf class // methods added: interpolation_average // // 20150612 (FG): added interpolation functionality // methods added: add_channel // select_channel // // 20141219 (AH): apply_montage updated to account for negative gain // // 20141216 (AH): set_signal_dimensions is updated so it only updates // the frequency for channels that their original freq. // is the same as channel 0 (EEG channels) // // local include files // #include "Edf.h" //***************************************************************************** // // public methods: get methods // //***************************************************************************** // method: get_sample_frequency // float Edf::get_sample_frequency(long chan_a) { // get the best guess at what the sample frequency should be // float fsamp = hdr_sample_frequency_d; if (chan_a >= (long)0) { fsamp = (float)hdr_chan_rec_size_d[chan_a] / (float)hdr_ghdi_dur_rec_d; } // round the sample frequency to 0.1 Hz // note: this is a hack to deal with how Edf files store the sample frquency // float new_fsamp = ((long)roundf(fsamp * (float)10.0)) * (float)0.1; // exit gracefully // return new_fsamp; } // method: get_hdr_chan_labels // // arguments: // char**& labels: channel labels (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel labels. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_labels(char**& labels_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a != (long)0) { cleanup(labels_a, nchans_a); } // loop over all labels // nchans_a = hdr_num_channels_signal_d; for (long i = 0; i < nchans_a; i++) { labels_a[i] = new char[strlen(hdr_chan_labels_d[i] + 1)]; strcpy(labels_a[i], hdr_chan_labels_d[i]); } // exit gracefully // return true; } // method: get_hdr_chan_trans_types // // arguments: // char**& ttypes: channel trans types (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel transducer types. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_trans_types(char**& ttypes_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { cleanup(ttypes_a, nchans_a); } // loop over all labels // nchans_a = hdr_num_channels_signal_d; for (long i = 0; i < nchans_a; i++) { ttypes_a[i] = new char[strlen(hdr_chan_trans_types_d[i] + 1)]; strcpy(ttypes_a[i], hdr_chan_trans_types_d[i]); } // exit gracefully // return true; } // method: get_hdr_chan_phys_dim // // arguments: // char**& physd: channel physical dimensions (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel physical dimensions. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_phys_dim(char**& physd_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { cleanup(physd_a, nchans_a); } // loop over all labels // nchans_a = hdr_num_channels_signal_d; for (long i = 0; i < nchans_a; i++) { physd_a[i] = new char[strlen(hdr_chan_phys_dim_d[i] + 1)]; strcpy(physd_a[i], hdr_chan_phys_dim_d[i]); } // exit gracefully // return true; } // method: get_hdr_chan_phys_min // // arguments: // double*& physm: channel physical minimum (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel physical minimum. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_phys_min(double*& physm_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { delete [] physm_a; } // copy the data // nchans_a = hdr_num_channels_signal_d; physm_a = new double[nchans_a]; memcpy(physm_a, hdr_chan_phys_min_d, sizeof(double) * nchans_a); // exit gracefully // return true; } // method: get_hdr_chan_phys_max // // arguments: // double*& physm: channel physical maximum (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel physical maximum. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_phys_max(double*& physm_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { delete [] physm_a; } // copy the data // nchans_a = hdr_num_channels_signal_d; physm_a = new double[nchans_a]; memcpy(physm_a, hdr_chan_phys_max_d, sizeof(double) * nchans_a); // exit gracefully // return true; } // method: get_hdr_chan_dig_min // // arguments: // long*& digm: channel digital minimum (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel digital minimum. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_dig_min(long*& digm_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { delete [] digm_a; } // copy the data // nchans_a = hdr_num_channels_signal_d; digm_a = new long[nchans_a]; memcpy(digm_a, hdr_chan_dig_min_d, sizeof(long) * nchans_a); // exit gracefully // return true; } // method: get_hdr_chan_dig_max // // arguments: // long*& digm: channel digital maximum (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel digital maximum. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_dig_max(long*& digm_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { delete [] digm_a; } // copy the data // nchans_a = hdr_num_channels_signal_d; digm_a = new long[nchans_a]; memcpy(digm_a, hdr_chan_dig_max_d, sizeof(long) * nchans_a); // exit gracefully // return true; } // method: get_hdr_chan_prefilt // // arguments: // char**& prefilt: channel prefilt (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel prefilt. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_prefilt(char**& prefilt_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { cleanup(prefilt_a, nchans_a); } // loop over all labels // nchans_a = hdr_num_channels_signal_d; for (long i = 0; i < nchans_a; i++) { prefilt_a[i] = new char[strlen(hdr_chan_prefilt_d[i] + 1)]; strcpy(prefilt_a[i], hdr_chan_prefilt_d[i]); } // exit gracefully // return true; } // method: gset_hdr_chan_rec_size // // arguments: // long*& digm: channel record size (output) // long& nchans: the number of channels (output) // // return: an boolean value indicating status // // This creates space and populates the channel digital maximum. // Note that it deallocates memory as needed. // bool Edf::get_hdr_chan_rec_size(long*& recsz_a, long& nchans_a) { // clear existing memory if necessary // if (nchans_a > 0) { delete [] recsz_a; } // copy the data // nchans_a = hdr_num_channels_signal_d; recsz_a = new long[nchans_a]; memcpy(recsz_a, hdr_chan_rec_size_d, sizeof(long) * nchans_a); // exit gracefully // return true; } //***************************************************************************** // // public methods: additional set methods needed for backward compatibility // //***************************************************************************** // method: get_labels // // arguments: // char** labels: output filename (input / output) // // return: an integer value containing the number of labels // // This method returns the labels found in an EDF header. // long Edf::get_labels(char** labels_a) { // get the number of channels // long num_channels = Edf::get_num_channels_file(); for (int i = 0; i < num_channels; i++) { strcpy(labels_a[i], hdr_chan_labels_d[i]); } // exit gracefully // return num_channels; } // method: get_channel_pos // // arguments: // char* label: a label containing the desired channel (input) // MATCH_MODE matmode: an enum indicating the precision of the match (input) // // return: a long integer containing the channel position // or -1 if it is not found. // // This method returns the position of channel in the set of labels in // the header. In fact this method performs the same function of find_match. // However, this method does not receive variables related to the header as // the latter does. // long Edf::get_channel_pos(const char* label_a, MATCH_MODE match_mode_a) { // save the match mode: // there are other methods depending on the selected match mode. // smmode_d = match_mode_a; // declare local variables // long pos; // take the position of label_a within the set of channels // if ((pos = Edf::find_match(label_a, hdr_ghdi_nsig_rec_d, hdr_chan_labels_d, smmode_d)) < 0) { fprintf(stdout, "Error: %s (line: %d) %s: channel [%s] not found\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, label_a); // return -1 if position was not found // return ERR_MATCH; } // return channel position // return pos; } // method: get_montage_channels // // arguments: // long& nl_a: the number of channels (output) // char** channels_a: the array containing all the channels specified (output) // // return: a boolean value indicating status. // // This method returns the unique channels of a montage specification and // the total number of all channels specified. // // Note that it returns all channels with no duplication. // bool Edf::get_montage_channels(long& nl_a, char** channels_a) { // declare local variables // bool status = true; // variable to hold the current index of channels_a // long new_occurrence = 0; // flag to check duplication // bool found; // loop over all channels in mlabels1_d // for (long i = 0; i < num_mlabels_d; i++) { // set flag to false // found = false; // loop over the values stored in channels_a so far // for (long j = 0; j < new_occurrence; j++) { // check if the current channel i was not stored yet // if (strcmp( mlabels1_d[i], channels_a[j]) == 0) { // set flag to true // found = true; // get out from loop to check channel i + 1 // break; } } // copy the first occurrence of a channel in montage specification: // since no duplication was found, store channel i into channels_a. // if (found == false) { channels_a[new_occurrence] = new char[strlen(mlabels1_d[i]) + 1]; strcpy(channels_a[new_occurrence++], mlabels1_d[i]); } } // loop over all channels in mlabels2_d // for (long i = 0; i < num_mlabels_d; i++) { // set flag to false // found = false; // check if the current channel i was not stored yet // for (long j = 0; j < new_occurrence; j++) { if (strcmp(mlabels2_d[i], channels_a[j]) == 0) { // set flag to true // found = true; // get out from loop to check channel i + 1 // break; } } // copy the first occurrence of a channel in montage specification: // since no duplication was found, store channel i into channels_a. // if (found == false) { channels_a[new_occurrence] = new char[strlen(mlabels2_d[i]) + 1]; strcpy(channels_a[new_occurrence++], mlabels2_d[i]); } } // total number of different channels // specified by the montage. // nl_a = new_occurrence; // exit gracefully // return status; } // method: check_montage // // arguments: // char* missing_channels: string containing the missing labels (output) // char* fname: EDF file (input) // long nmontage: number of montage channels (input) // MATCH_MODE match_mode: match mode desired (input) // char** montage: montage channels (input) // // return: a boolean value indicating if the file contains proper // channel assignments. // // This method checks if the header of an EDF file contains the channels // specified in montage. // // Note that the memory for missing_channels is allocated in the // check_montage utility driver program. Since the input can be either // a single EDF file or a list, memory for missing_channels is allocated // and deallocated constantly. // // Note also that missing_channels is a string instead of an array of // strings. That way, the missing channels can be outputed easily without // the need of loops. // bool Edf::check_montage(const char* missing_channels_a, const char* fname_a, long nmontage_a, MATCH_MODE match_mode_a, char** montage_a) { // declare local variables // VVectorDouble sig; long missing_count = 0; bool show_missing_channels = false; bool fail_file = false; // read the header from a file: // ignore the signal data // if (!read_edf(sig, fname_a, false, false)) { fprintf(stdout, "Error: %s (line: %d) %s: error opening (%s)\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, fname_a); return false; } // check verbosity level to additional information about the error // if (vrbl_d >= Vrbl::SHORT) { show_missing_channels = true; } // loop over all channels in montage // for (long i = 0; i < nmontage_a; i++) { // hold the position of montage channel i // long pos; if ((pos = Edf::find_match(montage_a[i], hdr_ghdi_nsig_rec_d, hdr_chan_labels_d, match_mode_a)) < 0) { // case 1: output the missing channels // if (show_missing_channels == true) { fail_file = true; if(missing_count == 0) { // assign the first channel not found to // missing_channels_a // strcpy((char*)missing_channels_a, montage_a[i]); } else { // concatenate the other channels missing // strcat((char*)missing_channels_a, Itgl::COMMA); strcat((char*)missing_channels_a, Itgl::SPACE); strcat((char*)missing_channels_a, montage_a[i]); } missing_count++; } // case 2: just output if there is a missing channel // else { // channel i of montage was not found: // file does not contain proper channel assignments // for the montage specified. // return false; } } } // file does not contain proper channel assignments: // this boolean variable handles the output of the missing channels. // if (fail_file == true) { return false; } // file contain proper channel assignments // return true; } // // end of file