如何用Pandas创建亚毫秒时间序列并下采样至1500Hz?
问题描述
作为Pandas时间序列新手,我有一小时2500Hz采样的电压数据,需要完成两项操作:
- A)为数据创建datetime索引/对象
- B)将其下采样至1500Hz
附示例代码:
original_hz = 1/2500 # 2500 hz downsample_to_hz = 1/1500 # 1500 hz # 1 second time index at the two sampling frequencies time_2500hz = np.arange(0, 1, original_hz) time_1500hz = np.arange(0, 1, downsample_to_hz) # example sine wave of recording at 2500hz amplitude = np.sin(time_2500hz)
请问如何对amplitude进行下采样和插值,使其与1500Hz采样的时间索引对齐?优先使用Pandas时间序列方案,也欢迎NumPy示例。
补充:发现Scipy的scipy.signal.decimate函数接近需求,但该函数的抽取因子q需为整数,无法适配所有场景。
解决方案
Pandas时间序列方案
步骤A:创建Datetime索引
假设数据从指定起始时间(示例用2024-01-01 00:00:00)开始,用pd.date_range生成精确的datetime索引,完美匹配2500Hz的采样间隔:
import pandas as pd import numpy as np # 1小时2500Hz数据的总采样数 total_samples = 2500 * 3600 start_time = "2024-01-01 00:00:00" # 生成datetime索引,频率为1/2500秒 dt_index = pd.date_range(start=start_time, periods=total_samples, freq=f"{1/2500}S") # 构造带索引的DataFrame(用正弦波模拟真实电压数据) amplitude = np.sin(np.arange(total_samples) * 1/2500 * 2 * np.pi) # 1Hz正弦波示例 df = pd.DataFrame({"voltage": amplitude}, index=dt_index)
步骤B:下采样至1500Hz
Pandas的resample方法直接支持非整数倍的采样率转换,结合插值即可对齐目标时间点:
# 目标采样频率的周期(1/1500秒) target_freq = f"{1/1500}S" # 按目标频率重采样,用线性插值补全数据 downsampled_df = df.resample(target_freq).interpolate(method="linear") # 验证结果:1小时1500Hz数据应有1500*3600=5,400,000行 print(len(downsampled_df)) # 输出5400000
如果需要避免信号混叠(高频失真),可以先对原始数据做低通滤波,再进行插值:
from scipy.signal import butter, filtfilt # 设计低通滤波器:截止频率设为目标采样率的奈奎斯特频率(1500Hz/2=750Hz) def butter_lowpass(cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = butter(order, normal_cutoff, btype='low', analog=False) return b, a # 对原始电压数据进行滤波 fs_original = 2500 cutoff_freq = 750 b, a = butter_lowpass(cutoff_freq, fs_original) df["filtered_voltage"] = filtfilt(b, a, df["voltage"]) # 滤波后再插值下采样 downsampled_filtered_df = df["filtered_voltage"].resample(target_freq).interpolate(method="linear")
NumPy方案
如果不用Pandas,直接基于时间数组进行插值也能实现需求:
步骤A:关联时间与数据
import numpy as np # 生成1小时的原始时间数组(单位:秒) time_2500hz = np.arange(0, 3600, 1/2500) amplitude = np.sin(time_2500hz * 2 * np.pi) # 1Hz正弦波示例 # 生成目标1500Hz的时间数组 time_1500hz = np.arange(0, 3600, 1/1500)
步骤B:插值对齐
用np.interp进行线性插值,直接将原始数据映射到目标时间点:
# 线性插值得到1500Hz采样的数据 downsampled_amplitude = np.interp(time_1500hz, time_2500hz, amplitude) # 可选:先滤波再插值,避免混叠 from scipy.signal import butter, filtfilt fs_original = 2500 cutoff_freq = 750 b, a = butter_lowpass(cutoff_freq, fs_original) filtered_amplitude = filtfilt(b, a, amplitude) downsampled_filtered_amplitude = np.interp(time_1500hz, time_2500hz, filtered_amplitude)
关于Scipy decimate的补充
scipy.signal.decimate要求抽取因子q为整数,像2500Hz→1500Hz这种非整数倍的转换(q=5/3)确实无法直接使用。上面的插值+可选滤波方案更通用,既能精准对齐时间点,也能通过前置滤波解决信号混叠问题。
内容的提问来源于stack exchange,提问作者Angus Campbell
相关产品推荐
相关产品推荐

