重采样后pandas Series执行scipy FFT触发索引错误的解决方案问询
报错根因
你触发ValueError: Can only tuple-index with a MultiIndex的核心原因是resampled_signal是一维pandas Series结构,仅包含数值列和时间索引,不存在第二列,[:,1]是二维数据(DataFrame/多索引Series)的索引写法,应用在普通Series上就会触发索引错误。
单数据集FFT实现修改
仅需要调整FFT调用的传参即可,不需要破坏原有Series结构:
将原有代码中的
yf = fft(resampled_signal[:,1])
修改为
yf = fft(resampled_signal.values)
resampled_signal.values会直接提取Series的数值数组传入FFT接口,原有resampled_signal的Series结构、时间索引完全保留不受影响。同时你需要把测试代码中print(resampled_signal.head())后的exit()注释或删除,否则程序会提前终止不会运行FFT相关逻辑。
双数据集重采样对齐方案
要实现两个数据集重采样后点数一致,按以下步骤操作即可:
- 先将两个原始信号都转为带时间索引的Series结构
- 计算两个信号时间范围的交集作为公共计算区间:
common_start = max(signal1.index.min(), signal2.index.min()) common_end = min(signal1.index.max(), signal2.index.max())
- 用完全相同的重采样规则对两个信号做裁剪、重采样、插值处理:
RESAMPLE_RULE = '1S' # 裁剪到公共时间区间 signal1_cut = signal1.loc[common_start:common_end] signal2_cut = signal2.loc[common_start:common_end] # 统一重采样+插值补全空值 signal1_resampled = signal1_cut.resample(RESAMPLE_RULE).mean().interpolate(method='time') signal2_resampled = signal2_cut.resample(RESAMPLE_RULE).mean().interpolate(method='time')
- 处理完成后校验长度一致即可:
assert len(signal1_resampled) == len(signal2_resampled),之后分别调用FFT计算结果再做差值运算即可。
修改后完整测试代码
import numpy as np import pandas as pd from datetime import datetime from datetime import timedelta import matplotlib import matplotlib.pyplot as plt from scipy.fft import fft, fftfreq datathick = "20210728_rig_thick.csv" with open(datathick) as f: lines = f.readlines() dates = [str(line.split(',')[0]) for line in lines] thick = [float(line.split(',')[1]) for line in lines] z = [float(line.split(',')[2]) for line in lines] date_thick = [datetime.strptime(x,'%Y-%m-%dT%H:%M:%S.%f').time() for x in dates] time_list_thick = [] for i in np.arange(0, len(date_thick)): q = date_thick[i] t = timedelta(hours= q.hour, minutes=q.minute,seconds=q.second, microseconds = q.microsecond).total_seconds() time_list_thick.append(float(t)) #---RESCALE----- signal = pd.Series(thick, index = pd.TimedeltaIndex(time_list_thick,unit = 's')) resampled_signal = signal.resample('1S').mean() resampled_signal = resampled_signal.interpolate(method='time') print(resampled_signal.head()) # 注释掉提前退出的代码 # exit() #----FFT Transform of Output and Noise ---- # Number of samples in normalized_tone SAMPLE_RATE = 1 DURATION = len(resampled_signal) N = SAMPLE_RATE * DURATION # 修改FFT传参 yf = fft(resampled_signal.values) print(yf) xf = fftfreq(N, 1 / SAMPLE_RATE) #------------------------------------------------ fig=plt.figure(figsize=(7.,7.)) ax=fig.add_subplot(1,1,1) ax.set_zorder(1) ax.patch.set_visible(False) ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) ax.spines['left'].set_visible(False) ax.spines['bottom'].set_visible(False) ax.set_xlabel('Frequency (Hz)') ax.set_ylabel('Amplitude (a.u)') ax.minorticks_on() # enable minor ticks ax.xaxis.set_ticks_position('bottom') ax.spines['left'].set_color('black') ax.yaxis.label.set_color('black') plt.yscale('log') ax.tick_params(direction='out', axis='y', which='both', pad=4, colors='black') ax.grid(b=True, which='major', color='#eeeeee', linestyle='-', zorder=1, linewidth=0.4) # turn on major grid ax.grid(b=True, which='minor', color='#eeeeee', linestyle='-', zorder=1, linewidth=0.4) # turn on minor grid ax.plot(np.abs(xf), np.abs(yf)) plt.savefig('fft.pdf', dpi=300, bbox_inches='tight', format='pdf') plt.savefig('fft.png', dpi=300, bbox_inches='tight', format='png')
内容的提问来源于stack exchange,提问作者tjsmert44
相关产品推荐
相关产品推荐

