信号的图小波变换(Python)

可以换个空间,从图域的角度进行分析,比如图傅里叶变换,图小波变换等图时频分析方法。图小波阈值降噪的基本思想是通过将时间序列信号转换成路图信号,再利用图小波变换分解成尺度函数系数和一系列对应不同尺度的谱图小波系数,然后设置阈值对图小波系数进行过滤处理,最后对尺度函数系数和滤波后的图小波系数进行图小波逆变换,重构得到降噪信号。

更具体地,图小波变换将路图信号分解成低频分量和高频分量,其中尺度函数系数包含信号的低频近似成分,图小波系数反映信号的高频细节成分。各尺度上的图小波系数在某些特定位置的幅值较大,对应于原始信号的奇变位置和重要信息,而其他大部分位置的幅值较小,对应于噪声干扰成分。噪声对应的图小波系数在每个尺度上的分布较均匀,且幅值随着尺度的减小而逐渐减小。因此,通常的降噪方法是设置一个合适的临界阈值ρ,并结合阈值函数对系数进行滤波。当图小波系数小于阈值ρ时,认为此系数主要由噪声引起,则将其置为零进行消除;当图小波系数大于或等于阈值ρ时,认为此系数主要由信号引起,则予以保留或进行收缩,从而得到估计谱图小波系数。最后,对所有剩余系数进行重构即可获得降噪信号。

import sys
import os
sys.path.append("src")


import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import wavelet_transform as wt
from pygsp import graphs
from time import time
if not os.path.exists("figs"):
    os.makedirs("figs")
def plot_graph_signal(
        G,
        signal,
        pos = None,
        vmin = None,
        vmax = None,
        ax = None,
        fig = None,
        colorbar = True,
        colorbar_label = "Values",
    ):
    if ax is None:
        fig, ax = plt.subplots(figsize = (4, 4))
    
    vmin = np.min(signal) if vmin is None else vmin
    vmax = np.max(signal) if vmax is None else vmax
   
    pathcollection = nx.draw_networkx_nodes(
        G, 
        pos, 
        node_color=signal,
        cmap=plt.cm.magma, 
        node_size=50,
        edgecolors="#909090",
        ax = ax,
        vmin = vmin,
        vmax = vmax
    )
    nx.draw_networkx_edges(
        G, 
        pos,
        edge_color="#909090", 
        ax = ax
    )
    
    ax.axis("off")
    if colorbar:
        fig.colorbar(pathcollection, ax = ax, label = colorbar_label)
        ax.figure.axes[-1].yaxis.label.set_size(14)
    return ax

Creating Graph

def create_grid_graph(size = 17):
    g = nx.grid_2d_graph(size, size)
    nodes = list(g.nodes)
    pos = {node: node for node in g.nodes}
    pos = np.array(list(pos.values()))
    for node in nodes:
        # get node position
        node_pos = np.array(node)
        # get all nodes closest than \sqrt 2
        distances = np.linalg.norm(pos - node_pos, axis = 1)
        idx_close = (distances < 2) & (distances != 0) & (distances != 1)
        close_node = np.random.choice(np.where(idx_close)[0])


        # select a random close node
        n1 = close_node


        # add edge
        g.add_edge(node, tuple(nodes[n1]))


    return g
# create 2D grid graph
np.random.seed(1)
g = create_grid_graph(17)




adj_matrix = nx.adjacency_matrix(g).todense()


# darw nodes by position
pos = {node: node for node in g.nodes}
pos = np.array(list(pos.values()))
# add random noise
#pos = pos + np.random.normal(0, 0.15, pos.shape)
pos = {node: pos[i] for i, node in enumerate(g.nodes)}
nx.draw(g, pos, node_size = 75, node_color = "#034e7b", edgecolors = "black", width = 1)
plt.axis("off")
plt.title("Grid Graph")
plt.savefig("figs/grid_graph.pdf", dpi = 300)

Fourier Transform

G = graphs.Graph(adj_matrix)
G.compute_fourier_basis()
fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize = (6, 4))
ax.hist(G.e, bins = 40)
ax.set_title("Distribution of Eigenvalues", fontsize = 16)
ax.set_xlabel("Eigenvalue", fontsize = 14)
ax.set_ylabel("Frequency", fontsize = 14)
plt.savefig("figs/eigenvalues_dist.svg", dpi = 300)
plt.show()
fig, axs = plt.subplots(nrows = 1, ncols = 3, figsize = (14, 4))
for i, idx in enumerate([4, 9, 14]):
    plot_graph_signal(
        g, 
        G.U[:, idx], 
        pos = pos, 
        ax = axs[i],
        vmin = -0.15,
        vmax = 0.10,
        fig=fig
    )
    axs[i].set_title(f"{idx+1}-th Eigenvector", fontsize = 14)
   
