def test_get_data_for_clock(self): """Test queries to the data store by experiment clock units.""" channels = ['ch1', 'ch2', 'TRG'] sample_hz = 100 trigger_at = 10 num_records = 1000 n_channels = len(channels) - 1 data = [ mock_record(n_channels) + [0 if (i + 1) < trigger_at else 1] for i in range(num_records) ] device = _MockConnector(data=data, device_spec=DeviceSpec(name="Mock_device", channels=channels, sample_rate=sample_hz)) daq = DataAcquisitionClient( connector=device, buffer_name='buffer_client_test_get_data_for_clock.db', raw_data_file_name=None, delete_archive=True, clock=CountClock()) daq.start_acquisition() time.sleep(0.2) daq.stop_acquisition() self.assertTrue(daq.is_calibrated) # rownum at calibration should be trigger_at self.assertEqual(trigger_at, daq.record_at_calib.rownum) self.assertEqual(trigger_at, daq.record_at_calib.timestamp) self.assertEqual(data[trigger_at - 1], daq.record_at_calib.data) # Test with clocks exactly synchronized. self.assertEqual(0.1, daq.offset) data_slice = daq.get_data_for_clock(calib_time=0.1, start_time=0.2, end_time=0.3) self.assertEqual(10, len(data_slice)) start_offset = 20 for i, record in enumerate(data_slice): # mock-data is 0-based, so we have to subtract 1 from the start. mock_data_index = i + start_offset - 1 self.assertEqual(record.data, data[mock_data_index]) # Test with clocks offset data_slice = daq.get_data_for_clock(calib_time=0.2, start_time=0.4, end_time=0.6) self.assertEqual(20, len(data_slice)) start_offset = 30 for i, record in enumerate(data_slice): # mock-data is 0-based, so we have to subtract 1 from the start. mock_data_index = i + start_offset - 1 self.assertEqual(record.data, data[mock_data_index]) daq.cleanup()
def __init__(self, *args, **kwargs): super(TestLslDevice, self).__init__(*args, **kwargs) self.server = None self.device_spec = DeviceSpec( name='LSL', channels=['C3', 'C4', 'Cz', 'FPz', 'POz', 'CPz', 'O1', 'O2'], sample_rate=100)
def test_zero_offset(self): """Test offset value override""" channels = ['ch1', 'ch2', 'TRG'] sample_hz = 100 trigger_at = 10 num_records = 500 n_channels = len(channels) - 1 data = [ mock_record(n_channels) + [0 if (i + 1) < trigger_at else 1] for i in range(num_records) ] device = _MockConnector(data=data, device_spec=DeviceSpec(name="Mock_device", channels=channels, sample_rate=sample_hz)) daq = DataAcquisitionClient(connector=device, buffer_name='buffer_client_test_offset.db', raw_data_file_name=None, delete_archive=True, clock=CountClock()) daq.is_calibrated = True # force the override. daq.start_acquisition() time.sleep(0.1) daq.stop_acquisition() self.assertTrue(daq.is_calibrated) self.assertEqual( daq.offset, 0.0, "Setting the is_calibrated to True\ should override the offset calcution.") daq.cleanup()
def test_missing_offset(self): """Test missing offset when no triggers are present in the data.""" channels = ['ch1', 'ch2', 'TRG'] sample_hz = 100 num_records = 500 # mock_data only has empty trigger values. n_channels = len(channels) - 1 data = [mock_record(n_channels) + [0] for i in range(num_records)] device = _MockConnector(data=data, device_spec=DeviceSpec(name="Mock_device", channels=channels, sample_rate=sample_hz)) daq = DataAcquisitionClient( connector=device, clock=CountClock(), buffer_name='buffer_client_test_missing_offset.db', raw_data_file_name=None, delete_archive=True) with daq: time.sleep(0.1) self.assertFalse(daq.is_calibrated) self.assertEqual(daq.offset, None) daq.cleanup()
def test_offset(self): """Test offset calculation""" channels = ['ch1', 'ch2', 'TRG'] sample_hz = 100 trigger_at = 10 num_records = 500 n_channels = len(channels) - 1 data = [ mock_record(n_channels) + [0 if (i + 1) < trigger_at else 1] for i in range(num_records) ] device = _MockConnector(data=data, device_spec=DeviceSpec(name="Mock_device", channels=channels, sample_rate=sample_hz)) daq = DataAcquisitionClient(connector=device, buffer_name='buffer_client_test_offset.db', raw_data_file_name=None, delete_archive=True, clock=CountClock()) daq.start_acquisition() time.sleep(0.1) daq.stop_acquisition() # The assertions should work before the stop_acquisition, but on some # Windows environments the tests were taking too long to setup and the # time would complete before any data had been processed. self.assertTrue(daq.is_calibrated) self.assertEqual(daq.offset, float(trigger_at) / sample_hz) daq.cleanup()
def __init__(self, *args, **kwargs): super(TestLslChannelConfig, self).__init__(*args, **kwargs) self.device_spec = DeviceSpec(name='DSI', channels=[ 'C3', 'C4', 'Cz', 'FPz', 'POz', 'CPz', 'O1', 'O2', 'TRG' ], sample_rate=300)
def spec(name=DEVICE_NAME, channels=DEVICE_CHANNELS, sample_rate=DEVICE_SAMPLE_RATE): """Creates a DeviceSpec for testing purposes""" return DeviceSpec(name=name, channels=channels, sample_rate=sample_rate, connection_methods=[ConnectionMethod.TCP])
def __init__(self, *args, **kwargs): super(TestDataAcquisitionClient, self).__init__(*args, **kwargs) num_channels = 25 num_records = 500 self.device_spec = DeviceSpec( name="Mock_device", channels=['ch' + str(i) for i in range(num_channels)], sample_rate=300.0) self.mock_data = list(mock_data(num_records, num_channels))
def test_connect(self): """Should require a connect call before initialization.""" device = LslConnector(connection_params={}, device_spec=DeviceSpec( name='LSL', channels=self.channels, sample_rate=self.sample_rate)) with pytest.raises(Exception): device.acquisition_init()
def test_device_info_channels(self): """Device should list the correct channels""" spec = DeviceSpec(name='LSL', channels=self.channels, sample_rate=self.sample_rate) device = LslConnector(connection_params={}, device_spec=spec) device.connect() device.acquisition_init() self.assertEqual(self.channels, device.channels)
def test_incorrect_frequency(self): """Provided sample_rate should match sample rate read from device""" device = LslConnector(connection_params={}, device_spec=DeviceSpec(name='LSL', channels=self.channels, sample_rate=300)) device.connect() with pytest.raises(Exception): device.acquisition_init()
def test_encoder(self): """It should encode array data that can be subsequently decoded.""" device_spec = DeviceSpec( name="DSI-VR300", channels=["P4", "Fz", "Pz", "F7", "PO8", "PO7", "Oz", "TRG"], sample_rate=300.0) protocol = DsiProtocol(device_spec) data = [float(i) for i in range(device_spec.channel_count)] encoded = protocol.encode(data) parsed = dsi.packet.parse(encoded) self.assertEqual(parsed.type, 'EEG_DATA') self.assertEqual(parsed.sensor_data, data)
def test_incorrect_number_of_channels(self): """A list of channels with len that does not match channel_count should raise an exception.""" spec = DeviceSpec(name='LSL', channels=['ch1', 'ch2'], sample_rate=self.sample_rate) device = LslConnector(connection_params={}, device_spec=spec) self.assertEqual(spec.channel_count, 2) self.assertNotEqual(len(device.channels), self.channel_count) device.connect() with pytest.raises(Exception): device.acquisition_init()
def test_read_data(self): """Should produce a valid data record.""" print(self.device_spec.channels) device = LslConnector(connection_params={}, device_spec=DeviceSpec( name='LSL', channels=self.channels, sample_rate=self.sample_rate)) device.connect() device.acquisition_init() data = device.read_data() self.assertTrue(len(data) > 0) self.assertEqual(len(data), len(device.channels)) for channel in data[0:-1]: self.assertTrue(isinstance(channel, float))
def test_protocol_init_messages(self): """Should have the channels and the sample_rate.""" device_spec = DeviceSpec( name="DSI-VR300", channels=["P4", "Fz", "Pz", "F7", "PO8", "PO7", "Oz", "TRG"], sample_rate=300.0) protocol = DsiProtocol(device_spec) init_messages = protocol.init_messages() channel_msg = init_messages[0] parsed1 = dsi.packet.parse(channel_msg) self.assertEqual(parsed1.type, 'EVENT') self.assertEqual(parsed1.event_code, 'SENSOR_MAP') self.assertEqual(parsed1.message, ','.join(device_spec.channels)) parsed2 = dsi.packet.parse(init_messages[1]) self.assertEqual(parsed2.type, 'EVENT') self.assertEqual(parsed2.event_code, 'DATA_RATE') self.assertEqual(parsed2.message, u',300')
def main(debug: bool = False): # pylint: disable=too-many-locals """Creates a sample lsl client that reads data from a sample TCP server (see demo/server.py). Data is written to a rawdata.csv file, as well as a buffer.db sqlite3 database. These files are written in whichever directory the script was run. The client/server can be stopped with a Keyboard Interrupt (Ctl-C).""" import time import sys # Allow the script to be run from the bci root, acquisition dir, or # demo dir. sys.path.append('.') sys.path.append('..') sys.path.append('../..') from bcipy.acquisition.devices import DeviceSpec from bcipy.acquisition.protocols.lsl.lsl_connector import LslConnector from bcipy.acquisition.client import DataAcquisitionClient from bcipy.acquisition.datastream.lsl_server import LslDataServer from bcipy.acquisition.datastream.tcp_server import await_start from bcipy.helpers.system_utils import log_to_stdout if debug: log_to_stdout() # Generic LSL device with 16 channels. device_spec = DeviceSpec(name="LSL_demo", channels=[ "Ch1", "Ch2", "Ch3", "Ch4", "Ch5", "Ch6", "Ch7", "Ch8", "Ch9", "Ch10", "Ch11", "Ch12", "Ch13", "Ch14", "Ch15", "Ch16" ], sample_rate=256.0) server = LslDataServer(device_spec=device_spec) await_start(server) # Device is for reading data. connector = LslConnector(connection_params={}, device_spec=device_spec) raw_data_name = 'demo_raw_data.csv' client = DataAcquisitionClient(connector=connector, raw_data_file_name=raw_data_name) try: client.start_acquisition() print("\nCollecting data for 3s... (Interrupt [Ctl-C] to stop)\n") while True: time.sleep(1) client.marker_writer.push_marker('calibration_trigger') time.sleep(2) # since calibration trigger was pushed after 1 second of sleep print(f"Offset: {client.offset}; this value should be close to 1.") client.stop_acquisition() client.cleanup() server.stop() print(f"\nThe collected data has been written to {raw_data_name}") break except KeyboardInterrupt: print("Keyboard Interrupt; stopping.") client.stop_acquisition() client.cleanup() server.stop() print(f"\nThe collected data has been written to {raw_data_name}")