反小波变换[/xpost信号处理]

10

主要问题:如何反转scipy.signal.cwt()函数。

我看到Matlab有一个反连续小波变换函数,它可以通过输入小波变换返回数据的原始形式,尽管您可以过滤掉不想要的切片。

MATALAB反向cwt函数

由于scipy似乎没有相同的功能,因此我一直在尝试找出如何使数据以相同的形式返回,同时消除噪声和背景。 我该怎么做? 我尝试将其平方以去除负值,但这给我带来了太大且不完全正确的值。

这是我一直在尝试的:

# Compute the wavelet transform
widths = range(1,11) 
cwtmatr = signal.cwt(xy['y'], signal.ricker, widths)

# Maybe we multiple by the original data? and square?
WT_to_original_data = (xy['y'] * cwtmatr)**2

这里有一个完全可编译的简短脚本,展示了我试图获取的数据类型以及我已经拥有的数据等:

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

# Make some random data with peaks and noise
def make_peaks(x):
    bkg_peaks = np.array(np.zeros(len(x)))
    desired_peaks = np.array(np.zeros(len(x)))
    # Make peaks which contain the data desired
    # (Mid range/frequency peaks)
    for i in range(0,10):
        center = x[-1] * np.random.random() - x[0]
        amp = 60 * np.random.random() + 10
        width = 10 * np.random.random() + 5
        desired_peaks += amp * np.e**(-(x-center)**2/(2*width**2))
    # Also make background peaks (not desired)
    for i in range(0,3):
        center = x[-1] * np.random.random() - x[0]
        amp = 40 * np.random.random() + 10
        width = 100 * np.random.random() + 100
        bkg_peaks += amp * np.e**(-(x-center)**2/(2*width**2))
    return bkg_peaks, desired_peaks

x = np.array(range(0, 1000))
bkg_peaks, desired_peaks = make_peaks(x)
y_noise = np.random.normal(loc=30, scale=10, size=len(x))
y = bkg_peaks + desired_peaks + y_noise
xy = np.array( zip(x,y), dtype=[('x',float), ('y',float)])

# Compute the wavelet transform
# I can't figure out what the width is or does?
widths = range(1,11) 
# Ricker is 2nd derivative of Gaussian
# (*close* to what *most* of the features are in my data)
# (They're actually Lorentzians and Breit-Wigner-Fano lines)
cwtmatr = signal.cwt(xy['y'], signal.ricker, widths)

# Maybe we multiple by the original data? and square?
WT = (xy['y'] * cwtmatr)**2


# plot the data and results
fig = plt.figure()
ax_raw_data = fig.add_subplot(4,3,1)
ax = {}
for i in range(0, 11):
    ax[i] = fig.add_subplot(4,3, i+2)

ax_desired_transformed_data = fig.add_subplot(4,3,12)

ax_raw_data.plot(xy['x'], xy['y'], 'g-')  
for i in range(0,10):
    ax[i].plot(xy['x'], WT[i])

ax_desired_transformed_data.plot(xy['x'], desired_peaks, 'k-')

fig.tight_layout()
plt.show()

这个脚本将输出以下图片:

output

第一个图是原始数据,中间的图是小波变换,最后一个图是我想要得到的处理后的数据(去除背景和噪音)。

有人有什么建议吗?非常感谢帮助。


谢谢@MrE,我已经查看了文档,但是并没有提供关于正在发生的事情的详细信息。我希望有一个scipy.signal.icwt函数可以获得反向并隐藏所有数学和技术细节,但似乎你必须自己执行。 所以,问题是我不理解如何执行cwt()函数的反向操作的数学原理。文档中并没有足够的描述。 - chase
抱歉,我误读了你的问题,我以为你没有看到那个函数。 - YXD
1个回答

4

我最终找到了一个提供反小波变换函数的包,名为mlpy。该函数是mlpy.wavelet.uwt。以下是我最终编写的可编译脚本,如果有人正在尝试进行噪声或背景去除,则可能会感兴趣:

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
import mlpy.wavelet as wave

