2. 步态周期检测基础

任务说明

本案例基于单轴加速度计(垂直方向,记为Acc_z)采集的步行数据,通过分析加速度波形中的周期性峰值特征,实现步态周期检测。输入为一段连续采样的加速度序列,输出为检测到的步态周期数量及每个周期的起止时间索引,用于后续步数计数与步态分析。

实现方案

步态周期检测的核心在于识别加速度波形中周期性出现的波峰。正常步行时,垂直加速度在每个步态周期内会出现一个明显的主波峰(脚触地时的冲击响应)。本案例采用以下处理流程:

  1. 信号预处理:对原始加速度序列进行滑动窗口均值滤波,抑制高频噪声,避免误检;
  2. 峰值检测:在滤波后的波形中寻找局部极大值点,要求该点值大于相邻采样点,且高于动态阈值(基于信号均值和标准差计算);
  3. 周期划分:相邻两个有效波峰之间的区间即为一个步态周期,记录起始与结束索引。

代码中内置一组模拟步行加速度数据(采样率50Hz,时长10秒,包含8个完整步态周期),用于演示完整的检测流程。检测结果以周期索引列表形式输出,便于直观验证。

代码实现

import numpy as np

def generate_walk_data(fs=50, duration=10.0, steps=8):
    """生成模拟步行垂直加速度数据(含噪声)"""
    t = np.arange(0, duration, 1/fs)
    n = len(t)
    # 基础步态波形:主峰 + 次峰(近似)
    base = np.zeros(n)
    step_period = duration / steps
    for i in range(steps):
        center = int((i + 0.5) * step_period * fs)
        # 主峰(高斯形状)
        base[center] += 1.2
        # 次峰(较小)
        if center + int(0.15*fs) < n:
            base[center + int(0.15*fs)] += 0.4
    # 平滑并添加噪声
    from scipy.ndimage import gaussian_filter1d
    smooth = gaussian_filter1d(base, sigma=3)
    noise = np.random.normal(0, 0.05, n)
    acc = smooth + noise + 9.8  # 叠加重力偏置
    return t, acc

def moving_average(x, window=5):
    """滑动均值滤波"""
    kernel = np.ones(window) / window
    return np.convolve(x, kernel, mode='same')

def detect_gait_cycles(acc, fs=50, min_peak_dist=0.3):
    """
    步态周期检测
    参数:
        acc: 垂直加速度序列
        fs: 采样率(Hz)
        min_peak_dist: 最小峰间距(秒),用于排除伪峰
    返回:
        cycles: 列表,每个元素为(起始索引, 峰值索引, 结束索引)
    """
    # 1. 滤波去噪
    filtered = moving_average(acc, window=5)
    
    # 2. 动态阈值
    mean_val = np.mean(filtered)
    std_val = np.std(filtered)
    threshold = mean_val + 0.5 * std_val
    
    # 3. 峰值检测
    min_dist_samples = int(min_peak_dist * fs)
    peaks = []
    n = len(filtered)
    for i in range(1, n-1):
        if filtered[i] > threshold:
            if filtered[i] >= filtered[i-1] and filtered[i] > filtered[i+1]:
                # 检查与上一个峰的最小距离
                if len(peaks) == 0 or (i - peaks[-1]) >= min_dist_samples:
                    peaks.append(i)
    
    # 4. 构建周期区间
    cycles = []
    for j in range(len(peaks)-1):
        start = peaks[j]
        end = peaks[j+1]
        cycles.append((start, peaks[j], end))
    
    return cycles

# ---------- 主程序 ----------
fs = 50  # 采样率 50Hz
t, acc_data = generate_walk_data(fs=fs, duration=10.0, steps=8)

# 执行检测
cycles = detect_gait_cycles(acc_data, fs=fs)

# 输出结果
print(f"采样点数: {len(acc_data)}")
print(f"检测到步态周期数: {len(cycles)}")
print("周期区间(起始索引, 峰值索引, 结束索引):")
for idx, (s, p, e) in enumerate(cycles):
    print(f"  周期{idx+1}: ({s}, {p}, {e})  时长: {(e-s)/fs:.2f}s")

运行与验证

运行方式:将上述代码保存为 gait_cycle_detect.py,在已安装 numpy 和 scipy 的Python环境中执行 python gait_cycle_detect.py。

验证方法:程序输出检测到的周期数量与区间索引。由于内置数据生成时设定了8个步态周期,且峰值检测算法基于波形特征,预期输出周期数为7(相邻峰构成完整周期区间)。若检测结果在6~8之间(受噪声影响可能略有偏差),说明算法正确识别了周期性步态特征。可通过调整 generate_walk_data 中的 steps 参数(如改为5或10)重新运行,观察检测数量是否随之线性变化,以验证算法的鲁棒性。

判定标准:检测到的周期数量与设定步数相差不超过1,且每个周期时长在合理步态范围(0.8s~1.5s)内,即判定检测通过。

检测流程示意

步态周期检测流程 阈值 周期1 周期2 时间 (秒) 加速度 (m/s²) 滤波后波形 检测峰值 周期区间

关键说明

本案例聚焦于步态周期检测的核心算法实现。代码中的模拟数据仅用于验证算法逻辑,实际应用时可将 acc_data 替换为真实传感器采集的加速度序列(需保证采样率一致)。检测算法对噪声和幅值变化具有一定的鲁棒性,但若实际信号存在剧烈漂移或异常冲击,建议先进行带通滤波(如0.5~5Hz)预处理,以提升检测稳定性。当前实现未包含该预处理步骤,如需处理复杂真实信号,可在此基础上扩展滤波模块。