This program should work with any amplifier that works with the AmpServer produced by EGI (http://www.egi.com/). All communication with the amplifier happens through the Amp Server's low-level Network Protocol. Amp Server Pro SDK is documented here. and the network API here.
-
Make sure that your AmpServer is running and can correctly record from its connected amplifier(s).
-
Start the EGIAmpServer app. You should see a window like the following.
-
Make sure that you have the correct IP address of the AmpServer assigned. The ports correspond to the default settings of the server and should not require a change.
-
If you have multiple amplifiers connected to the AmpServer and you would like to record from a specific one, you need to set the correct amplifier ID (these should be increasing from zero). Also make sure that you are using a supported number of channels and a supported sampling rate (the defaults should work).
-
To link the application to the LSL, click the "Link" button. If all goes well you should now have a new stream on the network with name "EGI NetAmp k" (k corresponding to the index of the amplifier) and type "EEG". If you get an error you might try to manually power on the desired Amp and try to link while it is either recording or stopped.
-
For subsequent uses you can save the desired settings from the GUI via File / Save Configuration. If the app is frequently used with different settings you might make a shortcut on the desktop that points to the app and appends to the Target field of the shortcut the snippet
-c name_of_config.cfgto denote the name of the config file that should be loaded at startup.
The CLI provides a lightweight alternative to the GUI:
./EGIAmpServerCLI [options]--config <file>- Load configuration from file--address <addr>- AmpServer IP address (default: 10.10.10.51)--cmd-port <port>- Command port (default: 9877)--data-port <port>- Data port (default: 9879)--amp-id <id>- Amplifier ID (default: 0)--sample-rate <hz>- Sample rate in Hz (default: 1000). Forces amplifier to this rate if already running at a different rate. Valid rates: 250, 500, 1000 (decimated) or 500, 1000, 2000, 4000, 8000 (native).--fast-recovery- Use native rate mode (no FPGA anti-alias filter) for lower latency. See Sample Rate Modes.--align-timestamps- Adjust timestamps to compensate for anti-alias filter delay. See Timestamp Alignment.--impedance- Enable impedance testing mode--native-format- Transmit raw int32 ADC counts instead of float microvolts--shutdown- Shutdown the Amp Server (terminates all connections)--help- Show help message
# Basic usage
./EGIAmpServerCLI --address 10.10.10.51
# With impedance testing
./EGIAmpServerCLI --address 10.10.10.51 --impedance
# With native format (int32 ADC counts)
./EGIAmpServerCLI --address 10.10.10.51 --native-format
# Low-latency mode (fast recovery)
./EGIAmpServerCLI --address 10.10.10.51 --sample-rate 1000 --fast-recovery
# With timestamp alignment for filter delay
./EGIAmpServerCLI --address 10.10.10.51 --sample-rate 1000 --align-timestampsWhen another application (e.g., Net Station Acquisition) has already started the amplifier, the CLI's behavior depends on whether you pass any rate or mode flags.
With no rate flags, the CLI detects the running amplifier, measures its current sample rate from the data stream, and attaches without disrupting the existing session:
# Attaches to whatever rate/mode the amp is already using
./EGIAmpServerCLI --address 10.10.10.51This is safe to use alongside Net Station — it will not stop or reconfigure the amplifier.
The following flags cause the CLI to stop, reconfigure, and restart the amplifier — even if it was started by another application:
--sample-rate <hz>— reinitializes if the detected rate differs from the requested rate--fast-recovery— reinitializes to ensure native (unfiltered) mode--align-timestamps— reinitializes at 500/1000 Hz to ensure decimated (filtered) mode, since the operating mode cannot be distinguished from the data stream alone
Warning: Reinitialization will interrupt any active Net Station recording. If you need to coexist with Net Station, omit these flags and let the CLI match the existing configuration.
If the amplifier is stopped or restarted externally while the CLI is streaming:
- Amp powered off by another app (e.g., Net Station clicks "Off"): The CLI detects stream loss and attempts to reinitialize the amplifier with its original settings.
- Amp restarted by another app (e.g., Net Station reconnects): The CLI detects the new stream, adapts to whatever rate the other app configured, and recreates its LSL outlets if the rate changed.
- Amp power-cycled or shutdown: The CLI waits up to 120 seconds for recovery before giving up.
The NA400/NA410 amplifiers support two operating modes that affect anti-aliasing and latency:
Uses the FPGA's digital anti-aliasing filter to downsample from the ADC's native rate. This provides:
- Better frequency response (~400 Hz bandwidth at 1000 Hz sample rate)
- Higher latency due to filter delay (36-112 samples depending on rate)
Available decimated rates: 250, 500, 1000 Hz
Bypasses the FPGA filter and samples directly at the requested rate. This provides:
- Lower latency (~3 samples)
- Reduced bandwidth (~1/4 of sample rate, e.g., 250 Hz at 1000 Hz sample rate)
- Optimized for EEG-TMS and real-time BCI applications
Available native rates: 500, 1000, 2000, 4000, 8000 Hz
Use --fast-recovery to enable native mode for rates that support both modes (500, 1000 Hz).
| Mode | Sample Rate | Filter Delay (samples) | Filter Delay (ms) |
|---|---|---|---|
| Decimated | 250 Hz | 112 | 448 ms |
| Decimated | 500 Hz | 66 | 132 ms |
| Decimated | 1000 Hz | 36 | 36 ms |
| Native | 500-8000 Hz | ~3 | ~3 ms |
When using decimated mode, the FPGA anti-aliasing filter introduces a delay between when brain activity occurs and when it appears in the data stream. The --align-timestamps option compensates for this by adjusting LSL timestamps backward by the filter delay amount.
- ERP analysis: Enable
--align-timestampsto align EEG data with event markers - Real-time BCI: Use
--fast-recoveryinstead (no filter delay to compensate) - Raw recording: Disable alignment if you prefer unmodified timestamps
Important: Timestamp alignment only works correctly when this application initializes the amplifier. If Net Station or another application previously initialized the amplifier, the current operating mode (decimated vs native) cannot be queried from AmpServer. In this case:
- The application will reinitialize the amplifier to ensure the correct mode
- This will interrupt any existing Net Station recording
- To avoid this, start EGIAmpServer before Net Station, or restart the amplifier
If you need to join an existing Net Station session without reinitialization, do not use --align-timestamps unless you are certain of the current mode.
The application supports electrode impedance measurement using the same algorithm as Net Station Acquisition.
When impedance mode is enabled:
- The amplifier is configured for impedance measurement (20 Hz calibration signal)
- Two LSL streams are created:
- EEG Stream (
type: EEG) - Raw amplifier data containing the calibration signal - Impedance Stream (
type: Impedance) - Calculated impedance values in kilo-ohms
- EEG Stream (
- The application cycles through each channel, measuring impedance one at a time
- A complete scan of all channels takes approximately 1-5 minutes depending on channel count
The impedance measurement follows Net Station's algorithm:
-
Initial State: All channels are "driving" the 20 Hz calibration signal
- Drive signals ON, 10K resistors OFF for all channels
- Oscillator enabled at 20 Hz sine wave, maximum amplitude (4095)
-
Per-Channel Measurement: For each channel:
- Turn OFF the drive signal (isolate channel from calibration)
- Turn ON the 10K reference resistor
- Wait ~1 second for signal to settle
- Measure peak-to-peak amplitude from collected samples
- Calculate impedance using:
Z = (idealSignal - amplitude) / (amplitude / 10) - Reset channel back to driving state
-
Output: After measuring all channels, the impedance values (in kOhms) are pushed to the LSL impedance stream
./EGIAmpServerCLI --address 10.10.10.51 --impedanceAdd to your ampserver_config.cfg:
<settings>
<impedance>true</impedance>
<!-- other settings -->
</settings>- Name:
EGI NetAmp <amp_id> - Type:
EEG - Rate: Configured sample rate (e.g., 1000 Hz)
- Channels: Depends on sensor net (32-256 channels)
- Format:
float32(default) orint32(with--native-format) - Unit:
microvolts(default) orcounts(with--native-format) - Behavior: Streams continuously with raw amplifier data (contains 20 Hz calibration signal during impedance mode)
When --native-format is enabled:
- Data is transmitted as raw int32 ADC counts instead of float microvolts
- Channel metadata includes a
conversionfield with the scaling factor - Downstream consumers can convert to microvolts:
microvolts = counts × conversion - This mode is useful for applications that need maximum precision or want to handle scaling themselves (e.g., NWB export)
- Name:
EGI NetAmp <amp_id> Impedance - Type:
Impedance - Rate: 1 Hz (regular rate)
- Channels: Same count and labels as EEG stream
- Unit:
kohms(kilo-ohms) - Behavior: Publishes current known impedance values every second
- Initially, all channels show 1000 kOhms (not yet measured)
- As each channel is measured, its value updates
- Values persist until the next measurement of that channel
Each sample in the impedance stream contains one value per channel:
- Good electrodes: Typically 5-50 kOhms
- Acceptable electrodes: 50-100 kOhms
- Poor electrodes: 100-200 kOhms
- Bad/disconnected electrodes: 1000 kOhms (maximum/clipped value)
cmd_TurnAll10KOhms(0) - 10K resistors OFF (channels driving)
cmd_TurnAllDriveSignals(1) - Drive signals ON (all channels active)
cmd_SetSubjectGround(0) - Subject ground OFF
cmd_SetCurrentSource(0) - Current source OFF
cmd_SetCalibrationSignalFreq(20) - 20 Hz calibration signal
cmd_SetWaveShape(0) - Sine wave
cmd_SetBufferedReference(0) - Buffered reference OFF
cmd_SetOscillatorGate(1) - Oscillator ON
cmd_SetReference10KOhms(0) - Reference 10K OFF
cmd_SetReferenceDriveSignal(0) - Reference drive signal OFF
cmd_SetDrivenCommon(0) - Driven leg OFF
cmd_SetCalibrationSignalAmplitude(4095) - Maximum amplitude
# To measure channel N:
cmd_TurnChannelDriveSignals(N, 0) - Turn OFF drive signal
cmd_TurnChannel10KOhms(N, 1) - Turn ON 10K resistor
# After measurement:
cmd_TurnChannelDriveSignals(N, 1) - Turn ON drive signal (reset)
cmd_TurnChannel10KOhms(N, 0) - Turn OFF 10K resistor (reset)
- Scan Duration: A full 256-channel scan takes approximately 5 minutes in single-channel mode
- No tiling sets yet: The current implementation measures one channel at a time. Tiling set support (faster, ~1 minute for 256 channels) is planned for a future release
- Ideal signal estimation: The "ideal signal" (expected amplitude with 0 impedance) is estimated from the first measurement. For more accurate results, gains calibration should be performed first
- Net Station compatibility: Running impedance mode will interfere with Net Station Acquisition if it's connected to the same amplifier
- Channel labels: Both streams use identical channel labels (E1, E2, ..., En)
Example Python code to process impedance data:
import pylsl
# Resolve both streams
streams = pylsl.resolve_byprop('type', 'EEG')
impedance_streams = pylsl.resolve_byprop('type', 'Impedance')
# Create inlets
eeg_inlet = pylsl.StreamInlet(streams[0])
imp_inlet = pylsl.StreamInlet(impedance_streams[0])
# Pull impedance data (arrives at 1 Hz)
imp_sample, timestamp = imp_inlet.pull_sample(timeout=2.0)
if imp_sample:
# Count how many channels have been measured
measured = sum(1 for z in imp_sample if z < 1000)
print(f"Measured: {measured}/{len(imp_sample)} channels")
for ch, z in enumerate(imp_sample):
if z >= 1000:
status = "not measured"
elif z < 50:
status = "good"
elif z < 100:
status = "ok"
elif z < 200:
status = "poor"
else:
status = "bad"
print(f"E{ch+1}: {z:.1f} kOhms ({status})")
# EEG data continues normally (contains calibration signal during impedance mode)
eeg_sample, timestamp = eeg_inlet.pull_sample()The DIN values are published on a separate LSL stream (not as a channel in the EEG stream). The stream is event-driven: a sample is only pushed when the DIN value changes.
- Name:
EGI NetAmp <amp_id>_DIN - Type:
Markers - Format:
int32 - Rate: Irregular (event-driven, only on change)
- Channels: 1 (
DIN) - Value range: 0-65535 (0x0000-0xFFFF)
- Idle value: 0 (all inputs off)
The amplifier's DIN lines are active-low with internal pull-ups. The application inverts the raw value so that 0 = idle and a set bit = active input.
import pylsl
# Resolve the DIN stream (separate from EEG)
streams = pylsl.resolve_byprop('type', 'Markers', timeout=5)
din_streams = [s for s in streams if s.name().endswith('_DIN')]
inlet = pylsl.StreamInlet(din_streams[0])
# Pull a DIN change event
sample, timestamp = inlet.pull_sample(timeout=5.0)
if sample:
din_value = int(sample[0])
# Extract individual bits (DIN1-DIN16)
din1 = (din_value >> 0) & 1 # Bit 0
din2 = (din_value >> 1) & 1 # Bit 1
din3 = (din_value >> 2) & 1 # Bit 2
# ... etc
# Or extract all 16 bits
bits = [(din_value >> i) & 1 for i in range(16)]
print(f"DIN1-16: {bits}")The amplifier's internal DIN ADC samples at a fixed 1 kHz rate, regardless of the EEG sample rate. The DIN stream only emits a sample when the value changes, so the effective timing resolution depends on the EEG sample rate (which determines how often the DIN register is read):
| EEG Sample Rate | DIN Poll Rate | Effective DIN Resolution |
|---|---|---|
| 250 Hz | Decimated (1 in 4 samples) | 4 ms |
| 500 Hz | Decimated (1 in 2 samples) | 2 ms |
| 1000 Hz | 1:1 mapping | 1 ms |
| 2000 Hz | Duplicated (2 per DIN sample) | 1 ms |
| 4000 Hz | Duplicated (4 per DIN sample) | 1 ms |
Recommendation: Use a sample rate of 1000 Hz or higher if precise DIN timing is required. At lower sample rates, fast TTL pulses (< 4ms at 250 Hz) may be missed.
The NA400/NA410 amplifiers have a 16-bit digital I/O port with active-low inputs (internal pull-ups). When no trigger device is connected, all lines are pulled high and the DIN stream reports 0 (idle). Grounding a line activates the corresponding bit.
The cmd_SetDigitalInOutDirection command can configure specific bits for output if needed (consult EGI documentation).
This application was written to behave near-identically to the BCI2000 AmpServer module that was originally created by EGI.
The configuration settings can be saved to a .cfg file (see File / Save Configuration) and subsequently loaded from such a file (via File / Load Configuration).
Importantly, the program can be started with a command-line argument of the form
EGIAmpServer.exe myconfig.cfg, which allows to load the config automatically at start-up.
The recommended procedure to use the app in production experiments is to make a shortcut on
the experimenter's desktop which points to a previously saved configuration customized to the
study being recorded to minimize the chance of operator error.
To use the mock server for development:
Terminal 1: Start mock server
python3 mock/mock_ampserver.py
Terminal 2: Run CLI or GUI against localhost
./cli/EGIAmpServerCLI --address 127.0.0.1
The mock server generates synthetic sine waves (10-50 Hz) with noise for the EEG data, so you can also verify the LSL stream in downstream applications.
See also Connecting to an Already-Running Amplifier for details on how the CLI behaves when attaching to an amp started by Net Station.
The following table documents how EGIAmpServer behaves when it is already connected and streaming, and Net Station Acquisition (NAS) subsequently interacts with the amplifier:
| NAS Action | EGIAmpServer Behavior | Stream Status |
|---|---|---|
| NAS launches and scans for devices | No change detected | Continues |
| NAS clicks "On" (connect) | No change (amp already running) | Continues |
| NAS starts recording | No change detected | Continues |
| NAS stops recording | No change detected | Continues |
| NAS clicks "Off" (disconnect) | ERROR: The stream was lost - stream terminates |
Stopped |
| NAS closes | No additional change | Already stopped |
Key finding: NAS powering off the amplifier terminates the EGIAmpServer data stream. The CLI process remains running but stops streaming data.
NAS has an "Amplifier Shutdown" button that is more severe than simply clicking "Off". When triggered while EGIAmpServer is streaming:
| Test | Result |
|---|---|
| EGIAmpServer stream | ERROR: The stream was lost - terminates |
| Ping amplifier (10.10.10.51) | FAILED - 100% packet loss |
| TCP connect to AmpServer | Succeeded (AmpServer software still running) |
| Query amplifier details | FAILED - Failed to get amplifier details |
| Start new stream | FAILED |
Recovery: The amplifier requires a power cycle to recover from this state. The AmpServer software remains accessible but cannot communicate with the shutdown amplifier hardware.
When using this application alongside Net Station Acquisition:
-
Start Net Station first: If you plan to use Net Station Acquisition, start it and initialize the amplifier (click "On") BEFORE connecting this app. Our app will detect the running amplifier and automatically use its sample rate.
-
Do not start Net Station after: If this app is already streaming and Net Station subsequently initializes the amplifier at a different sample rate, our app cannot detect this change. AmpServer only sends notifications to one subscriber, and Net Station consumes them when it's running.
-
Recommended workflow:
- Start Net Station Acquisition
- Initialize the amplifier at your desired sample rate (click "On")
- Start EGIAmpServer (GUI: click "Link", or CLI: run with no rate flags) — it will detect the running amp and match its sample rate
- Both applications will now receive data at the correct rate
After Net Station shuts down the amplifier (via "Shutdown" command), immediately starting this app may result in excessive dropped packets and eventual stream loss. This appears to be related to stale data in the connection. Workaround: Wait a moment and restart the app, or power cycle the amplifier.
The app automatically detects the sample rate when connecting to an already-running amplifier by measuring packet timing. This detection snaps to standard rates (250, 500, or 1000 Hz). If the amplifier is idle when connecting, the app uses the sample rate configured in the UI/config file.
