小波学习之一(单层一维离散小波变换DWT的Mallat算法C++和MATLAB实现) ---转载
1 Mallat算法
离散序列的Mallat算法分解公式如下:

其中,H(n)、G(n)分别表示所选取的小波函数对应的低通和高通滤波器的抽头系数序列。
从Mallat算法的分解原理可知,分解后的序列就是原序列与滤波器序列的卷积再进行隔点抽取而来。
离散序列的Mallat算法重构公式如下:

其中,h(n)、g(n)分别表示所选取的小波函数对应的低通和高通滤波器的抽头系数序列。
2 小波变换实现过程(C/C++)
2.1 小波变换结果序列长度
小波的Mallat算法分解后的序列长度由原序列长SoureLen和滤波器长FilterLen决定。从Mallat算法的分解原理可知,分解后的序列就是原序列与滤波器序列的卷积再进行隔点抽取而来。即分解抽取的结果长度为(SoureLen+FilterLen-1)/2。
2.2 获取滤波器组
对于一些通用的小波函数,简单起见,可以通过Matlab的wfilters(‘wavename’)获取4个滤波器;特殊的小波函数需要自行构造获得。
下面以db1小波函数(Haar小波)为例,其变换与重构滤波器组的结果如下:
- //matlab输入获取命令
- >> [Lo_D,Hi_D,Lo_R,Hi_R] = wfilters('db1')
- //获取的结果
- Lo_D =
- 0.7071 0.7071
- Hi_D =
- -0.7071 0.7071
- Lo_R =
- 0.7071 0.7071
- Hi_R =
- 0.7071 -0.7071
//matlab输入获取命令
>> [Lo_D,Hi_D,Lo_R,Hi_R] = wfilters('db1') //获取的结果
Lo_D =
0.7071 0.7071
Hi_D =
-0.7071 0.7071
Lo_R =
0.7071 0.7071
Hi_R =
0.7071 -0.7071
2.3 信号边界延拓
在Mallat算法中,假定输入序列是无限长的,而实际应用中输入的信号是有限的采样序列,这就会出现信号边界处理问题。对于边界信号的延拓一般有3种方法,即零延拓、对称延拓和周期延拓。
3种延拓方法比较情况如下:
对于正交小波变换来说,前两种延拓方法实现起来比较简单,但重建时会产生边界效应,而且分解的层数越多,产生的边界效应越显著。零延拓方法给人一种跳跃的感觉。至于对称性延拓,由于正交小波滤波器一般都是非对称性的(Haar小波基虽然是正交的,但它是非连续的),重建图象给人一种错位的感觉。相比较而言,只有最后一种延拓方式可以得到比较精确的重建结果,它不仅能保证分解与重建正确计算,而且恢复的质量也好。不过,周期性延拓方法虽然是常用的三种方法中比较好的方法,但会导致信号边缘的非连续性,从而会使得较高频率(子带)层的小波系数很大,即使信号本身相当平滑。从信号压缩的角度看,大的系数是希望避免的。信号的对称延拓可避免边缘的非连续性问题。然而,对称延拓只能和对称的小波滤波器一起适用。如果降低正交性要求,选择双正交小波变换,对称性延拓不失为一种好的方法。周期延拓可适用于任何小波变换,但可能导致输入序列边缘的不连续,使得高频系数较大。而对称延拓则避免了输入序列边界的不连续,是当前广泛采用的一种延拓方法。
下式中给出了最常用的对称延拓表达式。

当原序列长sLEN为偶数时延拓后的序列长为sLEN+2*(filterLEN),而原序列长为奇数时则需要在右端再延拓一个元素。注:在Matlab中默认使用了对称延拓。
2.4 小波分解
在db1小波函数下,离散序列的Mallat算法分解公式展开如下:

