脑电信号时频分析仿真

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:仅作个人学习记录用:

EEG(脑电信号)处理过程中,肯定避免不了对采集到的信号进行时频分析并绘制频谱图,所以本片笔记就记录一下博主自己写的一个简单脚本,用于绘制信号时频分析结果。


提示:以下是本篇文章正文内容,下面案例可供参考

一、时频分析是什么?

脑电信号的时频分析是观察大脑电活动随时间变化的频率成分。把脑电波拆解成不同频段的成分(如α波、β波),然后看这些成分如何随着时间变化。它能同时展示 “什么时候” 发生了 “什么样的” 脑活动,比单独看波形或频谱更能捕捉大脑动态的变化过程。这种方法可以揭示认知任务中或疾病状态下脑电活动的细微波动,是研究大脑功能的重要工具。

话不多说!!你能看到这篇帖子肯定是已经有基础认知了!!上代码!!!!

二、代码脚本

代码如下(示例):

clear;
close all;
fclose('all');
clc;

%% 信号频谱分析 - FFT实现

% 参数设置
Fs = 128;               % 采样频率 128 Hz
total_points = 120000;  % 总点数 120000
window_duration = 2;    % 窗长 2秒
step_duration = 0.5;    % 步长 0.5秒

% 计算窗口参数
window_length = Fs * window_duration;      % 窗长点数: 256点
step_length = Fs * step_duration;          % 步长点数: 64点
overlap_length = window_length - step_length; % 重叠点数: 192点

% 生成示例信号
% 假设信号包含10Hz和25Hz成分,加上一些噪声
t = (0:total_points-1)/Fs;
signal = 2*sin(2*pi*10*t) + 1.5*sin(2*pi*25*t) + 0.5*randn(size(t));

num_windows = floor((total_points - overlap_length) / step_length);
freq_axis = (0:window_length/2) * Fs / window_length;  % 单边频谱,y轴的索引

% 预分配存储时频结果的矩阵
time_freq_matrix = zeros(length(freq_axis), num_windows);
time_axis = zeros(1, num_windows);

% 创建汉明窗
window_func = hamming(window_length);

% 执行滑动窗口FFT(其实就是每次取一段窗口进行功率谱分析,然后画出来对应的功率谱图)
for i = 1:num_windows
    % 计算当前窗口的起始和结束索引
    start_index = (i-1) * step_length + 1;
    end_index = start_index + window_length - 1;
    
    % 提取当前窗口信号并加窗
    if end_index <= total_points
        windowed_signal = signal(start_index:end_index) .* window_func';
        
        % 执行FFT
        NFFT = 2^nextpow2(window_length);  % 使用2的幂次方提高FFT效率
        Y = fft(windowed_signal, NFFT);
        
        % 计算单边幅度谱 (取前NFFT/2+1个点)
        P2 = abs(Y/NFFT);       % 能量归一化,使频谱幅度反映信号真实幅度,也是为了补偿FFT求和操作导致的幅度放大
        P1 = P2(1:NFFT/2+1);    % 实信号的频谱是共轭对称的,只需要一半,还能减少数据量,提高后续处理效率
        P1(2:end-1) = 2*P1(2:end-1);    % 能量补偿,因为单边谱只包含了一半的能量信息,这样可以使单边谱的幅度与原始信号幅度对应
        
        % 确保P1长度与freq_axis匹配
        if length(P1) > length(freq_axis)
            P1 = P1(1:length(freq_axis));
        elseif length(P1) < length(freq_axis)
            P1(end+1:length(freq_axis)) = 0;
        end
        
        % 存储结果
        time_freq_matrix(:, i) = P1;        % 每列是一组结果
        time_axis(i) = (start_index + window_length/2) / Fs;  % 窗口中心时间
    end
end

%% 绘制时频分析结果
figure('Position', [100, 100, 1200, 800]);  % 控制画布位置和画布大小

% 子图1: 原始信号
subplot(3,1,1);
plot(t, signal);
title('原始信号 (120000点, 128Hz采样)');
xlabel('时间 (s)');
ylabel('幅度');
grid on;

% 子图2: 时频图 (手动FFT结果)
subplot(3,1,2);
imagesc(time_axis, freq_axis, 20*log10(time_freq_matrix + eps));  % 转换为dB
axis xy;  % 确保频率轴方向正确
colorbar;
title('时频分析 - 手动FFT实现 (窗长2s, 步长0.5s)');
xlabel('时间 (s)');
ylabel('频率 (Hz)');
ylim([0, Fs/2]);  % 显示奈奎斯特频率以下

% 子图3: 使用spectrogram函数对比
subplot(3,1,3);
[S, F, T] = spectrogram(signal, hamming(window_length), overlap_length, 1024, Fs);
surf(T, F, 10*log10(abs(S)), 'EdgeColor', 'none');
axis tight;
view(0, 90);
colorbar;
title('时频分析 - spectrogram函数结果');
xlabel('时间 (s)');
ylabel('频率 (Hz)');

上述代码中,涉及到了FFT变化后的单边频谱的计算问题,这个可以差一些公式,且对应执行代码中我已经写明了计算原理。


总结

这里需要注意的一个点,博主也曾经搞混过(如果下述观点有错误,欢迎及时指正,博主会尽快更改):假定输入信号的单位是uV

1、【FFT】的计算后的单位:
结果单位:uV,或者叫每Hz频率间隔内的信号幅度;

2、20log10【幅度谱】计算后的单位:
计算公式:20 × log₁₀(幅度值)
结果单位:dB (分贝),表示相对于1μV/Hz参考值的分贝值,是幅度密度的对数表示;
完整单位:dB re 1μV/Hz。

3、10log10【功率谱】计算后的单位
计算公式:10 × log₁₀(功率值)
结果单位:dB (分贝),表示相对于1(μV)²/Hz参考值的分贝值,是功率密度的对数表示
完整单位:dB re 1(μV)²/Hz。

功率谱和幅度谱的关系如下:

功率 ∝ 幅度²,取对数时:10log10(幅度²) = 20log10(幅度)

能帮到各位就最好不过咯~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值