功率谱密度估计 - welch方法的实现

一、welch方法原理

welch法功率谱密度估计核心总结为:信号分段、段间互相交叠、每段加窗后估算其功率谱密度,最后对所有段的估计结果进行平均得到该信号的功率谱密度。


二、MatLab代码实现

版本1:

clc;clear;close all;
fs = 44100;
t = 0:1/fs:1-1/fs;
in = randn(size(t));
 
winlen = 4096;
overlap = winlen/2;
 
load("myfir64.mat"); % 自己设计的64阶fir低通滤波器
filtercoe = myfir64;
out = filter(filtercoe, 1, in);

wd = hanning(winlen);
 
spectrum_Pxx = zeros(winlen/2+1,1);  % 累加每段估计的自功率谱密度
spectrum_Pxy = zeros(winlen/2+1,1);  % 累加每段估计的互功率谱密度

numSegments = fix((length(in) - overlap) / (winlen - overlap));

for i = 1:numSegments  % 分段估计
    % 自己分段帧移
    inSeg = in((i-1)*overlap+1:(i-1)*overlap+winlen);
    outSeg = out((i-1)*overlap+1:(i-1)*overlap+winlen);

    % 估计输入信号自功率谱密度
    in_fft = fft(inSeg.*wd');
    N = length(in_fft);
    in_fft = in_fft(1:floor(N/2)+1);
    in_fft(2:end-1) = 2*in_fft(2:end-1);
    Pxx_ = (abs(in_fft).^2)';
 
    % 估计输入、输出信号互功率谱密度
    out_fft = fft(outSeg.*wd');
    out_fft = out_fft(1:floor(N/2)+1);
    out_fft(2:end-1) = 2*out_fft(2:end-1);
    Pxy_ = abs(out_fft .* conj(in_fft))';
 
    % 累加每一段的功率谱密度
    spectrum_Pxx = Pxx_ + spectrum_Pxx;
    spectrum_Pxy = Pxy_ + spectrum_Pxy;
 
end

f = fs*(0:N/2)/N;
 
% 计算均值
spectrumAvg_Pxx = spectrum_Pxx ./ numSegments;
spectrumAvg_Pxy = spectrum_Pxy ./ numSegments;
 
H2 = spectrumAvg_Pxy ./ spectrumAvg_Pxx;
subplot(211);
plot(f, 20*log10(H2));
title("幅频曲线(自己实现的自功率谱、互功率谱估计)");xlabel("频率");ylabel("db");
 
%% 自带pwelch、cpsd
[Pxx,f1] = pwelch(in, hanning(winlen), overlap, winlen, fs);
[Pxy,f2] = cpsd(in, out, hanning(winlen), overlap, winlen, fs);
 
subplot(212);
plot(f1, 20*log10(abs(Pxy ./ Pxx)));
title("幅频曲线(自带的pwelch、cpsd函数)");xlabel("频率");ylabel("db");

版本2:

clc;clear;close all;
fs = 44100;
t = 0:1/fs:1-1/fs;
x = randn(size(t));
 
load("myfir64.mat");
filtercoe = myfir64;
y = filter(filtercoe, 1, x);

[Hx, w] = freqz(filtercoe, 1, fs);
fx = w*fs/2/pi;
subplot(211);
plot(fx, 20*log10(abs(Hx)));
title('理想幅频特性曲线');
xlabel('频率(Hz)');
ylabel('幅值(dB)');

inputLen = length(x);

winLen = 4096;
frmInc = winLen/2;
fftLen = winLen;
frmLen = winLen;

win = hanning(winLen)';

totalFrm = fix((inputLen-frmInc)/(winLen-frmInc));

Pxx = zeros(fftLen/2 + 1,1);
Pyx = zeros(fftLen/2 + 1,1);

for frmIdx = 1:totalFrm

    xFrm = x((frmIdx - 1) * frmInc + 1 : (frmIdx - 1)*frmInc+frmLen);
    yFrm = y((frmIdx - 1) * frmInc + 1 : (frmIdx - 1)*frmInc+frmLen);

    PyxTmp = CPSD_feed(xFrm,yFrm,win,fftLen)';
    PxxTmp = CPSD_feed(xFrm,[],win,fftLen)';

    Pyx = Pyx + PyxTmp;
    Pxx = Pxx + PxxTmp;

end

% KMU = totalFrm*norm(win)^2;
Pyx = Pyx ./ totalFrm;
Pxx = Pxx ./ totalFrm;

freqRes = 20*log10(abs(Pyx) ./ abs(Pxx));
f = fs * (0:fftLen/2)/fftLen;
subplot(212);
plot(f,freqRes);
title("估计");
% plot(freqRes);

function Pyx = CPSD_feed(x,y,window,fftLen)
    xw = x .* window;
    X = fft(xw, fftLen);

    if ~isempty(y)
        yw = y .* window;
        Y = fft(yw, fftLen);
        Pyx = Y .* conj(X);
        
    else
        Pyx = X .* conj(X);
    end
    Pyx = Pyx(1:floor(fftLen/2) + 1);
end


 版本3:

该版本用到如下方法:N点复序列求2个N点实序列的快速傅里叶变换

clc;clear;close all;
fs = 44100;
t = 0:1/fs:1-1/fs;
x = randn(size(t));
 
load("myfir64.mat");
filtercoe = myfir64;
y = filter(filtercoe, 1, x);

%% 理想的频响曲线绘制
[Hx, w] = freqz(filtercoe, 1, fs);
figure(1);
subplot(311);
fx = w*fs/2/pi;
plot(fx, 20*log10(abs(Hx)));
title('理想的幅频特性曲线');
xlabel('频率(Hz)');
ylabel('幅值(dB)');

figure(2);
subplot(311);
phaseResponse = angle(Hx);
plot(fx, phaseResponse);
title("理想相频特性曲线");

%% 自己实现cpsd、pwelch
winlen = 4096;
overlap = winlen/2;
nfft = winlen;

inputLen = length(x);

segNum = fix((inputLen - overlap) / (winlen - overlap));
 
spectrum_Pxx = zeros(winlen/2+1,1);  % 累加每段估计的自功率谱密度
spectrum_Pxy = zeros(winlen/2+1,1);  % 累加每段估计的互功率谱密度
 
for segIdx = 1:segNum  % 估计每段

    xSeg = x((segIdx-1)*overlap+1:(segIdx-1)*overlap+winlen);  % 输入信号分段交叠
    ySeg = y((segIdx-1)*overlap+1:(segIdx-1)*overlap+winlen);  % 输出信号分段交叠
    
    Pxx_ = myCpsd(xSeg, [], hanning(winlen), nfft);    % 估计输入信号自功率谱密度
    Pxy_ = myCpsd(xSeg, ySeg, hanning(winlen), nfft);  % 估计输入、输出信号互功率谱密度

    % 累加每段的功率谱密度
    spectrum_Pxx = spectrum_Pxx + Pxx_;
    spectrum_Pxy = spectrum_Pxy + Pxy_;

end

f = fs*(0:nfft/2)/nfft;
 
% 计算均值
spectrumAvg_Pxx = spectrum_Pxx / segNum;
spectrumAvg_Pxy = spectrum_Pxy / segNum;

% 估计的幅频特性曲线
H2 = spectrumAvg_Pxy ./ spectrumAvg_Pxx;
figure(1);
subplot(313);
plot(f, 20*log10(abs(H2)));
title("自己估计的幅频曲线");xlabel("频率");ylabel("db");

% 估计的相频特性曲线
phase_response = atan2(imag(H2),real(H2));
figure(2);
subplot(312);
plot(f, phase_response);
title("自己估计的相频特性曲线");

%% matlab自带pwelch、cpsd
[Pxx,f1] = pwelch(x, hanning(winlen), overlap, winlen, fs);
[Pxy,f2] = cpsd(y, x, hanning(winlen), overlap, winlen, fs);

% 幅频特性曲线
figure(1);
subplot(312);
H5 = Pxy ./ Pxx;
plot(f1, 20*log10(abs(H5)));
title("幅频曲线(Matlab自带的pwelch、cpsd函数)");xlabel("频率");ylabel("db");

figure(2);
subplot(313);
phase_response2 = atan2(imag(H5),real(H5));
plot(f1, phase_response2);
title("相频曲线(Matlab自带的pwelch、cpsd函数)");xlabel("频率");ylabel("db");

%% 功率谱密度估计函数
function Pe = myCpsd(x, y, window, nfft)
    
    if ~isempty(y)  % 互功率谱密度

        z = x .* window' + 1i .* y .* window'; 
        % x、y序列构造为1个复数序列z

        Z = fft(z, nfft);

        X = zeros(1, nfft);
        Y = zeros(1, nfft);

        % 分别求出x、y的fft
        R = real(Z);
        I = imag(Z);

        X(1) = R(1);
        Y(1) = I(1);

        for k = 2:nfft
            X(k) = 1/2*(Z(k) + conj(Z(nfft+2-k)));   
            Y(k) = -1i/2*(Z(k) - conj(Z(nfft+2-k)));   
        end

        Pe = X .* conj(Y);
    else   % 自功率谱密度

        X = fft(x .* window', nfft);
        Pe = X .* conj(X);
    end
        Pe = Pe(1:floor(nfft/2)+1)';

end
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: csd函数是MATLAB中用于估计两个信号的互功率谱密度的函数。它基于Welch方法,这是一种常用的频谱估计方法。 互功率谱密度是用于分析两个信号之间的相关性和相互影响的一种频域表示方法。它可以帮助我们了解信号之间的关系以及它们如何互相作用。 csd函数基于Welch法利用频谱平均的思想来估计互功率谱密度。Welch方法将信号分成若干段,然后对每个段进行傅里叶变换,最后将这些段的频谱密度估计平均起来,得到最终的互功率谱密度。 使用csd函数可以传入两个信号作为输入参数,还可以指定一些其他参数,如段数、重叠率、窗函数等。csd函数会根据输入的信号和参数进行频谱估计,并返回两个信号的互功率谱密度。 互功率谱密度的结果可以使用MATLAB中的plot函数进行可视化展示,可以观察信号之间的相互作用情况。 总而言之,MATLAB中的csd函数利用Welch方法来估计两个信号的互功率谱密度,为信号分析和相互作用研究提供了一种便捷的工具。 ### 回答2: csd函数是MATLAB中的一个函数,它用于估计两个信号的互功率谱密度。这个函数使用的是Welch法,它是一种非参数估计方法。所谓非参数估计方法,是指不依赖于任何关于信号统计特性的先验信息。 Welch法是一种经典的信号谱密度估计方法。它首先将两个信号分成多个段,每个段的长度是固定的。然后对每个段进行窗函数加窗,并对窗口后的段进行傅里叶变换。最后将每个段的幅值平方求平均,得到每个频率点上的互功率谱密度值。 在MATLAB中,我们可以使用csd函数来实现这个过程。csd函数接受两个信号作为输入,并根据用户指定的参数进行处理。参数可以包括段长度、窗函数类型等。 csd函数将返回一个功率谱密度估计的结果。这个结果是一个复数矩阵,每个点表示对应频率上的互功率谱密度值。 使用csd函数可以方便地估计两个信号的互功率谱密度,我们可以使用这些估计结果进行信号分析、滤波等操作。这样可以帮助我们更好地理解信号的特性,提高信号处理的效果。 总结起来,MATLAB中的csd函数利用Welch法对两个信号进行互功率谱密度估计。这个函数的使用简单方便,可以帮助我们更好地理解和处理信号。 ### 回答3: 在MATLAB中,函数csd可以利用Welch法来估计两个信号的互功率谱密度。首先,csd函数需要两个输入信号,假设分别为x和y。csd函数使用Welch法来对输入信号进行分段,并使用傅里叶变换来计算每个段的功率谱密度。Welch法是一种经典的频谱估计方法,它可以有效地减少估计的方差。 在使用csd函数时,可以通过设置一些参数来控制Welch法的估计过程。其中,重要的参数包括窗函数、重叠段数和每段的样本数。窗函数的选择可以影响估计结果的频率分辨率和平滑程度。常用的窗函数有汉宁窗、矩形窗和汉明窗等。重叠段数和每段的样本数可以控制估计的分辨能力和计算复杂度。 csd函数的输入输出都是复数形式的。输出是一个2维数组,表示两个信号之间的互功率谱密度。其中,每一行表示一个频率点,每一列表示一个段的估计结果。根据需要,可以使用plot函数将频谱密度可视化,以便更直观地分析信号之间的关系。 需要注意的是,csd函数只能对平稳信号进行功率谱密度的估计。对于非平稳信号,可以通过对信号进行分段来获得局部的功率谱密度估计。此外,对于非平稳信号,也可以使用频时分析方法,如短时傅里叶变换(STFT)或连续小波变换(CWT)来获得更详细的分析结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的马师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值