离散沃尔什变换(DWT)与DHT的实现思路其实是一致的,只是变换核需要经过一个变换,这里记录下原理和实现方法。
哈达玛变换核
哈达玛变换核具有递推性,也就是\(H_{2N}\)可以由\(H_{N}\)得到:
\[H_{2N}=\frac{1}{\sqrt{2}}
\left[
\begin{array}{cc}
H_{N} & H_{N} \\\\
H_{N} & -H_{N}
\end{array}
\right]
\]
哈达玛变换核的另一个特点是,变号次数乱序,以\(H_4\)为例,每行的变号次数分别如下:
\[H_4 = \frac{1}{2}
\left[
\begin{array}{cccc}
1&1&1&1 \\
1 &-1& 1 &-1 \\
1 &1 &-1& -1 \\
1 &-1 &-1 &1
\end{array}
\right]
\begin{array}{cccc}
0\\
3 \\
1 \\
2
\end{array}
\]
沃尔什变换核
沃尔什变换核可以从与哈达玛变换核间接得到,只需将DHT的变换核按变号次序递增重新排列即可
\[W_4 = \frac{1}{2}
\left[
\begin{array}{cccc}
1&1&1&1 \\
1 &1 &-1& -1 \\
1 &-1 &-1 &1 \\
1 &-1& 1 &-1 \\
\end{array}
\right]
\begin{array}{cccc}
0\\
1 \\
2 \\
3
\end{array}
\]
程序实现
生成DHT变换核
在scipy.linalg这个库中,已经实现了DHT的变换核生成,我们可以通过以下语句调用
from scipy.linalg import hadamard
H4 = hadamard(4)
生成DWT变换核
要得到沃尔什变换核,我们要先得到DHT变换核每一行的变号次数,然后按照变号次数排列,具体实现上我采用的方法如下:
生成变号次数向量invTimes
要获取H矩阵的变号次数,可以对H矩阵的每行取差分,然后取绝对值求和再除2(稍微一想就明白,这里不解释了哈),这些操作在numpy 中都有相应的函数diffMat = np.abs(np.diff(H))/2
invTimes = np.sum(diffMat,axis = 1)
对invTimes进行排序
对invTImes这个列向量排序并不难,问题是我们要在排序时或者排序后能对H矩阵做相同的排序操作,这里我想了很久发现可以通过numpy数组的花式索引来解决
numpy 排序方法不止一种,但我们想要的不是排序好的数组,而是排序的过程,也即是原数组每一行排序后在哪个位置,好在 ndarray 对象有 argsort() 方法能满足我们的需求,它返回的是原数组排序后的索引。#对invTImes排序会是这样,因为argsort()返回的是索引
invTImes[invTImes.argsort()]
对H矩阵做相同的排序操作
有了以上的铺垫,我们做相同的排序就会很简单了#用invTImes的排序方法对H矩阵的行排序
H[invTimes.argsort(),:]
以上过程封装后
def hada2wal(H):
diffMat = np.abs(np.diff(H))/2
invTimes = np.sum(diffMat,axis = 1)
W = H[invTimes.argsort(),:]
return W
效果对比
验证正确性
从结果的图来看,实现基本上是正确了,但如何确定实现正确了呢,这里用一下DWT的性质
DWT是正交变换,其变换矩阵是实正交对称阵,也就是说,其每一行做内积的结果是0,只有与自己内积时才有非零值
因此用W矩阵与其自身做矩阵乘法
得到对角阵,验证了结果是正交的,我们可以确定得到的沃尔什变换核是正确的