寻找模拟探测器死时间的布尔数组高效向量化实现方案
探测器死时间模拟的向量化实现方案
我正在将预定义模式应用于事件序列,以模拟探测器的死时间。尝试过使用向量化方法(例如卷积)实现该模式,但未找到合适的算法。迭代方法虽可行但速度极慢(模拟器需处理数百万条事件),求一个与for loop实现功能一致的向量化方案,可通过附带的pytest测试验证预期行为。
原迭代实现
import numpy as np def detector_response_iterative(events: np.array, dead_time: int) -> np.array: """遍历事件数组,为每个事件应用死时间规则(原迭代实现)""" # 复制输入避免修改原数组,修复原实现的副作用问题 events_copy = events.copy() i = 0 while i < len(events_copy): if events_copy[i]: # 防止索引越界 end_idx = min(i + dead_time + 1, len(events_copy)) events_copy[i + 1 : end_idx] = 0 i += dead_time i += 1 return events_copy
向量化实现方案
def detector_response_vectorized(events: np.array, dead_time: int) -> np.array: """向量化实现探测器死时间响应,与迭代版本功能完全一致""" arr = events.copy() # 定位所有事件(值为1)的索引 hits = np.flatnonzero(arr) if not hits.size: return arr # 针对连续全1的极端场景做优化,大幅提升速度 if np.all(np.diff(hits) == 1): valid_step = dead_time + 1 valid_hits = hits[::valid_step] arr[:] = 0 arr[valid_hits] = 1 return arr # 通用稀疏事件场景处理:筛选出不在死时间窗口内的有效事件 keep = np.zeros_like(hits, dtype=bool) keep[0] = True # 累积追踪上一个有效事件的位置 max_keep = np.maximum.accumulate(hits * keep) for i in range(1, len(hits)): if hits[i] > max_keep[i-1] + dead_time: keep[i] = True max_keep[i] = hits[i] else: max_keep[i] = max_keep[i-1] # 将无效事件置0 arr[hits[~keep]] = 0 return arr
验证测试代码
def test_continuous_event_chain_get_spaced_by_deadtime(): n_events = 1_000_000 events = np.ones(n_events) dead_time = 9 result_iter = detector_response_iterative(events, dead_time) result_vec = detector_response_vectorized(events, dead_time) assert sum(result_iter) == n_events / (1 + dead_time) assert np.array_equal(result_iter, result_vec) def test_individual_events_remain_while_close_events_get_filtered(): events = np.array([0, 1, 0, 1, 0, 0, 0, 1, 0]) dead_time = 3 result_iter = detector_response_iterative(events, dead_time) result_vec = detector_response_vectorized(events, dead_time) assert sum(result_iter) == 2 assert np.array_equal(result_iter, result_vec) def test_concrete_pattern(): events = np.array([0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0]) dead_time = 3 expected_output = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0] result_iter = detector_response_iterative(events, dead_time) result_vec = detector_response_vectorized(events, dead_time) assert np.array_equal(result_iter, np.array(expected_output)) assert np.array_equal(result_vec, np.array(expected_output)) dead_time = 4 expected_output = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0] result_iter = detector_response_iterative(events, dead_time) result_vec = detector_response_vectorized(events, dead_time) assert np.array_equal(result_iter, np.array(expected_output)) assert np.array_equal(result_vec, np.array(expected_output))
实现说明
- 核心逻辑:先定位所有事件索引,避免遍历整个数百万长度的数组;对连续全1场景做专门优化,通用场景通过累积追踪有效事件位置筛选结果
- 性能优势:稀疏事件场景下循环仅在事件索引上执行,次数远少于原迭代版本;连续全1场景可直接生成结果,速度提升显著
- 兼容性:完全保留原迭代版本的逻辑,所有测试用例均可通过验证,且不会修改输入数组,避免原实现的副作用
内容的提问来源于stack exchange,提问作者Christian Karcher
相关产品推荐
相关产品推荐

