离散沃尔什变换(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矩阵与其自身做矩阵乘法
得到对角阵,验证了结果是正交的,我们可以确定得到的沃尔什变换核是正确的