手动实现一维离散数据小波分解与重构

前言

本文集中前面主要介绍了离散数据的傅里叶变换,并且得到了较好的效果!那既然有了傅里叶变换这个工具,为什么还需要小波变换呢?因为:傅里叶变换只能告诉你原始信号中有哪些频率,但不能告诉你这些频率的信号出现在什么时间!也就说明:如果信号是"时变"的(频率随着时间是改变的),那么单纯用傅里叶变换所能反映的信息就十分有限了!因此,针对时变信号,我们使用小波变换。图1展示"时变信号"与"时不变信号"区别:

图1:时不变信号与时变信号

时不变与时变的区别,看下面的实现的代码就很轻易理解:

x = 0:0.001:1;

% 4个频率: 
f1 = 50; f2 = 80; f3 = 110; f4 = 20;

% 时不变信号: 多频
y1 = sin(2*pi*f1*x) + sin(2*pi*f2*x) + sin(2*pi*f3*x) + sin(2*pi*f4*x);
% 时变信号: 多频 
y2 = sin(2*pi*f1*x).*(x<=0.3) + sin(2*pi*f2*x).*(x>0.3 & x<=0.6)+...
     sin(2*pi*f3*x).*(x>0.6 & x<=0.8) + sin(2*pi*f4*x).*(x>0.8);

figure(1);

subplot(2,1,1);
plot(y1);
grid on;
xlabel('采样点'); ylabel('振幅');
axis([0 1000 -inf inf]);
title('时不变信号');

subplot(2,1,2);
plot(y2);
grid on;
xlabel('采样点'); ylabel('振幅');
axis([0 1000 -inf inf]);
title('时变信号')

本文同样考虑的是离散数据的小波变换使用。通过手动matlab编程实现小波变换"塔式分解"与"重构"来深刻了解小波变换实现的内在含义。之后,借助matlab自带的一系列相关小波变换程序来实现"时频分析"和"小波去噪"。

说明:本文更加侧重详细介绍matlab自带各种小波功能函数的使用!除了小波分解与重构的程序我们手动实现外,其他的各种操作都建议用自带函数实现。

小波分解:

小波分解的流程总结为:先将信号对半分解成"低频近似"与"高频细节"2个部分;同样的操作每次将上一次的"低频近似"部分再分成低频近似和高频细节部分,逐次细分(最多分解到每个部分只有1个点)。每次分出的高频细节部分不做分解。因此:每次分出低频近似部分相当于对本次信号做"低通滤波",分出的高频细节部分相当于对本次信号做"高通滤波"。所以:每次小波分解就是用1个低通滤波器和1个高通滤波器对本次信号做1次低通滤波和1次高通滤波而已。

由上述说明可得:小波分解的关键在于2个(一组)滤波器。对于现实的离散数据而言,滤波器看上去很高大上其实就是很简单的数字而已,滤波听起来很难,其实就是做"点乘相加"而已。离散小波分解中最简单的一组滤波器为:

低通滤波器:[0.5, 0.5];高通滤波器:[0.5, -0.5]

下面举例说明如何用上面这一组最简单滤波器对离散数据进行小波分解:

假设我们的离散数据为:[2,5,8, 9, 7, 4, -1, 1]

(1) 第一级分解:

低通滤波:
2*0.5 + 5*0.5 = 1 + 2.5 = 3.5

8*0.5 + 9*0.5 = 4 + 4.5 = 8.5

7*0.5 + 4*0.5 = 3.5 + 2 = 5.5

-1*0.5 + 1*0.5 = -0.5 + 0.5 = 0

得到低频近似部分:[3.5,8.5,5.5,0]

高通滤波:

2*0.5 + 5*(-0.5) = 1 - 2.5 = -1.5

8*0.5 + 9*(-0.5) = 4 - 4.5 = -0.5

7*0.5 + 4*(-0.5) = 3.5 - 2 = 1.5

-1*0.5 + 1*(-0.5) = -0.5 - 0.5 = -1

得到高频细节部分:[-1.5,-0.5,1.5,-1]

(2)第二级分解:

分解上一次分解得到的低频近似部分,高频细节不动。即待分解信号为:

[3.5,8.5,5.5,0]

低通滤波:

3.5*0.5 + 8.5*0.5 = 1.75 + 4.25 = 6

5.5*0.5 + 0*0.5 = 2.25 + 0 = 2.25

得到的低频近似部分为:[6,2.25]

高通滤波:

3.5*0.5 + 8.5*(-0.5) = 1.75 - 4.25 = -2.5

5.5*0.5 + 0*(-0.5) = 2.25 + 0 = 2.25

得到的高频细节部分为:[-2.5,2.25]

(3)第3级分解:

同理,待分解信号是上一次分解得到的低频近似部分:

[6,2.25]

低通滤波:

6*0.5 + 2.25*0.5 = 3 + 1.125 = 4.125

得到的低频近似部分为:[4.125]

高通滤波:

6*0.5 + 2.25*(-0.5) = 3 - 1.125 = 1.875

得到的高频细节部分为:[1.875]

到此为止,例子中给出的原始离散信号就达到了其最大分解级数(分解到元素只有1个)。整个过程很简单,只需注意每次点乘求和元素是无重合的。整个的多级分解过程如图2所示:

