1. 小波到底是什么?(它是一个“显微镜镜头”)
小波本质上就是一个波形很短的小函数,通常震荡几下就归零了。
- 具体公式:有很多种小波(如 Haar, db4, Mexican Hat)。最简单的叫Haar 小波,它的公式只有两段:
ψ(t)={1,0≤t<0.5−1,0.5≤t<10,其他 \psi(t) = \begin{cases} 1, & 0 \le t < 0.5 \\ -1, & 0.5 \le t < 1 \\ 0, & \text{其他} \end{cases}ψ(t)=⎩⎨⎧1,−1,0,0≤t<0.50.5≤t<1其他
长这样:┌─┐然后立刻└─┘,像一个正方形波,中间分开。
2. 怎么和信号计算?(滑动窗口 + 对比求和)
“局部”相乘求和。就像是拿着手电筒在黑墙上扫。
想象你的信号是一串长长的数字序列。
小波是一个很短的“尺子”(比如只有2个格子的Haar小波:[1, -1])。
计算步骤如下:
- 定位(平移bbb):把小波对准信号的第1个点。
- 相乘(内积):把小波覆盖范围内的信号点,和小波对应的点一一相乘。
- 求和:把这些乘积加起来。得到的这个总和(Sum),就是在这个位置的小波系数。
- 移动:把小波向右挪一格,对准第2个点,重复上面“相乘、求和”的过程。
所以:
- 它不是只乘一个点(那没法体现波形形状)。
- 它也不是一下子乘整个周期(那样就只有这一个数,没法知道哪一时刻发生了什么)。
- 它是每次只乘“小波长度”那么长的一小段信号,算出一个系数,然后再移到下一段。
3. 具体计算举例:为什么平滑信号是0,阶跃处是大值?
我们来做一个手算模拟。
设定信号:
假设有一个信号,前半段是平稳的(值都是2),中间突然跳变(阶跃),后半段变成值都是5。
为了方便,我们只取6个点来看:
f=[2,2,2,5,5,5] f = [2, \quad 2, \quad 2, \quad 5, \quad 5, \quad 5]f=[2,2,2,5,5,5]
注意:在第3个点和第4个点之间,发生了从2到5的突变。
设定小波:
用最简单的 Haar 小波(省去复杂的归一化系数,只看核心逻辑):
ψ=[1,−1] \psi = [1, \quad -1]ψ=[1,−1]
(这就意味着:左边采样点乘1,右边相邻采样点乘-1,然后相减)。
场景 A:在平滑区域(比如第1、2个点处)
- 对准位置:小波[1,−1][1, -1][1,−1]盖住信号的第1、2个点[2,2][2, 2][2,2]。
- 相乘:
- 第1个点:2×1=22 \times 1 = 22×1=2
- 第2个点:2×(−1)=−22 \times (-1) = -22×(−1)=−2
- 求和(得出系数):
2+(−2)=0 2 + (-2) = 02+(−2)=0
结果:系数为0。
- 解释:因为信号是平滑的(左边2,右边也是2),小波是“一正一负”的,两者完美抵消。这就是消失矩在起作用——对于常数信号,Haar小波的积分为0。
场景 B:在突变边缘(比如第3、4个点处)
这里发生了跳变,左边是2,右边突然变成5。
- 对准位置:小波[1,−1][1, -1][1,−1]正好盖住第3个点(2)和第4个点(5)。
- 注意:小波是[1,−1][1, -1][1,−1],也就是左边部分是正,右边部分是负。
- 相乘:
- 第3个点(左边):2×1=22 \times 1 = 22×1=2
- 第4个点(右边):5×(−1)=−55 \times (-1) = -55×(−1)=−5
- 求和(得出系数):
2+(−5)=−3 2 + (-5) = -32+(−5)=−3
结果:系数是-3。
- 解释:因为信号突变了,左边的2和右边的5不再相等,无法抵消。这个“-3”就是大尖峰!它告诉我们:这里刚刚发生了一个变化!
场景 C:跳变后的平滑区(比如第4、5个点处)
现在小波移到了第4、5个点[5,5][5, 5][5,5]。
- 相乘:
- 5×1=55 \times 1 = 55×1=5
- 5×(−1)=−55 \times (-1) = -55×(−1)=−5
- 求和:
5+(−5)=0 5 + (-5) = 05+(−5)=0
结果:系数又变回0了。
- 解释:虽然信号值变大了(变成了5),但在小波看来,这一小段内部依然是“平的”,没有变化,所以还是输出0。
4. 总结这一步计算过程
通过这个手算例子,可以看到:
- 内积(相乘求和):就是**“比较”**。小波在问信号:“这一小段左边和右边一样吗?”
- 结果为0:如果小波覆盖的这一小段信号是平滑的(多项式),左边和右边能通过正负抵消,结果就是0。
- 结果很大:如果小波正好卡在突变处(阶跃),左边和右边差很多,没法抵消,就会剩下一个很大的余数(比如 -3),这就是大尖峰。
5. CWT,连续小波变换
我们在上面做的是离散的(一个个点算),如果是连续的信号,那个公式:
Wf(a,b)=∫f(t)ψ(t−ba)dt W_f(a, b) = \int f(t) \psi(\frac{t-b}{a}) dtWf(a,b)=∫f(t)ψ(at−b)dt
翻译成大白话就是:
- ψ(t−ba)\psi(\frac{t-b}{a})ψ(at−b):把小波ψ\psiψ拉伸(aaa控制宽度)并平移(bbb控制位置)到时间点bbb。
- f(t)×…f(t) \times \dotsf(t)×…:把拉伸平移后的小波波形,与信号f(t)f(t)f(t)在当前范围内对应点相乘。
- ∫…dt\int \dots dt∫…dt:把所有乘积加起来(积分就是连续的求和)。
这和刚才手算[2,2]×[1,−1]=0[2, 2] \times [1, -1] = 0[2,2]×[1,−1]=0的过程是一模一样的,只不过一个是手动算6个点,电脑可能一秒钟算几百万个点。
6. Matlab仿真
%% 小波变换本质理解:DWT = 两两配对、互不重叠% 结论:长度 N 的信号经一级 DWT 得到 N/2 个细节 + N/2 个近似,% 总数仍为 N —— 无冗余,才能精确重构。clc;clear;close all;%% 1. 信号与 Haar 分析滤波器(与 MATLAB db1一致)f=[2,2,2,5,5,5];Lo_D=[1,1]/sqrt(2);% 近似(平均):两数之和 / sqrt(2)Hi_D=[-1,1]/sqrt(2);% 细节(差分):后减前 / sqrt(2)fprintf('matlab里的dwt计算为了能量保持不变,做差值或求平均会除以根号2');fprintf('原始信号: ');fprintf('%g ',f);fprintf('\n');%% 2. 手动计算:两两配对(窗口宽2、步长2,不重叠)n=length(f);npair=n/2;% 6 样本 -> 3 对cA_manual=zeros(1,npair);cD_manual=zeros(1,npair);fork=1:npair pair=f(2*k-1:2*k);% (f1,f2) (f3,f4) (f5,f6)cA_manual(k)=sum(pair.*Lo_D);% 加权平均cD_manual(k)=sum(pair.*Hi_D);% 加权差分end%% 3. MATLAB 函数对照(dwt 本质 = 滤波器卷积 + 隔2抽取)[cA,cD]=dwt(f,'db1');% db1 == Haarf_rec=idwt(cA,cD,'db1');% 逆变换重构验证recErr=max(abs(f_rec-f));disp('--- 细节系数 cD ---');disp([cD_manual;cD]);disp('--- 近似系数 cA ---');disp([cA_manual;cA]);fprintf('|ΔcD|=%.2e, |ΔcA|=%.2e\n',...abs(cD_manual-cD),abs(cA_manual-cA));fprintf('idwt 重构误差 = %.2e (3+3=6 个系数,信息零损失)\n',recErr);%% 4. 可视化figure('Name','DWT 本质:两两配对','NumberTitle','off','Position',[100100850850]);subplot(3,1,1);stem(1:n,f,'k','filled');hold on;grid on;xlabel('样本序号');title('原始信号序列');subplot(3,1,2);stem(1:npair,cD_manual,'b','filled','LineWidth',1.5);grid on;ylim([-13]);title(['手动配对计算的 cD = ['sprintf('%.4f ',cD_manual)']']);xlabel('配对编号 k \leftrightarrow 样本对 (f_{2k-1}, f_{2k})');subplot(3,1,3);stem(1:npair,cD,'r','filled','LineWidth',1.5);grid on;ylim([-13]);title(['dwt(''db1'') 输出的 cD = ['sprintf(' %.4f',cD)' ]']);ylim([-31]);xlabel('配对编号 k');说明:这里"一正一负"暴露了 DWT 实现里最容易踩的一个坑:卷积会自动把滤波器左右翻转。
根源:卷积 ≠ 相关
MATLAB 的dwt内部是"真卷积 + 隔2抽取":
cD(k)=∑mh~(m) f(2k−m),h~ 是 Hi_D 翻转后的核cD(k) = \sum_m \tilde{h}(m)\, f(2k-m), \quad \tilde{h} \text{ 是 } Hi\_D \text{ 翻转后的核}cD(k)=m∑h~(m)f(2k−m),h~是Hi_D翻转后的核
而手算是内积(相关):sum(pair .* Hi_D),滤波器不翻转。两者等效于用了两个互为镜像的滤波器:
| 使用的核 | 对配对 (2, 5) 的运算 | 结果 | |
|---|---|---|---|
| 手动(相关) | [−1,+1]/2[-1, +1]/\sqrt{2}[−1,+1]/2 | (5−2)/2(5-2)/\sqrt{2}(5−2)/2 | +2.1213 |
dwt(卷积) | [+1,−1]/2[+1, -1]/\sqrt{2}[+1,−1]/2(翻转后) | (2−5)/2(2-5)/\sqrt{2}(2−5)/2 | −2.1213 |