各种信号的模拟(ECG信号、质谱图、EEG信号),方便U-net训练

峰值检测模拟数据是人工生成的信号,用于模拟真实世界中含有峰值的信号(如心电图ECG、脑电图EEG、质谱图等)。这些数据包含:

  • 基础信号:周期性或趋势性成分

  • 噪声:随机扰动,模拟测量误差

  • 峰值:需要检测的局部极大值点

模拟数据示例:

复制代码
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks

# 创建一个具体的模拟信号示例
def create_simulation_example():
    # 1. 时间轴
    t = np.linspace(0, 10, 1000)
    
    # 2. 基础信号(背景趋势)
    base_signal = 0.5 * np.sin(2 * np.pi * 0.3 * t)  # 低频波动
    
    # 3. 添加不同类型的峰值
    signal = base_signal.copy()
    
    # 添加高斯型峰值(最常见)
    def add_gaussian_peak(position, height, width):
        return height * np.exp(-((t - position)**2) / (2 * width**2))
    
    # 添加洛伦兹型峰值(质谱常见)
    def add_lorentzian_peak(position, height, width):
        return height * (width**2) / ((t - position)**2 + width**2)
    
    # 添加几个不同类型的峰值
    signal += add_gaussian_peak(2.0, 1.2, 0.1)    # 尖锐的高斯峰
    signal += add_gaussian_peak(3.5, 0.8, 0.2)    # 较宽的高斯峰
    signal += add_lorentzian_peak(5.0, 1.0, 0.15) # 洛伦兹峰
    signal += add_gaussian_peak(6.8, 0.6, 0.08)   # 小峰
    signal += add_gaussian_peak(8.2, 1.5, 0.25)   # 大峰
    
    # 4. 添加噪声
    noise = np.random.normal(0, 0.1, len(t))  # 高斯白噪声
    noisy_signal = signal + noise
    
    # 5. 找到真正的峰值位置(用于验证)
    true_peaks, _ = find_peaks(signal, height=0.5, distance=20)
    
    # 6. 生成标签(ground truth)
    labels = np.zeros_like(t)
    for peak in true_peaks:
        # 在峰值中心附近标记
        start = max(0, peak - 5)
        end = min(len(t), peak + 6)
        labels[start:end] = 1
    
    return t, signal, noisy_signal, labels, true_peaks

# 生成数据并可视化
t, clean_signal, noisy_signal, labels, true_peaks = create_simulation_example()

# 绘制模拟信号
fig, axes = plt.subplots(3, 1, figsize=(12, 10))

# 1. 干净的信号(无噪声)
axes[0].plot(t, clean_signal, 'b-', linewidth=1.5, label='干净信号')
axes[0].plot(t[true_peaks], clean_signal[true_peaks], 'ro', 
            label='真实峰值', markersize=8)
axes[0].set_title('干净的模拟信号(无噪声)')
axes[0].set_ylabel('幅值')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# 2. 含噪声的信号(真实情况)
axes[1].plot(t, noisy_signal, 'g-', linewidth=1, alpha=0.7, label='含噪声信号')
axes[1].plot(t[true_peaks], noisy_signal[true_peaks], 'rx', 
            label='真实峰值位置', markersize=10, markeredgewidth=2)
axes[1].set_title('含噪声的模拟信号(真实测量情况)')
axes[1].set_ylabel('幅值')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

# 3. 标签(ground truth)
axes[2].plot(t, labels, 'r-', linewidth=2, label='峰值标签')
axes[2].fill_between(t, 0, labels, alpha=0.3, color='red')
axes[2].set_title('峰值标签(Ground Truth)')
axes[2].set_xlabel('时间')
axes[2].set_ylabel('标签 (0/1)')
axes[2].set_yticks([0, 1])
axes[2].set_yticklabels(['非峰值', '峰值'])
axes[2].legend()
axes[2].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 显示具体数据
print("模拟信号信息:")
print(f"信号长度:{len(t)} 个点")
print(f"时间范围:{t[0]:.1f} 到 {t[-1]:.1f}")
print(f"峰值数量:{len(true_peaks)} 个")
print(f"峰值位置(索引):{true_peaks}")
print(f"峰值位置(时间):{t[true_peaks]}")

