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小波)为例,其变换与重构滤波器组的结果如下:

  1. //matlab输入获取命令
  2. >> [Lo_D,Hi_D,Lo_R,Hi_R] = wfilters('db1')
  3. //获取的结果
  4. Lo_D =
  5. 0.7071    0.7071
  6. Hi_D =
  7. -0.7071    0.7071
  8. Lo_R =
  9. 0.7071    0.7071
  10. Hi_R =
  11. 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++源码如下。

  1. /**
  2. * @brief 小波变换之分解
  3. * @param sourceData 源数据
  4. * @param dataLen 源数据长度
  5. * @param db 过滤器类型
  6. * @param cA 分解后的近似部分序列-低频部分
  7. * @param cD 分解后的细节部分序列-高频部分
  8. * @return
  9. *         正常则返回分解后序列的数据长度,错误则返回-1
  10. */
  11. int Wavelet::Dwt(double *sourceData, int dataLen, Filter db, double *cA, double *cD)
  12. {
  13. if(dataLen < 2)
  14. return -1;
  15. if((NULL == sourceData)||(NULL == cA)||(NULL == cD))
  16. return -1;
  17. m_db = db;
  18. int filterLen = m_db.length;
  19. int n,k,p;
  20. int decLen = (dataLen+filterLen-1)/2;
  21. double tmp=0;
  22. cout<<"decLen="<<decLen<<endl;
  23. for(n=0; n<decLen; n++)
  24. {
  25. cA[n] = 0;
  26. cD[n] = 0;
  27. for(k=0; k<filterLen; k++)
  28. {
  29. p = 2*n-k;  // 感谢网友onetrain指正,此处由p = 2*n-k+1改为p = 2*n-k,解决小波重构后边界异常问题--2013.3.29 by hmm
  30. // 信号边沿对称延拓
  31. if((p<0)&&(p>=-filterLen+1))
  32. tmp = sourceData[-p-1];
  33. else if((p>dataLen-1)&&(p<=dataLen+filterLen-2))
  34. tmp = sourceData[2*dataLen-p-1];
  35. else if((p>=0)&&(p<dataLen-1))
  36. tmp = sourceData[p];
  37. else
  38. tmp = 0;
  39. // 分解后的近似部分序列-低频部分
  40. cA[n] += m_db.lowFilterDec[k]*tmp;
  41. // 分解后的细节部分序列-高频部分
  42. cD[n] += m_db.highFilterDec[k]*tmp;
  43. }
  44. }
  45. return decLen;
  46. }
/**
* @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      小波重构
  1. /**
  2. * @brief 小波变换之重构
  3. * @param cA 分解后的近似部分序列-低频部分
  4. * @param cD 分解后的细节部分序列-高频部分
  5. * @param cALength 输入数据长度
  6. * @param db 过滤器类型
  7. * @param recData 重构后输出的数据
  8. */
  9. void  Wavelet::Idwt(double *cA, double *cD,  int cALength, Filter db, double *recData)
  10. {
  11. if((NULL == cA)||(NULL == cD)||(NULL == recData))
  12. return;
  13. m_db = db;
  14. int filterLen = m_db.length;
  15. int n,k,p;
  16. int recLen = 2*cALength-filterLen+1;
  17. cout<<"recLen="<<recLen<<endl;
  18. for(n=0; n<recLen; n++)
  19. {
  20. recData[n] = 0;
  21. for(k=0; k<cALength; k++)
  22. {
  23. p = n-2*k+filterLen-1;
  24. // 信号重构
  25. if((p>=0)&&(p<filterLen))
  26. {
  27. recData[n] += m_db.lowFilterRec[p]*cA[k] + m_db.highFilterRec[p]*cD[k];
  28. //cout<<"recData["<<n<<"]="<<recData[n]<<endl;
  29. }
  30. }
  31. }
  32. }
