You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于PyWavelets的逆平稳小波变换信号重构失配问题咨询

问题描述

我尝试使用Python的PyWavelets库提供的逆平稳小波变换重构所有层级的近似系数和细节系数,编写的代码如下:

import numpy as np
import pywt
import matplotlib.pyplot as plt

def UDWT(Btotal, wname, Lps, Hps, edge_eff):
    Br =  Btotal[0]; Bt =  Btotal[1]; Bn =  Btotal[2]

    ## Set parameters needed for UDWT
    samplelength=len(Br)

    # If length of data is odd, turn into even numbered sample by getting rid 
    # of one point
    if np.mod(samplelength,2)>0:
        Br = Br[0:-1]
        Bt = Bt[0:-1]
        Bn = Bn[0:-1]
        
    samplelength = len(Br)

    # edge extension mode set to periodic extension by default with this
    # routine in the rice toolbox.
    pads = 2**(np.ceil(np.log2(abs(samplelength))))-samplelength  # for edge extension, This function 
                                                                  # returns 2^{ the next power of 2 }for input: samplelength

    ## Do the UDWT decompositon and reconstruction
    keep_all = {}
    for m in range(3):
        # Gets the data size up to the next power of 2 due to UDWT restrictions
        # Although periodic extension is used for the wavelet edge handling we are
        # getting the data up to the next power of 2 here by extending the data
        # sample with a constant value
        if (m==0):
            y = np.pad(Br,pad_width = int(pads/2) ,constant_values=np.nan)
        elif (m==1):
            y = np.pad(Bt,pad_width = int(pads/2) ,constant_values=np.nan)
        else:
            y = np.pad(Bn,pad_width = int(pads/2) ,constant_values=np.nan)

        # Decompose the signal using the UDWT
        nlevel = min(pywt.swt_max_level(y.shape[-1]), 8)  # Level of decomposition, impose upper limit 10
        Coeff  = pywt.swt(y, wname, nlevel)                # List of approximation and details coefficients 
                                                           # pairs in order similar to wavedec function:
                                                           # [(cAn, cDn), ..., (cA2, cD2), (cA1, cD1)]
        # Assign approx: swa and details: swd to 
        swa  = np.zeros((len(y),nlevel))
        swd  = np.zeros((len(y),nlevel))
       
        for o in range(nlevel):
            swa[:,o]  = Coeff[o][0]
            swd[:,o]  = Coeff[o][1]

        # Reconstruct all the approximations and details at all levels
        mzero = np.zeros(np.shape(swd))
        A     = mzero

        coeffs_inverse = list(zip(swa.T,mzero.T))
        invers_res  = pywt.iswt(coeffs_inverse, wname)
        D           = mzero

        for pp in range(nlevel):
            swcfs = mzero
            swcfs[:,pp] = swd[:,pp]
            coeffs_inverse2 = list(zip(np.zeros((len(swa),1)).T , swcfs.T))
            D[:,pp]         = pywt.iswt(coeffs_inverse2, wname)
            
        for jjj in range(nlevel-1,-1,-1):
            if (jjj==nlevel-1):
                A[:,jjj] = invers_res
            else:
                A[:,jjj] = A[:,jjj+1] + D[:,jjj+1]

        # *************************************************************************
        # VERY IMPORTANT: LINEAR PHASE SHIFT CORRECTION
        # *************************************************************************
        # Correct for linear phase shift in wavelet coefficients at each level. No
        # need to do this for the low-pass filters approximations as they will be
        # reconstructed and the shift will automatically be reversed. The formula
        # for the shift has been taken from Walden's paper, or has been made up by
        # me (can't exactly remember) -- but it is verified and correct.
        # *************************************************************************
        for j in range(1,nlevel+1):
            shiftfac = Hps*(2**(j-1));  
            for l in range(1,j):
                shiftfac = int(shiftfac + Lps*(2**(l-2))*((l-2)>=0)) ;
            swd[:,j-1]   = np.roll(swd[:,j-1],shiftfac)
            
            flds = {"A": A.T,
                    "D": D.T,
                    "swd"  : swd.T,
                    }
            Btot = ['Br', 'Bt', 'Bn'] # Used Just to name files

        keep_all[str(Btot[m])] = flds 

    # 1) Put all the files together into a cell structure
    Apr = {}
    Swd = {}

    pads  = int(pads)
    names = ['Br', 'Bt', 'Bn']
    for kk in range(3):
        A              = keep_all[names[kk]]['A']
        Apr[names[kk]] = A[:,int(pads/2):len(A)-int(pads/2)]

        swd            = keep_all[names[kk]]['swd']
        Swd[names[kk]] = swd[:,int(pads/2):len(A)-int(pads/2)]

    # Returns filters list for the current wavelet in the following order
    wavelet       = pywt.Wavelet(wname)
    [h_0,h_1,_,_] = wavelet.inverse_filter_bank
    filterlength  = len(h_0)
    
    if edge_eff:
        # 2)  Getting rid of the edge effects; to keep edges skip this section
        for j in range(1,nlevel+1):
            extra = int((2**(j-2))*filterlength) # give some reasoning for this eq
            for m in range(3):
                # for approximations
                Apr[names[m]][j-1][0:extra]   = np.nan
                Apr[names[m]][j-1][-extra:-1] = np.nan
                # for details
                Swd[names[m]][j-1][0:extra]   = np.nan
                Swd[names[m]][j-1][-extra:-1] = np.nan
    
    return  Apr, Swd, pads, nlevel