plt.suptitle("Eigenvectors of Graph", fontsize = 16)
plt.tight_layout()
plt.savefig("figs/eigenvectors.svg", dpi = 300)
plt.show()
simple_signal = np.zeros((2, 17, 17))


for i in range(17):
    for j in range(17):
        simple_signal[0, i, j] = (i + j)**2 / (34)**2
        simple_signal[1, i, j] = np.sin(i + j)


fig, axs = plt.subplots(nrows = 1, ncols = 2, figsize = (10, 4))
plot_graph_signal(
    g, 
    simple_signal[0].flatten(), 
    pos = pos, 
    ax = axs[0],
    vmin = -1,
    vmax = 1,
    fig=fig
)


plot_graph_signal(
    g, 
    simple_signal[1].flatten(), 
    pos = pos, 
    ax = axs[1],
    vmin = -1,
    vmax = 1,
    fig=fig,
    colorbar_label="Signal Value"
)


axs[0].set_title("Simple Signal 1", fontsize = 14)
axs[1].set_title("Simple Signal 2", fontsize = 14)


plt.suptitle("Fourier Transform of Two Signals", fontsize = 16)
plt.tight_layout()
plt.savefig("figs/simple_signals.svg", dpi = 300)
transformed_signal = [G.gft(signal.flatten()) for signal in simple_signal]


fig, axs = plt.subplots(nrows = 1, ncols = 2, figsize = (10, 4))


for i in range(2):
    axs[i].plot(G.e, transformed_signal[i])
    axs[i].set_ylabel("$\hat f(\lambda)$", fontsize = 14)
    axs[i].set_xlabel("$\lambda$", fontsize = 14)
    axs[i].set_title(f"Signal {i+1} Fourier Transform", fontsize = 14)
#plt.suptitle("Graph Fourier Transform of Signals")
plt.tight_layout()
plt.savefig("figs/fourier_transform.svg", dpi = 300)
plt.show()

Graph Wavelet Transform

signal = np.random.normal(0, 0.25, (17, 17)) + 3


for i in range(17):
    for j in range(17):
        if (i - 8)**2 + (j - 8)**2 <= 25:
            signal[i, j] += 3


signal = signal.flatten()


adj_matrix = np.array(nx.adjacency_matrix(g).todense())
wav = wt.WaveletTransform(
    adj_matrix = adj_matrix,
    n_timestamps=1,
    method = "exact_fast",
    scaling_function=False,
    n_filters=4
)
coeffs = wav.transform(signal.reshape(-1, 1))
coeffs_ = coeffs.reshape(17, 17, 4)
selected_nodes = [
    [11, 11],
    [12, 12],
    [15, 15],
]
selected_nodes_idx = [ x + y * 17 for (x, y) in selected_nodes]
fig = plt.figure(figsize = (6, 4))
pathcollection = nx.draw_networkx_nodes(
    g, 
    pos, 
    node_color=signal, 
    cmap=plt.cm.magma, 
    node_size=[100 if i in selected_nodes_idx else 50 for i in range(len(pos))],
    edgecolors=["#e7298a" if i in selected_nodes_idx else "#909090" for i in range(len(pos))],
    #vmin = 1
)
nx.draw_networkx_edges(g, pos, edge_color="#909090")
plt.colorbar(pathcollection, label = "Signal")
plt.title("Graph with Signal")
plt.axis("off")
plt.savefig("figs/graph_with_signal.svg", dpi = 300)
plt.show()






fig, axs = plt.subplots(nrows = 1, ncols = 3, figsize =(6, 2), sharex = True, sharey = True)


for i in range(3):
    c = np.abs(coeffs_[selected_nodes[i][0], selected_nodes[i][1], :])
    axs[i].bar(range(4), c, color = "#8da0cb")


    axs[i].set_xticks(range(4), labels = ["" for _ in range(4)])
    #axs[i].set_yticks([])
    axs[i].set_xlabel("Frenquencies")
    axs[i].set_ylabel("Coefficients")


plt.tight_layout()
plt.savefig("figs/coefs.svg", dpi = 300)
plt.show()

Fast Computation

graph_sizes = [5, 10, 15, 20, 25, 30]
exact_time = []
cheb_time = []
cheb_error = []


for n_g in graph_sizes:
    signal = np.random.random((n_g**2, 20))
    g = create_grid_graph(n_g)
    adj_matrix = nx.adjacency_matrix(g).todense()
    times_ = []
    for _ in range(10):
        start = time()
        wav = wt.WaveletTransform(
            adj_matrix = adj_matrix,
            n_timestamps=20,
            method = "exact_low_memory",
            scaling_function=False,
            n_filters=4
        )
        coeffs_exact = wav.transform(signal)
        end = time()
        times_.append(end - start)
    exact_time.append(np.mean(times_))


    times_ = []
    for _ in range(10):
        start = time()
        wav = wt.WaveletTransform(
            adj_matrix = adj_matrix,
            n_timestamps=20,
            method = "chebyshev",
            scaling_function=False,
            n_filters=4
        )
        coeffs_cheb = wav.transform(signal)
        end = time()
        times_.append(end - start)
    cheb_time.append(np.mean(times_))
    cheb_error.append(np.mean(np.abs(coeffs_exact - coeffs_cheb) / np.abs(coeffs_exact)))