其它的db小波,不再详述。小波分解C++源码如下。
- /**
- * @brief 小波变换之分解
- * @param sourceData 源数据
- * @param dataLen 源数据长度
- * @param db 过滤器类型
- * @param cA 分解后的近似部分序列-低频部分
- * @param cD 分解后的细节部分序列-高频部分
- * @return
- * 正常则返回分解后序列的数据长度,错误则返回-1
- */
- int Wavelet::Dwt(double *sourceData, int dataLen, Filter db, double *cA, double *cD)
- {
- if(dataLen < 2)
- return -1;
- if((NULL == sourceData)||(NULL == cA)||(NULL == cD))
- return -1;
- m_db = db;
- int filterLen = m_db.length;
- int n,k,p;
- int decLen = (dataLen+filterLen-1)/2;
- double tmp=0;
- cout<<"decLen="<<decLen<<endl;
- for(n=0; n<decLen; n++)
- {
- cA[n] = 0;
- cD[n] = 0;
- for(k=0; k<filterLen; k++)
- {
- p = 2*n-k; // 感谢网友onetrain指正,此处由p = 2*n-k+1改为p = 2*n-k,解决小波重构后边界异常问题--2013.3.29 by hmm
- // 信号边沿对称延拓
- if((p<0)&&(p>=-filterLen+1))
- tmp = sourceData[-p-1];
- else if((p>dataLen-1)&&(p<=dataLen+filterLen-2))
- tmp = sourceData[2*dataLen-p-1];
- else if((p>=0)&&(p<dataLen-1))
- tmp = sourceData[p];
- else
- tmp = 0;
- // 分解后的近似部分序列-低频部分
- cA[n] += m_db.lowFilterDec[k]*tmp;
- // 分解后的细节部分序列-高频部分
- cD[n] += m_db.highFilterDec[k]*tmp;
- }
- }
- return decLen;
- }
/**
* @brief 小波变换之分解
* @param sourceData 源数据
* @param dataLen 源数据长度
* @param db 过滤器类型
* @param cA 分解后的近似部分序列-低频部分
* @param cD 分解后的细节部分序列-高频部分
* @return
* 正常则返回分解后序列的数据长度,错误则返回-1
*/
int Wavelet::Dwt(double *sourceData, int dataLen, Filter db, double *cA, double *cD)
{
if(dataLen < 2)
return -1;
if((NULL == sourceData)||(NULL == cA)||(NULL == cD))
return -1; m_db = db;
int filterLen = m_db.length;
int n,k,p;
int decLen = (dataLen+filterLen-1)/2;
double tmp=0;
cout<<"decLen="<<decLen<<endl; for(n=0; n<decLen; n++)
{
cA[n] = 0;
cD[n] = 0;
for(k=0; k<filterLen; k++)
{
p = 2*n-k; // 感谢网友onetrain指正,此处由p = 2*n-k+1改为p = 2*n-k,解决小波重构后边界异常问题--2013.3.29 by hmm // 信号边沿对称延拓
if((p<0)&&(p>=-filterLen+1))
tmp = sourceData[-p-1];
else if((p>dataLen-1)&&(p<=dataLen+filterLen-2))
tmp = sourceData[2*dataLen-p-1];
else if((p>=0)&&(p<dataLen-1))
tmp = sourceData[p];
else
tmp = 0; // 分解后的近似部分序列-低频部分
cA[n] += m_db.lowFilterDec[k]*tmp; // 分解后的细节部分序列-高频部分
cD[n] += m_db.highFilterDec[k]*tmp;
} } return decLen;
}
2.5 小波重构
- /**
- * @brief 小波变换之重构
- * @param cA 分解后的近似部分序列-低频部分
- * @param cD 分解后的细节部分序列-高频部分
- * @param cALength 输入数据长度
- * @param db 过滤器类型
- * @param recData 重构后输出的数据
- */
- void Wavelet::Idwt(double *cA, double *cD, int cALength, Filter db, double *recData)
- {
- if((NULL == cA)||(NULL == cD)||(NULL == recData))
- return;
- m_db = db;
- int filterLen = m_db.length;
- int n,k,p;
- int recLen = 2*cALength-filterLen+1;
- cout<<"recLen="<<recLen<<endl;
- for(n=0; n<recLen; n++)
- {
- recData[n] = 0;
- for(k=0; k<cALength; k++)
- {
- p = n-2*k+filterLen-1;
- // 信号重构
- if((p>=0)&&(p<filterLen))
- {
- recData[n] += m_db.lowFilterRec[p]*cA[k] + m_db.highFilterRec[p]*cD[k];
- //cout<<"recData["<<n<<"]="<<recData[n]<<endl;
- }
- }
- }
- }
/**
* @brief 小波变换之重构
* @param cA 分解后的近似部分序列-低频部分
* @param cD 分解后的细节部分序列-高频部分
* @param cALength 输入数据长度
* @param db 过滤器类型
* @param recData 重构后输出的数据
*/
void Wavelet::Idwt(double *cA, double *cD, int cALength, Filter db, double *recData)
{
if((NULL == cA)||(NULL == cD)||(NULL == recData))
return; m_db = db;
int filterLen = m_db.length; int n,k,p;
int recLen = 2*cALength-filterLen+1;
cout<<"recLen="<<recLen<<endl; for(n=0; n<recLen; n++)
{
recData[n] = 0;
for(k=0; k<cALength; k++)
{
p = n-2*k+filterLen-1; // 信号重构
if((p>=0)&&(p<filterLen))
{
recData[n] += m_db.lowFilterRec[p]*cA[k] + m_db.highFilterRec[p]*cD[k];
//cout<<"recData["<<n<<"]="<<recData[n]<<endl;
} }
}
}
2.6 c++实现结果

