论文复现8

本次复现的论文Vital Sign Detection of FMCW Radar Based on Improved Adaptive Parameter Variational Mode Decomposition来自沈阳航空航天大学,和论文复现7中的文章很相似,该研究由国家自然科学基金项目(61671310)等多个项目资助1

我们使用的数据库、软件等与论文复现7一致。

****开始****

首先,这篇文章并未引用优化算法对参数进行优化,而是采用网格搜索,也就是预设参数范围、步长,逐个测试验证,这样的好处是速度快,但处理复杂情况,它的局限性会突显。此外,其优化目标由两项组成,第一项是常见的能量损失率,第二项是筛选出呼吸、心跳能量集中的频带(模式判别),因此产生了两个阈值,这两个阈值设置不到会导致分解失效。

预处理过程中,该研究认为去除直流分量是重要的,我们实现一个简洁的圆拟合去直流偏移方法,利用线性最小二乘快速求解圆心,并将其作为直流分量减去:

Matlab 复制代码
function sig_corrected = removeDCOffsetByCircleFit(complex_signal)
    % 输入: complex_signal 行向量
    % 输出: 去除直流偏移后的复信号
    x = real(complex_signal);
    y = imag(complex_signal);
    
    % 最小二乘圆拟合 (Taubin 法)
    n = length(x);
    % 构建矩阵 A = [x, y, ones]
    A = [x(:), y(:), ones(n,1)];
    b = -(x(:).^2 + y(:).^2);
    % 求解 A * [a; b; c] = b  使得 (x+a)^2+(y+b)^2 = R^2
    sol = A \ b;
    a = sol(1);   % x 中心偏移
    b = sol(2);   % y 中心偏移
    % 直流偏移量
    DC_I = -a;
    DC_Q = -b;
    
    % 减去直流
    sig_corrected = complex_signal - (DC_I + 1j*DC_Q);
end

优化过程:

Matlab 复制代码
function [bestK, bestAlpha, lossMat] = iapvmd_optimize_params(signal, fs, K_range, alpha_coarse, fine_step, thresh_r, thresh_h)
% IAPVMD 参数优化(能量损失率 + 模式判别)
% 呼吸频带 0.05-0.7 Hz,心音频带 0.8-3 Hz
% 输入:
%   signal         : 行向量
%   fs             : 采样率 (Hz)
%   K_range        : 例如 2:7
%   alpha_coarse   : 粗搜索的 alpha 向量,例如 100:100:6000
%   fine_step      : 精搜索步长(默认 10)
%   thresh_r, thresh_h : 能量占比阈值(默认 0.9)
% 输出:
%   bestK, bestAlpha : 最优参数
%   lossMat          : 粗搜索损失矩阵

if nargin < 6 || isempty(thresh_r), thresh_r = 0.9; end
if nargin < 7 || isempty(thresh_h), thresh_h = 0.9; end
if nargin < 5 || isempty(fine_step), fine_step = 10; end

signal = signal(:).';
N = length(signal);
E_total = sum(abs(fft(signal)).^2);

K_range = K_range(K_range >= 2);
if isempty(K_range)
    error('K_range 必须包含 >=2 的值');
end

band_resp = [0.05, 0.7];
band_heart = [0.8, 3.0];

fprintf('=== IAPVMD 粗搜索阶段(步长 = %.1f) ===\n', mean(diff(alpha_coarse)));
lossMat = zeros(length(K_range), length(alpha_coarse));
bestLoss = inf;
bestK_coarse = K_range(1);
bestAlpha_coarse = alpha_coarse(1);

for iK = 1:length(K_range)
    K = K_range(iK);
    for iA = 1:length(alpha_coarse)
        alpha = alpha_coarse(iA);
        loss = computeLossWithDiscrimination(signal, fs, K, alpha, E_total, band_resp, band_heart, thresh_r, thresh_h);
        lossMat(iK,iA) = loss;
        if loss < bestLoss
            bestLoss = loss;
            bestK_coarse = K;
            bestAlpha_coarse = alpha;
        end
        fprintf('  K=%d, α=%.1f → 有效=%d, 损失=%.6f %s\n', K, alpha, loss<1, loss, ...
                ternary(loss==bestLoss && loss<bestLoss,'*',''));
    end
end
fprintf('粗搜索最优: K=%d, α=%.1f, 损失=%.6f\n', bestK_coarse, bestAlpha_coarse, bestLoss);

% 精搜索
fprintf('\n=== IAPVMD 精搜索阶段(步长 = %.1f) ===\n', fine_step);
alpha_low  = max(alpha_coarse(1), bestAlpha_coarse - 200);
alpha_high = min(alpha_coarse(end), bestAlpha_coarse + 200);
alpha_range_fine = alpha_low : fine_step : alpha_high;
if ~any(abs(alpha_range_fine - bestAlpha_coarse) < 1e-6)
    alpha_range_fine = sort([alpha_range_fine, bestAlpha_coarse]);
end

