Beispiel #1
0
def make_log(raw, condition=64):  # pragma: no cover
    import warnings
    warnings.warn("This code is not tested!")
    codes = read_raw(maybe_open(raw), np.float64, True)[3]
    log = []
    for i in codes.nonzero()[0]:
        log.append(
            struct.pack("<HHHBB", codes[i], (i & 0xffff0000) >> 16, i & 0xffff,
                        condition, 0))
        if codes[i] in (PAUSE_CODE, DELETE_CODE):
            condition += 1
    return "".join(log)
Beispiel #2
0
def make_log(raw, condition=64): # pragma: no cover
    import warnings; warnings.warn("This code is not tested!")
    codes = read_raw(maybe_open(raw), np.float64, True)[3]
    log = []
    for i in codes.nonzero()[0]:
        log.append(struct.pack("<HHHBB",
                               codes[i], (i & 0xffff0000) >> 16, i & 0xffff,
                               condition,
                               0))
        if codes[i] in (PAUSE_CODE, DELETE_CODE):
            condition += 1
    return "".join(log)
Beispiel #3
0
def read_log(file_like):
    fo = maybe_open(file_like)
    ticks = []
    events = []
    while True:
        event = fo.read(8)
        if not event:
            break
        (code, tick_hi, tick_lo, condition, flag) \
               = struct.unpack("<HHHBB", event)
        ticks.append(tick_hi << 16 | tick_lo)
        events.append((code, condition, flag))
    df = pandas.DataFrame(events, columns=["code", "condition", "flag"],
                          index=ticks)
    df["flag_data_error"] = np.asarray(df["flag"] & 0o100, dtype=bool)
    df["flag_rejected"] = np.asarray(df["flag"] & 0o40, dtype=bool)
    df["flag_polinv"] = np.asarray(df["flag"] & 0o20, dtype=bool)
    return df
Beispiel #4
0
def read_log(file_like):
    fo = maybe_open(file_like)
    ticks = []
    events = []
    while True:
        event = fo.read(8)
        if not event:
            break
        (code, tick_hi, tick_lo, condition, flag) \
               = struct.unpack("<HHHBB", event)
        ticks.append(tick_hi << 16 | tick_lo)
        events.append((code, condition, flag))
    df = pandas.DataFrame(events,
                          columns=["code", "condition", "flag"],
                          index=ticks)
    df["flag_data_error"] = np.asarray(df["flag"] & 0o100, dtype=bool)
    df["flag_rejected"] = np.asarray(df["flag"] & 0o40, dtype=bool)
    df["flag_polinv"] = np.asarray(df["flag"] & 0o20, dtype=bool)
    return df