3 小波变换实现(MATLAB)
使用matlab小波工具箱实现db4的情况如下。
1、MatlabDB4.m文件内容。
- %加载txt数据示例
- s=importdata('data2.txt'); %load data2.txt;
- subplot(521);plot(s); %画出原始信号的波形图
- title('原始信号');
- [cA,cD]=dwt(s,'db4'); %采用db4小波并对信号进行一维离散小波分解。
- y=idwt(cA,cD,'db4'); %一维离散小波反变换
- subplot(522);
- plot(cA); %画出波形图
- title('MATLAB低频部分dwt-cA');
- subplot(523);
- plot(cD); %画出波形图
- title('MATLAB高频部分dwt-cD');
- subplot(524);
- plot(y); %画出波形图
- title('MATLAB重构idwt');
%加载txt数据示例
s=importdata('data2.txt'); %load data2.txt;
subplot(521);plot(s); %画出原始信号的波形图
title('原始信号'); [cA,cD]=dwt(s,'db4'); %采用db4小波并对信号进行一维离散小波分解。
y=idwt(cA,cD,'db4'); %一维离散小波反变换
subplot(522);
plot(cA); %画出波形图
title('MATLAB低频部分dwt-cA'); subplot(523);
plot(cD); %画出波形图
title('MATLAB高频部分dwt-cD'); subplot(524);
plot(y); %画出波形图
title('MATLAB重构idwt');
2、波形图如下。

