MATLAB 心电ECG分析系统(R峰检测、心率检测 含GUI界面)

        记录一个简单的小项目,供大家参考。

        废话少说直接上图:

        模块一:加载dat文件

function ecg_raw = loadECGData(path, datafile, samples2read)
% 加载并解码ECG二进制数据 
% 输入:
%   path - 数据文件路径 
%   datafile - 数据文件名 
%   samples2read - 读取样本数 
% 输出:
%   ecg_raw - 原始ECG信号 
 
    signald = fullfile(path, datafile);
    fid2 = fopen(signald,'r');  
    A = fread(fid2, [3, samples2read], 'uint8')';  
    fclose(fid2);
    
    % 数据解码 
    M2H = bitshift(A(:,2), -4);
    M1H = bitand(A(:,2), 15);
    M(:,1) = bitshift(M1H,8) + A(:,1);
    M(:,2) = bitshift(M2H,8) + A(:,3);
    
    % 信号截取与基线校正 
    ecg_raw = M(100:end-1000,1) - 1024;
end 

模块二:ECG滤波

function ecg_filtered = filterECG(ecg_raw, Fs)
% ECG信号滤波处理
% 输入:
%   ecg_raw - 原始ECG信号
%   Fs - 采样频率
% 输出:
%   ecg_filtered - 滤波后信号

    % 基线漂移去除
    hpFilt = designfilt('highpassiir', 'FilterOrder', 4, ...
        'HalfPowerFrequency', 0.5, 'SampleRate', Fs, 'DesignMethod', 'butter');
    ecg_base = filtfilt(hpFilt, ecg_raw);
    
    % 带通滤波
    bpFilt = designfilt('bandpassiir', 'FilterOrder', 4, ...
        'HalfPowerFrequency1', 0.5, 'HalfPowerFrequency2', 40, 'SampleRate', Fs);
    ecg_bp = filtfilt(bpFilt, ecg_base);
    
    % 工频干扰消除
    notch_freq = 50;
    wo = notch_freq/(Fs/2);  
    bw = wo/35;
    [num, den] = iirnotch(wo, bw);
    ecg_filtered = filtfilt(num, den, ecg_bp);
end

模块三:R峰检测

function adjusted_r_peaks = detectRPeaks(ecg_signal, Fs)
% R峰检测算法 
% 输入:
%   ecg_signal - 滤波后ECG信号 
%   Fs - 采样频率 
% 输出:
%   adjusted_r_peaks - 校正后的R峰位置索引 
 
    % QRS波增强 
    bpFilt = designfilt('bandpassiir', 'FilterOrder', 2, ...
        'HalfPowerFrequency1', 5, 'HalfPowerFrequency2', 15, 'SampleRate', Fs);
    filtered = filtfilt(bpFilt, ecg_signal);
    
    % 微分处理 
    diff_signal = diff([0; filtered]);
    squared = diff_signal.^2;
    
    % 移动平均 
    window_size = round(0.15 * Fs);
    integrated = movmean(squared, window_size);
    
    % 阈值检测 
    thr = 3 * mean(integrated);
    min_interval = 0.2 * Fs; 
    peaks = find(integrated > thr);
    r_peaks = peaks([true; diff(peaks) > min_interval]);
    
    % 局部最大值精修 
    search_win = 40;
    adjusted_r_peaks = zeros(size(r_peaks));
    for i = 1:length(r_peaks)
        start_idx = r_peaks(i);
        end_idx = min(start_idx + search_win, length(ecg_signal));
        [~, max_pos] = max(ecg_signal(start_idx:end_idx));
        adjusted_r_peaks(i) = start_idx + max_pos - 1;
    end 
    
    % 去重处理 
    [adjusted_r_peaks, ~] = unique(adjusted_r_peaks); 
    adjusted_r_peaks = sort(adjusted_r_peaks);
end 

模块四:GUI界面

