如何将2D信号/时间序列数据段缩放至-1到1之间?
峰谷间信号分段缩放至[-1,1]的实现
核心逻辑
对于每一段相邻峰-谷(或谷-峰)之间的信号,以该段的波峰值为1、波谷值为-1(反之亦然),通过线性归一化将区间内所有数据点映射到[-1, 1]。统一公式如下:
scaled = 2 * (x - seg_min) / (seg_max - seg_min) - 1
其中seg_min是当前段的最小值,seg_max是当前段的最大值,公式会自动根据峰谷的大小关系调整输出符号。
完整可复现代码
import numpy as np from findpeaks import findpeaks # 1. 生成随机测试信号 np.random.seed(42) t = np.linspace(0, 10, 500) signal = np.sin(t) + 0.3 * np.random.randn(len(t)) + 0.5 * np.cos(2*t) # 2. 检测波峰与波谷 fp = findpeaks(method='peakdetect') results = fp.fit(signal) peaks = results['df'][results['df']['peak'] == 1].index.values troughs = results['df'][results['df']['valley'] == 1].index.values # 3. 合并峰谷并按时间排序,补充首尾端点确保全覆盖 extrema = np.sort(np.concatenate([peaks, troughs])) if extrema[0] != 0: extrema = np.insert(extrema, 0, 0) if extrema[-1] != len(signal)-1: extrema = np.append(extrema, len(signal)-1) # 4. 分段缩放信号(numpy向量运算,高效简洁) scaled_signal = np.zeros_like(signal) for start, end in zip(extrema[:-1], extrema[1:]): segment = signal[start:end+1] seg_min, seg_max = segment.min(), segment.max() scaled_signal[start:end+1] = 2 * (segment - seg_min) / (seg_max - seg_min) - 1 # 5. 可视化验证(可选) import matplotlib.pyplot as plt fig, (ax1, ax2) = plt.subplots(2,1, figsize=(10,6)) ax1.plot(t, signal, label='Original Signal') ax1.scatter(t[peaks], signal[peaks], c='r', marker='^', label='Peaks') ax1.scatter(t[troughs], signal[troughs], c='g', marker='v', label='Troughs') ax1.legend() ax1.set_title('Original Signal with Peaks/Troughs') ax2.plot(t, scaled_signal, label='Scaled Signal') ax2.scatter(t[peaks], scaled_signal[peaks], c='r', marker='^') ax2.scatter(t[troughs], scaled_signal[troughs], c='g', marker='v') ax2.axhline(y=1, color='r', linestyle='--') ax2.axhline(y=-1, color='g', linestyle='--') ax2.legend() ax2.set_title('Scaled Signal (Each segment mapped to [-1,1])') plt.tight_layout() plt.show()
关键说明
- 先对峰谷索引排序并补充信号首尾端点,确保每一段连续信号都被处理
- 用numpy向量运算替代逐点循环,既符合Pythonic风格又保证效率
- 分段独立计算极值进行缩放,避免全局缩放丢失局部信号细节
内容的提问来源于stack exchange,提问作者wildcat89
相关产品推荐
相关产品推荐

