小波分析—— 3. 实现一个简单的Haar小波

news2024/9/22 17:18:31

由于小波在应用形式上与卷积很相似,所以如果你有需要,可以查看我以前写过的内容:

  • 信号采样基本概念 —— 冲激函数
  • 卷积计算——1. 关于卷积的基本概念
  • 卷积计算——2. 一些常用于图像的卷积核与应用

另外常见的信号处理工具,傅里叶变化,可以查看以下章节:

  • 浅谈傅里叶——1. 从无穷级数到欧拉公式
  • 浅谈傅里叶——2. 连续傅里叶公式推导与三角函数正交性
  • 浅谈傅里叶——3. 傅立叶收敛性证明与非周期信号的推广
  • 浅谈傅里叶——4. 傅里叶的特点分析与短时傅里叶
  • 浅谈傅里叶——5. 短时傅里叶的缺点与卷积的基本概念
  • 浅谈傅里叶——5. 短时傅里叶的缺点与卷积的基本概念
  • 浅谈傅里叶——6. 采样、频率与一个简易的DFT函数
  • 浅谈傅里叶——7. 带有相位信息的一维DFT实现方法
  • 浅谈傅里叶——8. 一维iDFT的实现

文章目录

  • Haar小波的基本实现原理
  • 代码实现
    • Haar小波分解过程
    • Haar小波复原过程
    • 比较结果
  • 一些其他实现手段

Haar小波的基本实现原理

小波分析是一种数学方法,用于分析和处理时间序列数据。 它的基本思想是将时间序列数据分解为多个不同尺度的部分,以便在分解后的每个尺度上更好地理解数据的特征。

这里写图片描述

其中一种常用的小波变换方法是Haar小波变换。 Haar小波变换是一种离散小波变换,它可以将时间序列数据分解为近似信息和细节信息。 近似信息是数据的一个粗略的表示,细节信息包含数据的细微差别。 这样,在分解后的不同尺度上分析数据可以得到更清晰的视图。

通常,Haar小波变换是一种递归算法,可以对数据进行多次变换。 在每次变换中,它将数据分成相邻的对,并计算每对的平均值和差值。 平均值是近似信息,差值是细节信息。 这两个信息都保存在列表中。 接下来,程序将使用近似信息作为下一次变换的输入。

在多次变换后,Haar小波变换将生成一组近似信息和细节信息的列表。 列表中的每个元素都对应于不同的尺度。 这些信息可以用于分析数据的不同特征。

与Haar小波变换相对应的是Haar小波逆变换。 这种逆变换可以将Haar小波变换分解后的信息合并成原始时间序列数据。 它使用相同的递归算法,但是它是将信息合并而不是分离。

代码实现

Haar小波分解过程

现在让我们来看看给出的代码。 首先,定义了一个名为discrete_wavelet_transform的函数,该函数接受两个参数:数据列表和深度。 深度表示要进行多少次变换。

函数开始执行时,首先限制深度为所需的变换数量,以将整个数据列表转换为整数。 然后初始化一个空列表,用于存储不同尺度的细节信息。

def discrete_wavelet_transform(data, depth):
    # Haar Discrete Wavelet Transform, depth passes
    depth = min(int(math.log2(len(data))), depth)  # Limit depth to the number of passes needed to transform the entire data list
    details = []  # Initialize empty list to store details at different scales

    # Loop through the number of passes
    for d in range(depth):
        # Initialize empty lists for approximations and details for the current pass
        approximations, details_for_pass = [], []
        # Loop through data by pairs of values
        for i in range(0, len(data), 2):
            # Append the average of the pair to the list of approximations
            approximations.append(sum(data[i:i+2]) / 2)
            # Append the difference between the first value of the pair and the average to the list of details
            details_for_pass.append(data[i] - approximations[-1])
        # Add current details to the beginning of the list
        details = details_for_pass + details
        # Replace data with approximations for the next pass
        data = approximations

    return approximations, details  # Return approximations and details at different scales

接下来,开始一个循环,循环次数为深度。 在循环的每次迭代中,都会初始化一个近似信息列表和当前循环的细节信息列表。 然后,开始另一个循环,循环次数为数据列表的长度,每次循环都会跳过两个值。 在循环的每次迭代中,都会计算对的平均值并将其添加到近似信息列表中,并将对的第一个值与平均值之差添加到细节信息列表中。

