Пример #1
0
def create_synthetic_eeghdf_file():

    U, D, s2u, of = gen_synthetic_signal(fs=10, duration_sec=2)
    hf = eeghdf.EEGHDFWriter(hdf_file_name='synthetic.eeg.h5', fileattr='w')
    hf.write_patient_info('test, subject',
                          patientcode='0000000',
                          gender='unknown',
                          birthdate_isostring='2018-01-01T12:00')
    T = 2
    nchan = 5
    fs = 10
    labels = [str(ii) for ii in range(nchan)]

    U, D, s2u, dig_offsets = gen_synthetic_signal()
    print('D:', D)
    dig_maxs = D.max(axis=1)
    dig_mins = D.min(axis=1)
    phys_maxs = U.max(axis=1)
    phys_mins = U.min(axis=1)
    phys_units = ['s', 'uV', 'uV', 'uV', 'uV']
    record = hf.create_record_block(record_duration_seconds=T,
                                    start_isodatetime='2018-01-01T13:00.00',
                                    end_isodatetime='2018-01-01T13:00.02',
                                    number_channels=nchan,
                                    num_samples_per_channel=fs * T,
                                    sample_frequency=fs,
                                    signal_labels=labels,
                                    signal_physical_maxs=phys_maxs,
                                    signal_physical_mins=phys_mins,
                                    signal_digital_mins=dig_mins,
                                    signal_digital_maxs=dig_maxs,
                                    physical_dimensions=phys_units,
                                    patient_age_days=1 / 24)

    # need to create edf_annotations
    hf.write_annotations_b([], record=record)
    signals = hf.hdf['record-0']['signals']
    signals[:] = D
    return {'hf': hf, 'U': U, 'D': D, 's2u': s2u, 'offsets': of}
