Finding peaks in a very noisy signal
44 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Vitek Stepien
el 17 de Sept. de 2024
Editada: Vitek Stepien
el 19 de Sept. de 2024
Hi, I have a large set of noisy signals, see examples below.
I want to calculate the mean frequency of the pulsations, and to do that I have to first numerically detect the peaks. I have an algorithm, but it relies heavily on empirical choice of parameters for the findpeaks function, and typically it takes me 3-4 tries before I get them right for a certain dataset.
Can someone point me in the right direction on how to make my algorithm more adaptive, or how to approach this differently? My code pasted below. Code in .mlx and test files added as an attachment.
filename = uigetfile("Test*.mat");
if ~(filename), return, end
load(filename,"dt","signal")
time = dt*(1:length(signal));
halfM = 0.5*mean(signal);
% First find maxima separated by a multiple of time step, of a minimum height of 1% of the max value in the whole dataset
[pks, locs] = findpeaks(signal, time,"MinPeakDistance",5*dt,"MinPeakProminence",0.01*max(signal));
% Then find minima to make sure closely spaced, sharp peaks are differentiated in the next step
[min_pks, min_locs] = findpeaks(-signal, time,"MinPeakDistance",5*dt,"MinPeakProminence",0.01*max(signal));
% Combine minimum and maximum points
pks = [pks -min_pks]; locs = [locs min_locs];
% Sort the points for further processing
[locs, idx] = sort(locs); pks = pks(idx);
% Custom values for minimum separation and maximum peak width
minSep = 5e-9; maxPW = 1e6;
% Plot the results with peak prominences and widths marked
figure
findpeaks(pks, locs, "MinPeakProminence", halfM, "MinPeakHeight", 2*halfM, "MinPeakDistance", minSep, "MaxPeakWidth", maxPW,"Annotate","extents");
% Plot the original signal with all peaks and valleys marked in small orange dots,
% and major peaks marked in large yellow dots
figure, plot(time, signal), hold on, scatter(locs, pks, Marker=".",LineWidth=1)
[pks,locs] = findpeaks(pks, locs, "MinPeakProminence", halfM, "MinPeakHeight", 2*halfM, "MinPeakDistance", minSep, "MaxPeakWidth", maxPW);
scatter(locs, pks, Marker="o", MarkerFaceColor="flat"), hold off
xlabel 'Time [\mus]', ylabel 'Signal power [a.u.]'
0 comentarios
Respuesta aceptada
Star Strider
el 17 de Sept. de 2024
Your signals have broadband noiise, so a frequency-selective filter is not going to apply here. The Savitzky-Golay filter (or wavelet denoising) are best suited for signals with broadband noise, so I miplemented it here. Change the ‘framelen’ value to give the best result. (I chose a 3-order polynomiial, since that generally works best imn my experience, however you can experiiment with that as well.)
Try this —
files = dir('*.mat');
for k = 1:numel(files)
LD = load(files(k).name);
Fs(k) = 1/LD.dt;
s{k} = LD.signal;
L = numel(s{k});
t{k} = linspace(0, L-1, L)/Fs(k);
end
figure
tiledlayout(numel(files),1)
for k = 1:numel(files)
nexttile
plot(t{k}, s{k})
grid
xlabel('Time')
ylabel('Amplitude')
title(string(files(k).name))
end
sgtitle('Original')
figure
tiledlayout(numel(files),1)
for k = 1:numel(files)
nexttile
[FTs1,Fv] = FFT1(s{k},t{k});
plot(Fv, abs(FTs1)*2)
grid
xlabel('Frequency')
ylabel('Magnitude')
xlim([0 5E+8])
title(string(files(k).name))
end
sgtitle('Fourier Transforms')
figure
tiledlayout(numel(files),1)
for k = 1:numel(files)
nexttile
framelen = 1+5E+3;
s_filt = sgolayfilt(double(s{k}), 3, framelen);
plot(t{k}, s_filt)
grid
xlabel('Time')
ylabel('Amplitude')
title(string(files(k).name))
end
sgtitle('Savitzky-Golay Filtered Signal')
function [FTs1,Fv] = FFT1(s,t)
% Arguments:
% s: Signal Vector Or Matrix
% t: Associated Time Vector
t = t(:);
L = numel(t);
if size(s,2) == L
s = s.';
end
Fs = 1/mean(diff(t));
Fn = Fs/2;
NFFT = 2^nextpow2(L);
FTs = fft((s - mean(s)) .* hann(L).*ones(1,size(s,2)), NFFT)/sum(hann(L));
Fv = Fs*(0:(NFFT/2))/NFFT;
% Fv = linspace(0, 1, NFFT/2+1)*Fn;
Iv = 1:numel(Fv);
Fv = Fv(:);
FTs1 = FTs(Iv,:);
end
.
9 comentarios
Star Strider
el 19 de Sept. de 2024
Thank you!
As always, my pleasure!
I iintend to continue working on my independent components analysis function, since I believe it can be helpful here, and in other appications. When I get it up and running successfully, I will update that analysis here as well.
I wish you well in your research.
If I can be of any further help, please let me know.
Más respuestas (1)
Ver también
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!