Beispiel #5
0
def load_erpss(raw,
               log,
               calibration_events="condition == 0",
               lazy=True,
               calibrate=False,
               calibrate_half_width_ticks=5,
               calibrate_low_cursor_time=None,
               calibrate_high_cursor_time=None,
               calibrate_pulse_size=None,
               calibrate_polarity=1):
    dtype = np.float64

    metadata = {}
    if isinstance(raw, basestring):
        metadata["raw_file"] = os.path.abspath(raw)
    if isinstance(log, basestring):
        metadata["log_file"] = os.path.abspath(log)
    metadata["calibration_events"] = str(calibration_events)

    raw = maybe_open(raw)
    log = maybe_open(log)

    (fetcher, hz, channel_names, raw_codes, data,
     header_metadata) = read_raw(raw, dtype, lazy)
    metadata.update(header_metadata)
    if calibrate:
        units = "uV"
    else:
        units = "RAW"
    data_format = DataFormat(hz, units, channel_names)

    total_ticks = raw_codes.shape[0]

    raw_log_events = read_log(log)
    expanded_log_codes = np.zeros(raw_codes.shape, dtype=int)
    try:
        expanded_log_codes[raw_log_events.index] = raw_log_events["code"]
    except IndexError as e:
        raise ValueError("log file claims event at position where there is "
                         "no data: %s" % (e, ))
    # Sometimes people "delete" events by setting the high (sign) bit of the
    # code in the log file (e.g. with 'logpoke'). So we ignore this bit when
    # comparing log codes to raw codes -- mismatches here do not indicate an
    # error -- and then are careful to use the log codes, rather than the
    # raw codes, below.
    if np.any((expanded_log_codes & ~0x8000) != (raw_codes & ~0x8000)):
        raise ValueError("raw and log files have mismatched codes")
    del raw_codes
    del expanded_log_codes

    pause_events = (raw_log_events["code"] == PAUSE_CODE)
    delete_events = (raw_log_events["code"] == DELETE_CODE)
    break_events = pause_events | delete_events
    break_ticks = raw_log_events.index[break_events]
    # The pause/delete code appears at the last sample of the old era, so if
    # used directly, adjacent pause ticks give contiguous spans of recording
    # as (pause1, pause2]. (Confirmed by checking by hand in a real recording
    # that the data associated with the sample that has the pause code is
    # contiguous with the sample before, but not the sample after.)  Adding +1
    # to each of them then converts this to Python style [pause1, pause2)
    # intervals. There is a pause code at the last record of the file, but not
    # one at the first, so we add that in explicitly.
    break_ticks += 1
    span_edges = np.concatenate(([0], break_ticks))
    assert span_edges[0] == 0
    assert span_edges[-1] == total_ticks

    span_slices = [
        slice(span_edges[i], span_edges[i + 1])
        for i in xrange(len(span_edges) - 1)
    ]

    dataset = Dataset(data_format)
    for span_slice in span_slices:
        if lazy:
            lr = LazyRecspan(fetcher, dtype, len(channel_names),
                             span_slice.start, span_slice.stop)
            dataset.add_lazy_recspan(lr, span_slice.stop - span_slice.start,
                                     metadata)
        else:
            dataset.add_recspan(data[span_slice, :], metadata)

    span_starts = [s.start for s in span_slices]
    recspan_ids = []
    start_ticks = []
    for tick in raw_log_events.index:
        recspan_id = bisect.bisect(span_starts, tick) - 1
        span_slice = span_slices[recspan_id]
        span_start = span_slice.start
        span_stop = span_slice.stop
        assert span_start <= tick < span_stop
        recspan_ids.append(recspan_id)
        start_ticks.append(tick - span_start)
    stop_ticks = [tick + 1 for tick in start_ticks]
    dataset.add_events(recspan_ids, start_ticks, stop_ticks, raw_log_events)

    for delete_event in dataset.events_query({"code": DELETE_CODE}):
        delete_event.recspan_info["deleted"] = True

    for cal_event in dataset.events_query(calibration_events):
        for key in list(cal_event):
            del cal_event[key]
        cal_event["calibration_pulse"] = True

    if calibrate:
        for kwarg in [
                "calibrate_low_cursor_time", "calibrate_high_cursor_time",
                "calibrate_pulse_size"
        ]:
            if locals()[kwarg] is None:
                raise ValueError("when calibrating, %s= argument must be "
                                 "specified" % (kwarg, ))
        half_width = dataset.data_format.ticks_to_ms(
            calibrate_half_width_ticks)
        cal_vals = {}
        for which, cursor_time in [("low", calibrate_low_cursor_time),
                                   ("high", calibrate_high_cursor_time)]:
            # Round cursor to nearest tick
            cursor_tick = dataset.data_format.ms_to_ticks(cursor_time)
            cursor_time = dataset.data_format.ticks_to_ms(cursor_tick)
            erp = dataset.rerp("calibration_pulse",
                               cursor_time - half_width,
                               cursor_time + half_width,
                               "1",
                               all_or_nothing=True,
                               overlap_correction=False,
                               verbose=False)
            cal_vals[which] = erp.betas["Intercept"].mean()
        cal_diffs = cal_vals["high"] - cal_vals["low"]
        calibrate_pulse_size *= calibrate_polarity
        # For each channel, we want to multiply by a factor with units uV/raw
        # We have calibrate_pulse_size uV = cal_diffs raw
        cal_scaler = calibrate_pulse_size / cal_diffs
        dataset.transform(np.diagflat(np.asarray(cal_scaler)))

    return dataset