bestLoss_fine = inf;
bestAlpha_fine = bestAlpha_coarse;
for iA = 1:length(alpha_range_fine)
    alpha = alpha_range_fine(iA);
    loss = computeLossWithDiscrimination(signal, fs, bestK_coarse, alpha, E_total, band_resp, band_heart, thresh_r, thresh_h);
    if loss < bestLoss_fine
        bestLoss_fine = loss;
        bestAlpha_fine = alpha;
    end
    fprintf('  K=%d, α=%.1f → 有效=%d, 损失=%.6f %s\n', bestK_coarse, alpha, loss<1, loss, ...
            ternary(loss==bestLoss_fine && loss<bestLoss_fine,'*',''));
end
fprintf('精搜索最优: K=%d, α=%.1f, 损失=%.6f\n', bestK_coarse, bestAlpha_fine, bestLoss_fine);

bestK = bestK_coarse;
bestAlpha = bestAlpha_fine;
end

function loss = computeLossWithDiscrimination(signal, fs, K, alpha, E_total, band_resp, band_heart, thresh_r, thresh_h)
    try
        [u, ~, omega] = vmd(signal, alpha, 0, K, false, 1, 1e-7);
        L = size(u,1);
        if L == 0, loss = 1; return; end
        N = length(signal);
        f = (0:N-1) * (fs / N);
        omega_Hz = omega * fs;
        valid = false;
        E_imf_sum = 0;
        for k = 1:L
            Pxx = abs(fft(u(k,:))).^2;
            totalE = sum(Pxx);
            if totalE == 0, continue; end
            E_imf_sum = E_imf_sum + totalE;
            idx_r = (f >= band_resp(1)) & (f <= band_resp(2));
            idx_h = (f >= band_heart(1)) & (f <= band_heart(2));
            ratio_r = sum(Pxx(idx_r)) / totalE;
            ratio_h = sum(Pxx(idx_h)) / totalE;
            if ratio_r > thresh_r || ratio_h > thresh_h
                valid = true;
            end
        end
        if ~valid
            loss = 1;
        else
            loss = abs(E_imf_sum - E_total) / (E_total + eps);
        end
    catch
        loss = 1;
    end
end

function s = ternary(cond, t, f)
    if cond, s = t; else, s = f; end
end

重构信号有一个筛选机制,呼吸信号用基频+谐波重构,心跳是用心跳频段的IMF去除呼吸谐波IMF后重构。但我觉得,如果只是估计呼吸率,那谐波可以直接滤除,而后续的如果呼吸谐波和心跳基波接近,那么就会降低心率检测的效果。

Matlab 复制代码
function [respSignal, heartSignal, respRate_Hz, heartRate_Hz] = iapvmd_reconstruct(signal, fs, K, alpha, delta_r, delta_h, print_ratios)
% 基于信号分组法的 IAPVMD 重构(改进频带:呼吸0.05-0.7Hz,心跳0.8-3Hz)
% 输入:
%   signal      : 行向量
%   fs          : 采样率 (Hz)
%   K, alpha    : VMD 参数
%   delta_r     : 呼吸频带能量占比阈值(默认 0.9)
%   delta_h     : 心音频带能量占比阈值(默认 0.9)
%   print_ratios: 是否打印每个IMF的能量占比(默认 false)
% 输出:
%   respSignal, heartSignal : 重构信号(行向量)
%   respRate_Hz, heartRate_Hz : 估计频率 (Hz)

if nargin < 5 || isempty(delta_r), delta_r = 0.9; end
if nargin < 6 || isempty(delta_h), delta_h = 0.9; end
if nargin < 7 || isempty(print_ratios), print_ratios = false; end

signal = signal(:).';
N = length(signal);
if N < 10
    respSignal = signal; heartSignal = signal;
    respRate_Hz = NaN; heartRate_Hz = NaN;
    return;
end

if K < 2
    warning('K 必须 >= 2,自动设为 2');
    K = 2;
end


tau = 0.01;
[u, ~, omega] = vmd(signal, alpha, tau, K, false, 1, 1e-7);

L = size(u,1);
if L == 0
    respSignal = signal; heartSignal = signal;
    respRate_Hz = NaN; heartRate_Hz = NaN;
    return;
end

% 频率轴和模态中心频率(归一化后乘以 fs)
f = (0:N-1) * (fs / N);
omega_Hz = omega * fs;

% 呼吸和心音频带
band_resp = [0.05, 0.7];
band_heart = [0.8, 3.0];

% 计算每个模态在呼吸/心音频带的能量占比
Er_ratio = zeros(1, L);
Eh_ratio = zeros(1, L);
for k = 1:L
    Pxx = abs(fft(u(k,:))).^2;
    totalE = sum(Pxx);
    if totalE == 0, continue; end
    idx_r = (f >= band_resp(1)) & (f <= band_resp(2));
    idx_h = (f >= band_heart(1)) & (f <= band_heart(2));
    Er_ratio(k) = sum(Pxx(idx_r)) / totalE;
    Eh_ratio(k) = sum(Pxx(idx_h)) / totalE;
end

