AFD(自适应傅立叶变换)的matlab实现
AFD(Adaptive Fourier Decomposition,自适应傅里叶分解)是一种先进的信号分解方法,它通过一种贪婪算法,自适应地从信号中选取最具能量的单分量(Monocomponent),最终将信号表示为一系列正交的核函数(通常是经过放缩和平移的复指数函数)的线性组合。
与传统的傅里叶变换相比,AFD能更好地处理非平稳信号,并具有更快的收敛速度。
1. 核心函数:AFD_Core.m
函数实现了AFD的核心迭代过程。
function [Coeffs, Basis, rm] = AFD_Core(signal, t, MaxIter, Threshold, precompute_ae)
% AFD_CORE 自适应傅里叶分解核心算法
%
% 输入:
% signal - 输入信号(行或列向量)
% t - 时间轴或采样点坐标
% MaxIter - 最大分解迭代次数
% Threshold - 能量剩余阈值,当剩余信号能量低于此值时停止迭代
% precompute_ae - 预计算所有a值对应的基函数,速度快但耗内存。设为false更省内存但慢。
%
% 输出:
% Coeffs - 分解系数 [c1, c2, ..., cN]
% Basis - 基函数(每一列是一个基函数)
% rm - 每次迭代后的剩余信号(每一列是一个剩余信号)
if nargin < 5
precompute_ae = true; % 默认预计算以提高速度
end
% 将信号转换为列向量
signal = signal(:);
N = length(signal);
rm = zeros(N, MaxIter); % 初始化剩余信号存储
Coeffs = zeros(1, MaxIter); % 初始化系数存储
Basis = zeros(N, MaxIter); % 初始化基函数存储
% 归一化时间轴到 [0, 1] 或保持原样,确保复指数基定义正确。
% 这里假设 t 已经是 [0, 1] 区间,或者是一个任意的采样序列。
% 关键是保证基函数 e^{i * w * t} 定义一致。
% 初始剩余信号就是原始信号
R_current = signal;
% 创建一个搜索网格来寻找最佳参数 'a'
% 'a' 是一个复数,|a| < 1,在单位圆盘内。
% 我们创建一个网格进行搜索
num_search_points = 1000;
% 在单位圆盘内生成搜索点 (r * exp(1i*theta))
r_vals = linspace(0, 0.99, 30); % 半径从0到0.99
theta_vals = linspace(0, 2*pi, 50); % 角度从0到2pi
[R, Theta] = meshgrid(r_vals, theta_vals);
a_search_grid = R .* exp(1i * Theta);
a_search_grid = a_search_grid(:); % 展平为列向量
% 预计算所有搜索点a对应的基函数e_a(t)(如果选择此模式)
if precompute_ae
% 预计算所有基函数 (庞大矩阵: N x num_search_points)
all_basis = zeros(N, length(a_search_grid));
for idx = 1:length(a_search_grid)
a = a_search_grid(idx);
% 计算核函数 e_a(t) = sqrt(1-|a|^2) / (1 - conj(a) * exp(1i * w * t))
% 这里简化处理:假设 w 对应 2*pi* (从0到1的频率变化)
% 注意:这是一个标准化的核函数,构成单位圆盘上的正交基
kernel = sqrt(1 - abs(a)^2) ./ (1 - conj(a) * exp(1i * 2*pi * t));
kernel = kernel / norm(kernel); % 确保基函数是单位范数的
all_basis(:, idx) = kernel;
end
end
% AFD 贪婪迭代分解
for iter = 1:MaxIter
% 计算当前剩余信号的能量
energy_rm = norm(R_current)^2;
if energy_rm < Threshold
fprintf('迭代在第 %d 次停止,剩余能量低于阈值。\n', iter);
% 截断输出
Coeffs = Coeffs(1:iter-1);
Basis = Basis(:, 1:iter-1);
rm = rm(:, 1:iter-1);
return;
end
% 在搜索网格上寻找最佳 'a',使得投影系数绝对值最大
max_proj_val = 0;
best_a = 0;
best_basis = zeros(N, 1);
if precompute_ae
% 模式1:使用预计算的基函数(速度快)
proj_vals = R_current' * all_basis; % 计算所有投影
[max_proj_val, max_idx] = max(abs(proj_vals)); % 找到最大投影
best_a = a_search_grid(max_idx);
best_basis = all_basis(:, max_idx);
else
% 模式2:动态计算基函数(节省内存)
for idx = 1:length(a_search_grid)
a = a_search_grid(idx);
% 动态计算核函数 e_a(t)
kernel = sqrt(1 - abs(a)^2) ./ (1 - conj(a) * exp(1i * 2*pi * t));
kernel = kernel / norm(kernel);
proj_val = dot(R_current, kernel); % 计算投影
if abs(proj_val) > max_proj_val
max_proj_val = abs(proj_val);
best_a = a_search_grid(idx);
best_basis = kernel;
end
end
end
% 计算最佳系数 c_m = <R_{m-1}, e_{a_m}>
c_m = dot(R_current, best_basis);
% 存储结果
Coeffs(iter) = c_m;
Basis(:, iter) = best_basis;
% 更新剩余信号: R_m = R_{m-1} - c_m * e_{a_m}
R_current = R_current - c_m * best_basis;
rm(:, iter) = R_current;
fprintf('迭代 %d: 系数 = %.4f%+.4fi, 参数 a = %.4f%+.4fi, 剩余能量 = %.6f\n', ...
iter, real(c_m), imag(c_m), real(best_a), imag(best_a), energy_rm);
end
fprintf('达到最大迭代次数 %d。\n', MaxIter);
end
2. 重构函数:AFD_Reconstruct.m
这个函数使用AFD分解得到的系数和基函数来重构信号。
function reconstructed_signal = AFD_Reconstruct(Coeffs, Basis)
% AFD_RECONSTRUCT 使用AFD分解的系数和基函数重构信号
%
% 输入:
% Coeffs - 来自 AFD_Core 的系数向量
% Basis - 来自 AFD_Core 的基函数矩阵(每一列是一个基)
%
% 输出:
% reconstructed_signal - 重构出的信号
% 简单地将基函数按系数线性组合
reconstructed_signal = Basis * Coeffs(:);
end
3. 演示脚本:Demo_AFD.m
这个脚本展示了如何使用AFD分解一个合成信号并重构它。
% Demo_AFD.m
% 自适应傅立叶分解 (AFD) 演示
clear; close all; clc;
%% 1. 生成一个测试信号
fs = 1000; % 采样率
T = 1; % 信号时长
t = 0:1/fs:T-1/fs; % 时间向量
N = length(t);
% 构造一个由多个频率成分组成的信号
f1 = 5; f2 = 20; f3 = 45;
component1 = 2 * sin(2*pi*f1*t);
component2 = 1 * sin(2*pi*f2*t + pi/4);
component3 = 0.5 * sin(2*pi*f3*t + pi/2);
signal = component1 + component2 + component3;
% 添加一些噪声
noise_level = 0.1;
signal = signal + noise_level * randn(1, N);
signal = signal'; % 转换为列向量
%% 2. 执行AFD分解
MaxIter = 20; % 最大迭代次数
Threshold = 1e-6; % 停止阈值
fprintf('开始AFD分解...\n');
[Coeffs, Basis, rm] = AFD_Core(signal, t, MaxIter, Threshold, true);
%% 3. 重构信号
reconstructed_signal = AFD_Reconstruct(Coeffs, Basis);
%% 4. 结果可视化
figure('Position', [100, 100, 1200, 800]);
% 4.1 绘制原始信号和重构信号
subplot(3, 2, [1, 2]);
plot(t, signal, 'b', 'LineWidth', 1.5, 'DisplayName', '原始信号');
hold on;
plot(t, reconstructed_signal, 'r--', 'LineWidth', 1.5, 'DisplayName', 'AFD重构');
title('原始信号 vs. AFD重构信号');
xlabel('时间 (s)');
ylabel('幅度');
legend('show');
grid on;
% 4.2 绘制分解系数(复数,显示幅度和相位)
subplot(3, 2, 3);
stem(1:length(Coeffs), abs(Coeffs), 'filled');
title('AFD系数幅度');
xlabel('分量索引');
ylabel('系数幅度');
grid on;
subplot(3, 2, 4);
stem(1:length(Coeffs), angle(Coeffs), 'filled');
title('AFD系数相位');
xlabel('分量索引');
ylabel('系数相位 (rad)');
grid on;
% 4.3 绘制前几个基函数的实部
subplot(3, 2, 5);
num_basis_to_plot = min(4, size(Basis, 2));
for i = 1:num_basis_to_plot
plot(t, real(Basis(:, i)), 'DisplayName', ['基 ', num2str(i)]);
hold on;
end
title('前几个基函数 (实部)');
xlabel('时间 (s)');
ylabel('幅度');
legend('show');
grid on;
% 4.4 绘制剩余信号能量衰减
subplot(3, 2, 6);
residual_energy = sum(rm.^2, 1); % 计算每次迭代的剩余能量
semilogy(1:length(residual_energy), residual_energy, 'o-', 'LineWidth', 1.5);
title('剩余信号能量衰减');
xlabel('迭代次数');
ylabel('能量 (对数尺度)');
grid on;
%% 5. 计算并显示误差
final_error = norm(signal - reconstructed_signal) / norm(signal);
fprintf('\nAFD分解完成。\n');
fprintf('使用的分量数量: %d\n', length(Coeffs));
fprintf('最终相对重构误差: %.4f%%\n', final_error * 100);
参考代码 AFD(自适应傅立叶变换)的matlab实现代码 www.youwenfan.com/contentcne/101061.html
运行演示:
只需在MATLAB命令窗口中运行 Demo_AFD。脚本将生成一个测试信号,对其进行分解,并绘制原始信号、重构信号、分解系数、基函数和能量衰减图。
这个实现是AFD的一个基础版本。对于更高级的应用(如2D-AFD用于图像处理),核心思想是相似的,但基函数和搜索过程需要扩展到更高维度。

浙公网安备 33010602011771号