Пример #2
0
def edf2hdf(fn, outfn='', anonymize=False, verbose=False):
    """
    convert an edf file @fn to hdf5 using fairly straightforward mapping
    if no @outfn is specified, then use the same name as the @fn but change extention to "eeg.h5"

    return True if successful
    
    """

    if not outfn:
        base = os.path.basename(fn)
        base, ext = os.path.splitext(base)

        # outfn = os.path.join(hdf_dir, base)
        outfn = base + '.eeg.h5'
        
        # all the data point related stuff

    with edflib.EdfReader(fn) as ef:

        # read all EDF+ header information in just the way I want it
        header = {
            'file_name': os.path.basename(fn),
            'filetype': ef.filetype,
            'patient_name': ef.patient_name,
            'patientcode': ef.patientcode,
            'gender': ef.gender,

            'signals_in_file': ef.signals_in_file,
            'datarecords_in_file': ef.datarecords_in_file,
            'file_duration_100ns': ef.file_duration_100ns,
            'file_duration_seconds': ef.file_duration_seconds,
            'startdate_date': datetime.date(ef.startdate_year, ef.startdate_month, ef.startdate_day),
            'start_datetime': datetime.datetime(ef.startdate_year, ef.startdate_month, ef.startdate_day,
                                                ef.starttime_hour, ef.starttime_minute, ef.starttime_second),
            'starttime_subsecond_offset': ef.starttime_subsecond,

            'birthdate_date': ef.birthdate_date,
            'patient_additional': ef.patient_additional,
            'admincode': ef.admincode,  # usually the study eg. C13-100
            'technician': ef.technician,
            'equipment': ef.equipment,
            'recording_additional': ef.recording_additional,
            'datarecord_duration_100ns': ef.datarecord_duration_100ns,
        }
        if verbose:
            pprint.pprint(header)
            debug = print
        else:
            def nulfunction(*args,**kwargs):
                return None
            debug = nulfunction

        #  use arrow
        start_datetime = header['start_datetime']

        # end_date_time = datetime.datetime(ef.enddate_year, ef.enddate_month, ef.enddate_day, ef.endtime_hour,
        # ef.endtime_minute, ef.endtime_second) # tz naive
        # end_date_time - start_date_time
        duration = datetime.timedelta(seconds=header['file_duration_seconds'])
        

        # derived information
        birthdate = header['birthdate_date']
        if birthdate:
            age = arrow.get(start_datetime) - arrow.get(header['birthdate_date'])

            debug('predicted age: %s' % age)
            # total_seconds() returns a float
            debug('predicted age (seconds): %s' % age.total_seconds())
        else:
            age = datetime.timedelta(seconds=0)
            birthdate = ''

        if anonymize:
            raise Exception('not implemented')


        # anonymized version if necessary
        header['end_datetime'] = header['start_datetime'] + duration

        ############# signal array information ##################

        # signal block related stuff
        nsigs = ef.signals_in_file

        # again know/assume that this is uniform sampling across signals
        # for each record block 
        fs0 = ef.samplefrequency(0)
        signal_frequency_array = ef.get_signal_freqs()
        # print("signal_frequency_array::\n", repr(signal_frequency_array))
        assert all(signal_frequency_array == fs0)

        nsamples0 = ef.samples_in_file(0)  # samples per channel
        debug('nsigs=%s, fs0=%s, nsamples0=%s\n' % (nsigs, fs0, nsamples0))

        num_samples_per_signal = ef.get_samples_per_signal()  # np array
        # print("num_samples_per_signal::\n", repr(num_samples_per_signal), '\n')
        assert all(num_samples_per_signal == nsamples0)

        file_duration_sec = ef.file_duration_seconds
        #print("file_duration_sec", repr(file_duration_sec))

        # Note that all annotations except the top row must also specify a duration.

        # long long onset; /* onset time of the event, expressed in units of 100
        #                     nanoSeconds and relative to the starttime in the header */

        # char duration[16]; /* duration time, this is a null-terminated ASCII text-string */

        # char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; /* description of the
        #                             event in UTF-8, this is a null term string of max length 512*/

        # start("x.y"), end, char[20]
        # annotations = ef.read_annotations_as_array() # get numpy array of
        # annotations
        annotations_b = ef.read_annotations_b_100ns_units()
        # print("annotations_b::\n")
        # pprint.pprint(annotations_b)  # get list of annotations

        signal_text_labels = ef.get_signal_text_labels()
        debug("signal_text_labels::\n")
        if verbose:
            pprint.pprint(signal_text_labels)
        
        # ef.recording_additional

        # print()
        signal_digital_mins = np.array(
            [ef.digital_min(ch) for ch in range(nsigs)])
        signal_digital_total_min = min(signal_digital_mins)

        #print("digital mins:", repr(signal_digital_mins))
        #print("digital total min:", repr(signal_digital_total_min))

        signal_digital_maxs = np.array(
            [ef.digital_max(ch) for ch in range(nsigs)])
        signal_digital_total_max = max(signal_digital_maxs)
      
        #print("digital maxs:", repr(signal_digital_maxs))
        #print("digital total max:", repr(signal_digital_total_max))

        signal_physical_dims = [
            ef.physical_dimension(ch) for ch in range(nsigs)]
        # print('signal_physical_dims::\n')
        # pprint.pprint(signal_physical_dims)
        #print()

        signal_physical_maxs = np.array(
            [ef.physical_max(ch) for ch in range(nsigs)])

        #print('signal_physical_maxs::\n', repr(signal_physical_maxs))

        signal_physical_mins = np.array(
            [ef.physical_min(ch) for ch in range(nsigs)])

        #print('signal_physical_mins::\n', repr(signal_physical_mins))

        # this don't seem to be used much so I will put at end
        signal_prefilters = [ef.prefilter(ch).strip() for ch in range(nsigs)]
        #print('signal_prefilters::\n')
        # pprint.pprint(signal_prefilters)
        #print()
        signal_transducers = [ef.transducer(ch).strip() for ch in range(nsigs)]
        #print('signal_transducers::\n')
        #pprint.pprint(signal_transducers)

        with eeghdf.EEGHDFWriter(outfn, 'w') as eegf:
            if header['birthdate_date']:
                birthdate_isostring = header['birthdate_date'].strftime('%Y-%m-%d')
            else:
                birthdate_isostring = ''
                
            eegf.write_patient_info(patient_name=header['patient_name'],
                                    patientcode=header['patientcode'],
                                    gender=header['gender'],
                                    birthdate_isostring=birthdate_isostring,
                                    # gestational_age_at_birth_days
                                    # born_premature
                                    patient_additional=header['patient_additional'])


            rec = eegf.create_record_block(record_duration_seconds=header['file_duration_seconds'],
                                           start_isodatetime=str(header['start_datetime']),
                                           end_isodatetime=str(header['end_datetime']),
                                           number_channels=header['signals_in_file'],
                                           num_samples_per_channel=nsamples0,
                                           sample_frequency=fs0,
                                           signal_labels=signal_text_labels,
                                           signal_physical_mins=signal_physical_mins,
                                           signal_physical_maxs=signal_physical_maxs,
                                           signal_digital_mins=signal_digital_mins,
                                           signal_digital_maxs=signal_digital_maxs,
                                           physical_dimensions=signal_physical_dims,
                                           patient_age_days=age.total_seconds() / 86400.0,
                                           signal_prefilters=signal_prefilters,
                                           signal_transducers=signal_transducers,
                                           technician=header['technician'])

            eegf.write_annotations_b(annotations_b)  # may be should be called record annotations

            edfblock_itr = edf_block_iter_generator(
                ef,
                nsamples0,
                100 * ef.samples_in_datarecord(0)*header['signals_in_file'], # samples_per_chunk roughly 100 datarecords at a time
                dtype='int32')

            signals = eegf.stream_dig_signal_to_record_block(rec, edfblock_itr)
    
        return True # we succeeded
