详解python实现小波变换的一个简单例子


Posted in Python onJuly 18, 2019

最近工作需要,看了一下小波变换方面的东西,用python实现了一个简单的小波变换类,将来可以用在工作中。

简单说几句原理,小波变换类似于傅里叶变换,都是把函数用一组正交基函数展开,选取不同的基函数给出不同的变换。例如傅里叶变换,选择的是sin和cos,或者exp(ikx)这种复指数函数;而小波变换,选取基函数的方式更加灵活,可以根据要处理的数据的特点(比如某一段上信息量比较多),在不同尺度上采用不同的频宽来对已知信号进行分解,从而尽可能保留多一点信息,同时又避免了原始傅里叶变换的大计算量。以下计算采用的是haar基,它把函数分为2段(A1和B1,但第一次不分),对第一段内相邻的2个采样点进行变换(只考虑A1),变换矩阵为

sqrt(0.5)       sqrt(0.5)

sqrt(0.5)        -sqrt(0.5)

变换完之后,再把第一段(A1)分为两段,同样对相邻的点进行变换,直到无法再分。

下面直接上代码

Wavelet.py

import math
 
class wave:
  def __init__(self):
    M_SQRT1_2 = math.sqrt(0.5)
    self.h1 = [M_SQRT1_2, M_SQRT1_2]
    self.g1 = [M_SQRT1_2, -M_SQRT1_2]
    self.h2 = [M_SQRT1_2, M_SQRT1_2]
    self.g2 = [M_SQRT1_2, -M_SQRT1_2]
    self.nc = 2
    self.offset = 0
 
  def __del__(self):
    return
 
class Wavelet:
  def __init__(self, n):
    self._haar_centered_Init()
    self._scratch = []
    for i in range(0,n):
      self._scratch.append(0.0)
    return
    
  def __del__(self):
    return
    
  def transform_inverse(self, list, stride):
    self._wavelet_transform(list, stride, -1)
    return
    
  def transform_forward(self, list, stride):
    self._wavelet_transform(list, stride, 1)
    return
    
  def _haarInit(self):
    self._wave = wave()
    self._wave.offset = 0
    return
    
  def _haar_centered_Init(self):
    self._wave = wave()
    self._wave.offset = 1
    return
    
  def _wavelet_transform(self, list, stride, dir):
    n = len(list)
    if (len(self._scratch) < n):
      print("not enough workspace provided")
      exit()
    if (not self._ispower2(n)):
      print("the list size is not a power of 2")
      exit()
    
    if (n < 2):
      return
 
    if (dir == 1): # 正变换
      i = n
      while(i >= 2):
        self._step(list, stride, i, dir)
        i = i>>1
       
    if (dir == -1):  # 逆变换
      i = 2
      while(i <= n):
        self._step(list, stride, i, dir)
        i = i << 1
    return
    
  def _ispower2(self, n):
    power = math.log(n,2)
    intpow = int(power)
    intn = math.pow(2,intpow)
    if (abs(n - intn) > 1e-6):
      return False
    else:
      return True
      
  def _step(self, list, stride, n, dir):
    for i in range(0, len(self._scratch)):
      self._scratch[i] = 0.0
    
    nmod = self._wave.nc * n
    nmod -= self._wave.offset
    n1 = n - 1
    nh = n >> 1
    
    if (dir == 1): # 正变换
      ii = 0
      i = 0
      while (i < n):
        h = 0
        g = 0
        ni = i + nmod
        for k in range(0, self._wave.nc):
          jf = n1 & (ni + k)
          h += self._wave.h1[k] * list[stride*jf]
          g += self._wave.g1[k] * list[stride*jf]
        self._scratch[ii] += h
        self._scratch[ii + nh] += g
        i += 2
        ii += 1
    
    if (dir == -1):  # 逆变换
      ii = 0
      i = 0
      while (i < n):
        ai = list[stride*ii]
        ai1 = list[stride*(ii+nh)]
        ni = i + nmod
        for k in range(0, self._wave.nc):
          jf = n1 & (ni + k)
          self._scratch[jf] += self._wave.h2[k] * ai + self._wave.g2[k] * ai1
        i += 2
        ii += 1
        
    for i in range(0, n):
      list[stride*i] = self._scratch[i]

测试代码如下:

test.py

import math
import Wavelet
 
waveletn = 256
waveletnc = 20  #保留的分量数
wavelettest = Wavelet.Wavelet(waveletn)
waveletorigindata = []
waveletdata = []
for i in range(0, waveletn):
  waveletorigindata.append(math.sin(i)*math.exp(-math.pow((i-100)/50,2))+1)
  waveletdata.append(waveletorigindata[-1])
  
