-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Acquisition device refactor #122
Conversation
…tor; fixed acquisition demos and tests; added unit tests for new functionality
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some suggestions, but works locally for me and I like the approach!
bcipy/acquisition/client.py
Outdated
@@ -87,6 +90,9 @@ def __init__(self, | |||
self._max_wait = 0.1 # for process loop | |||
|
|||
self.marker_writer = NullMarkerWriter() | |||
|
|||
# column in the acquisition data used to calculate offset. | |||
self.offset_column = OFFSET_COLUMN_NAME |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be more meaningful to call it a trigger column and require that it's present. We're going to refactor the way we handle offset correction in a future ticket.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I went back and forth on this one. I'll go ahead and rename it to trigger_column for clarity.
info = StreamInfo(stream_name, | ||
"EEG", len(channels), | ||
self.sample_hz, | ||
log.debug("Starting LSL server for device: %s", device_spec.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use f strings here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging is actually the one place where python is optimized to use the old string formatting style and f-strings can lead to some inefficiencies: https://docs.python.org/3/howto/logging.html#optimization. In this particular case it's probably not a big deal, but some code linters will provide a warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know that! I just assumed f strings are more performant.
"description": "Wearable Sensing DSI-VR300" | ||
}, | ||
{ | ||
"name": "g.USBamp-1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that we're registering our devices this way
bcipy/acquisition/devices.py
Outdated
description=config['description']) | ||
|
||
|
||
SUPPORTED_DEVICES = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's move this to the top of the file
bcipy/acquisition/devices.py
Outdated
|
||
def supported_devices() -> Dict[str, DeviceSpec]: | ||
"""Returns the currently supported devices keyed by name.""" | ||
global SUPPORTED_DEVICES |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this call needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should prefix SUPPORTED_DEVICES
with an underscore. My intent is that it's a private implementation detail of the module and shouldn't be accessed directly.
bcipy/acquisition/devices.py
Outdated
|
||
|
||
# Initialize the SUPPORTED_DEVICES | ||
load() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be called in init_acquistion or in some other fashion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll re-work this a bit to call load
when SUPPORTED_DEVICES is first accessed. There is other code that uses this module, so I don't want to make that code always have to explicitly load devices, but I agree that this doesn't need to be done at import time.
@@ -46,49 +49,87 @@ def inlet_name(inlet) -> str: | |||
return name.replace('-', '_') | |||
|
|||
|
|||
class LslDevice(Device): | |||
"""Driver for any device streaming data through the LabStreamingLayer lib. | |||
def channel_names(stream_info: pylsl.StreamInfo) -> List[str]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like these could be a part of the lsldevice class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally had this as a class method, but it didn't reference any instance variables and I got a linter warning about it so I pulled it out into a utility function. It may be useful in other contexts when we are looking at multiple LSL sources.
@@ -231,8 +230,7 @@ def read_data(self): | |||
if not marker.is_empty and timestamp >= marker.timestamp: | |||
trg = marker.trg | |||
log.debug(("Appending %s marker %s to sample at time %s; ", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use f strings
data = [ | ||
mock_record(n_channels) + [0 if (i + 1) < trigger_at else 1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be useful to define a function to produce this or set it as a class value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I still want to take a pass through the code and revisit mocked EEG data.
Overview
Refactored the acquisition module to separate the concept of a device (ex. DSI-24 headset) and a connection method to that device (TCP or LSL).
Ticket
https://www.pivotaltracker.com/story/show/175322346
Contributions
Test
Documentaion