Пример #3
0
def edf2hdf(fn, outfn="", hdf_dir="", anonymize=False):
    """
    convert an edf file to hdf5 using fairly straightforward mapping
    return True if successful
    
    by default (if outfn and hdf_dir are not set)
       the output is put in the same directory as the input file
    you can also specify the output file (full path) by setting outfn directly
    or simple specify a different target directory by specifying @hdf_dir as a directory path

    @database_sourcel_label tells us which database it came from LPCH_NK or STANFORD_NK
       this is important!
    """

    if not outfn:
        parentdir = os.path.dirname(fn)
        base = os.path.basename(fn)
        base, ext = os.path.splitext(base)

        base = base + DEFAULT_EXT
        if hdf_dir:
            outfn = os.path.join(hdf_dir, base)
        else:
            outfn = os.path.join(parentdir, base)
            # debug('outfn:', outfn)
        # all the data point related stuff

    with edflib.EdfReader(fn) as ef:

        # read all EDF+ header information in just the way I want it
        header = {
            "file_name":
            os.path.basename(fn),
            "filetype":
            ef.filetype,
            "patient_name":
            ef.patient_name,
            "patientcode":
            ef.patientcode,
            "studyadmincode":
            ef.admincode,
            "gender":
            ef.gender,
            "signals_in_file":
            ef.signals_in_file,
            "datarecords_in_file":
            ef.datarecords_in_file,
            "file_duration_100ns":
            ef.file_duration_100ns,
            "file_duration_seconds":
            ef.file_duration_seconds,
            "startdate_date":
            datetime.date(ef.startdate_year, ef.startdate_month,
                          ef.startdate_day),
            "start_datetime":
            datetime.datetime(
                ef.startdate_year,
                ef.startdate_month,
                ef.startdate_day,
                ef.starttime_hour,
                ef.starttime_minute,
                ef.starttime_second,
            ),
            "starttime_subsecond_offset":
            ef.starttime_subsecond,
            "birthdate_date":
            ef.birthdate_date,  # str
            "patient_additional":
            ef.patient_additional,  # str
            "admincode":
            ef.admincode,  # usually the study eg. C13-100
            "technician":
            ef.technician,
            "equipment":
            ef.equipment,
            "recording_additional":
            ef.recording_additional,
            "datarecord_duration_100ns":
            ef.datarecord_duration_100ns,
        }
        # defbug
        debug("original header")
        debug(pprint.pformat(header))

        #  use arrow
        start_datetime = header["start_datetime"]

        duration = datetime.timedelta(seconds=header["file_duration_seconds"])

        # derived information
        birthdate = header["birthdate_date"]
        if birthdate:
            age = arrow.get(start_datetime) - arrow.get(
                header["birthdate_date"])

            debug("predicted age: %s" % age)
            # total_seconds() returns a float
            debug("predicted age (seconds): %s" % age.total_seconds())
        else:
            age = datetime.timedelta(seconds=0)

        if anonymize:
            anonymous_header = create_simple_anonymous_header(header)
            header = anonymous_header

        header["end_datetime"] = header["start_datetime"] + duration

        ############# signal array information ##################

        # signal block related stuff
        nsigs = ef.signals_in_file

        # again know/assume that this is uniform sampling across signals
        fs0 = ef.samplefrequency(0)
        signal_frequency_array = ef.get_signal_freqs()
        dfs = np.diff(signal_frequency_array)
        dfs_ind = np.where(dfs != 0.0)
        dfs_ind = dfs_ind[0]
        last_ind = 0
        for dd in dfs_ind + 1:
            debug("block:", signal_frequency_array[last_ind:dd])
            last_ind = dd
        debug("last block:", signal_frequency_array[last_ind:])

        debug("where does sampling rate change?", np.where(dfs != 0.0))
        debug("elements:", signal_frequency_array[np.where(dfs != 0.0)])
        debug("signal_frequency_array::\n", repr(signal_frequency_array))
        debug("len(signal_frequency_array):", len(signal_frequency_array))

        assert all(signal_frequency_array[:-3] == fs0)

        nsamples0 = ef.samples_in_file(0)  # samples per channel
        debug("nsigs=%s, fs0=%s, nsamples0=%s\n" % (nsigs, fs0, nsamples0))

        num_samples_per_signal = ef.get_samples_per_signal()  # np array
        debug("num_samples_per_signal::\n", repr(num_samples_per_signal), "\n")

        # assert all(num_samples_per_signal == nsamples0)

        file_duration_sec = ef.file_duration_seconds
        # debug("file_duration_sec", repr(file_duration_sec))

        # Note that all annotations except the top row must also specify a duration.

        # long long onset; /* onset time of the event, expressed in units of 100
        #                     nanoSeconds and relative to the starttime in the header */

        # char duration[16]; /* duration time, this is a null-terminated ASCII text-string */

        # char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; /* description of the
        #                             event in UTF-8, this is a null term string of max length 512*/

        # start("x.y"), end, char[20]
        # annotations = ef.read_annotations_as_array() # get numpy array of
        # annotations

        annotations_b = ef.read_annotations_b_100ns_units()

        # debug("annotations_b::\n")
        # pprint.pprint(annotations_b)  # get list of annotations

        signal_text_labels = ef.get_signal_text_labels()
        debug("signal_text_labels::\n")
        debug(pprint.pformat(signal_text_labels))
        debug("normalized text labels::\n")
        signal_text_labels_lpch_normalized = [
            normalize_lpch_signal_label(label) for label in signal_text_labels
        ]
        debug(pprint.pformat(signal_text_labels_lpch_normalized))

        # ef.recording_additional

        # debug()
        signal_digital_mins = np.array(
            [ef.digital_min(ch) for ch in range(nsigs)])
        signal_digital_total_min = min(signal_digital_mins)

        debug("digital mins:", repr(signal_digital_mins))
        debug("digital total min:", repr(signal_digital_total_min))

        signal_digital_maxs = np.array(
            [ef.digital_max(ch) for ch in range(nsigs)])
        signal_digital_total_max = max(signal_digital_maxs)

        debug("digital maxs:", repr(signal_digital_maxs))
        # debug("digital total max:", repr(signal_digital_total_max))

        signal_physical_dims = [
            ef.physical_dimension(ch) for ch in range(nsigs)
        ]
        # debug('signal_physical_dims::\n')
        # pprint.pformat(signal_physical_dims)
        # debug()

        signal_physical_maxs = np.array(
            [ef.physical_max(ch) for ch in range(nsigs)])

        # debug('signal_physical_maxs::\n', repr(signal_physical_maxs))

        signal_physical_mins = np.array(
            [ef.physical_min(ch) for ch in range(nsigs)])

        # debug('signal_physical_mins::\n', repr(signal_physical_mins))

        # this don't seem to be used much so I will put at end
        signal_prefilters = [ef.prefilter(ch).strip() for ch in range(nsigs)]
        # debug('signal_prefilters::\n')
        # pprint.pformat(signal_prefilters)
        # debug()
        signal_transducers = [ef.transducer(ch).strip() for ch in range(nsigs)]
        # debug('signal_transducers::\n')
        # pprint.pformat(signal_transducers)

        with eeghdf.EEGHDFWriter(outfn, "w") as eegf:
            eegf.write_patient_info(
                patient_name=header["patient_name"],
                patientcode=header["patientcode"],
                gender=header["gender"],
                birthdate_isostring=str(header["birthdate_date"]),
                # gestational_age_at_birth_days
                # born_premature
                patient_additional=header["patient_additional"],
            )

            signal_text_labels_lpch_normalized = [
                normalize_lpch_signal_label(label)
                for label in signal_text_labels
            ]

            rec = eegf.create_record_block(
                record_duration_seconds=header["file_duration_seconds"],
                start_isodatetime=str(header["start_datetime"]),
                end_isodatetime=str(header["end_datetime"]),
                number_channels=header["signals_in_file"],
                num_samples_per_channel=nsamples0,
                sample_frequency=fs0,
                signal_labels=signal_text_labels_lpch_normalized,
                signal_physical_mins=signal_physical_mins,
                signal_physical_maxs=signal_physical_maxs,
                signal_digital_mins=signal_digital_mins,
                signal_digital_maxs=signal_digital_maxs,
                physical_dimensions=signal_physical_dims,
                patient_age_days=age.total_seconds() / 86400.0,
                signal_prefilters=signal_prefilters,
                signal_transducers=signal_transducers,
                technician=header["technician"],
                studyadmincode=header["studyadmincode"],
            )

            eegf.write_annotations_b(
                annotations_b)  # may be should be called record annotations

            edfblock_itr = edf_block_iter_generator(
                ef,
                nsamples0,
                100 * ef.samples_in_datarecord(0) * header[
                    "signals_in_file"],  # samples_per_chunk roughly 100 datarecords at a time
                dtype="int32",
            )

            signals = eegf.stream_dig_signal_to_record_block(rec, edfblock_itr)

        return True