4 小结
在此,采用C++实现了dbN系列小波的单层一维离散小波变换,通过对比db4小波变换发现(笔者也同样对比验证了db1-db3),C++实现效果和Matlab效果完全一样。通过这一过程,可以很好地帮助理解小波变换的Mallat算法原理,并将C++代码快速应用到工程实践,同时对MATLAB小波工具箱的实现细节也有更深入的理解。相关文献表明,C++代码实现的DWT算法比Matlab小波工具箱dwt方法效率更高。
注:对小波变换见识还不深,有问题者,欢迎提出讨论交流,对源码细节感兴趣的tx,可以到如下链接下载。
小波学习之一(单层一维离散小波变换DWT的Mallat算法C++和MATLAB实现) ---转载的更多相关文章
- 小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化)--转载
小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化) 在上回<小波学习之一>中,已经详细介绍了Mallat算法C++实现,效果还可以,但也存在一些问题,比如,代码 ...
- [Python ]小波变化库——Pywalvets 学习笔记
[Python ]小波变化库——Pywalvets 学习笔记 2017年03月20日 14:04:35 SNII_629 阅读数:24776 标签: python库pywavelets小波变换 更多 ...
- 小波变化库——Pywalvets学习笔记
笔记 术语(中英对照): 尺度函数:scaling function(又称父函数 father wavelet) 小波函数:wavelet function(又称母函数 mother wavelet) ...
- 基于python的小波阈值去噪算法
https://blog.csdn.net/alwaystry/article/details/52756051 发表于 2018-01-10 16:32:17 嵌入式设计应用 +关注 小波图像去噪原 ...
- 小波说雨燕 第三季 构建 swift UI 之 UI组件集-视图集(六)Picker View视图 学习笔记
想对PickerView进行操作,只能在代码中操作. 下面 ,再添加三个label组件,然后将所有组件配置到代码中(看代码),然后要实现对PickerView的操作,就要实现它的DataSource协 ...
- 多尺度二维离散小波重构waverec2
clc,clear all,close all; load woman; [c,s]=wavedec2(X,2,'haar');%进行2尺度二维离散小波分解.分解小波函数haar %多尺度二维离散小波 ...
- 单尺度二维离散小波重构(逆变换)idwt2
clc,clear all,close all; load woman; %单尺度二维离散小波分解.分解小波函数haar [cA,cH,cV,cD]=dwt2(X,'haar'); %单尺度二维离散小 ...
- 多尺度二维离散小波分解wavedec2
对X进行N尺度小波分解 [C,S]=wavedec2(X,N,'wname'); clc,clear all,close all; load woman; [c,s]=wavedec2(X,2,'db ...
- 单尺度二维离散小波分解dwt2
clc,clear all,close all; load woman; [cA,cH,cV,cD]=dwt2(X,'haar');%单尺度二维离散小波分解.分解小波函数haar figure,ims ...
随机推荐
- logstash配置文件
1. 安装 logstash 安装过程很简单,直接参照官方文档: https://www.elastic.co/guide/en/logstash/current/installing-logsta ...
- 小程序动态添加class及调接口传递多个参数
1.动态添加class <view class="step2 {{indication == 2 ?'on':''}}"> <view class='tc lef ...
- luffy之多条件登录与极验滑动验证码
多条件登录 JWT扩展的登录视图,在收到用户名与密码时,也是调用Django的认证系统中提供的authenticate()来检查用户名与密码是否正确. 我们可以通过修改Django认证系统的认证后端( ...
- Jamie and Tree CodeForces - 916E (换根)
大意: n节点树, 每个点有权值, 三种操作: 1,换根. 2, lca(u,v)的子树权值全部增加x. 3, 查询子树权值和. 先不考虑换根, 考虑子树x加v的贡献 (1)对fa[x]到根的树链贡献 ...
- python记录_day05 字典
字典 字典由花括号表示{ },元素是key:value的键值对,元素之间用逗号隔开 特点:1.字典中key是不能重复的 且是不可变的数据类型,因为字典是使用hash算法来计算key的哈希值,然后用哈希 ...
- mybatis中的mapper接口文件以及selectByExample类的实例函数详解
记录分为两个部分,第一部分主要关注selectByExample类的实例函数的实现:第二部分讨论Mybatis框架下基本的实例函数. (一)selectByExample类的实例函数的实现 当你启动项 ...
- MySql从一窍不通到入门(五)Sharding:分表、分库、分片和分区
转载:用sharding技术来扩展你的数据库(一)sharding 介绍 转载:MySQL架构方案 - Scale Out & Scale Up. 转载: 数据表分区策略及实现(一) 转载:M ...
- IDEA Activiti Designer插件---actiBPM汉字乱码问题
1.找到IDEA的安装目录 2.用编辑器打开,在文件末尾添加 -Dfile.encoding=UTF-8
- ssm的web项目,浏览器使用get方法传递中文参数时,出现乱码
ssm的web项目,浏览器使用get链接传递的为中文参数时,出现乱码 做搜索功能时,搜索手机,那么浏览器传递的参数为中文参数“手机”,但传递的默认编码格式为iso-8859-1,所以传到后台时,是乱码 ...
- 从使用角度看 ReentrantLock 和 Condition
java 语言中谈到锁,少不了比较一番 synchronized 和 ReentrantLock 的原理,本文不作分析,只是简单介绍一下 ReentrantLock 的用法,从使用中推测其内部的一些原 ...