The control plane API uses Protocol Buffers and gRPC, and is defined in the synapse-api repo. It has five core function calls:
- Info
- Configure
- Start
- Stop
- Query
By default, Synapse devices are unconfigured and will do nothing when first turned on. The main component of a device's configuration is the signal chain which defines a flow of information through the device. Your signal chain configuration is built using standard Synapse Nodes and can include a Synapse App. Synapse Apps are neural processing applications built and deployed by the user. Apps are deployed on-device within the signal chain using the kApplication node type. This allows you to integrate custom neural engineering tools into standard workflows on hardware for minimal latency.
Python Client Scripts
The Synapse API includes a Python client library. Below are a series of Python client script examples.
Device Discovery
To begin, you must first request the devices available in the API. The discover command will display a procedurally generated name and the IP address for all Synapse devices on the network.
import synapse as syn
from synapse.utils.discover import discover
discovered = discover()Info on Devices
After your device(s) have been discovered, you can use the info command to print info on all peripherals available to the device.
import synapse as syn
# Connect to a device
device = syn.Device(uri)
# Get the device's info
info = device.info()
assert info is not None, "Couldn't get device info"
print(f"Device info: {info}")
# {
# name: "twelve-duckling-stampede";
# serial: "SFI00001",
# synapse_version: ""
# firmware_version: "",
# status: {...},
# peripherals: [...],
# configuration: {...}
# }Node Configuration
You can add nodes with the config.add_node(node) command and connect them with the config.connect(node1, node2) command. A typical electrical recording signal chain might include the following nodes, but their exact arrangement and number is not prescriptive:
- An Electrical Broadband node to ingest raw electrical voltages.
- A Spectral Filter node to remove extraneous signals from the raw data.
- A Spike Detect node to translate the analog signal into a digital one.
- A Synapse App employing a custom neural engineering tool such as a feature decoder.
- A DiskWriter node to write data to on-board storage on your Synapse device.
For example, you could arrange the collection of nodes above into a linear shape, or you could create a branching structure with DiskWriters connected to both the broadband and app nodes. This branching structure would save the raw broadband data and the app output to separate HDF5 files in device storage to preserve a record of the unprocessed raw data, while also saving your app outputs. Both files would contain the same timestamps for post-hoc synchronization. Data saved to HDF5 format is currently restricted to broadband frame format.
Additionally, taps can be used to stream data output from any node in the signal chain over wifi to the client computer. Multiple taps can be streamed simultaneously using a Python client script. Streaming taps using the synapsectl CLI is currently restricted to streaming from one tap at a time, and in broadband frame format.
After you have configured the signal chain, you can update your device to the current configuration by calling device.configure(config). The term "configuration" may be used interchangeably with "signal chain" in these docs when the context is not otherwise ambiguous.
Linear vs. Branching Signal Chains
Signal chains are not required to be perfectly linear; a single data source node can output to multiple data sinks or a single sink can accept data from multiple sources. The config.connect(node1, node2) command can be repeated for each connection.
Device Configuration
Synapse uses nodes (including Synapse App) to collect, process, and stream data to and from Synapse devices. Synapse nodes are linked together to create the signal chain. Signal chains can be arranged in linear or branching configurations, and multiple signal chains can be used in parallel.
Below is an example showing node configuration outputting broadband data to a connected spectral filter node:
import synapse as syn
## set channel map and reference
channels = [
syn.Channel(
id=channel_num,
electrode_id=channel_num * 2,
reference_id=channel_num * 2 + 1
) for channel_num in range(32)
]
## Add broadband source node
broadband = syn.BroadbandSource(
peripheral_id=2,
sample_rate_hz=30000,
bit_width=12,
gain=20.0,
signal=syn.SignalConfig(
electrode=syn.ElectrodeConfig(
channels=channels,
low_cutoff_hz=500.0,
high_cutoff_hz=6000.0,
)
)
)
## add spectral filter node
spectral_filter = syn.SpectralFilter(
method = syn.api.spectral_filter_pb2.SpectralFilterMethod.kBandStop,
low_cutoff_hz = 55,
high_cutoff_hz = 65
)
## connect broadband output to filters
config = syn.Config()
config.add_node(spectral_filter)
config.add_node(broadband)
config.connect(broadband, spectral_filter)Devices must be reconfigured if you want to update the signal chain.
Start/Stop Devices
You can start or stop signal chains that have been configured on a device using the start and stop commands.
# Start the device
ok = device.start()
# ...
# Stop the device
ok = device.stop()