# 打印前50个点的数据示例
print("\n前50个数据点示例:")
print("索引 | 时间 | 干净信号 | 含噪信号 | 标签")
print("-" * 60)
for i in range(50):
    if i in true_peaks[:3]:  # 标记前几个峰值
        marker = "★"
    else:
        marker = " "
    print(f"{i:4d} | {t[i]:5.2f} | {clean_signal[i]:7.3f} | {noisy_signal[i]:7.3f} | {labels[i]:3.0f} {marker}")

真实应用场景对应的模拟数据:

ECG信号、质谱图、EEG信号、也包括PPG信号

复制代码
import numpy as np
import matplotlib.pyplot as plt

def create_ecg_like_signal():
    """生成类似心电图的信号(ECG-like)"""
    t = np.linspace(0, 10, 2000)
    
    # ECG特征波形
    ecg = np.zeros_like(t)
    
    # 模拟心跳(大约72次/分钟)
    heartbeat_interval = 0.8  # 秒
    num_beats = int(10 / heartbeat_interval)
    
    for i in range(num_beats):
        beat_start = i * heartbeat_interval
        
        # P波(心房收缩)
        p_wave = 0.2 * np.exp(-((t - beat_start)**2) / (2 * 0.02**2))
        
        # QRS复合波(心室收缩)
        qrs = 1.5 * np.exp(-((t - (beat_start + 0.15))**2) / (2 * 0.03**2))
        
        # T波(心室恢复)
        t_wave = 0.4 * np.exp(-((t - (beat_start + 0.3))**2) / (2 * 0.05**2))
        
        ecg += p_wave + qrs + t_wave
    
    # 添加基线漂移和噪声
    baseline_drift = 0.1 * np.sin(2 * np.pi * 0.1 * t)
    noise = np.random.normal(0, 0.05, len(t))
    
    return t, ecg + baseline_drift + noise

def create_mass_spec_like_signal():
    """生成类似质谱图的信号"""
    t = np.linspace(0, 100, 1000)
    
    # 基线
    signal = 0.1 * np.ones_like(t)
    
    # 添加不同m/z比的峰
    peak_positions = [20, 35, 50, 65, 80]
    peak_heights = [1.0, 0.7, 0.9, 0.5, 0.8]
    peak_widths = [0.5, 0.3, 0.4, 0.6, 0.2]
    
    for pos, height, width in zip(peak_positions, peak_heights, peak_widths):
        signal += height * np.exp(-((t - pos)**2) / (2 * width**2))
    
    # 质谱特有的噪声(Poisson噪声)
    noise = np.random.poisson(5, len(t)) / 50
    
    return t, signal + noise

def create_eeg_like_signal():
    """生成类似脑电图的信号"""
    t = np.linspace(0, 5, 1000)
    
    # 不同频率的脑电波
    delta = 0.3 * np.sin(2 * np.pi * 2 * t)    # δ波 (1-4 Hz)
    theta = 0.2 * np.sin(2 * np.pi * 6 * t)    # θ波 (4-8 Hz)
    alpha = 0.4 * np.sin(2 * np.pi * 10 * t)   # α波 (8-12 Hz)
    beta = 0.1 * np.sin(2 * np.pi * 20 * t)    # β波 (12-30 Hz)
    
    signal = delta + theta + alpha + beta
    
    # 添加事件相关电位(ERP)尖峰
    spike_times = [1.2, 2.4, 3.6]
    for spike_time in spike_times:
        spike = 0.8 * np.exp(-((t - spike_time)**2) / (2 * 0.02**2))
        signal += spike
    
    # EEG噪声
    noise = np.random.normal(0, 0.1, len(t))
    
    return t, signal + noise