/**
* @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文件内容。

  1. %加载txt数据示例
  2. s=importdata('data2.txt'); %load data2.txt;
  3. subplot(521);plot(s); %画出原始信号的波形图
  4. title('原始信号');
  5. [cA,cD]=dwt(s,'db4'); %采用db4小波并对信号进行一维离散小波分解。
  6. y=idwt(cA,cD,'db4'); %一维离散小波反变换
  7. subplot(522);
  8. plot(cA); %画出波形图
  9. title('MATLAB低频部分dwt-cA');
  10. subplot(523);
  11. plot(cD); %画出波形图
  12. title('MATLAB高频部分dwt-cD');
  13. subplot(524);
  14. plot(y); %画出波形图
  15. 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实现) ---转载的更多相关文章

  1. 小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化)--转载

    小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化)   在上回<小波学习之一>中,已经详细介绍了Mallat算法C++实现,效果还可以,但也存在一些问题,比如,代码 ...

  2. [Python ]小波变化库——Pywalvets 学习笔记

    [Python ]小波变化库——Pywalvets 学习笔记 2017年03月20日 14:04:35 SNII_629 阅读数:24776 标签: python库pywavelets小波变换 更多 ...

  3. 小波变化库——Pywalvets学习笔记

    笔记 术语(中英对照): 尺度函数:scaling function(又称父函数 father wavelet) 小波函数:wavelet function(又称母函数 mother wavelet) ...

  4. 基于python的小波阈值去噪算法

    https://blog.csdn.net/alwaystry/article/details/52756051 发表于 2018-01-10 16:32:17 嵌入式设计应用 +关注 小波图像去噪原 ...

  5. 小波说雨燕 第三季 构建 swift UI 之 UI组件集-视图集(六)Picker View视图 学习笔记

    想对PickerView进行操作,只能在代码中操作. 下面 ,再添加三个label组件,然后将所有组件配置到代码中(看代码),然后要实现对PickerView的操作,就要实现它的DataSource协 ...

  6. 多尺度二维离散小波重构waverec2

    clc,clear all,close all; load woman; [c,s]=wavedec2(X,2,'haar');%进行2尺度二维离散小波分解.分解小波函数haar %多尺度二维离散小波 ...

  7. 单尺度二维离散小波重构(逆变换)idwt2

    clc,clear all,close all; load woman; %单尺度二维离散小波分解.分解小波函数haar [cA,cH,cV,cD]=dwt2(X,'haar'); %单尺度二维离散小 ...

  8. 多尺度二维离散小波分解wavedec2

    对X进行N尺度小波分解 [C,S]=wavedec2(X,N,'wname'); clc,clear all,close all; load woman; [c,s]=wavedec2(X,2,'db ...

  9. 单尺度二维离散小波分解dwt2

    clc,clear all,close all; load woman; [cA,cH,cV,cD]=dwt2(X,'haar');%单尺度二维离散小波分解.分解小波函数haar figure,ims ...

随机推荐

  1. source code spark

    http://blog.csdn.net/pelick/article/category/1556747 http://www.cnblogs.com/hseagle/

  2. centos 安装 和 linux 简单命令

    1. centos 安装 参照:https://www.cnblogs.com/tiger666/articles/10259102.html 安装过程注意点: 1. 安装过程中的选择安装Basic ...

  3. NIM 博弈 牛客小白月赛2 E-是是非非

    题目链接 分析:一个裸的NIM博弈 对于一个Nim游戏的局面(a1,a2,...,an),它是P-position(即当前局面先手必败)当且仅当a1^a2^...^an=0,其中^表示异或(xor)运 ...

  4. mysql命令查询

    含义 命令 查看gtid是否开启 show variables like '%gtid%';  查看只读信息 show global variables like "%read_only%& ...

  5. link标签实现给网页标题前加一个小图标favicon.ico

    使用方法如下:1.<link rel="shortcut icon " type="images/x-icon" href="./favicon ...

  6. ireport部署到Linux服务器上遇到的问题解决

    ireport报表在本地Windows环境运行正常,一旦部署到Linux环境上出现了如下问题: 1.打开报表,后台直接报net.sf.jasperreports.engine.util.JRFontN ...

  7. js动态检测加载 JQ

    var jqcdnurl = 'https://cdn.bootcss.com/jquery/3.2.1/jquery.js'; //控制台输出 function log() { for (var i ...

  8. Version Control System

    Version  Control System(版本控制系统),是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统.版本控制系统不仅可以应用于软件源代码的文本文件,而且可以对任何类型 ...

  9. 函数使用八:BP_EVENT_RAISE

    此函数是关联触发一个已经定义的事件,这个事件可以放到SM36里设置JOB,这样就做成了一个事件触发JOB的东西. Import EVENTID                    事件ID ,对应S ...

  10. WDA基础四:Select-option的使用

    select option是方便用户和数据处理的,就是丑了点... 前面使用的input直接做查询条件有哥弊端,就是查询的时候需要判断字段是否有选择条件,然后要将选择条件做成range table.. ...