aa = np.sin(np.linspace(0,2*np.pi,100000))+0.05*np.random.rand(100000)
bb = np.cos(np.linspace(0,2*np.pi,100000))+0.05*np.random.rand(100000)
cc = np.cos(np.linspace(0,4*np.pi,100000))+0.05*np.random.rand(100000)
Btotal = [aa,bb,cc]

wname     ='coif2'
Lps       = 7;          #   Low pass filter phase shift for level 1 Coiflet2
Hps       = 4;          #   High pass filter phase shift for level 1 Coiflet2
edge_eff = False

Apr, Swd, pads, nlevel = UDWT(Btotal, wname, Lps, Hps, edge_eff)

### Add the details at all levels with the highest level approximations 
##  to compare with the original timeseries. (The equation shown in website)
new = Swd['Br'][0]
for i in range(1,nlevel):
    new = Swd['Br'][i]+new
sig = Apr['Br'][-1]+new

### Now plot to comapre ##
## Reconstructed signal 1
plt.plot(sig)
### Second way to get reconstructed signal
### aa first level details with approximations
plt.plot(Apr['Br'][-1] +Swd['Br'][-1] )
### Original signal
plt.plot(aa)
plt.show()

我参照Matlab小波工具箱文档描述的流程进行实现,但得到的重构时间序列与原始信号无法完全匹配,请问该如何排查问题并解决?

排查与解决步骤
  • 填充值错误使用NaN
    PyWavelets的swt和iswt接口无法处理NaN数值,你使用np.nan作为填充值会导致小波变换计算全部异常。建议改为边界值填充:比如使用np.pad的mode='symmetric'对称填充,或者用0、信号均值作为常量填充值。
  • 相位修正逻辑顺序错误
    你的代码中先执行了各层级细节系数的重构计算,后执行相位修正逻辑,修正后的swd完全没有参与到D的重构过程中,相位修正完全失效。需要调整代码顺序:先完成swd的相位偏移修正,再执行各层级细节系数的逆变换重构。
  • 系数顺序与重构求和逻辑不匹配
    pywt.swt返回的系数顺序为[(最高层级近似cAn, 最高层级细节cDn), ..., (最低层级近似cA1, 最低层级细节cD1)],你当前的求和逻辑没有匹配该顺序,导致重构时系数累加错误。建议先输出各层级swa、swd的数值,确认顺序后调整累加逻辑。
  • 相位偏移参数与偏移方向不匹配
    你硬编码了Coif2小波的相位偏移参数Lps=7、Hps=4,需要确认该参数是否和PyWavelets内置的Coif2滤波器参数匹配,同时确认np.roll的偏移方向是否正确:正参数为右移,负参数为左移,方向错误会导致整体信号偏移。
  • 填充裁剪不对称
    你计算的pads可能为奇数,左右填充长度不对称,后续裁剪时使用int(pads/2)会导致信号错位。建议调整填充逻辑确保左右填充长度一致,裁剪时分别取左右对应长度的偏移量。
  • 先关闭边缘效应处理做基础验证
    排查时先将edge_eff设为False,避免边缘置NaN的逻辑干扰核心重构正确性的验证,确认核心重构逻辑正确后再开启边缘效应处理。

内容的提问来源于stack exchange,提问作者jokerp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 02:06:02