Wavelet.wavelettest.transform_forward(waveletdata, 1)
newdata = sorted(waveletdata, key = lambda ele: abs(ele), reverse=True)
for i in range(waveletnc, waveletn):  # 筛选出前 waveletnc个分量保留
  for j in range(0, waveletn):
    if (abs(newdata[i] - waveletdata[j]) < 1e-6):
      waveletdata[j] = 0.0
      break
  
Wavelet.wavelettest.transform_inverse(waveletdata, 1)
waveleterr = 0.0
for i in range(0, waveletn):
  print(waveletorigindata[i], ",", waveletdata[i])
  waveleterr += abs(waveletorigindata[i] - waveletdata[i])/abs(waveletorigindata[i])
print("error: ", waveleterr/waveletn)

当waveletnc = 20时,可得到下图,误差大约为2.1

详解python实现小波变换的一个简单例子

当waveletnc = 100时,则为下图,误差大约为0.04

详解python实现小波变换的一个简单例子

当waveletnc = 200时,得到下图,误差大约为0.0005

详解python实现小波变换的一个简单例子

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
使用go和python递归删除.ds store文件的方法
Jan 22 Python
python实现根据图标提取分类应用程序实例
Sep 28 Python
Python中的类与对象之描述符详解
Mar 27 Python
使用matplotlib画散点图的方法
May 25 Python
Python多线程原理与用法实例剖析
Jan 22 Python
Python实现定期检查源目录与备份目录的差异并进行备份功能示例
Feb 27 Python
使用Python实现跳一跳自动跳跃功能
Jul 10 Python
python将三维数组展开成二维数组的实现
Nov 30 Python
tensorflow求导和梯度计算实例
Jan 23 Python
django模板获取list中指定索引的值方式
May 14 Python
Pytest如何使用skip跳过执行测试
Aug 13 Python
Python并发编程实例教程之线程的玩法
Jun 20 Python
Django基础知识 URL路由系统详解
Jul 18 #Python
对Django项目中的ORM映射与模糊查询的使用详解
Jul 18 #Python
Django基础知识 web框架的本质详解
Jul 18 #Python
django 使用全局搜索功能的实例详解
Jul 18 #Python
Django中Middleware中的函数详解
Jul 18 #Python
对DJango视图(views)和模版(templates)的使用详解
Jul 17 #Python
react+django清除浏览器缓存的几种方法小结
Jul 17 #Python
You might like
php加水印的代码(支持半透明透明打水印,支持png透明背景)
2013/01/17 PHP
js自定义事件及事件交互原理概述(一)
2013/02/01 Javascript
鼠标划过实现延迟加载并隐藏层的js代码
2013/10/11 Javascript
jQuery实现鼠标经过时出现隐藏层文字链接的方法
2015/10/12 Javascript
JavaScript统计网站访问次数的实现代码
2015/11/18 Javascript
js倒计时简单实现方法
2015/12/17 Javascript
全面解析jQuery $(document).ready()和JavaScript onload事件
2016/06/08 Javascript
jQuery Ajax请求后台数据并在前台接收
2016/12/10 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
2017/01/20 Javascript
JavaScript中for循环的几种写法与效率总结
2017/02/03 Javascript
js实现5秒倒计时重新发送短信功能
2017/02/05 Javascript
vue使用watch 观察路由变化,重新获取内容
2017/03/08 Javascript
vue 做移动端微信公众号采坑经验记录
2018/04/26 Javascript
使用javascript做在线算法编程
2018/05/25 Javascript
老生常谈JavaScript获取CSS样式的方法(兼容各浏览器)
2018/09/19 Javascript
使用preload预加载页面资源时注意事项
2020/02/03 Javascript
vant组件中 dialog的确认按钮的回调事件操作
2020/11/04 Javascript
在vue中嵌入外部网站的实现
2020/11/13 Javascript
vue.js实现点击图标放大离开时缩小的代码
2021/01/27 Vue.js
[01:21]DOTA2 新英雄 森海飞霞
2020/12/18 DOTA
python切换hosts文件代码示例
2013/12/31 Python
python实现人人网登录示例分享
2014/01/19 Python
Python模块、包(Package)概念与用法分析
2019/05/31 Python
Python基于正则表达式实现计算器功能
2020/07/13 Python
Python爬虫教程之利用正则表达式匹配网页内容
2020/12/08 Python
CSS3属性box-shadow使用指南
2014/12/09 HTML / CSS
Oasis服装官网:时尚女装在线
2020/07/09 全球购物
公司业务主管岗位职责
2013/12/07 职场文书
初中数学教学反思
2014/01/16 职场文书
审计主管岗位职责
2014/01/31 职场文书
总经理司机职责
2014/02/02 职场文书
秋季运动会演讲稿
2014/09/16 职场文书
2014年度培训工作总结
2014/11/27 职场文书
给客户的检讨书
2014/12/21 职场文书
慈善献爱心倡议书
2015/04/27 职场文书
导游词之晋城蟒河
2019/12/12 职场文书