Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The official format specification can be found on GitHub as raw HTML files. We've adapted it for use with Open Ephys in the following wayby extending some base classes of the NWB specification to hold extra data that might be provided by the software. Extension files for the official NWB API will be provided as per the standard. The resulting format is as follows:

Open Ephys NWB File Structure (based on version 1.0.

...

6)

(NOTE: The current version of the NWB record format on the development branch of Open Ephys is untested and unfinished so it might have bugs or fields not completely complying with the specification. A current known issue is that the messages and event timestamps are not saved in seconds but in sample numbers. The value in seconds can be manually obtained by dividing the sample number by the relevant source sample rate)

...

)

...

Top-level groups (always created):

/acquisition

...

/identifier: from text fields in recording options (text)
/nwb_version: 'NWB-1.0.4_beta6' (text)
/session_description: <blank string> (text)

...

    ./source: processor name + number + subprocessor number if needed (text attr)
    ./help: 'Stores acquired voltage data from extracellular recordings' (text attr)

...

        ./unit: 'seconds' (text attr)
 

For writing spike data, we use the NWB SpikeEventSeries:

/acquisition/timeseries/spikes/electrode<***>/recording<**>
    ./ancestry: ['TimeSeries', 'SpikeEventSeries'] (text array attr)
    ./comments: <empty> (text attr)
    ./description: electrode name (text attr)
    ./neurodata_type: 'TimeSeries' (text attr)
    ./source: processor name + number    ./oe_extra_info
        ./schema_id: 'openephys:extra_info/' (text attr)
        ./channel<****>
            ./schema_id: 'openephys:<channel_info>/'
            ./name: channel info object name (text attr)
    ./help: 'Snapshorts of spike events from data' (attr, text)
    ./data: X spikes x Y channels x Z samples (int16 array)
        ./conversion: bitVolts (float32 attr)
        ./resolution: 1/2^16 * bitVolts (float32 attr)
        ./unit: 'volt' (text attr)
    ./timestamps: X timestamps relative to experiment start time (float64 array)
        ./interval: 1 (int32 attr)
        ./unit: 'seconds' (text attr)
 

For writing messages, we use the NWB AnnotationSeries:

/acquisition/timeseries/messages/recording<**>
    ./ancestry: ['TimeSeries', 'AnnotationSeries'] (text array attr)
    ./comments: <empty> (text attr)
    ./description: <empty> (text attr)
    ./neurodata_type: 'TimeSeries' (text attr)
    ./source: 'Message center' (text attr)
    ./help: 'Time-stamped annotations about an experiment' (attr, text)
    ./data: N messages as text array
        ./conversion: 'NaN' (float32 attr)
        ./resolution: 'NaN' (float32 attr)
        ./unit: 'n/a' (text attr)
    ./num_samples: N (int32, stored at end of recording)
    ./timestamps: N timestamps relative to experiment start time (float64 array)
        ./interval: 1 (int32 attr)
        ./unit: 'seconds' (text attr)
 

For writing events, we use the NWB IntervalSeries:

/acquisition/timeseries/events/recording<**>
    ./ancestry: ['TimeSeries', 'IntervalSeries'] (text array attr)
    ./comments: <empty> (text attr)
    ./description: <empty> (text attr)
    ./neurodata_type: 'TimeSeries' (text attr)
    ./source: 'All processors' (text attr)
    ./help: 'Stores the start and stop times for events' (attr, text)
    ./data: N events [+(channel#) for event 'on', -(channel#) for event 'off'] (int8 array)
        ./conversion: 'NaN' (float32 attr)
        ./resolution: 'NaN' (float32 attr)
        ./unit: 'n/a' (text attr)
    ./control: N processor IDs for each event (uint8 array)
    ./num_samples: N (int32, stored at end of recording)
    ./timestamps: N timestamps relative to experiment start time (float64 array)
        ./interval: 1 (int32 attr)
        ./unit: 'seconds'            ./description: channel info object description (text attr)
            ./identifier: channel info object identifier (text attr)
            ./source_index: index of this channel in source processor (uint16 attr)
            ./source_type_index: index of this type of channel in source processor (uint16 attr)
            ./channel_metadata
                ./schema_id: 'openephys:metadata/' (text attr)
                ./<metadata name>: L values or text string
                    ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                    ./description: metadata description (text attr)
                    ./identifier: metadata identifier (text attr)
 

For writing spike data, we use the NWB SpikeEventSeries:

/acquisition/timeseries/spikes/electrode<***>/recording<**>
    ./ancestry: ['TimeSeries', 'SpikeEventSeries'] (text array attr)
    ./comments: <empty> (text attr)
    ./description: electrode name (text attr)
    ./neurodata_type: 'TimeSeries' (text attr)
    ./source: processor name + number + subprocessor number if needed (text attr)
    ./help: 'Snapshorts of spike events from data' (attr, text)
    ./data: X spikes x Y channels x Z samples (int16 array)
        ./conversion: bitVolts (float32 attr)
        ./resolution: 1/2^16 * bitVolts (float32 attr)
        ./unit: 'volt' (text attr)
    ./timestamps: X timestamps relative to experiment start time (float64 array)
        ./interval: 1 (int32 attr)
        ./unit: 'seconds' (text attr)
    ./oe_extra_info
        ./schema_id: 'openephys:<channel_info>/'
        ./name: channel info object name (text attr)
        ./description: channel info object description (text attr)
        ./identifier: channel info object identifier (text attr)
        ./source_index: index of this channel in source processor (uint16 attr)
        ./source_type_index: index of this type of channel in source processor (uint16 attr)
        ./channel_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name>: L values or text string
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)
        ./spike_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name> X spikes x L values or X spikes strings
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)
 

