You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中定位一维信号中受刺激区域的索引

分离一维信号中的受刺激段并提取起止点

问题背景

现有一维信号,包含基线水平段和受刺激后的高振幅段,需要识别并分离出所有受刺激段,同时获取这些段的起始与终止时间点。

解决方案思路

核心是通过阈值检测区分基线与刺激段,再提取连续的高振幅区间:

  • 利用基线信号的统计特征(均值+3倍标准差)设定阈值,过滤基线噪声的干扰
  • 将信号转换为二值掩码,标记出超过阈值的区域
  • 从掩码中提取连续的高振幅区间,转换为时间维度的起止点

完整实现代码

import numpy as np
import matplotlib.pyplot as plt
import random
from scipy.ndimage import label, find_objects

def generate_random_decimal_array(start, end, size):
    random_array = [random.uniform(start, end) for _ in range(size)]
    return random_array

# ----------------------
# 1. 生成模拟信号
# ----------------------
fs = 200  # 采样频率(Hz)
t_total = 5  # 总时长(秒)
t = np.linspace(0, t_total, int(fs * t_total), endpoint=False)

baseline_amplitude = 0.05
stimulus_duration = 1  # 刺激持续时长(秒)
recovery_duration = 1  # 恢复时长(秒)
num_stimuli = 3  # 刺激段数量

# 初始化基线噪声信号
signal = baseline_amplitude * np.random.randn(len(t))

# 随机生成刺激段的采样点起止索引
stimulus_periods = []
for _ in range(num_stimuli):
    start = random.randint(0, len(t) - int(fs * (stimulus_duration + recovery_duration)))
    end = start + int(fs * stimulus_duration)
    stimulus_periods.append((start, end))

# 叠加刺激信号和恢复段
for start, end in stimulus_periods:
    signal[start:end] = generate_random_decimal_array(0.3, 1.5, (end - start))
    recovery_start = end
    recovery_end = recovery_start + int(fs * recovery_duration)
    signal[recovery_start:recovery_end] = baseline_amplitude * np.random.randn(recovery_end - recovery_start)

# ----------------------
# 2. 检测受刺激段
# ----------------------
# 计算基线阈值:基线均值 + 3倍标准差(99.7%置信区间,过滤噪声)
baseline_mean = np.mean(signal[signal < 0.2])  # 先粗略筛选基线点计算统计量
baseline_std = np.std(signal[signal < 0.2])
threshold = baseline_mean + 3 * baseline_std

# 生成二值掩码:超过阈值的标记为1
mask = signal > threshold

# 提取连续的高振幅区间(受刺激段)
labeled_mask, num_features = label(mask)
segments = find_objects(labeled_mask)

# 转换为时间维度的起止点
stimulus_time_intervals = []
for seg in segments:
    start_idx = seg[0].start
    end_idx = seg[0].stop - 1  # 修正为区间最后一个采样点的索引
    start_time = t[start_idx]
    end_time = t[end_idx]
    stimulus_time_intervals.append((round(start_time, 2), round(end_time, 2)))

# ----------------------
# 3. 可视化验证
# ----------------------
plt.figure(figsize=(12, 6))
plt.plot(t, signal, label='原始信号', alpha=0.7)
plt.axhline(y=threshold, color='r', linestyle='--', label=f'检测阈值: {round(threshold, 3)}')

# 标记检测到的刺激段
for idx, (start_t, end_t) in enumerate(stimulus_time_intervals):
    plt.axvspan(start_t, end_t, color='g', alpha=0.2, label=f'检测到的刺激段 {idx+1}')

plt.title('受刺激段检测结果')
plt.xlabel('时间 (s)')
plt.ylabel('振幅')
plt.legend()
plt.grid(True)
plt.show()

# 输出检测到的起止时间
print("检测到的受刺激段时间区间:")
for i, (start, end) in enumerate(stimulus_time_intervals):
    print(f"段 {i+1}: 起始时间 {start}s,终止时间 {end}s")

关键说明

  • 阈值设定:采用基线均值+3倍标准差,既能有效区分基线噪声和刺激信号,又能避免误判
  • 区间提取:使用scipy.ndimage的label和find_objects工具,快速定位连续的高振幅区域
  • 结果验证:通过可视化对比原始信号和检测标记,确保结果准确性

内容的提问来源于stack exchange,提问作者Talha Anwar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 04:18:20