# 可视化不同应用场景
fig, axes = plt.subplots(3, 1, figsize=(12, 12))

# 1. 心电图信号
t_ecg, ecg_signal = create_ecg_like_signal()
axes[0].plot(t_ecg, ecg_signal, 'b-', linewidth=1)
axes[0].set_title('心电图 (ECG) 模拟信号', fontsize=14)
axes[0].set_xlabel('时间 (秒)')
axes[0].set_ylabel('电压 (mV)')
axes[0].grid(True, alpha=0.3)
axes[0].set_xlim(0, 3)  # 显示前3秒

# 标记R峰
r_peaks = np.arange(0, 3, 0.8)  # 假设0.8秒一个心跳
for peak in r_peaks:
    idx = np.argmin(np.abs(t_ecg - peak))
    axes[0].plot(t_ecg[idx], ecg_signal[idx], 'ro', markersize=6)

# 2. 质谱信号
t_ms, ms_signal = create_mass_spec_like_signal()
axes[1].stem(t_ms, ms_signal, linefmt='b-', markerfmt=' ', basefmt=' ')
axes[1].set_title('质谱图 (Mass Spectrometry) 模拟信号', fontsize=14)
axes[1].set_xlabel('质荷比 (m/z)')
axes[1].set_ylabel('强度')
axes[1].grid(True, alpha=0.3)

# 标记峰值
ms_peaks = [20, 35, 50, 65, 80]
for peak in ms_peaks:
    idx = np.argmin(np.abs(t_ms - peak))
    axes[1].plot(t_ms[idx], ms_signal[idx], 'ro', markersize=6)

# 3. 脑电图信号
t_eeg, eeg_signal = create_eeg_like_signal()
axes[2].plot(t_eeg, eeg_signal, 'b-', linewidth=1)
axes[2].set_title('脑电图 (EEG) 模拟信号', fontsize=14)
axes[2].set_xlabel('时间 (秒)')
axes[2].set_ylabel('电压 (µV)')
axes[2].grid(True, alpha=0.3)

# 标记ERP尖峰
eeg_peaks = [1.2, 2.4, 3.6]
for peak in eeg_peaks:
    idx = np.argmin(np.abs(t_eeg - peak))
    axes[2].plot(t_eeg[idx], eeg_signal[idx], 'ro', markersize=6)

plt.tight_layout()
plt.show()

各种奇特的信号模拟:

复制代码
def create_challenging_signals():
    """创建具有挑战性的信号,测试峰值检测算法"""
    t = np.linspace(0, 10, 1000)
    
    fig, axes = plt.subplots(3, 2, figsize=(15, 12))
    
    # 1. 重叠峰
    ax = axes[0, 0]
    signal = np.zeros_like(t)
    # 两个重叠的高斯峰
    signal += np.exp(-((t - 4.0)**2) / (2 * 0.15**2))
    signal += 0.8 * np.exp(-((t - 4.2)**2) / (2 * 0.15**2))
    signal += np.random.normal(0, 0.05, len(t))
    ax.plot(t, signal, 'b-')
    ax.set_title('重叠峰(难以分离)')
    ax.grid(True, alpha=0.3)
    
    # 2. 变化基线
    ax = axes[0, 1]
    baseline = 0.3 * np.sin(2 * np.pi * 0.2 * t)
    peaks = 0.8 * np.exp(-((t - 3.0)**2) / (2 * 0.1**2))
    peaks += 0.6 * np.exp(-((t - 6.0)**2) / (2 * 0.1**2))
    signal = baseline + peaks + np.random.normal(0, 0.05, len(t))
    ax.plot(t, signal, 'b-')
    ax.plot(t, baseline, 'r--', alpha=0.5, label='基线')
    ax.set_title('变化基线下的峰')
    ax.legend()
    ax.grid(True, alpha=0.3)
    
    # 3. 高噪声
    ax = axes[1, 0]
    signal = np.exp(-((t - 5.0)**2) / (2 * 0.1**2))
    noise = np.random.normal(0, 0.3, len(t))  # 高噪声
    noisy_signal = signal + noise
    ax.plot(t, noisy_signal, 'b-', alpha=0.7)
    ax.plot(t, signal, 'r-', alpha=0.5, label='真实信号')
    ax.set_title('高噪声环境')
    ax.legend()
    ax.grid(True, alpha=0.3)
    
    # 4. 小峰靠近大峰
    ax = axes[1, 1]
    signal = 1.0 * np.exp(-((t - 4.0)**2) / (2 * 0.2**2))
    signal += 0.2 * np.exp(-((t - 4.5)**2) / (2 * 0.05**2))  # 小峰
    signal += np.random.normal(0, 0.05, len(t))
    ax.plot(t, signal, 'b-')
    ax.set_title('小峰靠近大峰(易被掩盖)')
    ax.grid(True, alpha=0.3)
    
    # 5. 宽峰和窄峰混合
    ax = axes[2, 0]
    signal = 0.7 * np.exp(-((t - 3.0)**2) / (2 * 0.3**2))  # 宽峰
    signal += 0.9 * np.exp(-((t - 7.0)**2) / (2 * 0.05**2))  # 窄峰
    signal += np.random.normal(0, 0.05, len(t))
    ax.plot(t, signal, 'b-')
    ax.set_title('宽峰和窄峰混合')
    ax.grid(True, alpha=0.3)
    
    # 6. 非对称峰
    ax = axes[2, 1]
    # 使用非对称函数创建峰
    from scipy.stats import skewnorm
    signal = 1.0 * skewnorm.pdf(t, -5, loc=5, scale=0.2)  # 左偏峰
    signal += 0.8 * skewnorm.pdf(t, 5, loc=8, scale=0.15)  # 右偏峰
    signal += np.random.normal(0, 0.03, len(t))
    ax.plot(t, signal, 'b-')
    ax.set_title('非对称峰(非高斯形状)')
    ax.grid(True, alpha=0.3)
    
    plt.suptitle('峰值检测的各种挑战场景', fontsize=16)
    plt.tight_layout()
    plt.show()

create_challenging_signals()

关键要点:

  1. 模拟数据的目的

    • 在没有真实数据时开发和测试算法

    • 控制实验条件(已知峰值位置)

    • 测试算法对不同挑战的鲁棒性

  2. 常见峰值类型

    • 高斯峰(对称)

    • 洛伦兹峰(质谱)

    • 非对称峰(色谱)

    • 尖峰(EEG/ECG)

  3. 关键参数

    • 峰高(信号强度)

    • 峰宽(时间/频率范围)

    • 信噪比(SNR)

    • 峰密度(单位时间内的峰数)

  4. 为什么使用模拟数据训练U-Net

    • 可以生成无限量的训练数据

    • 每个样本都有准确的标签(ground truth)

    • 可以设计特定难度的样本

    • 在应用到真实数据前验证算法有效性

这样的模拟数据可以帮助我们训练和测试峰值检测算法,确保它能够处理真实世界中可能遇到的各种情况。

相关推荐
荒诞硬汉19 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国20 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
flysh0520 小时前
C# 架构设计:接口 vs 抽象类的深度选型指南
开发语言·c#
2501_9418824820 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
bkspiderx20 小时前
C++中的volatile:从原理到实践的全面解析
开发语言·c++·volatile
小鸡吃米…20 小时前
机器学习中的回归分析
人工智能·python·机器学习·回归
沛沛老爹20 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理
专注_每天进步一点点20 小时前
【java开发】写接口文档的札记
java·开发语言
代码方舟20 小时前
Java企业级实战:对接天远名下车辆数量查询API构建自动化风控中台
java·大数据·开发语言·自动化