精确的数据分析是一项严肃的事业(也是我的热情所在),需要对您正在研究的系统有深入的了解。这里是 cmets,不幸的是,我怀疑你的问题根本没有一个简单的好答案——你必须考虑一下。数据分析基本上总是需要“讨论”的。
首先是您的数据和一般问题:
-
当您谈论噪声时,在数据分析中,这意味着统计上的随机波动。最常见的是高斯分布(有时也是其他分布,例如泊松)。高斯噪声是 a) 每个 bin 中的随机噪声和 b) 在正负方向上对称的噪声。因此,您在约 20 秒的峰值观察到的不是噪音。与随机噪声相比,它具有非常不同、非常系统和扩展的特性。这是一件必须有来历的“神器”,但我们只能在此推测。在实际应用中,研究和移除此类工件是最昂贵和最耗时的任务。
-
查看您的数据,随机噪声可以忽略不计。这是非常精确的数据。例如,在约 150 秒及之后,直到小数点后四位都没有可见的随机波动。
-
在断定这不是常识中的噪音之后,它可能至少有两件事:a)您正在研究的系统的一个特征,因此,您可以开发一个模型/公式,并且您可以“适合”的数据。 b) 测量链某处带宽有限的特性,因此,这里是高频截止。参见例如https://en.wikipedia.org/wiki/Ringing_artifacts 。不幸的是,对于 a 和 b,没有包罗万象的通用解决方案。而且您的问题描述(即使是代码和数据)也不足以提出理想的方法。
-
现在花了大约一个小时处理您的数据并绘制了一些图表。我相信(推测)约 10 秒的极其尖锐的特征不能是数据的“物理”属性。它简直太极端/太陡了。这里从根本上发生了一些事情。我的猜测可能是某些设备刚刚打开(之前关闭)。因此,之前的数据是没有意义的,之后还有很短的时间来稳定系统。在这种情况下实际上没有其他选择,只能完全丢弃数据,直到系统稳定在 40 秒左右。这也使您的问题变得微不足道。只需删除前 40 秒,最大值就会变得明显。
那么您可以使用哪些技术解决方案,请不要太沮丧,因为您必须自己考虑这个问题并为您的案例组装最佳解决方案。我将您的数据复制到两个 numpy 数组 x 和 y 中,并在 python 中运行以下测试:
去除不稳定时间
这是简单的解决方案——我更喜欢它。
plt.figure()
plt.xlabel('time')
plt.ylabel('signal')
plt.plot(x, y, label="original")
y_cut = y
y_cut[:40] = 0
plt.plot(x, y_cut, label="cut 40s")
plt.legend()
plt.grid()
plt.show()
注意只有在你有点疯狂(关于数据)的情况下才能继续阅读下面的内容。
滑动窗口
您提到了“滑动窗口”,它最适合随机噪声(您没有)或周期性波动(您也没有)。滑动窗口只是对连续的 bin 进行平均,平均掉随机波动。从数学上讲,这是一个卷积。
从技术上讲,您实际上可以像这样解决您的问题(自己尝试更大的 Nwindow 值):
Nwindow=10
y_slide_10 = np.convolve(y, np.ones((Nwindow,))/Nwindow, mode='same')
Nwindow=20
y_slide_20 = np.convolve(y, np.ones((Nwindow,))/Nwindow, mode='same')
Nwindow=30
y_slide_30 = np.convolve(y, np.ones((Nwindow,))/Nwindow, mode='same')
plt.xlabel('time')
plt.ylabel('signal')
plt.plot(x,y, label="original")
plt.plot(x,y_slide_10, label="window=10")
plt.plot(x,y_slide_20, label='window=20')
plt.plot(x,y_slide_30, label='window=30')
plt.legend()
#plt.xscale('log') # useful
plt.grid()
plt.show()
因此,从技术上讲,您可以成功压制最初的“驼峰”。但不要忘记这是一个手动调整的而不是通用的解决方案......
任何滑动窗口解决方案的另一个警告:这总是会扭曲您的时间。由于您根据上升或下降信号在一个时间间隔内进行平均,因此您的卷积轨迹会在时间上前后移动(轻微但显着)。在您的特定情况下,这不是问题,因为主信号区域基本上没有时间依赖性(非常平坦)。
频域
这应该是灵丹妙药,但对于您的示例来说,它也不能很好/容易地工作。这不能更好地工作的事实是对我的主要暗示,即前 40 年代的数据最好被丢弃....(即在科学工作中)
您可以使用快速傅里叶变换在频域中检查您的数据。
import scipy.fft
y_fft = scipy.fft.rfft(y)
# original frequency domain plot
plt.plot(y_fft, label="original")
plt.xlabel('frequency')
plt.ylabel('signal')
plt.yscale('log')
plt.show()
频率结构代表数据的特征。峰值为零是约 100 秒后的稳定区域,驼峰与(快速)时间变化有关。您现在可以四处玩转并更改频谱(--> 过滤器),但我认为频谱太人工了,因此在这里不会产生很好的结果。尝试使用其他数据,您可能会印象深刻!我尝试了两件事,首先将高频区域切掉(设置为零),其次,在频域中应用滑动窗口滤波器(将峰值保留在 0,因为无法触及。尝试一下,你就知道为什么了)。
# cut high-frequency by setting to zero
y_fft_2 = np.array(y_fft)
y_fft_2[50:70] = 0
# sliding window in frequency
Nwindow = 15
Start = 10
y_fft_slide = np.array(y_fft)
y_fft_slide[Start:] = np.convolve(y_fft[Start:], np.ones((Nwindow,))/Nwindow, mode='same')
# frequency-domain plot
plt.plot(y_fft, label="original")
plt.plot(y_fft_2, label="high-frequency, filter")
plt.plot(y_fft_slide, label="frequency sliding window")
plt.xlabel('frequency')
plt.ylabel('signal')
plt.yscale('log')
plt.legend()
plt.show()
将其转换回时域:
# reverse FFT into time-domain for plotting
y_filtered = scipy.fft.irfft(y_fft_2)
y_filtered_slide = scipy.fft.irfft(y_fft_slide)
# time-domain plot
plt.plot(x[:500], y[:500], label="original")
plt.plot(x[:500], y_filtered[:500], label="high-f filtered")
plt.plot(x[:500], y_filtered_slide[:500], label="frequency sliding window")
# plt.xscale('log') # useful
plt.grid()
plt.legend()
plt.show()
产量
这些解决方案存在明显的波动,这使得它们对您的目的基本上无用。这导致我进行最后的练习,再次在“频率滑动窗口”时域上应用滑动窗口滤波器
# extra time-domain sliding window
Nwindow=90
y_fft_90 = np.convolve(y_filtered_slide, np.ones((Nwindow,))/Nwindow, mode='same')
# final time-domain plot
plt.plot(x[:500], y[:500], label="original")
plt.plot(x[:500], y_fft_90[:500], label="frequency-sliding window, slide")
# plt.xscale('log') # useful
plt.legend()
plt.show()
我对这个结果很满意,但它仍然有非常小的振荡,因此不能解决你原来的问题。
结论
多么有趣。一小时浪费了。也许它对某人有用。也许对你来说娜塔莎。请不要让我生气……