绘图工具 (plot)
PyWayne 绘图工具库 - 增强型频谱分析模块
本模块提供专业的时频分析可视化工具,特别优化用于:
IMU 传感器数据(加速度计、陀螺仪)
生理信号(PPG、ECG、呼吸)
振动分析
音频信号处理
主要特性:
SpecgramAxes: 增强型频谱图类 - 支持频率单位转换(Hz ↔ bpm ↔ kHz) - 多种归一化模式(全局/局部/不归一化) - 优化的色彩映射(Parula风格) - 完整返回值支持交互分析
parula_map: MATLAB风格色彩映射 - 感知均匀的色彩分布 - 适合科学可视化
get_specgram_params: 参数推荐函数 - 根据信号特性自动推荐STFT参数 - 支持时间/频率分辨率优化
SpecgramAxes 类
- class SpecgramAxes(Axes)
自定义的频谱图坐标轴类,支持高级频谱分析和可视化。
主要特性:
支持频率缩放(如 Hz 转 bpm)
多种标度模式(线性、dB、全局归一化、局部归一化)
优化的可视化效果
完整的返回值支持交互分析
主要属性和方法:
name: 类属性,投影名称为 ‘z_norm’。
- specgram(x, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, noverlap=None, cmap=None, xextent=None, pad_to=None, sides=None, scale_by_freq=None, mode=None, scale=None, vmin=None, vmax=None, freq_scale=1.0, normalize='global', **kwargs)
绘制增强型频谱图(STFT时频分析)。
将数据分割成 NFFT 长度的片段,计算每个片段的频谱,并以彩色图显示。 支持频率缩放、多种归一化模式,适用于各类信号分析场景。
参数说明:
x (1-D array): 输入信号数组。
NFFT (int, default: 256): FFT窗口长度(每段数据点数)。
越大 → 频率分辨率越高,时间分辨率越低
建议设为2的幂次方以提高FFT效率
常用值: 128, 256, 512, 1024
Fs (float, default: 2): 采样频率 (Hz)。频率分辨率 = Fs / NFFT
noverlap (int, default: 128): 相邻窗口的重叠点数。
越大 → 时间分辨率越高,计算量越大
典型值: NFFT * 0.5 ~ 0.9
例如 NFFT=256, noverlap=192 (75%重叠)
cmap (Colormap, optional): 色彩映射。推荐使用
parula_map(MATLAB风格)mode ({‘default’, ‘psd’, ‘magnitude’, ‘angle’, ‘phase’}, default: ‘psd’): 频谱类型
‘psd’: 功率谱密度 (推荐用于能量分析)
‘magnitude’: 幅度谱 (推荐用于频率成分分析)
‘angle’: 相位谱(不展开)
‘phase’: 相位谱(展开)
scale ({‘default’, ‘linear’, ‘dB’}, default: ‘dB’): 幅度标度
‘dB’: 分贝标度,适合大动态范围信号
‘linear’: 线性标度
‘default’: 根据mode自动选择
normalize ({‘global’, ‘local’, ‘none’}, default: ‘global’): 归一化方式 (仅在 scale=’linear’ 时生效)
‘global’: 全局归一化 Z/max(Z),保留相对强度关系
‘local’: 按时间段归一化,每列独立缩放到[0,1]
‘none’: 不归一化
freq_scale (float, default: 1.0): 频率缩放因子
1.0: 保持Hz (默认)
60: Hz → bpm (心率/呼吸等生理信号)
0.001: Hz → kHz
输出频率 = 原始频率 × freq_scale
Fc (float, default: 0): 中心频率偏移 (Hz),用于下变频信号的频率轴校正。
detrend ({‘none’, ‘mean’, ‘linear’} or callable, default: ‘none’): 去趋势方法
window (callable or ndarray, optional): 窗函数。默认使用汉宁窗。
pad_to (int, optional): 零填充长度,可以大于 NFFT 来提高频率分辨率
scale_by_freq (bool, default: True): 是否按频率缩放密度值(仅PSD模式)
sides ({‘default’, ‘onesided’, ‘twosided’}, optional): 频谱类型
xextent (tuple, optional): 时间轴范围 (xmin, xmax)。默认自动计算。
vmin, vmax (float, optional): 色彩映射的值域范围。
kwargs: 传递给
imshow的其他参数(如 aspect, interpolation)。
返回值:
spec (2D ndarray): 频谱数据矩阵,shape (n_freqs, n_times)
freqs (1D ndarray): 频率轴数组 (已应用 freq_scale 和 Fc)
t (1D ndarray): 时间轴数组(各段的中心时刻)
im (AxesImage): matplotlib 图像对象,可用于添加colorbar
应用场景:
IMU传感器数据分析(加速度计、陀螺仪)
生理信号处理(PPG心率、ECG、呼吸信号)
振动分析和故障诊断
音频信号频谱分析
支持通过自定义参数调整绘图效果,满足科研和工程中的定制需求
基础示例:
>>> import matplotlib.pyplot as plt >>> from pywayne.plot import regist_projection, parula_map >>> import numpy as np >>> >>> # 注册自定义projection >>> regist_projection() >>> >>> # 创建频谱图 >>> fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'}) >>> fs = 100 # 采样率 >>> t = np.linspace(0, 10, fs*10) >>> signal = np.sin(2*np.pi*5*t) + 0.5*np.sin(2*np.pi*15*t) >>> >>> spec, freqs, t, im = ax.specgram( ... x=signal, ... Fs=fs, ... NFFT=100, ... noverlap=50, ... cmap=parula_map, ... mode='magnitude', ... scale='dB' ... ) >>> ax.set_ylabel('Frequency (Hz)') >>> ax.set_xlabel('Time (s)') >>> plt.colorbar(im, label='Magnitude (dB)') >>> plt.show()
生理信号分析示例:
>>> # PPG信号,转换为bpm显示 >>> fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'}) >>> spec, freqs, t, im = ax.specgram( ... x=ppg_signal, ... Fs=100, ... NFFT=400, # 4秒窗口 ... noverlap=300, ... freq_scale=60, # Hz -> bpm ... scale='dB' ... ) >>> ax.set_ylabel('Heart Rate (bpm)') >>> ax.set_ylim(40, 180) # 典型心率范围 >>> plt.show()
振动分析示例:
>>> # 振动数据,使用全局归一化 >>> fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'}) >>> spec, freqs, t, im = ax.specgram( ... x=vibration_data, ... Fs=1000, ... NFFT=1024, ... noverlap=512, ... scale='linear', ... normalize='global' # 全局归一化 ... ) >>> plt.colorbar(im, label='Normalized Magnitude') >>> plt.show()
parula_map 色彩映射
- parula_map
MATLAB风格的Parula色彩映射,提供感知均匀的色彩分布,特别适合科学可视化。
特性:
感知均匀的色彩过渡
适合频谱图、热图等科学数据可视化
与MATLAB的parula colormap兼容
示例:
>>> from pywayne.plot import parula_map >>> import matplotlib.pyplot as plt >>> import numpy as np >>> >>> # 使用parula色彩映射 >>> data = np.random.randn(100, 100) >>> plt.imshow(data, cmap=parula_map) >>> plt.colorbar() >>> plt.show()
regist_projection 函数
- regist_projection()
注册自定义 SpecgramAxes projection。
在使用 SpecgramAxes 绘制频谱图前必须调用此函数。
应用场景:
在使用 matplotlib 时注册自定义投影,扩展默认的 Axes 功能
允许用户通过指定 projection=’z_norm’ 来使用特定的频谱图绘制功能
示例:
>>> from pywayne.plot import regist_projection >>> regist_projection() >>> import matplotlib.pyplot as plt >>> fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'}) >>> # 现在可以使用 ax.specgram() 了
get_specgram_params 函数
- get_specgram_params(signal_length, sampling_rate, time_resolution=None, freq_resolution=None, overlap_ratio=0.75)
根据信号长度和期望的分辨率,推荐 STFT 参数。
参数:
signal_length (int): 信号长度(采样点数)
sampling_rate (float): 采样率 (Hz)
time_resolution (float, optional): 期望的时间分辨率(秒)。优先级高于 freq_resolution
freq_resolution (float, optional): 期望的频率分辨率(Hz)。当 time_resolution 未指定时使用
overlap_ratio (float, default: 0.75): 窗口重叠比例 (0-1之间)
返回值:
params (dict): 推荐的参数字典,包含:
‘NFFT’: FFT窗口长度
‘noverlap’: 重叠点数
‘actual_freq_res’: 实际频率分辨率
‘actual_time_res’: 实际时间分辨率
‘n_segments’: 预计的时间段数
‘window_duration’: 窗口持续时间(秒)
‘step_duration’: 步进持续时间(秒)
‘overlap_ratio’: 重叠比例
应用场景:
自动优化STFT参数设置
根据信号特性和分析需求推荐合适的窗口参数
在不确定参数设置时提供专业建议
示例:
>>> from pywayne.plot import get_specgram_params >>> >>> # 根据期望的时间分辨率推荐参数 >>> params = get_specgram_params( ... signal_length=10000, ... sampling_rate=100, ... time_resolution=0.1 # 期望0.1秒时间分辨率 ... ) >>> print(params) {'NFFT': 256, 'noverlap': 192, 'actual_freq_res': 0.390625, ...} >>> # 根据期望的频率分辨率推荐参数 >>> params = get_specgram_params( ... signal_length=10000, ... sampling_rate=100, ... freq_resolution=0.5 # 期望0.5Hz频率分辨率 ... ) >>> # 直接使用推荐参数 >>> regist_projection() >>> fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'}) >>> spec, freqs, t, im = ax.specgram( ... x=signal, ... Fs=100, ... NFFT=params['NFFT'], ... noverlap=params['noverlap'] ... )
使用指南
完整工作流程示例:
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from pywayne.plot import regist_projection, parula_map, get_specgram_params
>>>
>>> # 1. 生成测试信号(模拟IMU数据)
>>> fs = 100 # 采样率100Hz
>>> duration = 30 # 30秒数据
>>> t = np.linspace(0, duration, fs * duration)
>>> signal = (np.sin(2*np.pi*2*t) + # 2Hz基频
... 0.5*np.sin(2*np.pi*8*t) + # 8Hz谐波
... 0.2*np.random.randn(len(t))) # 噪声
>>>
>>> # 2. 获取推荐参数
>>> params = get_specgram_params(
... signal_length=len(signal),
... sampling_rate=fs,
... time_resolution=0.5 # 期望0.5秒时间分辨率
... )
>>> print(f"推荐NFFT: {params['NFFT']}, noverlap: {params['noverlap']}")
>>>
>>> # 3. 注册投影并创建频谱图
>>> regist_projection()
>>> fig, ax = plt.subplots(figsize=(12, 6), subplot_kw={'projection': 'z_norm'})
>>>
>>> # 4. 绘制频谱图
>>> spec, freqs, t_spec, im = ax.specgram(
... x=signal,
... Fs=fs,
... NFFT=params['NFFT'],
... noverlap=params['noverlap'],
... cmap=parula_map,
... scale='dB'
... )
>>>
>>> # 5. 美化图形
>>> ax.set_ylabel('Frequency (Hz)')
>>> ax.set_xlabel('Time (s)')
>>> ax.set_ylim(0, 20) # 关注0-20Hz范围
>>> plt.colorbar(im, label='Magnitude (dB)')
>>> plt.title('IMU Signal Spectrogram Analysis')
>>> plt.tight_layout()
>>> plt.show()
交互式分析示例:
>>> # 添加点击事件,查看特定时刻的频谱
>>> def on_click(event):
... if event.xdata and event.inaxes == ax:
... time_idx = np.argmin(np.abs(t_spec - event.xdata))
... plt.figure(figsize=(8, 4))
... plt.plot(freqs, spec[:, time_idx])
... plt.xlabel('Frequency (Hz)')
... plt.ylabel('Magnitude')
... plt.title(f'FFT at t={event.xdata:.2f}s')
... plt.grid(True)
... plt.show()
>>>
>>> fig.canvas.mpl_connect('button_press_event', on_click)
通过上述工具和示例,可以快速掌握 plot 模块中各功能的使用方法,这对于进行专业的时频分析和频谱图绘制提供了强大支持。模块特别适用于IMU传感器数据、生理信号、振动分析等领域的信号处理需求。