function create_gui()
    % 参数配置 
    PATH = 'C:\ECG-GUI';
    SAMPLES2READ = 660000;
    Fs = 360;
 
    % 创建主界面 
    fig = uifigure('Name', '心电分析系统', 'Position', [100 100 800 650],...
        'Color', [0.96 0.96 0.96], 'Resize', 'on');
    
    % 初始化数据存储 
    fig.UserData = struct('ecg_raw',[], 'ecg_filtered',[], 'Fs', Fs, 'avgInterval', NaN);
    
    % ===================================================================== 
    % 界面组件 
    % ===================================================================== 
    % 顶部标题 
    uilabel(fig, 'Text','心电信号处理系统', 'FontSize',20,...
        'Position',[200 600 400 40], 'FontColor',[0.2 0.2 0.6],...
        'HorizontalAlignment','center');
 
    % 按钮组 
    btnPanel = uipanel(fig, 'Position',[50 550 700 50],...
        'BackgroundColor',[0.9 0.9 0.9], 'BorderType','none');
    
    loadDataBtn = uibutton(btnPanel, 'Text','加载数据', 'Position',[80 10 100 30],...
        'ButtonPushedFcn', @loadData);
    
    filterBtn = uibutton(btnPanel, 'Text','信号滤波', 'Position',[210 10 100 30],...
        'Tag','btnFilter', 'ButtonPushedFcn', @processFilter, 'Enable','off');

    detectBtn = uibutton(btnPanel, 'Text','R峰检测', 'Position',[340 10 100 30],...
        'Tag','btnDetect', 'ButtonPushedFcn', @showRPeaks, 'Enable','off');
    
    heartRateBtn = uibutton(btnPanel, 'Text','计算心率', 'Position',[470 10 100 30],...
        'ButtonPushedFcn', @calculateHeartRate, 'Enable','off');
    
    % 波形显示区域 
    axRaw = axes(fig, 'Position',[0.08 0.45 0.85 0.26],...
        'XTickLabel',[], 'FontSize',10, 'Tag','RawAxes');
    title(axRaw, '原始信号 (点击"加载数据"选择文件)');
    
    axFiltered = axes(fig, 'Position',[0.08 0.14 0.85 0.26],...
        'FontSize',10, 'Tag','FilteredAxes');
    xlabel(axFiltered, '时间 (s)');
    title(axFiltered, '处理结果区');
 
    % 状态显示栏 
    infoPanel = uipanel(fig, 'Position',[50 500 700 40],...
        'BackgroundColor',[0.95 0.95 0.95]);
    
    uilabel(infoPanel, 'Text','R波数量:', 'Position',[20 5 80 30],...
        'FontColor',[0.2 0.2 0.6], 'FontSize',12,...
        'HorizontalAlignment','right');
    
    fig.UserData.txtCount  = uilabel(infoPanel, 'Text','0',...
        'Position',[110 5 100 30], 'FontSize',12);
    
    uilabel(infoPanel, 'Text','平均间期:', 'Position',[220 5 80 30],...
        'FontColor',[0.2 0.2 0.6], 'FontSize',12,...
        'HorizontalAlignment','right');
    
    fig.UserData.txtInterval  = uilabel(infoPanel, 'Text','0 s',...
        'Position',[310 5 120 30], 'FontSize',12);
    
    uilabel(infoPanel, 'Text','平均心率:', 'Position',[440 5 80 30],...
        'FontColor',[0.2 0.2 0.6], 'FontSize',12,...
        'HorizontalAlignment','right');
    
    fig.UserData.txtHeartRate  = uilabel(infoPanel, 'Text','0 bpm',...  % 添加心率显示
        'Position',[530 5 120 30], 'FontSize',12);
 
    % ===================================================================== 
    % 回调函数 
    % ===================================================================== 
    % 1. 数据加载 
    function loadData(~,~)
        try 
            [file, path] = uigetfile(fullfile(PATH,'*.dat'), '选择ECG文件');
            if isequal(file,0), return; end 
            
            % 读取数据 
            rawData = loadECGData(path, file, SAMPLES2READ);
            fig.UserData.ecg_raw  = rawData;
            
            % 显示原始信号 
            t = (100:6100)/Fs;
            cla(axRaw);
            plot(axRaw, t, rawData(100:6100), 'b', 'LineWidth',0.8);
            title(axRaw, sprintf('原始信号: %s', file));
            xlabel(axRaw, ''); 
            grid(axRaw, 'on');
            axis(axRaw, 'tight');
            
            % 启用后续功能 
            filterBtn.Enable = 'on';
            
        catch ME 
            uialert(fig, sprintf('数据加载失败:\n%s', ME.message),  '错误');
        end 
    end 
 
    % 2. 信号滤波 
    function processFilter(~,~)
        try 
            if isempty(fig.UserData.ecg_raw) 
                uialert(fig, '请先加载数据', '警告'); return;
            end 
            
            % 执行滤波 
            filtered = filterECG(fig.UserData.ecg_raw,  Fs);
            fig.UserData.ecg_filtered  = filtered;
            
            % 显示处理结果 
            t = (100:6100)/Fs;
            cla(axFiltered);
            plot(axFiltered, t, filtered(100:6100),...
                'Color',[0 0.5 0], 'LineWidth',1);
            title(axFiltered, '滤波后信号');
            grid(axFiltered, 'on');
            axis(axFiltered, 'tight');
            
            % 启用检测按钮
            detectBtn.Enable = 'on';

            % 启用计算心率按钮
            heartRateBtn.Enable = 'on';

            % 强制刷新界面
            drawnow limitrate;
        catch ME
            uialert(fig, sprintf('滤波失败:\n%s', ME.message),  '错误');
        end
    end 
 
    % 3. R峰检测 
    function showRPeaks(~,~)
        try 
            if isempty(fig.UserData.ecg_filtered) 
                uialert(fig, '请先进行滤波处理', '警告'); return;
            end 
            
            % 执行检测 
            peaks = detectRPeaks(fig.UserData.ecg_filtered,  Fs);
            validPeaks = peaks(peaks >= 100 & peaks <=6100);
            
            % 更新显示 
            hold(axFiltered, 'on');
            plot(axFiltered, validPeaks/Fs,... 
                fig.UserData.ecg_filtered(validPeaks),... 
                'rv', 'MarkerSize',8, 'MarkerFaceColor','r');
            hold(axFiltered, 'off');
            
            % 计算统计值 
            peakCount = numel(peaks);
            if peakCount > 1 
                intervals = diff(peaks)/Fs;
                avgInterval = mean(intervals);
            else 
                avgInterval = NaN;
            end 
            
            % 更新状态栏 
            fig.UserData.txtCount.Text  = num2str(peakCount);
            if ~isnan(avgInterval)
                fig.UserData.txtInterval.Text  =...
                    sprintf('%.3f s', avgInterval);
                fig.UserData.avgInterval = avgInterval; % 保存平均间期
            else 
                fig.UserData.txtInterval.Text  = 'N/A';
            end 
            
        catch ME 
            uialert(fig, sprintf('检测失败:\n%s', ME.message),  '错误');
        end 
    end 

    % 4. 计算心率
    function calculateHeartRate(~,~)
        try
            if isnan(fig.UserData.avgInterval) || fig.UserData.avgInterval == 0
                uialert(fig, '请先完成R峰检测', '警告');
                return;
            end
            
            % 计算平均心率 (bpm)
            heartRate = 60 / fig.UserData.avgInterval;
            fig.UserData.txtHeartRate.Text = sprintf('%.2f bpm', heartRate);
        catch ME
            uialert(fig, sprintf('计算心率失败:\n%s', ME.message), '错误');
        end
    end 
end

        运行GUI界面这个程序即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值