diff --git a/.gitignore b/.gitignore index 658ea20..ea88596 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ __pycache__/ # Distribution / packaging +release/ build/ dist/ dist_nuitka/ diff --git a/Zmq/filterProcess.py b/Zmq/filterProcess.py index cc0971a..302df45 100644 --- a/Zmq/filterProcess.py +++ b/Zmq/filterProcess.py @@ -194,6 +194,8 @@ class SlidingFilter(threading.Thread): self._beta_step_counter = 0 self._beta_steps_per_second = max(1, int(round(1.0 / step_sec))) # 5 + self.slide_window = None # 滑动窗口缓存 (n_chan, window_size) + self.slide_ready = False # 窗口是否已填满初始数据 # 预计算滤波器系数(仅执行一次) self._init_filters() @@ -238,42 +240,60 @@ class SlidingFilter(threading.Thread): def run(self): """线程主逻辑:精确200ms触发一次滤波""" - interval = self.step_sec # 200ms = 0.2秒 - next_run_time = time.perf_counter() - while self.running.is_set(): - # 1. 精确定时等待 - current_time = time.perf_counter() - if current_time < next_run_time: - time.sleep(next_run_time - current_time) - next_run_time += interval - else: - algo_log("滤波耗时超过200ms,定时偏移", level='debug') - next_run_time = time.perf_counter() + interval + interval = self.step_sec # 0.2s + # 以启动时刻为绝对时间基准(核心改动) + base_time = time.perf_counter() + frame_count = 0 # 帧计数器,用于对齐时序 - # ========== 新增核心判断:无新数据则直接跳过 ========== + while self.running.is_set(): + # 计算理论执行时刻:严格按帧序号 × 步长 + expect_time = base_time + frame_count * interval + current_time = time.perf_counter() + + # 精确定时等待 + if current_time < expect_time: + time.sleep(expect_time - current_time) + else: + # 处理超时:仅告警,不重置基准(防止累积偏移) + algo_log(f"滤波任务超时,偏移 {(current_time - expect_time)*1000:.1f} ms", level='debug') + + frame_count += 1 # 帧序号自增,保证周期绝对稳定 if not self.ring_buffer.check_and_clear_new_data(): # 无新数据,不执行滤波、不发送数据 continue - - # 2. 有新数据,才执行原有滤波逻辑 + + # ========== 原有滤波逻辑 ========== try: - window_data = self.ring_buffer.get_latest_n_points(self.window_size) - if window_data is None: - algo_log(f"缓存数据不足,当前缓存{self.ring_buffer.GetDataLenCount()}点,需{self.window_size}点", level='debug') - continue + if not self.slide_ready: + # 阶段1:首次填满3s初始窗口 + full_data = self.ring_buffer.get_latest_n_points(self.window_size) + if full_data is None: + algo_log("初始窗口数据不足", level='debug') + continue + self.slide_window = full_data + self.slide_ready = True + else: + # 阶段2:正常滑动 → 取最新50个新点,增量拼接 + new_step_data = self.ring_buffer.get_latest_n_points(self.step_size) + if new_step_data is None: + algo_log("滑动步长数据不足", level='debug') + continue + # 增量滑动:丢弃前50点,拼接新50点(标准滑动窗口) + self.slide_window = np.hstack([ + self.slide_window[:, self.step_size:], + new_step_data + ]) - filtered_data, filtered_full = self._filter_window_data(window_data) - # algo_log(f"滤波后{filtered_data.shape}数据", level='debug') + filtered_data, filtered_full = self._filter_window_data(self.slide_window[:64, :]) - # ========== beta_psd 每秒计算一次(Fp1/Fp2,通道索引 0/1)========== + # Beta PSD 每秒计算一次 self._beta_step_counter += 1 if self._beta_step_counter >= self._beta_steps_per_second: self._beta_step_counter = 0 - # 仅推送数据到队列,不阻塞等待计算完成 - self._beta_thread.push_data(filtered_full[:2, :].copy()) + self._beta_thread.push_data(filtered_full[:2, :]) if self.filter_result_callback is not None: - self.filter_result_callback(filtered_data[:64, :]) + self.filter_result_callback(filtered_data) except Exception as e: algo_log(f"滤波执行异常: {e}", level='error') diff --git a/release/runDecoder.dist_v0.0.0_beta_20260611.7z b/release/runDecoder.dist_v0.0.0_beta_20260611.7z deleted file mode 100644 index 8736d9d..0000000 Binary files a/release/runDecoder.dist_v0.0.0_beta_20260611.7z and /dev/null differ diff --git a/release/脑电范式算法库zmq接口说明_v1.docx b/release/脑电范式算法库zmq接口说明_v1.docx deleted file mode 100644 index 5a5f4c0..0000000 Binary files a/release/脑电范式算法库zmq接口说明_v1.docx and /dev/null differ