AEDAT 3.1
The file starts with several required header lines, as specified here. The version header line is always the first one, followed by the 3.1 format header line, followed by any others and last the header end line.
After the header, a series of typed event packets, which contain in turn all the various events, are written out.
All integer data and fields are always signed and little-endian. This is a departure from previous AEDAT formats, motivated by the fact all the systems we support, currently x86(_64) and ARM, are in fact native little-endian systems, and doing so avoids unnecessary conversion operations.
Header Lines
Version header line (required): described here, always the first header line. Specifically, the line is:
#!AER-DAT3.1\r\n
Format header line (required): follows right after the version line, looking like this:
#Format: <FORMAT>\r\n.
The Format header line describes how the event packets have to be interpreted later on, allowing for optimizations and extensions to be added as needed. Possible formats are: RAW (ID=0x00, default).
Source Identifier header line (required): human-readable identifiers for all event source IDs present in the file are a mandatory part of the header. The corresponding header line shall look like this:
#Source <ID>: <DESCRIPTION>\r\n
If multiple sources are present, they must be placed in increasing order by numerical ID (0, 1, 2, 3, …). The description part must be an element from the list of supported devices. When re-logging or re-transmitting data, new source headers have to be created representing the new file or network source. The old source headers have to be preserved always, by adding a ‘-’ (minus) sign in front of them.
Example: #-Source 0: DVS128\r\n
Start Time header line (required): this header line encodes the time at which we started transmitting or logging data. The format is the following:
#Start-Time: %Y-%m-%d %H:%M:%S (TZ%z)\r\n
Time is encoded according to the C strftime() function, see ‘man strftime’.
End of header line (required): follows right after all the other header lines, looking like this:
#!END-HEADER\r\n
This allows to clearly determine where the file header ends and data starts.
Event Packets
Each event packet is made up of a common header, followed by its specific event data.
This is not the same header as above, which is placed at the start of a file!
This header is specific to each and every event packet.
Header
The common header has a constant size of 28 bytes and the following format:
Bytes |
Meaning |
Description |
---|---|---|
0-1 |
eventType |
Numerical type ID, unique to each event type (see ‘Event Types’ table). |
2-3 |
eventSource |
Numerical source ID, identifies who generated the events inside a system. |
4-7 |
eventSize |
Size of one event in bytes. |
8-11 |
eventTSOffset |
Offset from the start of an event, in bytes, at which the main 32 bit time-stamp can be found. |
12-15 |
eventTSOverflow |
Overflow counter for the standard 32bit event time-stamp. Used to generate the 64 bit time-stamp. |
16-19 |
eventCapacity |
Maximum number of events this packet can store. **This always equals eventNumber in files and streams, it can only have a different value for in-memory packets. |
20-23 |
eventNumber |
Total number of events present in this packet (valid + invalid). |
24-27 |
eventValid |
Total number of valid events present in this packet. |
By multiplying eventCapacity with eventSize, and adding the 28 bytes of header size, you can quickly and precisely calculate the total size of an event packet.
Ordering
Event packets must be ordered in such a way to guarantee timestamp monotonicity. This means that for all packets of a same type and source, the timestamps must always be monotonically increasing. Further, between packets of different types belonging to the same source, the main timestamp of the first event decides the order in which packets should be written. If this timestamp is equal between different packets, they can be ordered by increasing event type ID, but this is not a requirement, only a suggestion.
Timestamp monotonicity does not need to be guaranteed globally between multiple sources, as any one of them can operate on different time-scales. No order is enforced between sources.
While this ordering requires some additional processing when writing, it greatly simplifies reading, since one always just has to read up to the next packet with a greater first timestamp than whatever timestamp one is interested in, and is guaranteed to have seen all relevant packets with events up to that point.
The FRAME_EVENT packet type has four timestamps defined. Of these, “End of Frame” is considered the main timestamp for the purpose of ordering. More generically, the timestamp that is indicated by the ‘eventTSOffset’ header field is the one relevant for ordering.
If timestamp reset events occur during a recording (because of device synchronisation or manual reset), then packet timestamp order is no longer monotonic as subsequent timestamps start again from zero. A timestamp reset event of type SPECIAL_EVENT will indicate such a reset clearly.
Events
The first 100 event type IDs are reserved for expansion of this format. If you create event types within a private distribution, we recommend that you number them from 100 upwards.
The following event types are supported by default:
Event ID |
Event |
Description |
---|---|---|
0 |
SPECIAL_EVENT |
Encodes special occurrences, such as timestamp related notifications or external input events. |
1 |
POLARITY_EVENT |
Contains change information, with an X/Y address and an ON/OFF polarity. The (0, 0) address is in the upper left corner (standard computer graphics format). |
2 |
FRAME_EVENT |
Encodes intensity frames, like you would get from a normal APS camera. It supports multiple channels for color, as well as multiple Regions of Interest (ROI). The (0, 0) pixel is in the upper left corner (standard computer graphics format). |
3 |
IMU6_EVENT |
Contains data coming from the Inertial Measurement Unit chip, with the 3-axes accelerometer and 3-axes gyroscope. Temperature is also included. |
4 |
IMU9_EVENT |
Contains data coming from the Inertial Measurement Unit chip, with the 3-axes accelerometer and 3-axes gyroscope. Temperature is also included. Further, 3-axes from the magnetometer are included, which can be used to get a compass-like heading. |
12 |
SPIKE_EVENT |
Encodes events from a Dynap-se chip. This event contains information about which chipid generated the event, as well as which core id and which neuron. These addresses are available if the user configure the SRAM of the Dynap-se to route out spikes. Therefore the user can mask or route devices depending on the routing scheme that he decides to use. |
Further, the first bit (bit 0) of the first byte of any event is reserved to be a validity bit. This bit is used to mark whether an event is still valid or not, and can be used to efficiently filter out events from a packet. ‘0’ in the 0th bit of the first byte means invalid, ‘1’ means valid. This way zeroing-out an event packet sets all its events to invalid. Care must be taken to put the field containing the validity mark always as the first member of an event.
Also, to generate the full 64 bit timestamp, which doesn’t suffer from wrap-around problems, the packet-level 32 bit timestamp (eventTSOverflow) and the event-level 32 bit timestamp have to be composed as follows:
fullTS = (packet.eventTSOverflow << 31) | event.timestamp
(The shift is of 31 bits rather than 32 because of the signed representation).
The various event types and their precise encoding are described in the following sections.
Special Event
Bytes |
Meaning |
Description |
---|---|---|
0-3 |
32 bit data |
Holds information on the special event. |
4-7 |
32 bit timestamp |
Event-level microsecond timestamp. |
Bytes 0-3 are divided in the following way:
Bits |
Description |
---|---|
0 |
Validity mark |
1-7 |
Type of special event (up to 128 types supported) |
8-31 |
Optional data (up to 24 bits) |
Currently, the following special event types are defined:
Type ID |
Type |
Description |
---|---|---|
0 |
TIMESTAMP_WRAP |
A 32 bit timestamp wrap occurred. No ‘optional data’ present. |
1 |
TIMESTAMP_RESET |
A timestamp reset occurred. No ‘optional data’ present. Note: Timestamp reset will have the highest possible timestamp value, to ensure it is always the last event of an event stream, and acts thus as a separator between the old and the new event time stream. |
2 |
EXTERNAL_INPUT_RISING_EDGE |
A rising edge was detected (External Input module on device). No ‘optional data’ present. |
3 |
EXTERNAL_INPUT_FALLING_EDGE |
A falling edge was detected (External Input module on device). No ‘optional data’ present. |
4 |
EXTERNAL_INPUT_PULSE |
A pulse was detected (External Input module on device). No ‘optional data’ present. |
5 |
DVS_ROW_ONLY |
A DVS row-only event was detected (a row address without any following column addresses). ‘Optional data’ is present, encoding the address of the row that generated this DVS row-only event. |
6 |
EXTERNAL_INPUT1_RISING_EDGE |
A rising edge was detected (External Input module on device, optional Detector 1). No ‘optional data’ present. |
7 |
EXTERNAL_INPUT1_FALLING_EDGE |
A falling edge was detected (External Input module on device, optional Detector 1). No ‘optional data’ present. |
8 |
EXTERNAL_INPUT1_PULSE |
A pulse was detected (External Input module on device, optional Detector 1). No ‘optional data’ present. |
9 |
EXTERNAL_INPUT2_RISING_EDGE |
A rising edge was detected (External Input module on device, optional Detector 2). No ‘optional data’ present. |
10 |
EXTERNAL_INPUT2_FALLING_EDGE |
A falling edge was detected (External Input module on device, optional Detector 2). No ‘optional data’ present. |
11 |
EXTERNAL_INPUT2_PULSE |
A pulse was detected (External Input module on device, optional Detector 2). No ‘optional data’ present. |
12 |
EXTERNAL_GENERATOR_RISING_EDGE |
A rising edge was generated (External Input Generator module on device), and an event injected to show this. No ‘optional data’ present. |
13 |
EXTERNAL_GENERATOR_FALLING_EDGE |
A falling edge was generated (External Input Generator module on device), and an event injected to show this. No ‘optional data’ present. |
14 |
APS_FRAME_START |
An APS frame capture has started (Frame Event will follow). No ‘optional data’ present. |
15 |
APS_FRAME_END |
An APS frame capture has completed (Frame Event is alongside). No ‘optional data’ present. |
16 |
APS_EXPOSURE_START |
An APS frame exposure has started (Frame Event will follow). No ‘optional data’ present. |
17 |
APS_EXPOSURE_END |
An APS frame exposure has completed (Frame Event will follow). No ‘optional data’ present. |
Polarity Event
Bytes |
Meaning |
Description |
---|---|---|
0-3 |
32 bit data |
Holds information on the polarity (luminosity change) event. |
4-7 |
32 bit timestamp |
Event-level microsecond timestamp. |
Bytes 0-3 are divided in the following way:
Bits |
Description |
---|---|
0 |
Validity mark |
1 |
Polarity (luminosity change): ‘1’ means increase (ON), ‘0’ means decrease (OFF). |
2-16 |
Y event address, up to 15 bits. (0, 0) in upper left corner of screen. |
17-31 |
X event address, up to 15 bits. (0, 0) in upper left corner of screen. |
Frame Event
Bytes |
Meaning |
Description |
---|---|---|
0-3 |
32 bit data |
Holds information on the frame event. |
4-7 |
32 bit Start of Frame Capture timestamp |
Event-level microsecond Start of Frame Capture timestamp. |
8-11 |
32 bit End of Frame Capture timestamp |
Event-level microsecond End of Frame Capture timestamp. NOTE: This timestamp is considered the primary timestamp for the purpose of ordering packets. |
12-15 |
32 bit Start of Exposure timestamp |
Event-level microsecond Start of Exposure timestamp. |
16-19 |
32 bit End of Exposure timestamp |
Event-level microsecond End of Exposure timestamp. |
20-23 |
X length |
X axis length in pixels. |
24-27 |
Y length |
Y axis length in pixels. |
28-31 |
X position |
X axis position (upper left offset) in pixels. |
32-35 |
Y position |
Y axis position (upper left offset) in pixels. |
36-End of Event |
Pixels |
Pixel array, 16 bit unsigned integers, normalized to 16 bit depth. Values represent intensity at that pixel and are ready for direct display. First pixel (0, 0) is in upper left corner of screen. Pixels are laid out row by row (increasing X axis), going from top to bottom (increasing Y axis). While the pixel array goes on until the end of the Frame event, only the pixels up to (‘X length’ * ‘Y length’ * ‘Channel number’) are actually valid and contain relevant data. The rest have a value of zero and should not be accessed. |
Bytes 0-3 are divided in the following way:
Bits |
Description |
---|---|
0 |
Validity mark |
1-3 |
Color channels number, to track multiple color channels, for example RGB. Valid values are: GRAYSCALE(1), RGB(3) and RGBA(4). |
4-7 |
Color filter information, used for interpolating color images (demosaicing). Valid values are: MONO(0), RGBG(1), GRGB(2), GBGR(3), BGRG(4), RGBW(5), GRWB(6), WBGR(7), BWRG(8). |
8-14 |
ROI (Region of Interest) identifier (up to 128). |
15-31 |
Reserved for future expansion. |
A frame is considered to be one event - a “frame event”. A frame packet may contain 1 or more frame events. Multiplying eventSize by eventCapacity still gives the length of the data portion of the packet in bytes.
The Frame event is slightly different in that it doesn’t have a constant, fixed size across all events, due to the pixel data which may vary due to ROI readouts or different resolutions.
Within a Frame event packet, all Frame events do have the same, constant size, as given by the eventSize field in the event packet header. This is as expected and follows the usual scheme.
As such, it’s a simple matter to look at the eventSize field of a Frame event packet’s header to figure out the exact size of a Frame event for that particular packet, and thus where each Frame event begins.
Within a Frame event, only pixels up to (‘X length’ * ‘Y length’ * ‘Channel number’) can be accessed with the expectation of having valid values. There might be more pixels than that, determined by how much memory was allocated for the Frame event, but those will all be zero, if they do exist.
Frame Events can directly be used with standard libraries such as OpenCV. For example the following code can be used to generate an OpenCV Mat ‘frameMat’ from a Frame Event ‘f’, sharing the same pixel array memory:
Size frameSize(caerFrameEventGetLengthX(f),
caerFrameEventGetLengthY(f));
Mat frameMat(frameSize,
CV_16UC(caerFrameEventGetChannelNumber(f)),
caerFrameEventGetPixelArrayUnsafe(f));
IMU 6-axes Event
The X, Y and Z axes are referred to the camera plane. X increases to the right, Y going up and Z towards where the lens is pointing. Rotation for the gyroscope is counter-clockwise along the increasing axis, for all three axes.
Bytes |
Meaning |
Description |
---|---|---|
0-3 |
32 bit info |
Holds information on the special event. This is needed right now only to hold the validity mark, and is sized to 4 bytes for performance/alignment reasons. |
4-7 |
32 bit timestamp |
Event-level microsecond timestamp. |
8-11 |
accel_x (float) |
Acceleration in the X axis, measured in g (9.81m/s²). |
12-15 |
accel_y (float) |
Acceleration in the Y axis, measured in g (9.81m/s²).. |
16-19 |
accel_z (float) |
Acceleration in the Z axis, measured in g (9.81m/s²). |
20-23 |
gyro_x (float) |
Rotation in the X axis, measured in °/s. |
24-27 |
gyro_y (float) |
Rotation in the Y axis, measured in °/s. |
28-31 |
gyro_z (float) |
Rotation in the Z axis, measured in °/s. |
32-35 |
temp (float) |
Temperature, measured in °C. |
Bytes 0-3 are divided in the following way:
Bits |
Description |
---|---|
0 |
Validity mark |
1-31 |
Reserved for future expansion |
All floating point values are in IEEE 754-2008 binary32 format, little endian.
IMU 9-axes Event
The X, Y and Z axes are referred to the camera plane. X increases to the right, Y going up and Z towards where the lens is pointing. Rotation for the gyroscope is counter-clockwise along the increasing axis, for all three axes.
Bytes |
Meaning |
Description |
---|---|---|
0-3 |
32 bit info |
Holds information on the IMU 6-axes event. This is needed right now only to hold the validity mark, and is sized to 4 bytes for performance/alignment reasons. |
4-7 |
32 bit timestamp |
Event-level microsecond timestamp. |
8-11 |
accel_x (float) |
Acceleration in the X axis, measured in g (9.81m/s²). |
12-15 |
accel_y (float) |
Acceleration in the Y axis, measured in g (9.81m/s²).. |
16-19 |
accel_z (float) |
Acceleration in the Z axis, measured in g (9.81m/s²). |
20-23 |
gyro_x (float) |
Rotation in the X axis, measured in °/s. |
24-27 |
gyro_y (float) |
Rotation in the Y axis, measured in °/s. |
28-31 |
gyro_z (float) |
Rotation in the Z axis, measured in °/s. |
32-35 |
temp (float) |
Temperature, measured in °C. |
36-39 |
comp_x (float) |
Magnetometer X axis, measured in µT (magnetic flux density). |
40-43 |
comp_y (float) |
Magnetometer Y axis, measured in µT (magnetic flux density). |
44-47 |
comp_z (float) |
Magnetometer Z axis, measured in µT (magnetic flux density). |
Bytes 0-3 are divided in the following way:
Bits |
Description |
---|---|
0 |
Validity mark |
1-31 |
Reserved for future expansion |
All floating point values are in IEEE 754-2008 binary32 format, little endian.
Spike (Dynap-SE) Event
Bytes |
Meaning |
Description |
---|---|---|
0-3 |
32 bit data |
Holds information on the spike event from the Dynap-se device. |
4-7 |
32 bit timestamp |
Event-level microsecond timestamp. |
Bytes 0-3 are divided in the following way:
Bits |
Description |
---|---|
0 |
Validity mark |
1-5 |
Core id, this is the virtual_core_id programmed in the SRAM cell of the Dynap-se (bits <28:29>) |
6-11 |
Chip id, this is the destination_core_id programmed in the SRAM cell of the Dynap-se (bits <18:21>) |
12-31 |
Neuron id, the source neuron address |
Formats
Here the specifics about the event packet encoding formats, as given by the Format header line:
RAW (ID=0x00)
A direct dump of the memory holding an event packet. No processing is needed at input, allocating the right amount of memory and reading the bytes into it directly is sufficient.