Beispiel #6
0
def load_erpss(raw, log, calibration_events="condition == 0",
               lazy=True,
               calibrate=False,
               calibrate_half_width_ticks=5,
               calibrate_low_cursor_time=None,
               calibrate_high_cursor_time=None,
               calibrate_pulse_size=None,
               calibrate_polarity=1):
    dtype = np.float64

    metadata = {}
    if isinstance(raw, basestring):
        metadata["raw_file"] = os.path.abspath(raw)
    if isinstance(log, basestring):
        metadata["log_file"] = os.path.abspath(log)
    metadata["calibration_events"] = str(calibration_events)

    raw = maybe_open(raw)
    log = maybe_open(log)

    (fetcher, hz, channel_names, raw_codes, data, header_metadata
     ) = read_raw(raw, dtype, lazy)
    metadata.update(header_metadata)
    if calibrate:
        units = "uV"
    else:
        units = "RAW"
    data_format = DataFormat(hz, units, channel_names)

    total_ticks = raw_codes.shape[0]

    raw_log_events = read_log(log)
    expanded_log_codes = np.zeros(raw_codes.shape, dtype=int)
    try:
        expanded_log_codes[raw_log_events.index] = raw_log_events["code"]
    except IndexError as e:
        raise ValueError("log file claims event at position where there is "
                         "no data: %s" % (e,))
    # Sometimes people "delete" events by setting the high (sign) bit of the
    # code in the log file (e.g. with 'logpoke'). So we ignore this bit when
    # comparing log codes to raw codes -- mismatches here do not indicate an
    # error -- and then are careful to use the log codes, rather than the
    # raw codes, below.
    if np.any((expanded_log_codes & ~0x8000) != (raw_codes & ~0x8000)):
        raise ValueError("raw and log files have mismatched codes")
    del raw_codes
    del expanded_log_codes

    pause_events = (raw_log_events["code"] == PAUSE_CODE)
    delete_events = (raw_log_events["code"] == DELETE_CODE)
    break_events = pause_events | delete_events
    break_ticks = raw_log_events.index[break_events]
    # The pause/delete code appears at the last sample of the old era, so if
    # used directly, adjacent pause ticks give contiguous spans of recording
    # as (pause1, pause2]. (Confirmed by checking by hand in a real recording
    # that the data associated with the sample that has the pause code is
    # contiguous with the sample before, but not the sample after.)  Adding +1
    # to each of them then converts this to Python style [pause1, pause2)
    # intervals. There is a pause code at the last record of the file, but not
    # one at the first, so we add that in explicitly.
    break_ticks += 1
    span_edges = np.concatenate(([0], break_ticks))
    assert span_edges[0] == 0
    assert span_edges[-1] == total_ticks

    span_slices = [slice(span_edges[i], span_edges[i + 1])
                   for i in xrange(len(span_edges) - 1)]

    dataset = Dataset(data_format)
    for span_slice in span_slices:
        if lazy:
            lr = LazyRecspan(fetcher, dtype, len(channel_names),
                             span_slice.start, span_slice.stop)
            dataset.add_lazy_recspan(lr, span_slice.stop - span_slice.start,
                                     metadata)
        else:
            dataset.add_recspan(data[span_slice, :], metadata)

    span_starts = [s.start for s in span_slices]
    recspan_ids = []
    start_ticks = []
    for tick in raw_log_events.index:
        recspan_id = bisect.bisect(span_starts, tick) - 1
        span_slice = span_slices[recspan_id]
        span_start = span_slice.start
        span_stop = span_slice.stop
        assert span_start <= tick < span_stop
        recspan_ids.append(recspan_id)
        start_ticks.append(tick - span_start)
    stop_ticks = [tick + 1 for tick in start_ticks]
    dataset.add_events(recspan_ids, start_ticks, stop_ticks,
                       raw_log_events)

    for delete_event in dataset.events_query({"code": DELETE_CODE}):
        delete_event.recspan_info["deleted"] = True

    for cal_event in dataset.events_query(calibration_events):
        for key in list(cal_event):
            del cal_event[key]
        cal_event["calibration_pulse"] = True

    if calibrate:
        for kwarg in ["calibrate_low_cursor_time",
                      "calibrate_high_cursor_time",
                      "calibrate_pulse_size"]:
            if locals()[kwarg] is None:
                raise ValueError("when calibrating, %s= argument must be "
                                 "specified" % (kwarg,))
        half_width = dataset.data_format.ticks_to_ms(calibrate_half_width_ticks)
        cal_vals = {}
        for which, cursor_time in [("low", calibrate_low_cursor_time),
                                   ("high", calibrate_high_cursor_time)]:
            # Round cursor to nearest tick
            cursor_tick = dataset.data_format.ms_to_ticks(cursor_time)
            cursor_time = dataset.data_format.ticks_to_ms(cursor_tick)
            erp = dataset.rerp("calibration_pulse",
                               cursor_time - half_width,
                               cursor_time + half_width,
                               "1",
                               all_or_nothing=True,
                               overlap_correction=False,
                               verbose=False)
            cal_vals[which] = erp.betas["Intercept"].mean()
        cal_diffs = cal_vals["high"] - cal_vals["low"]
        calibrate_pulse_size *= calibrate_polarity
        # For each channel, we want to multiply by a factor with units uV/raw
        # We have calibrate_pulse_size uV = cal_diffs raw
        cal_scaler = calibrate_pulse_size / cal_diffs
        dataset.transform(np.diagflat(np.asarray(cal_scaler)))

    return dataset