1
+ # Import necessary packages
1
2
import os
2
3
import numpy as np
3
4
import matplotlib .pyplot as plt
4
5
5
- # Load data from headstage64 tutorial workflow
6
- suffix = '0' ; # Change to match file names' suffix
7
- # Change this to the directory of your data. In this example, data's in the same directory as this data loading Python script
8
- data_directory = os .path .dirname (os .path .realpath (__file__ ))
9
- start_t = 1.0 # when to start plotting data (seconds)
10
- dur = 1.0 # duration of data to plot
6
+ #%% Set parameters for loading data
11
7
12
- plt .close ('all' )
8
+ suffix = 0 # Change to match filenames' suffix
9
+ data_directory = 'C:/Users/open-ephys/Documents/data/hs64' # Change to match files' directory
10
+ plot_num_channels = 10 # Number of channels to plot
11
+ start_t = 3.0 # Plot start time (seconds)
12
+ dur = 2.0 # Plot time duration (seconds)
13
+
14
+ # RHD2164 constants
15
+ ephys_uV_multiplier = 0.195
16
+ aux_uV_multiplier = 37.4
17
+ offset = 32768
18
+ num_channels = 64
19
+
20
+ #%% Load acquisition session data
13
21
14
- #%% Metadata
15
22
dt = {'names' : ('time' , 'acq_clk_hz' , 'block_read_sz' , 'block_write_sz' ),
16
23
'formats' : ('datetime64[us]' , 'u4' , 'u4' , 'u4' )}
17
24
meta = np .genfromtxt (os .path .join (data_directory , f'start-time_{ suffix } .csv' ), delimiter = ',' , dtype = dt , skip_header = 1 )
18
- print (f"Recording was started at { meta ['time' ]} GMT" )
19
-
20
- #%% RHD2164 ephys data
21
- start_t = 1.0 # when to start plotting data (seconds)
22
- dur = 1.0 # duration of data to plot
23
- plot_channel_offset_uV = 1000 # Vertical offset between each channel in the time series
24
-
25
- hs64 = {}
26
- hs64 ['time' ] = np .fromfile (os .path .join (data_directory , f'rhd2164-clock_{ suffix } .raw' ), dtype = np .uint64 ) / meta ['acq_clk_hz' ]
27
- hs64 ['ephys' ] = np .reshape (np .fromfile (os .path .join (data_directory , f'rhd2164-ephys_{ suffix } .raw' ), dtype = np .uint16 ), (- 1 , 64 ))
28
-
29
- # Make arrays for plotting
30
- b = np .bitwise_and (hs64 ['time' ] >= start_t , hs64 ['time' ] < start_t + dur )
31
- time = hs64 ['time' ][b ]
32
- rhd2164_ephys = hs64 ['ephys' ][b , :].astype (np .double )
33
-
34
- # Convert to uV and offset each channel by some plot_channel_offset_uV
35
- bit_depth = 16
36
- scalar = 0.195
37
- offset = (2 ** (bit_depth - 1 )) * scalar
38
- rhd2164_ephys = rhd2164_ephys * scalar - offset + np .arange (rhd2164_ephys .shape [1 ])[None , :] * offset / 4
39
-
40
- fig = plt .figure ()
41
- plt .plot (time , rhd2164_ephys , 'k' , linewidth = 0.25 )
42
- plt .tick_params (axis = 'y' , which = 'both' , left = False , right = False , labelleft = False )
43
- plt .xlabel ("time (sec)" )
44
- plt .ylabel ("channel" )
45
- plt .title ('RHD2164 Ephys Data' )
46
- fig .set_size_inches (5 ,8 )
47
- plt .tight_layout ()
25
+ print (f'Recording was started at { meta ["time" ]} GMT' )
26
+ print (f'Acquisition clock rate was { meta ["acq_clk_hz" ] / 1e6 } MHz' )
27
+
28
+ #%% Load RHD2164 data
48
29
49
- #%% RHD2164 aux data
50
- hs64 ['aux' ] = np .reshape (np .fromfile (os .path .join (data_directory , f'rhd2164-aux_{ suffix } .raw' ), dtype = np .uint16 ), (- 1 , 3 ))
30
+ rhd2164 = {}
51
31
52
- # Make arrays for plotting
53
- b = np .bitwise_and (hs64 ['time' ] >= start_t , hs64 ['time' ] < start_t + dur )
54
- time = hs64 ['time' ][b ]
55
- rhd2164_aux = hs64 ['aux' ][b , :].astype (np .double )
32
+ # Load RHD2164 clock data and convert clock cycles to seconds
33
+ rhd2164 ['time' ] = np .fromfile (os .path .join (data_directory , f'rhd2164-clock_{ suffix } .raw' ), dtype = np .uint64 ) / meta ['acq_clk_hz' ]
56
34
57
- # Convert to uV and offset each channel by some plot_channel_offset_uV
58
- scalar = 37.4
59
- rhd2164_aux_wave = (rhd2164_aux - 2 ** ( bit_depth - 1 )) * scalar
35
+ # Load and scale RHD2164 ephys data
36
+ ephys = np . reshape ( np . fromfile ( os . path . join ( data_directory , f'rhd2164-ephys_ { suffix } .raw' ), dtype = np . uint16 ), ( - 1 , num_channels ))
37
+ rhd2164 [ 'ephys_uV' ] = (ephys . astype ( np . float32 ) - offset ) * ephys_uV_multiplier
60
38
61
- plt .figure ()
62
- plt .plot (time , rhd2164_aux_wave )
63
- plt .xlabel ("time (sec)" )
64
- plt .ylabel ("channel" )
65
- plt .title ('RHD2164 Auxiliary Data' )
39
+ # Load and scale RHD2164 aux data
40
+ aux = np .reshape (np .fromfile (os .path .join (data_directory , f'rhd2164-aux_{ suffix } .raw' ), dtype = np .uint16 ), (- 1 , 3 ))
41
+ rhd2164 ['aux_uV' ] = (aux .astype (np .float32 ) - offset ) * aux_uV_multiplier
42
+
43
+ rhd2164_time_mask = np .bitwise_and (rhd2164 ['time' ] >= start_t , rhd2164 ['time' ] < start_t + dur )
44
+
45
+ #%% Load BNO055 data
66
46
67
- #%% Bno055
68
47
dt = {'names' : ('clock' , 'euler' , 'quat' , 'is_quat_id' , 'accel' , 'grav' , 'temp' ),
69
48
'formats' : ('u8' , '(1,3)f8' , '(1,4)f8' , '?' , '(1,3)f8' , '(1,3)f8' , 'f8' )}
70
49
bno055 = np .genfromtxt (os .path .join (data_directory , f'bno055_{ suffix } .csv' ), delimiter = ',' , dtype = dt )
71
50
51
+ # Convert clock cycles to seconds
72
52
bno055_time = bno055 ['clock' ] / meta ['acq_clk_hz' ]
73
53
74
- plt . figure ( )
54
+ bno055_time_mask = np . bitwise_and ( bno055_time >= start_t , bno055_time < start_t + dur )
75
55
76
- plt .subplot (231 )
77
- plt .plot (bno055_time , bno055 ['euler' ].squeeze ())
78
- plt .xlabel ("time (sec)" )
79
- plt .ylabel ("angle (deg.)" )
80
- plt .ylim (- 185 , 365 )
81
- plt .legend (['yaw' , 'pitch' , 'roll' ])
82
- plt .title ('Euler' )
56
+ #%% Load TS4231 data
83
57
84
- plt .subplot (232 )
85
- plt .plot (bno055_time , bno055 ['quat' ].squeeze ())
86
- plt .xlabel ("time (sec)" )
87
- plt .ylim (- 1.1 , 1.1 )
88
- plt .legend (['X' , 'Y' , 'Z' , 'W' ])
89
- plt .title ('Quaternion' )
58
+ # Load TS4231 data
59
+ dt = {'names' : ('clock' , 'position' ),
60
+ 'formats' : ('u8' , '(1,3)f8' )}
61
+ ts4231 = np .genfromtxt (os .path .join (data_directory , f'ts4231_{ suffix } .csv' ), delimiter = ',' , dtype = dt )
90
62
91
- plt .subplot (233 )
92
- plt .plot (bno055_time , bno055 ['accel' ].squeeze ())
93
- plt .xlabel ("time (sec)" )
94
- plt .ylabel ("accel. (m/s^2)" )
95
- plt .legend (['X' , 'Y' , 'Z' ])
96
- plt .title ('Lin. Accel.' )
63
+ # Convert clock cycles to seconds
64
+ ts4231_time = ts4231 ['clock' ] / meta ['acq_clk_hz' ]
97
65
98
- plt .subplot (234 )
99
- plt .plot (bno055_time , bno055 ['grav' ].squeeze ())
100
- plt .xlabel ("time (sec)" )
101
- plt .ylabel ("accel. (m/s^2)" )
102
- plt .legend (['X' , 'Y' , 'Z' ])
103
- plt .title ('Gravity Vec.' )
66
+ ts4231_time_mask = np .bitwise_and (ts4231_time >= start_t , ts4231_time < start_t + dur )
104
67
105
- plt .subplot (235 )
106
- plt .plot (bno055_time , bno055 ['temp' ].squeeze ())
107
- plt .xlabel ("time (sec)" )
108
- plt .ylabel ("temp. (°C)" )
109
- plt .title ('Headstage Temp.' )
68
+ #%% Plot time series
110
69
111
- plt .tight_layout ( )
70
+ fig = plt .figure ( figsize = ( 12 , 10 ) )
112
71
113
- #%% TS4231
114
- dt = {'names' : ('clock' , 'position' ),
115
- 'formats' : ('u8' , '(1,3)f8' )}
116
- ts4231 = np .genfromtxt (os .path .join (data_directory , f'ts4231_{ suffix } .csv' ), delimiter = ',' , dtype = dt )
72
+ # Plot RHD2164 ephys data
73
+ plt .subplot (711 )
74
+ plt .plot (rhd2164 ['time' ][rhd2164_time_mask ], rhd2164 ['ephys_uV' ][:,0 :plot_num_channels ][rhd2164_time_mask ])
75
+ plt .xlabel ('Time (seconds)' )
76
+ plt .ylabel ('Voltage (µV)' )
77
+ plt .title ('RHD2164 Ephys Data' )
117
78
118
- ts4231_time = ts4231 ['clock' ] / meta ['acq_clk_hz' ]
119
- plt .figure ()
79
+ # Plot RHD2164 aux data
80
+ plt .subplot (712 )
81
+ plt .plot (rhd2164 ['time' ][rhd2164_time_mask ], rhd2164 ['aux_uV' ][rhd2164_time_mask ])
82
+ plt .xlabel ('Time (seconds)' )
83
+ plt .ylabel ('Voltage (µV)' )
84
+ plt .title ('RHD2164 Aux Data' )
85
+
86
+ # Plot BNO055 data
87
+ plt .subplot (713 )
88
+ plt .plot (bno055_time [bno055_time_mask ], bno055 ['euler' ].squeeze ()[bno055_time_mask ])
89
+ plt .xlabel ('Time (seconds)' )
90
+ plt .ylabel ('degrees' )
91
+ plt .title ('Euler Angles' )
92
+ plt .legend (['Yaw' , 'Pitch' , 'Roll' ])
93
+
94
+ plt .subplot (714 )
95
+ plt .plot (bno055_time [bno055_time_mask ], bno055 ['quat' ].squeeze ()[bno055_time_mask ])
96
+ plt .xlabel ('Time (seconds)' )
97
+ plt .title ('Quaternion' )
98
+ plt .legend (['X' , 'Y' , 'Z' , 'W' ])
120
99
121
- plt .plot (ts4231_time , ts4231 ['position' ].squeeze ())
122
- plt .xlabel ("time (sec)" )
123
- plt .ylabel ("position (units)" )
124
- plt .legend (['x' , 'y' , 'z' ])
100
+ plt .subplot (715 )
101
+ plt .plot (bno055_time [bno055_time_mask ], bno055 ['accel' ].squeeze ()[bno055_time_mask ])
102
+ plt .xlabel ('Time (seconds)' )
103
+ plt .ylabel ('m/s\u00b2 ' )
104
+ plt .title ('Linear Acceleration' )
105
+ plt .legend (['X' , 'Y' , 'Z' ])
106
+
107
+ plt .subplot (716 )
108
+ plt .plot (bno055_time [bno055_time_mask ], bno055 ['grav' ].squeeze ()[bno055_time_mask ])
109
+ plt .xlabel ('Time (seconds)' )
110
+ plt .ylabel ('m/s\u00b2 ' )
111
+ plt .title ('Gravity Vector' )
112
+ plt .legend (['X' , 'Y' , 'Z' ])
113
+
114
+ # Plot TS4231 data
115
+ plt .subplot (717 )
116
+ plt .plot (ts4231_time [ts4231_time_mask ], ts4231 ['position' ].squeeze ()[ts4231_time_mask ])
117
+ plt .xlabel ('Time (seconds)' )
118
+ plt .ylabel ('Position (units)' )
125
119
plt .title ('Position Data' )
120
+ plt .legend (['X' , 'Y' , 'Z' ])
121
+
122
+ fig .tight_layout ()
126
123
127
124
plt .show ()
0 commit comments