qldsdk-lm
Python SDK for X8/X8M/AR4/AR4M portable EEG devices(Windows x64,Python 3.10 及以上)。
通过 ctypes 封装厂商 liblibAr4SDK.dll,提供设备发现、连接、采集、数据订阅、数字/物理值换算和 EDF+ 存储。
| 设备 | 说明 | 真机验证 |
|---|---|---|
| AR4 / AR4M | 4 通道 EEG + 三轴加速度计,单设备 / Hub | 是 |
| X8 / X8M | 8 通道 EEG,单设备 / Hub | 否 |
安装
pip install qldsdk-lm # 依赖 numpy、loguru、pyedflib==0.1.42
包内自带 x64 的 liblibAr4SDK.dll,只发布 win_amd64 wheel。
| Python | pyedflib 0.1.42 安装方式 | 验证状态 |
|---|---|---|
| 3.10–3.12 | 官方 wheel,直接安装 | 3.12.13 已验证(含真机) |
| 3.13 | 源码编译 | 3.13.7 单元测试通过 |
| 3.14 / 3.15 | 源码编译 | 未验证 |
3.13 及以上需要先安装 Microsoft C++ Build Tools(勾选"使用 C++ 的桌面开发"),并按下方说明设置 PYTHONUTF8=1。
从源码开发:
py -3.12 -m venv venv
venv\Scripts\activate
pip install -e .
pip install -r requirements-dev.txt # 测试依赖
使用
import time
from queue import Empty
from qldsdk.lm import AR4M, configure_logger
configure_logger(log_dir="./logs", level="INFO")
hub = AR4M()
try:
hub.search() # 后台每 2 秒枚举一次,新设备自动连接
deadline = time.time() + 15
while not hub.devices and time.time() < deadline:
time.sleep(0.5)
mac, dev = next(iter(hub.devices.items()))
print(dev.box_name, dev.serial_number, dev.box_mac, dev.sample_frequency, "Hz")
dev.set_storage_path("./data") # EDF+:ar4_<序列号>_<年月日>_<时分秒>_<毫秒>.edf
topic, q = dev.subscribe("physical") # eeg 单位 µV,acc 单位 mG
dev.start_acquisition()
try:
end = time.time() + 10
while time.time() < end:
try:
pkt = q.get(timeout=1) # pkt.eeg[ch][sample]
except Empty:
continue
finally:
dev.stop_acquisition()
dev.unsubscribe(topic)
finally:
hub.close() # 必须:释放 SDK 连接
已知 MAC 时可直接 AR4("0x43df64e8335b3b9b")(构造即连接),用完调用 disconnect()。
API 概要
设备 AR4 / X8(基类 LMDevice):
- 标识:
box_name设备名称,serial_number设备序列号(SDK box_info 的boxId),box_macMAC(0x+ 16 位小写十六进制),device_tag日志/文件名标记(序列号,未知时为 MAC),head_mac记录子 MAC - 参数:
sample_frequency、channel_count、eeg_phy_min/eeg_phy_max、connected、recording - 方法:
start_acquisition()、stop_acquisition()、disconnect()、subscribe("digital" | "physical")、unsubscribe(topic)、eeg2phy()、acc2phy()、set_storage_path(path, enable=True, fill_lost=False)、fill_lost battery_level尚未实现,恒为 0
Hub AR4M / X8M:search()、stop_search()、close()、devices、add_device(mac) -> bool、remove_device(mac) -> bool
数据包 LMPacket:time_stamp(ms)、pkg_id、notify_id、eeg[ch][sample]、acc[axis][sample](无加速度计时为 None)。digital 订阅为 int 数字量,physical 订阅为 float 物理量。
异常(均继承 LMDeviceException):DeviceConnectionError、AcquisitionError、DLLLoadError。
EDF 存储
- pyedflib 0.1.42 写 EDF+,每条记录 1 秒
- 采样率取设备实际采样率,仅支持 500 / 1000 Hz;其它采样率在
start_acquisition()时抛AcquisitionError - 写入设备原始数字量,头部使用设备的数字/物理量程,读取端还原为 µV
- 头部 equipment 字段为
<设备类型>_<序列号>,recording additional 字段为MAC_<mac> - 丢包处理由
set_storage_path(path, fill_lost=...)配置,默认不补:fill_lost=False(默认):丢失的数据直接跳过,EDF 时长会短于实际采集时长fill_lost=True:按丢失的采样点数补物理 0,保持时间轴连续- 两种方式都会记录一条丢包告警日志;订阅者收到的数据始终不补 0
- 开始时间为第一个采样点的时刻:EDF 头部只能精确到秒,因此头部写整秒,开头补 (秒以下部分 × 采样率) 个物理 0,使第一个真实采样点落在正确时刻(误差主要来自约 12–50 ms 的无线传输延迟)
- 停止采集时末尾不足 1 秒的部分补物理 0
- 文件名精确到毫秒,同名文件已存在时追加
_1、_2…,不会覆盖已有文件
dev.set_storage_path("./data", fill_lost=True) # 丢包补 0
···
安装异常时先对齐编码再尝试
bash
set PYTHONUTF8=1 pip install pyedflib==0.1.42
powershell
$env:PYTHONUTF8="1" pip install pyedflib==0.1.42 ···
日志
设备相关日志以 [序列号] 开头,并在 record["extra"]["device"] 中携带序列号,可按设备过滤:
from loguru import logger
logger.add("dev_210125010255.log", filter=lambda r: r["extra"].get("device") == "210125010255")
测试
venv\Scripts\python -m pytest tests/unit # 不需要设备
venv\Scripts\python -m pytest tests/integration -m integration # 需要 AR4
venv\Scripts\python -m pytest tests/system -m system # 需要 AR4,约 18 分钟
注意:SDK 独占串口和 UDP 54366
同一时刻只能有一个进程加载 SDK。若上一个进程没有退出(或另一个程序正在采集),新进程打开串口会失败(Windows 错误 5)、绑定 UDP 54366 会失败,表现为设备枚举恒为 0。遇到时先确认没有其它进程占用:
Get-NetUDPEndpoint -LocalPort 54366 | Select OwningProcess
卡在串口 I/O 里的进程无法用 taskkill 结束,需要拔插 USB 接收器。
许可证
MIT
Metadata
Release files for qldsdk-lm 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| qldsdk_lm-0.1.2.tar.gz | 3.9 MB | Without provenance | Details for qldsdk_lm-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| qldsdk_lm-0.1.2-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details for qldsdk_lm-0.1.2-py3-none-win_amd64.whl |
Total release size: 7.7 MB
Release files / qldsdk_lm-0.1.2.tar.gz
| Download URL | qldsdk_lm-0.1.2.tar.gz |
|---|---|
| Size | 3.9 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
44980628e3e97da8232779c497d66732fc8ca76cb01d1bcffe60f9deb5ad4c25
|
|
BLAKE2b-256 checksum How to use checksums |
18a19a25e080be246c8411509620d75f01b58a34344cc709504b00c7b0742900
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / qldsdk_lm-0.1.2-py3-none-win_amd64.whl
| Download URL | qldsdk_lm-0.1.2-py3-none-win_amd64.whl |
|---|---|
| Size | 3.9 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
d8be53dba0ef5e80987c5197aaed6420926afaac9bcc15cfa1c1486932db6330
|
|
BLAKE2b-256 checksum How to use checksums |
afe9f58bf0f889116dd9111f958a88801a1444f96d3b16a4c1754fd38f42be14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Security for qldsdk-lm 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.