图2:离散信号小波多级分解示意图

注意:不同组的高通和低通滤波中都有这样的一个规律:两者的区别只是高通滤波器第2个值负数而已;数都是一样的。

小波多级分解清楚了,那怎么"重构/恢复"回去呢?塔式分解的逆向合成而已。根据滤波器的规律,我们可以设:

滤波器:\begin{cases} [a,a] & 低通滤波器 \\ [a,-a] & 高通滤波器 \\ \end{cases}

以2级分解到3级为例,我们知道:

6*a + 2.25*a = 3级低通近似

6*a + 2.25*(-a) = 3级高通细节

那么逆过程就是,我们知道了3级低通近似和高通细节的值,我们还知道滤波器的数值(a已知),然后反推2级低通近似和高通细节数值,即:

2级低通近似*a + 2级高通细节*a = 4.125

2级低通近似*a + 2级高通细节*(-a) = 1.875

所以:

2级低通近似 = \frac{4.125 + 1.875}{2}

2级高通细节 = \frac{4.125 - 1.875}{2}

这样我们就得到了2级低通近似和2解高通细节,然后逐级往上递推即可实现重构/恢复~ so easy.

整个分解过程我们清楚了,现在我们引入一些专业的名词:在离散数据中,一组低通高通滤波器,其实就是"小波基函数"!取不同的小波基函数其实就是滤波器里面的数值不同而已。最常用的"haar小波基"。下面我们就利用haar小波基,在matlab里手动实现小波分解与重构:

matlab手动实现小波分解程序:

clc ; clear;

% 每次修改这里的原始数据, 个数最好是2^n
% x = [9 7 3 5];
 x = [2 5 8 9 7 4 -1 1];
% x = [2 5 8 9 7 4 -1 1 2 1 8 3 8 0 3 1];

order_max = log(length(x))/log(2);
fprintf('当前数据最多分解%d阶\n',order_max);
order = double(input('自定义分解阶数( order<order_max ):'));

% matlab默认的haar小波基函数:
low = [1/sqrt(2) 1/sqrt(2)];
high = [1/sqrt(2) -1/sqrt(2)];

new = zeros(1,length(x));  % 最后结果 —— 均值 + 差值
ave = zeros(1,length(x)/2);   % 均值(低频)记录
dec = zeros(1,length(x)/2);   % 差值(高频)记录

% 小波循环分解部分: 其实就是低通和高通2种情况的卷积计算 
m = 1;
xtmp = x;
for norder = 1:order
    for n = 1:2:length(xtmp)
        ave(m) = sum(xtmp(n:n+1).*low);
        dec(m) = sum(xtmp(n:n+1).*high);
        m = m + 1;
    end
    % 下面2句的赋值过程, 总体是从后往前赋值的~
    % 进入过的高频就不会动了; 进入的低频再下次就会被自己分解出的高频和低频取代——总体从后往前√
    new( length(xtmp)/2+1:length(xtmp) ) = dec( 1:2^(order_max-norder) ); % 记录每次更新的高频内容; 
    new( 1:length(xtmp)/2 ) = ave( 1:2^(order_max-norder) );              % 记录每次更新的低频内容;
    xtmp = ave( 1:2^(order_max-norder) );
    m = 1;
end

fprintf('手写%d级分解结果为:\n',order);
new
 
fprintf('matlab自带%d级分解结果为:\n',order);
wavedec(x,order,'haar')

matlab手动实现小波重构/恢复程序:

clc ; clear;

% 每次修改这里的原始数据, 个数最好是2^n
% x = [9 7 3 5];
 x = [2 5 8 9 7 4 -1 1];
% x = [2 5 8 9 7 4 -1 1 2 1 8 3 8 0 3 1];

order_max = log(length(x))/log(2);
fprintf('当前数据最多分解%d阶\n',order_max);
order = double(input('自定义分解阶数( order<order_max ):'));

% 直接用知自带的分解函数:
new = wavedec(x,order,'haar');  

% 小波重构——任意haar基函数全能重构回去
% 计算的系数: 与基函数有关
tmp1 = 1/( low(1) + high(1) );

% 迭代重构开始:
xrec = zeros(1,length(new));  % 记录复原的数据
new_rec = new;

for norder = order_max+1-order : order_max  % 这个规律让任意低阶都可以适用
    m = 1;  % 专门用来记录"前半段"位置——给奇数位用的
    for n = 1:2^norder
        half = 2^norder/2;  % 当前重构区间的一半——也是用来给奇数位计算用的
        if mod(n,2) ~= 0  
            % 奇数时操作: 
            xrec(n) = tmp1*( new_rec(m) + new_rec(m+half) );   
            m = m + 1;
        else
            % 偶数时操作: 
            xrec(n) = (new_rec(m-1) - low(1)*xrec(n-1))/low(2);       
        end
    end 
    new_rec(1:n) = xrec(1:n);  % 每次要更新的(后一次重构基于前一次结果): 从前往后
end

fprintf('%d级分解后重构:\n',order);
new_rec

fprintf('自带的%d级重构结构:\n',order);
[C,S] = wavedec(x,order,'haar');
waverec(C,S,'haar')
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容