fig, axs = plt.subplots(nrows = 1, ncols = 2, figsize = (7, 2.5))
axs[0].plot(graph_sizes, exact_time, label = "Exact")
axs[0].plot(graph_sizes, cheb_time, label = "Chebyshev")


axs[1].plot(graph_sizes, cheb_error, label = "Chebyshev")
for i in range(2):
    axs[i].set_xlabel("Graph Size")
    axs[i].set_xticks(graph_sizes, labels = [int(x*x*20) for x in graph_sizes])
axs[0].set_ylabel("Time (s)")
axs[0].legend()
axs[1].set_ylabel("Mean Absolute\nPercentage Error")
plt.suptitle("Time and Error of Exact and Chebyshev Methods")
plt.tight_layout()
plt.savefig("figs/time_error.pdf", dpi = 300)
plt.show()
n_order = [10, 20, 30, 40, 50]
cheb_time = []
cheb_error = []


g = create_grid_graph(17)
adj_matrix = nx.adjacency_matrix(g).todense()
signal = np.random.random((17**2, 20))
wav = wt.WaveletTransform(
    adj_matrix = adj_matrix,
    n_timestamps=20,
    method = "exact_low_memory",
    scaling_function=False,
    n_filters=4
)
coeffs_exact = wav.transform(signal)


for order in n_order:
    times_ = []
    for i in range(10):
        start = time()
        wav = wt.WaveletTransform(
            adj_matrix = adj_matrix,
            n_timestamps=20,
            method = "chebyshev",
            scaling_function=False,
            n_filters=4,
            order_chebyshev=order,
        )
        coeffs_cheb = wav.transform(signal)
        end = time()
        times_.append(end - start)
    cheb_time.append(np.mean(times_))
    # append MAPE
    cheb_error.append(np.mean(np.abs(coeffs_exact - coeffs_cheb) / np.abs(coeffs_exact)))
fig, axs = plt.subplots(nrows = 1, ncols = 2, figsize = (7, 2.5))


axs[0].plot(n_order, cheb_time, label = "Chebyshev")
axs[1].plot(n_order, cheb_error, label = "Chebyshev")


for i in range(2):
    axs[i].set_xlabel("Chebyshev Order")
    axs[i].set_xticks(n_order)
axs[0].set_ylabel("Time (s)")
axs[1].set_ylabel("Mean Absolute\nPercentage Error")
axs[1].set_yscale("log")
plt.suptitle("Time and Error of Chebyshev Method")
plt.tight_layout()
plt.savefig("figs/time_error_cheb_order.pdf", dpi = 300)
plt.show()
擅长领域:现代信号处理,机器学习,深度学习,数字孪生,时间序列分析,设备缺陷检测、设备异常检测、设备智能故障诊断与健康管理PHM等。
知乎学术咨询:https://www.zhihu.com/consult/people/792359672131756032?isMe=1
擅长领域:现代信号处理,机器学习,深度学习,数字孪生,时间序列分析,设备缺陷检测、设备异常检测、设备智能故障诊断与健康管理PHM等。

擅长领域:现代信号处理,机器学习,深度学习,数字孪生,时间序列分析,设备缺陷检测、设备异常检测、设备智能故障诊断与健康管理PHM等。

相关推荐
志远1997几秒前
笔试算法-编程练习-01-J-24
数据结构·python·算法·京东·大厂笔试
老歌老听老掉牙2 分钟前
Solidworks二次开发:样条曲线、平移、旋转和扫描切除
python·二次开发·solidworks
Fourier_xyz3 分钟前
Floyd 判圈算法学习:Leetcode142. 环形链表 II,Leetcode287. 寻找重复数
学习·算法·链表·图论
菜比乌斯反演3 分钟前
Hitachi Vantara Programming Contest 2024(AtCoder Beginner Contest 368)ABCDEF
数据结构·算法·图论
吃小南瓜�5 分钟前
贪心算法-分数背包问题
c++·算法·贪心算法
guanpinkeji5 分钟前
旧衣回收小程序系统,为市场发展提供新模式
java·开发语言·小程序·小程序开发·回收·旧衣回收·旧衣回收小程序
微凉的衣柜5 分钟前
稚晖君智元机器人远程机器人系列发布:引领具身智能新高度
人工智能·深度学习·机器人
hbrown20 分钟前
Flask+LayUI开发手记(二):LayUI弹出层表单的校验
python·flask·layui
未来的嗒嘀嗒20 分钟前
空状态设计教程:连接用户体验的桥梁
人工智能
**启程**21 分钟前
Keil C51 插件 快速复制一行
windows·python·单片机