% 打印能量占比(如果开启)
if print_ratios
    fprintf('\n%-6s %-12s %-20s %-20s\n', 'IMF#', '中心频率(Hz)', '呼吸频带能量占比', '心音频带能量占比');
    for k = 1:L
        fprintf('%-6d %-12.3f %-20.4f %-20.4f\n', k, omega_Hz(k), Er_ratio(k), Eh_ratio(k));
    end
    fprintf('阈值设置: 呼吸占比 > %.2f, 心跳占比 > %.2f\n', delta_r, delta_h);
end

% 呼吸集合 L_set,心跳集合 H_set
L_set = find(Er_ratio > delta_r);
H_set = find(Eh_ratio > delta_h);

% ----------呼吸谐波集合 G 的构建 ----------
% 遍历所有呼吸模态,对每个呼吸模态考虑 (v+2) 倍谐波,v=0,1,2
G_set = [];
if ~isempty(L_set)
    for g = L_set
        base_freq = omega_Hz(g);
        for v = 0:2
            harmonic = (v+2) * base_freq;
            % 寻找最接近谐波频率的模态索引
            [~, idx] = min(abs(omega_Hz - harmonic));
            % 如果该模态属于心跳集合且尚未加入 G_set,则加入
            if ismember(idx, H_set) && ~ismember(idx, G_set)
                G_set(end+1) = idx;
            end
        end
    end
    G_set = unique(G_set);  % 去重
end
% ------------------------------------------------

% 重构呼吸信号 (L ∪ G)
if ~isempty(union(L_set, G_set))
    respSignal = sum(u(union(L_set, G_set), :), 1);
else
    respSignal = zeros(1, N);
end

% 重构心跳信号 (H \ G)
heart_set = setdiff(H_set, G_set);
if ~isempty(heart_set)
    heartSignal = sum(u(heart_set, :), 1);
else
    heartSignal = zeros(1, N);
end

% 频率估计(使用相应频带)
respRate_Hz = getDominantFreq(respSignal, fs, band_resp);
heartRate_Hz = getDominantFreq(heartSignal, fs, band_heart);
end

function freq = getDominantFreq(signal, fs, band)
    signal = signal(:).';
    if isempty(signal) || length(signal) < 5
        freq = NaN; return;
    end
    try
        [Pxx, f] = periodogram(signal, [], 4096, fs);
    catch
        N = length(signal);
        Y = fft(signal);
        Pxx = abs(Y(1:floor(N/2)+1)).^2 / N;
        f = fs * (0:floor(N/2)) / N;
    end
    idx = (f >= band(1)) & (f <= band(2));
    if any(idx)
        [~, maxIdx] = max(Pxx(idx));
        f_band = f(idx);
        freq = f_band(maxIdx);
    else
        freq = NaN;
    end
end

模式判别"(Mode Discrimination)是本文的一个创新点,在算法的参数选择阶段 ,被用作一个分解有效性 的硬性约束(筛选器),即必须有一个IMF几乎都是呼吸频段、一个IMF几乎都是是心跳的频段,否则分解不成功,但我认为,这个要求可能过于苛刻,尤其是本文仅使用网格搜索参数的情况,在信号重构阶段 :它真正作为分类与归属的约束,根据能量占比决定每个IMF分配到呼吸信号还是心跳信号,并处理谐波干扰。

1L. Qu, C. Liu, T. Yang and Y. Sun, "Vital Sign Detection of FMCW Radar Based on Improved Adaptive Parameter Variational Mode Decomposition," in IEEE Sensors Journal, vol. 23, no. 20, pp. 25048-25060, 15 Oct.15, 2023, doi: 10.1109/JSEN.2023.3312513.

****结束****

相关推荐
ji198594433 小时前
MATLAB 求散点曲线斜率
开发语言·算法·matlab
kaikaile19953 小时前
MATLAB 实现:Koch & Zhao 图像水印算法(DCT域)
开发语言·算法·matlab
阿里matlab建模师5 小时前
基于matlab时域频域处理的语音信号变声处理系统设计与算法原理(论文+程序源码+GUI图形用户界面)——变声算法
算法·matlab·语音识别
简简单单做算法5 小时前
基于OFDM的车联网雷达通信一体化感知算法matlab性能仿真
matlab·ofdm·车联网·雷达通信一体化
rit84324995 小时前
MATLAB近红外光谱预处理:平滑与求导(MSV方法)
数据结构·算法·matlab
神仙别闹5 小时前
基于 MATLAB SVM 方法对数字进行分类训练和预测
支持向量机·matlab·分类
nwsuaf_huasir6 小时前
matlab绘制尺寸和字体合适的图片插入到latex的方法
android·开发语言·matlab
KWTXX2 天前
测试工具-论文 MATLAB 仿真复现【成功】
开发语言·matlab
jllllyuz2 天前
MATLAB实现滚动轴承故障诊断(外圈故障)
开发语言·人工智能·matlab
slandarer2 天前
MATLAB | 韦恩图的高阶版: UpSet图 更新升级啦!
开发语言·matlab