LoopIT

Monitoring LoopIT output with Lab Streaming Layer (LSL)

neuroConn GmbH

2026-06-05

Introduction

The LoopIT publishes its live data over Lab Streaming Layer (LSL), the de-facto standard for time-synchronised data streams in neuroscience. Any LSL client on the same network can discover the device’s streams and pull samples, without touching the control interface. This path is read-only: it is for monitoring and recording, not control.

This document explains what the device advertises, how to find and read it, and how the streams relate to the fields you mark for streaming in a script. It assumes you know what a TCP/IP network is and can run a small Python program, but not that you have used LSL before.

What gets streamed

The device exposes its data as one or more LSL outlets. There is one outlet per internal data source that has fields marked for streaming — for example the real-time scripting engine’s outputs are published as one outlet, and the event-driven engine’s as another. Within an outlet, each marked field becomes one channel.

A field is marked for streaming by the emit flag in a script’s interface block. If a script declares 1w emit unsigned ticks;, then ticks appears as a channel on that engine’s outlet. Fields without emit are read on request over the parameter server but are not streamed.

Stream metadata

When you resolve the device’s streams, each outlet describes itself with the following metadata. Knowing the shape helps you pick the right stream and interpret its channels.

Property Value
Stream name the internal source’s identifier (for example emit/ralee for the real-time engine, emit/evee for the event-driven engine)
Type various
Source id the device host name, then ::, then the source’s path and version (stable across reconnections)
Manufacturer neuroconn
Sample rate declared as 1000 Hz
Sample format 64-bit floating point (double), which carries the device’s integer values exactly

Each channel additionally carries a label, a unit, a type, a bit width and a count, taken straight from the field’s definition in the interface. The channel label has the form module.index.field (for example ral.0.ticks), so you can map a channel back to the exact field that produced it.

Because channels mirror a device’s specific configuration and the script currently running, the exact stream and channel set is device- and script-dependent. Discover it at runtime rather than assuming a fixed layout. There is no separate event or marker stream; everything is a continuous channel, and discrete events appear as a channel whose value changes (for example a flag going from 0 to 1).

Finding and reading a stream

LSL clients resolve streams by a property such as name or type, then open an inlet to pull samples. Resolve rather than hard-code, so your client keeps working when the configuration changes. A short Python example using pylsl:

from pylsl import resolve_byprop, StreamInlet

# find the real-time engine's outlet by name
streams = resolve_byprop("name", "emit/ralee", timeout=5)
inlet = StreamInlet(streams[0])

# read the channel labels from the stream's metadata
info = inlet.info()
ch = info.desc().child("channels").child("channel")
while not ch.empty():
    print(ch.child_value("label"), ch.child_value("unit"))
    ch = ch.next_sibling()

# pull samples
while True:
    sample, timestamp = inlet.pull_sample()
    print(timestamp, sample)

You can resolve by type (various) if you want every LoopIT-style stream, or by name for a specific engine. Reading the channel metadata first, as above, tells you what each value in sample means.

The official LSL documentation is the best reference for client libraries in other languages and for the resolve operations:

Troubleshooting

  • No streams found. LSL discovery uses multicast, which some networks restrict. Confirm the client and device are on the same subnet and read the LSL network-connectivity guide linked above; you may need to configure known peers.
  • A field is missing from the stream. Only fields with the emit flag are streamed. Check the script’s interface block, and confirm the script that declares the field is the one currently deployed.
  • Channel order looks different than expected. Do not rely on position; read the channel label metadata and match by name.
  • Values look unscaled. Channel values are the device’s integers carried as doubles; use the channel unit metadata to convert to physical units. Some analysis results are pre-scaled (for example a moving average returned ×1000) — the field name and unit indicate this.

Frequently asked questions

What streams and channels will I see? It depends on the device’s configuration and the script currently running. Resolve the streams at runtime and read their channel metadata; do not hard-code names. See What gets streamed and Stream metadata.

How do I monitor a value computed by my script? Mark the field emit in the script’s interface block; it then appears as a channel, labelled ral.0.<field>, on the engine’s outlet. See What gets streamed.

Can I control the device over LSL? No. LSL is read-only monitoring. Use the JSON parameter server for control.

References

LoopIT documentation · neuroConn