For writing messages, we use the NWB AnnotationSeries:

/acquisition/timeseries/messages/recording<**>/text<*****>
    ./ancestry: ['TimeSeries', 'AnnotationSeries'] (text array attr)
    ./comments: <empty> (text attr)
    ./description: channel info object description (text attr)
    ./neurodata_type: 'TimeSeries' (text attr)
    ./source: processor name + number + subprocessor number if needed (text attr)
    ./help: 'Time-stamped annotations about an experiment' (attr, text)
    ./data: N messages as text array
        ./conversion: 'NaN' (float32 attr)
        ./resolution: 'NaN' (float32 attr)
        ./unit: 'n/a' (text attr)
    ./control: N uint8 representing virtual channel numbers. usually all zeros.
    ./num_samples: N (int32, stored at end of recording)
    ./timestamps: N timestamps relative to experiment start time (float64 array)
        ./interval: 1 (int32 attr)
        ./unit: 'seconds' (text attr)
    ./oe_extra_info
        ./schema_id: 'openephys:<channel_info>/'
        ./name: channel info object name (text attr)
        ./description: channel info object description. Same as base class description (text attr)
        ./identifier: channel info object identifier (text attr)
        ./source_index: index of this channel in source processor (uint16 attr)
        ./source_type_index: index of this type of channel in source processor (uint16 attr)
        ./channel_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name>: L values or text string
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)
        ./spike_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name>  N x L values or N strings
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)
 

For writing TTL events, we use a custom derived version of the NWB IntervalSeries called TTLSeries:

/acquisition/timeseries/events/recording<**>/ttl<*****>
    ./ancestry: ['TimeSeries', 'IntervalSeries', 'TTLSeries'] (text array attr)
    ./comments: <empty> (text attr)
    ./description: channel info object description (text attr)
    ./neurodata_type: 'TimeSeries' (text attr)
    ./source: processor name + number + subprocessor number if needed (text attr)
    ./help: 'Stores the start and stop times for TTL events' (attr, text)
    ./data: N events [+(channel#) for event 'on', -(channel#) for event 'off'] (int8 array)
        ./conversion: 'NaN' (float32 attr)
        ./resolution: 'NaN' (float32 attr)
        ./unit: 'n/a' (text attr)
    ./control: N uint8 representing virtual channel numbers. Same as absolute value of data
    ./num_samples: N (int32, stored at end of recording)
    ./timestamps: N timestamps relative to experiment start time (float64 array)
        ./interval: 1 (int32 attr)
        ./unit: 'seconds' (text attr)
    ./oe_extra_info
        ./schema_id: 'openephys:<channel_info>/'
        ./name: channel info object name (text attr)
        ./description: channel info object description. Same as base class description (text attr)
        ./identifier: channel info object identifier (text attr)
        ./source_index: index of this channel in source processor (uint16 attr)
        ./source_type_index: index of this type of channel in source processor (uint16 attr)
        ./channel_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name>: L values or text string
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)
        ./event_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name>  N x L values or N strings
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)


For writing Binary events, we use a custom derived version of the NWB  Timeseries called BinarySeries:

/acquisition/timeseries/events/recording<**>/binary<*****>
    ./ancestry: ['TimeSeries', 'BinarySeries'] (text array attr)
    ./comments: <empty> (text attr)
    ./description: channel info object description (text attr)
    ./neurodata_type: 'TimeSeries' (text attr)
    ./source: processor name + number + subprocessor number if needed (text attr)
    ./help: 'Stores arbitrary binary data' (attr, text)
    ./data: N events x L lenth of data, any kind of numeric type.
        ./conversion: 'NaN' (float32 attr)
        ./resolution: 'NaN' (float32 attr)
        ./unit: 'n/a' (text attr)
    ./control: N uint8 representing virtual channel numbers. Usually all zeros.
    ./num_samples: N (int32, stored at end of recording)
    ./timestamps: N timestamps relative to experiment start time (float64 array)
        ./interval: 1 (int32 attr)
        ./unit: 'seconds' (text attr)
    ./oe_extra_info
        ./schema_id: 'openephys:<channel_info>/'
        ./name: channel info object name (text attr)
        ./description: channel info object description. Same as base class description (text attr)
        ./identifier: channel info object identifier (text attr)
        ./source_index: index of this channel in source processor (uint16 attr)
        ./source_type_index: index of this type of channel in source processor (uint16 attr)
        ./channel_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name>: L values or text string
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)
        ./event_metadata
            ./schema_id: 'openephys:metadata/' (text attr)
            ./<metadata name>  N x L values or N strings
                ./schema_id: 'openephys:<text_metadata>' or 'openephys:<number_metadata>' (text attr)
                ./description: metadata description (text attr)
                ./identifier: metadata identifier (text attr)


* = processorID_subprocessorID (e.g., 101_1, 102_1, etc.)

...

*** = index of electrode (1, 2, 3, etc.)

****=index of recorded channel

*****=index of recorded event of the specific type


Rules for creating new files, versus creating new groups:

...