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用于图像处理),核心思想是相似的,但基函数和搜索过程需要扩展到更高维度。

posted @ 2025-08-25 10:15  u95900090  阅读(108)  评论(0)    收藏  举报