# Make some random data with peaks and noise
############################################################
def gen_data():
    def make_peaks(x):
        bkg_peaks = np.array(np.zeros(len(x)))
        desired_peaks = np.array(np.zeros(len(x)))
        # Make peaks which contain the data desired
        # (Mid range/frequency peaks)
        for i in range(0,10):
            center = x[-1] * np.random.random() - x[0]
            amp = 100 * np.random.random() + 10
            width = 10 * np.random.random() + 5
            desired_peaks += amp * np.e**(-(x-center)**2/(2*width**2))
        # Also make background peaks (not desired)
        for i in range(0,3):
            center = x[-1] * np.random.random() - x[0]
            amp = 80 * np.random.random() + 10
            width = 100 * np.random.random() + 100
            bkg_peaks += amp * np.e**(-(x-center)**2/(2*width**2))
        return bkg_peaks, desired_peaks

    # make x axis
    x = np.array(range(0, 1000))
    bkg_peaks, desired_peaks = make_peaks(x)
    avg_noise_level = 30
    std_dev_noise = 10
    size = len(x)
    scattering_noise_amp = 100
    scat_center = 100
    scat_width = 15
    scat_std_dev_noise = 100
    y_scattering_noise = np.random.normal(scattering_noise_amp, scat_std_dev_noise, size) * np.e**(-(x-scat_center)**2/(2*scat_width**2))
    y_noise = np.random.normal(avg_noise_level, std_dev_noise, size) + y_scattering_noise
    y = bkg_peaks + desired_peaks + y_noise
    xy = np.array( zip(x,y), dtype=[('x',float), ('y',float)])
    return xy
# Random data Generated
#############################################################

xy = gen_data()

# Make 2**n amount of data
new_y, bool_y = wave.pad(xy['y'])
orig_mask = np.where(bool_y==True)

# wavelet transform parameters
levels = 8
wf = 'h'
k = 2

# Remove Noise first
# Wave transform
wt = wave.uwt(new_y, wf, k, levels)
# Matrix of the difference between each wavelet level and the original data
diff_array = np.array([(wave.iuwt(wt[i:i+1], wf, k)-new_y) for i in range(len(wt))])
# Index of the level which is most similar to original data (to obtain smoothed data)
indx = np.argmin(np.sum(diff_array**2, axis=1))
# Use the wavelet levels around this region
noise_wt = wt[indx:indx+1]
# smoothed data in 2^n length
new_y = wave.iuwt(noise_wt, wf, k)

# Background Removal
error = 10000
errdiff = 100
i = -1
iter_y_dict = {0:np.copy(new_y)}
bkg_approx_dict = {0:np.array([])}
while abs(errdiff)>=1*10**-24:
    i += 1
    # Wave transform
    wt = wave.uwt(iter_y_dict[i], wf, k, levels)

    # Assume last slice is lowest frequency (background approximation)
    bkg_wt = wt[-3:-1]
    bkg_approx_dict[i] = wave.iuwt(bkg_wt, wf, k)

    # Get the error
    errdiff = error - sum(iter_y_dict[i] - bkg_approx_dict[i])**2
    error = sum(iter_y_dict[i] - bkg_approx_dict[i])**2

    # Make every peak higher than bkg_wt
    diff = (new_y - bkg_approx_dict[i])
    peak_idxs_to_remove = np.where(diff>0.)[0]
    iter_y_dict[i+1] = np.copy(new_y)
    iter_y_dict[i+1][peak_idxs_to_remove] = np.copy(bkg_approx_dict[i])[peak_idxs_to_remove]

# new data without noise and background
new_y = new_y[orig_mask]
bkg_approx = bkg_approx_dict[len(bkg_approx_dict.keys())-1][orig_mask]
new_data = diff[orig_mask] 

##############################################################
# plot the data and results
fig = plt.figure()

ax_raw_data = fig.add_subplot(121)
ax_WT = fig.add_subplot(122)

ax_raw_data.plot(xy['x'], xy['y'], 'g')
for bkg in bkg_approx_dict.values():
    ax_raw_data.plot(xy['x'], bkg[orig_mask], 'k')

ax_WT.plot(xy['x'], new_data, 'y')


fig.tight_layout()
plt.show()

现在我得到的输出如下所示: Shifting Background Removal 从图中可以看出,背景去除仍存在问题(每次迭代后都会向右移动),但是 这是另一个问题,我将在这里解决


1
你可以通过首先将小波系数与两个对齐函数之一对齐(并且必须坚持相应的小波),正确地反转小波系数的一部分。然后,您可以单独恢复每个尺度--我无法使其一次反转范围。 - jwalker
谢谢,我会研究一下的。 - chase
2
我现在正在用pywt替换mlpy,目前看起来不错。虽然它不包括逆变换,但我在这里找到了:https://groups.google.com/d/msg/pywavelets/tLh9ObKJaoc/hksGDLHwGpMJ。 - jwalker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接