在当前循环结束后,将当前细节信息添加到细节信息列表的开头。 然后用近似信息替换数据列表,以便进行下一次变换。

Haar小波复原过程

接下来是另一个函数,名为inverse_discrete_wavelet_transform,它接受近似信息和细节信息列表作为参数。 该函数执行Haar小波逆变换,并返回原始时间序列数据。

def inverse_discrete_wavelet_transform(approximations, details):
    # Haar Inverse Discrete Wavelet Transform, depth passes
    N = len(approximations + details)  # Calculate length of original data
    sums = [sum([[k] * (N // len(approximations)) for k in approximations], [])]  # Initialize a list of sums with approximations
    bs, i = N // 2, 0  # Initialize block size and index

    # Loop until block size becomes 0 or all details have been processed
    while bs > 0 and i < len(details):
        # Initialize a list of values for the current block of details
        values = []
        # Loop through the current block of details
        for a in details[::-1][i:i+bs]:
            # Append alternating negative and positive values to the list of values
            values.extend([-a] * (N // (2 * bs)))
            values.extend([a] * (N // (2 * bs)))
        # Reverse the list of values and add it to the list of sums
        sums.append(values[::-1])
        # Move to the next block of details
        i += bs
        # Divide block size by 2
        bs //= 2

    # Calculate reconstructed data by summing values at each index in list of sums
    rec_data = [sum([s[j] for s in sums]) for j in range(N)]
    return rec_data  # Return reconstructed data

首先计算原始数据的长度,然后将近似信息和细节信息放在一个列表中。 然后初始化一个和的列表,并将近似信息添加到该列表中。 初始化块大小并将其设置为原始数据的一半,并初始化索引。

然后进入一个循环,循环将持续到块大小为0或处理完所有细节信息为止。 在每次循环迭代中,都会初始化一个值列表,用于存储当前块的细节信息。 然后进入另一个循环,循环次数为当前块的细节信息。 在循环的每次迭代中,都会将负值和正值的序列分别添加到值列表中。 这些值列表的大小都是原始数据的一半除以当前块的大小。

然后将值列表翻转,并将其添加到和的列表中。 接下来,将索引设置为当前块的细节信息数量,并将块大小除以2。

最后,计算原始时间序列数据的重建数据。 这是通过对和的列表中的每个索引的值求和来实现的。

比较结果

接下来相对比较简单,首先生成了一个具有1024个样本的正弦波。 然后调用discrete_wavelet_transform函数,将数据列表和10(即要进行的变换次数)作为参数。

接下来,调用inverse_discrete_wavelet_transform函数,将获得的近似信息和细节信息作为参数。

最后,在主函数的循环中,打印出原始数据和重建数据的每对值。

def main():
    # generate a sin(x) for a sine wave
    signal = [math.sin(math.pi * float(i)/100.0) for i in range(100)]

    # Apply the DWT to the data with a depth of 8
    approx, details = discrete_wavelet_transform(signal, 2)

    # Reconstruct the original data from the approximations and details
    r_signal = inverse_discrete_wavelet_transform(approx, details)

    # compare the reconstructed data with the original data
    for i in range(len(signal)):
        # print the original data and the reconstructed data and keep the output to 2 decimal places
        print('{:.2f} {:.2f}'.format(signal[i], r_signal[i]))


if __name__ == '__main__':
    main()  # Call the main function

一些其他实现手段

其他小波的计算过程有很多相似地方,而Haar显然是最简单的一种方式。不过在弄明白Haar小波的基础上是很容易开发出其他小波分解。一些最常见的小波分解方法包括 小波包分解曲线小波分解小波变换。 这些方法都有其自己的优势和缺点,并且在实现上有所不同。

小波包分解是一种常用的小波分解方法,其中使用可以选择的基小波进行变换。 这些基小波有不同的性质,可以更好地分离不同类型的信息。 小波包分解通常使用数学公式来实现。

曲线小波分解是另一种常见的小波分解方法,它使用曲线拟合来提取信息。 这种方法可以用于分离带有连续曲线的信息。 曲线小波分解通常使用数学公式来实现。

小波变换是另一种常见的小波分解方法,它使用小波函数来提取信息。 小波函数是被设计用于小波变换的特殊函数。 小波变换通常使用数学公式来实现。

与Haar小波分解相比,这些方法通常更具精度,但是实现较为复杂。 Haar小波分解是一种简单而有效的小波分解方法,它使用两个宽度相等的区间来进行变换。 Haar小波分解使用简单的算术运算来实现,因此它很容易理解和实现。 然而,它的精度较低,因此在许多情况下可能不是最佳选择。

小波分解通常用于分析和重建时间序列数据。 它的原理是将时间序列数据的不同频率成分分离出来,以便可以单独分析和处理。 小波分解可以用于许多不同的应用领域,包括图像处理,信号处理,声音处理等。

所以,作为一种比FFT更先进的替代工具,熟练掌握它可以帮助研究人员更好地了解数据,并进行有意义的分析和决策。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity脚本(三)

视频教程&#xff1a;https://www.bilibili.com/video/BV12s411g7gU?p128 目录 Time Prefab Animation Time Time.time&#xff1a;自应用程序启动以来&#xff0c;每帧的开始时间&#xff08;只读&#xff09; Time.deltaTime&#xff1a;每帧间隔&#xff0c;或说完…

SpringData

文档&#xff1a;D:\springdata SpringData是一个用来简化dao层开发的框架.在保证了各个底层存储特性同时,提供了一套统一的数据访问API.它可以很好的支持常用的关系型数据库和非关系型数据库. 使用SpringData做为dao层开发技术,将大大简化代码&#xff0c;而且其API比各个技…

【力扣周赛#326】6279.数组乘积中的不同质因数数目+6196.将字符串分割成值不超过K的子字符串+6280.范围内最接近的两个质数

目录 6278.统计能整除数字的位数 - 简单ac 6279.数组乘积中的不同质因数数目 - 质因数 6196.将字符串分割成值不超过K的子字符串 - 贪心 6280.范围内最接近的两个质数 - 质数筛 贪心 6278.统计能整除数字的位数 - 简单ac 6278. 统计能整除数字的位数 class Solution {pu…

aws codebuild 配置codecommit更新触发和squid正向代理

本文主要讨论如何通过监听codecommit仓库自动触发codebuild的构建&#xff0c;以及为codebuild配置正向代理 通过codecommit更新触发codebuild codecommit触发器相关 每个codecommit最多配置10个触发器 sns触发器 为sns创建lambda函数订阅&#xff0c;在lambda日志中查看s…

一个例题,了解包装类

下列代码输出什么,为什么? public class Test3 {public static void main(String[] args) {Integer a1 100;Integer a2 Integer.valueOf(100);Integer a3 new Integer(100);System.out.println(a1 a2);System.out.println(a1 a3);System.out.println(a1.equals(a3));Sys…

分离编译、类型萃取、变参模板

分离编译 一个程序由若干个源文件共同实现&#xff0c;每个源文件单独编译生成目标文件&#xff0c;最后将所有的目标文件链接起来形成单一可执行文件的过程称之为分离编译模式。模板不支持分离编译 编译器报的这种错误属于链接性错误&#xff0c;也就是当程序预处理、编译、汇…

Sutherland–Hodgman 算法介绍(简单易懂)

目录 一、算法介绍 二、算法描述 三、计算细节补充 四、算法总结 一、算法介绍 我们使用Sutherland–Hodgman算法来裁剪多边形的边&#xff0c;一般是给你一个多边形顶点序列(P1,P2,P3,P4,…Pn)让你裁剪&#xff0c;最终裁剪掉裁剪多边形的外部部分(下图黑框就是裁剪多边形…

大中型政企机构网络安全建设发展趋势研究报告

声明 本文是学习大中型政企机构网络安全建设发展趋势研究报告. 下载地址而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 研究背景 大中型政企机构是网络安全保护的重中之重&#xff0c;也是国内网络安全建设投入最大&#xff0c;应用新技术、新产品最…

Proteus8仿真:51单片机25AA020A(SPI接口EEPROM)的使用

51单片机25AA020A实验内容25AA020A引脚功能SPI信号模拟8位写8位读EEPROM读写函数EEPROM写使能EEPROM写一个Byte实验程序例程main.c工程文件Microchip的25AA020A是一个2Kbit串行电可擦除可编程只读存储器&#xff08;EEPROM&#xff09;。内存可以通过一个简单的串行外围接口&am…

第三十讲:神州路由器路由重分发配置

RIP和OSPF协议是目前应用最广泛的路由协议&#xff0c;两种协议交接的场合也很多见&#xff0c;两种协议的重分布是比较常见的配置。主校区原来所采用的网络协议为OSPF&#xff0c;而分校区采用的路由协议是RIP&#xff0c;采用RIP和OSPF重分发技术可以解决此问题。 实验拓扑图…

HDLBits练习汇总-14-时序逻辑设计测试--状态机(二)

水箱问题&#xff08;Exams/ece241 2013 q4&#xff09; 一个大水库的水为几个用户服务。为了保持足够高的水位&#xff0c;三个传感器以5英寸的间隔垂直放置。当水位高于最高传感器S3时&#xff0c;输入流量应为零。当液位低于最低传感器(Si)时&#xff0c;流量应处于最大(公…

【技术分享】戴尔工作站安装Win10+Ubuntu20.04双系统避坑指南

文章目录引言1.安装前的几个注意事项&#xff08;避坑指南&#xff09;1.1.有多块硬盘&#xff0c;该如何分配给Win10和Ubuntu系统&#xff1f;1.2.Ubuntu分区应该怎么分&#xff1f;2.系统安装步骤2.1.下载系统镜像2.2.制作U盘启动盘2.3.进入Win10系统分配系统空间2.4.BIOS设置…

82.【LibraryManger】

图书管理系统(一)、搭建环境1.数据库语句2.导入需要的依赖(二)、配置文件3.创建MyBatis的xml文件 mybais-config.xml4.创建dao层接口以及dao层的 mapper.xml5.创建数据库的资源 database.properties6.创建spring的配置文件 spring-dao.xml【】7.创建service层的接口以及servcie…

查找

章节目录&#xff1a;一、线性查找1.1 概述1.2 代码示例二、二分查找2.1 概述2.2 代码示例三、插值查找3.1 概述3.2 代码示例四、斐波那契查找4.1 概述4.2 代码示例五、结束语一、线性查找 1.1 概述 线性查找又称顺序查找&#xff0c;是一种最简单的查找方法&#xff0c;它的…

若依框架:前端登录组件与图像验证码|用户登录逻辑

在上一篇《若依框架&#xff1a;前端项目结构与初始页面渲染流程》中&#xff0c;我们探讨了与“vue.config.js文件配置、.env模式和环境变量配置、vue-router全局导航守卫配置、vue-router路由配置简介”相关的内容&#xff0c;书接上回&#xff0c;我们继续探讨若依前端项目的…

【C语言进阶】字符函数与字符串函数

目录 1、函数介绍 1.1 strlen 1.2 strcpy 1.3 strcat 1.4 strcmp 1.5 strncpy 1.6 strncat 1.7 strncmp 1.8 strstr 1.9 strtok 1.10 strerror 【补】字符分类函数&#xff1a; 1.11 memcpy 1.12 memmove 1.13 memcmp 1.14 memset 1、函数介绍 1.1 strlen siz…

基于卷积神经网络的高光谱分类(1D、2D、3D-CNN)

算法原理 卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;CNN&#xff09;是深度学习中最常见的一种 算法&#xff0c;它具有强大的特征学习能力。CNN 通过结合局部感知区域、共享权重、空间或者 时间上的降采样来充分利用数据本身包含的局部性等特征&…

绘图仪 与 示波器 Plotter Oscilloscope

【后台管理&#xff0c;这哪里是广告了&#xff1f;图都是百度搜的&#xff0c;又没有销售信息&#xff0c;就事论事而已&#xff01;】 Plotter &#xff1a; 对低频信号持续测量并绘制到一张很长的纸上&#xff0c;通常是卷纸。 常见的比如传统心电图机&#xff08;图左&am…

『分分钟玩转VueRouter●下』我对VueRouter在项目中如何使用的理解

路由的设置会根据系统中用户角色的数量而有所不同&#xff0c;大致分为三种单角色同权限、单角色不同权限、多角色。这里的角色均是只一种身份&#xff0c;而不是用户量。接下来的讲解纯属个人见解&#xff0c;大型项目会将不同权限的用户直接分开开发不同的系统。如果是小型多…

c++基础——for循环

for循环是循环的一种 以下是 for 循环的结构&#xff1a; for (初始化; 判断条件; 更新) {循环体; } 执行顺序&#xff1a; for 语句的三个部分中&#xff0c;任何一个部分都可以省略。其中&#xff0c;若省略了判断条件&#xff0c;相当于判断条件永远为真。 for (int i …