This commit is contained in:
Ivey Song
2026-06-09 19:30:27 +08:00
parent 7b5f4f6eb9
commit a9dbe7261b
5 changed files with 363 additions and 30 deletions

View File

@@ -11,8 +11,8 @@ N_CHAN = 66 # 通道数: 64 EEG + 1 标签值 + 1 标签序号
EEG_FREQ = 10 # EEG 正弦波频率 Hz
EEG_AMP = 100.0 # EEG 幅值 100μV
LABEL_INTERVAL = 5 # 标签间隔秒数
# SERVER_ADDR = 'tcp://127.0.0.1:8100'
SERVER_ADDR = 'tcp://10.200.27.140:8100'
SERVER_ADDR = 'tcp://127.0.0.1:8100'
LABEL_CMD_ADDR = 'tcp://127.0.0.1:8101' # 接收来自上位机范式的标签命令
# 发送间隔: 每包 5 采样点 / 250Hz = 20ms
PKT_INTERVAL = N_SAMPLES_PER_PKT / FS
@@ -67,9 +67,41 @@ def main():
sock.connect(SERVER_ADDR)
print(f"[{datetime.now().strftime('%H:%M:%S')}] ZMQ Dealer 连接到 {SERVER_ADDR}")
# ========== 上位机标签命令监听 ==========
# 使用线程安全的队列接收来自 ssmvep_main.py 的标签命令
# 标签值: 1 (train 0), 2 (train 1), 99 (predict)
pending_label = [None] # [label_value or None]
label_lock = threading.Lock()
label_cmd_sock = ctx.socket(zmq.PULL)
label_cmd_sock.bind(LABEL_CMD_ADDR)
print(f"[{datetime.now().strftime('%H:%M:%S')}] 标签命令监听绑定到 {LABEL_CMD_ADDR}")
stop_recv = threading.Event()
def label_cmd_thread():
"""监听来自上位机范式的标签命令,写入 pending_label"""
while not stop_recv.is_set():
try:
msg = label_cmd_sock.recv_string(zmq.NOBLOCK)
label_val = int(msg)
with label_lock:
pending_label[0] = label_val
ts = datetime.now().strftime('%H:%M:%S')
label_name = {1: 'train_0', 2: 'train_1', 99: 'predict'}.get(label_val, str(label_val))
print(f"[{ts}] 收到标签命令: {label_name} -> label={label_val}")
except zmq.Again:
time.sleep(0.005)
except Exception as e:
print(f"[label_cmd_thread] 错误: {e}")
time.sleep(0.01)
label_thread = threading.Thread(target=label_cmd_thread, daemon=True)
label_thread.start()
print(f"[{datetime.now().strftime('%H:%M:%S')}] 标签命令监听线程已启动")
# 后台消费线程:持续 recv 从 ROUTER 返回的数据,避免 server 发送队列积压
recv_count = [0]
stop_recv = threading.Event()
def consumer_thread():
"""消费线程:阻塞 recv丢弃收到的数据仅用于清空 ROUTER 发送队列"""
@@ -98,7 +130,7 @@ def main():
print(f"[{datetime.now().strftime('%H:%M:%S')}] 开始发送模拟数据 ...")
print(f" 采样率: {FS}Hz | 每包 {N_SAMPLES_PER_PKT} 采样点 | 发送间隔 {PKT_INTERVAL*1000:.0f}ms")
print(f" EEG: {EEG_FREQ}Hz 正弦波 | 幅值 {EEG_AMP}μV")
print(f" 标签: {LABEL_INTERVAL}s 末尾采样点触发 | label 1/2 交替")
print(f" 标签: 来自上位机范式命令 (train_0=1, train_1=2, predict=99)")
print("-" * 50)
try:
@@ -108,30 +140,21 @@ def main():
# 构建当前包
packet = build_packet(global_sample_idx)
# 检查是否需要放置标签
if should_send_label(global_sample_idx):
if label_type == 1:
label1_count += 1
label_value = 1
label_number = label1_count
else:
label2_count += 1
label_value = 2
label_number = label2_count
# 标签放在当前包最后一个采样点(索引 4
packet[4, 64] = label_value
packet[4, 65] = label_number
# 检查是否有来自上位机范式的挂起标签命令
with label_lock:
ext_label = pending_label[0]
if ext_label is not None:
pending_label[0] = None
if ext_label is not None:
# 将标签写入当前包所有5个采样点的第65通道 (index 64)
# 覆盖全部采样点确保 event_inner_idx 无论落在哪个位置都能被正确检测
packet[:, 64] = float(ext_label)
ts = datetime.now().strftime('%H:%M:%S')
print(f"[{ts}] 标签触发: label={label_value}, 序号={label_number} "
f"(global_sample_idx={global_sample_idx})")
print(f"[{ts}] 标签: label={ext_label} -> ch64[all 5 samples] (global_sample_idx={global_sample_idx})")
# 交替标签类型
label_type = 2 if label_type == 1 else 1
# 发送: multipart 3帧 [identity, '', data]
# 使用标准格式3帧ROUTER 会自动附加 ZMQ 分配的客户端身份
# 发送: multipart 2帧 ['', data]
# 使用标准格式ROUTER 会自动附加 ZMQ 分配的客户端身份
sock.send_multipart([
b'',
packet.tobytes()
@@ -156,6 +179,7 @@ def main():
finally:
stop_recv.set()
consumer.join(timeout=2)
label_cmd_sock.close()
sock.close()
ctx.term()