Пример #4
0
def edf2hdf2(fn, outfn='', hdf_dir='', anonymize=False):
    """
    convert an edf file to hdf5 using fairly straightforward mapping
    return True if successful
    
    @database_sourcel_label tells us which database it came from LPCH_NK or STANFORD_NK
       this is important!
    """

    if not outfn:
        dir_name = os.path.dirname(fn)
        if not hdf_dir:
            hdf_dir = dir_name
        base = os.path.basename(fn)
        base, ext = os.path.splitext(base)

        base = base + '.eeg.h5'
        outfn = os.path.join(hdf_dir, base)
        # print('outfn:', outfn)
        # all the data point related stuff

    with edflib.EdfReader(fn) as ef:

        # read all EDF+ header information in just the way I want it
        header = {
            'file_name':
            os.path.basename(fn),
            'filetype':
            ef.filetype,
            'patient_name':
            ef.patient_name,
            'patientcode':
            ef.patientcode,
            'studyadmincode':
            ef.admincode,
            'gender':
            ef.gender,
            'signals_in_file':
            ef.signals_in_file,
            'datarecords_in_file':
            ef.datarecords_in_file,
            'file_duration_100ns':
            ef.file_duration_100ns,
            'file_duration_seconds':
            ef.file_duration_seconds,
            'startdate_date':
            datetime.date(ef.startdate_year, ef.startdate_month,
                          ef.startdate_day),
            'start_datetime':
            datetime.datetime(ef.startdate_year, ef.startdate_month,
                              ef.startdate_day, ef.starttime_hour,
                              ef.starttime_minute, ef.starttime_second),
            'starttime_subsecond_offset':
            ef.starttime_subsecond,
            'birthdate_date':
            ef.birthdate_date,
            'patient_additional':
            ef.patient_additional,
            'admincode':
            ef.admincode,  # usually the study eg. C13-100
            'technician':
            ef.technician,
            'equipment':
            ef.equipment,
            'recording_additional':
            ef.recording_additional,
            'datarecord_duration_100ns':
            ef.datarecord_duration_100ns,
        }
        pprint.pprint(header)

        #### validation code #####
        validator = None
        # if source_database_label=='LPCH_NK':
        #     validator = ValidateTrackHeaderLPCH(header=header)
        # elif source_database_label== 'STANFORD_NK':
        #     validator = ValidateTrackHeaderStanford(header=header)
        # else:
        #     raise ValidationError

        # if not validator.is_valid():
        #     print('problem with this file:', fn)
        #     print(validator.errors,validator.error_code,
        #           validator.error_params)

        #     return False, validator
        # else:
        #     print('\nvalid header::')
        #     pprint.pprint(validator.cleaned_data)
        #     header = validator.cleaned_data

        # from here on the header is valid and cleaned

        #  use arrow
        start_datetime = header['start_datetime']

        # end_date_time = datetime.datetime(ef.enddate_year, ef.enddate_month, ef.enddate_day, ef.endtime_hour,
        # ef.endtime_minute, ef.endtime_second) # tz naive
        # end_date_time - start_date_time
        duration = datetime.timedelta(seconds=header['file_duration_seconds'])

        # derived information
        birthdate = header['birthdate_date']
        if birthdate:
            age = arrow.get(start_datetime) - arrow.get(
                header['birthdate_date'])

            debug('predicted age: %s' % age)
            # total_seconds() returns a float
            debug('predicted age (seconds): %s' % age.total_seconds())
        else:
            age = datetime.timedelta(seconds=0)

        # if anonymize:
        #     if source_database_label== 'LPCH_NK':
        #         anonymizer = AnonymizeTrackHeaderLPCH(header, source_database_label=source_database_label)
        #     if source_database_label == 'STANFORD_NK':
        #         anonymizer = AnonymizeTrackHeaderStanford(header, source_database_label=source_database_label)

        #     header = anonymizer.anonymous_header  # replace the original header with the anonymous one
        #     print('anonymized header')
        #     pprint.pprint(header)

        # anonymized version if necessary
        header['end_datetime'] = header['start_datetime'] + duration

        ############# signal array information ##################

        # signal block related stuff
        nsigs = ef.signals_in_file

        # again know/assume that this is uniform sampling across signals
        fs0 = ef.samplefrequency(0)
        signal_frequency_array = ef.get_signal_freqs()
        dfs = np.diff(signal_frequency_array)
        dfs_ind = np.where(dfs != 0.0)
        dfs_ind = dfs_ind[0]
        last_ind = 0
        for dd in dfs_ind + 1:
            print("block:", signal_frequency_array[last_ind:dd])
            last_ind = dd
        print("last block:", signal_frequency_array[last_ind:])

        print("where does sampling rate change?", np.where(dfs != 0.0))
        print("elements:", signal_frequency_array[np.where(dfs != 0.0)])
        print("signal_frequency_array::\n", repr(signal_frequency_array))
        print("len(signal_frequency_array):", len(signal_frequency_array))

        assert all(signal_frequency_array[:-3] == fs0)

        nsamples0 = ef.samples_in_file(0)  # samples per channel
        print('nsigs=%s, fs0=%s, nsamples0=%s\n' % (nsigs, fs0, nsamples0))

        num_samples_per_signal = ef.get_samples_per_signal()  # np array
        print("num_samples_per_signal::\n", repr(num_samples_per_signal), '\n')

        # assert all(num_samples_per_signal == nsamples0)

        file_duration_sec = ef.file_duration_seconds
        #print("file_duration_sec", repr(file_duration_sec))

        # Note that all annotations except the top row must also specify a duration.

        # long long onset; /* onset time of the event, expressed in units of 100
        #                     nanoSeconds and relative to the starttime in the header */

        # char duration[16]; /* duration time, this is a null-terminated ASCII text-string */

        # char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; /* description of the
        #                             event in UTF-8, this is a null term string of max length 512*/

        # start("x.y"), end, char[20]
        # annotations = ef.read_annotations_as_array() # get numpy array of
        # annotations

        annotations_b = ef.read_annotations_b_100ns_units()

        # print("annotations_b::\n")
        # pprint.pprint(annotations_b)  # get list of annotations

        signal_text_labels = ef.get_signal_text_labels()
        print("signal_text_labels::\n")
        pprint.pprint(signal_text_labels)
        print("normalized text labels::\n")
        signal_text_labels_lpch_normalized = [
            normalize_lpch_signal_label(label) for label in signal_text_labels
        ]
        pprint.pprint(signal_text_labels_lpch_normalized)

        # ef.recording_additional

        # print()
        signal_digital_mins = np.array(
            [ef.digital_min(ch) for ch in range(nsigs)])
        signal_digital_total_min = min(signal_digital_mins)

        print("digital mins:", repr(signal_digital_mins))
        print("digital total min:", repr(signal_digital_total_min))

        signal_digital_maxs = np.array(
            [ef.digital_max(ch) for ch in range(nsigs)])
        signal_digital_total_max = max(signal_digital_maxs)

        print("digital maxs:", repr(signal_digital_maxs))
        #print("digital total max:", repr(signal_digital_total_max))

        signal_physical_dims = [
            ef.physical_dimension(ch) for ch in range(nsigs)
        ]
        # print('signal_physical_dims::\n')
        # pprint.pprint(signal_physical_dims)
        #print()

        signal_physical_maxs = np.array(
            [ef.physical_max(ch) for ch in range(nsigs)])

        #print('signal_physical_maxs::\n', repr(signal_physical_maxs))

        signal_physical_mins = np.array(
            [ef.physical_min(ch) for ch in range(nsigs)])

        #print('signal_physical_mins::\n', repr(signal_physical_mins))

        # this don't seem to be used much so I will put at end
        signal_prefilters = [ef.prefilter(ch).strip() for ch in range(nsigs)]
        #print('signal_prefilters::\n')
        # pprint.pprint(signal_prefilters)
        #print()
        signal_transducers = [ef.transducer(ch).strip() for ch in range(nsigs)]
        #print('signal_transducers::\n')
        #pprint.pprint(signal_transducers)

        if not header[
                'patient_name']:  # iassume is "EDF" file so need to split patient info
            try:
                s = ef.patient
                print('local subject:', s)

                patientcode, gender, dob, name, age_str = s.split(
                )  # the age_str seems illegal per edfplus
                print("try this:")

                header['patient_name'] = name
                header['birthdate_date'] = dob
                header['gender'] = gender
                header['patient_additional'] = age_str
                header['patientcode'] = patientcode
            except:
                pass
            try:
                s = ef.patient
                ss = s.split()
                if len(ss) > 0:
                    header['patient_name'] = ss[0]
                header['patient_additional'] = s
            except:
                pass

        with eeghdf.EEGHDFWriter(outfn, 'w') as eegf:
            eegf.write_patient_info(
                patient_name=header['patient_name'],
                patientcode=header['patientcode'],
                gender=header['gender'],
                birthdate_isostring=header['birthdate_date'],
                # gestational_age_at_birth_days
                # born_premature
                patient_additional=header['patient_additional'])

            signal_text_labels_lpch_normalized = [
                normalize_lpch_signal_label(label)
                for label in signal_text_labels
            ]

            rec = eegf.create_record_block(
                record_duration_seconds=header['file_duration_seconds'],
                start_isodatetime=str(header['start_datetime']),
                end_isodatetime=str(header['end_datetime']),
                number_channels=header['signals_in_file'],
                num_samples_per_channel=nsamples0,
                sample_frequency=fs0,
                signal_labels=signal_text_labels_lpch_normalized,
                signal_physical_mins=signal_physical_mins,
                signal_physical_maxs=signal_physical_maxs,
                signal_digital_mins=signal_digital_mins,
                signal_digital_maxs=signal_digital_maxs,
                physical_dimensions=signal_physical_dims,
                patient_age_days=age.total_seconds() / 86400.0,
                signal_prefilters=signal_prefilters,
                signal_transducers=signal_transducers,
                technician=header['technician'],
                studyadmincode=header['studyadmincode'])

            eegf.write_annotations_b(
                annotations_b)  # may be should be called record annotations

            edfblock_itr = edf_block_iter_generator(
                ef,
                nsamples0,
                100 * ef.samples_in_datarecord(0) * header[
                    'signals_in_file'],  # samples_per_chunk roughly 100 datarecords at a time
                dtype='int32')

            signals = eegf.stream_dig_signal_to_record_block(rec, edfblock_itr)

        return True, validator  # we succeeded