Borrar filtros
Borrar filtros

Find peaks and valley of sinusoidal curve

21 visualizaciones (últimos 30 días)
Maria Inês
Maria Inês el 12 de Abr. de 2023
Comentada: Mathieu NOE el 14 de Jun. de 2023
Hello, I have a code that reads a file and converts it into a graph which, in turn, applies the detrend filter. However, it is not enough and I needed to know the peaks and valleys of this new graph and then subtract the values from the peaks to the valleys in order to normalize the curves. I tried to find it with findpeaks but it didn't work. How can I do it?
TY
function startupFcn(app)
data=readmatrix('ensaios_controlo.xlsx','sheet','analise');
time_control=data(:,2);
strain_control=data(:,3);
t_control=seconds(time_control);
t_control.Format = 'hh:mm:ss';
plot(app.UIAxes,t_control,strain_control)
s=rms(strain_control);
app.RMS_controlEditField.Value=s;
end
% Button pushed function: FileButton
function FileButtonPushed(app, event)
[name,path]=uigetfile('.xlsx','Select a file');
app.file=fullfile(path,name);
data_2=readmatrix(app.file,"Sheet",'Untitled');
time=data_2(:,2);
strain=data_2(:,3);
x=seconds(time);
x.Format = 'hh:mm:ss';
d=rms(strain);
app.RMSEditField.Value=d;
if (1342<d)&&(d<1483)
msgbox("Don't need analyse.","non-modal");
else
app.TabGroup.SelectedTab=app.DataTab;
plot(app.UIAxes3,x,strain,"r");
yline(app.UIAxes2,0)
yline(app.UIAxes2,-2800);
end
end
% Button pushed function: AnalyseButton
function AnalyseButtonPushed(app, event)
data_2=readmatrix(app.file,"Sheet",'Untitled');
time=data_2(:,2);
strain=data_2(:,3);
strain_2 = detrend(strain,6);
x=seconds(time);
x.Format = 'hh:mm:ss';
d=rms(strain);
app.RMSEditField.Value=d;
pks = findpeaks(strain);
findpeaks(strain);
pks_v= findpeaks(-strain);
findpeaks(-strain);
if (1342<d)&&(d<1483)
msgbox("Don't need analyse.","non-modal");
else
app.TabGroup.SelectedTab=app.AnalyseTab;
plot(app.UIAxes2,x,strain,"r");
hold(app.UIAxes2,'on');
plot(app.UIAxes2,x,strain_2,"b");
yline(app.UIAxes2,0)
yline(app.UIAxes2,-2800);
end
end
  5 comentarios
Maria Inês
Maria Inês el 12 de Abr. de 2023
I apologize, I have now attached the files. The file to normalize the values that will have to be chosen in the "file" button is "test_15_seco". In the Data tab, the graph corresponding to the values in the file appears and I want to transform the maximum value into zero.
dpb
dpb el 13 de Abr. de 2023
app.file='https://www.mathworks.com/matlabcentral/answers/uploaded_files/1353474/provete_15_seco.xlsx';
data_2=readmatrix(app.file,"Sheet",'Untitled');
time=data_2(:,2);
strain=data_2(:,3);
strain_2 = detrend(strain,6);
x=seconds(time);
x.Format = 'hh:mm:ss';
d=rms(strain);
app.RMSEditField.Value=d;
pks = findpeaks(strain);
findpeaks(strain);
pks_v= findpeaks(-strain);
findpeaks(-strain);
if (1342<d)&&(d<1483)
msgbox("Don't need analyse.","non-modal");
else
%app.TabGroup.SelectedTab=app.AnalyseTab;
plot(x,strain,"r");
hold on
plot(x,strain_2,"b");
yline(0)
yline(-2800);
end
What are we to make of that???
Now explain what, specifically, you're trying to do here. It would certainly help to supply some context to the problem so folks have at least a half-chance of understanding the rationale behind the machinations--generally that is a help in devising a solution; to know the end goal and why.

Iniciar sesión para comentar.

Respuesta aceptada

Mathieu NOE
Mathieu NOE el 13 de Abr. de 2023
So far I understand you want the strain plot have all top peaks being on y = 0 line , like in your reference data file (ensaios_controlo.xlsx)
so this is my suggestion, and no I am not using findpeaks this time... I prefer peakseek which is simpler and faster and does the job very well here ( a no brainer almost)
you can access at the FEX page here ,
or simply use the code provided below
also , no need to do any preliminary detrending, you can skip that.
Result is the new magenta line , see it has all top peaks aligned with y = 0
Zoom :
Code :
data_2=readmatrix("provete_15_seco.xlsx","Sheet",'Untitled');
time=data_2(:,2);
strain=data_2(:,3);
x=seconds(time);
x.Format = 'hh:mm:ss';
d=rms(strain);
app.RMSEditField.Value=d;
if (1342<d)&&(d<1483)
msgbox("Don't need analyse.","non-modal");
else
%app.TabGroup.SelectedTab=app.AnalyseTab;
% plot(x,strain,"r");
% hold on
plot(x,strain,"b");
yline(0)
yline(-2800);
hold on
% shift strain so that it positive peaks are on the y = 0 line
[locs, pks]=peakseek(strain);
x_peaks = x(locs);
yshift = interp1(x_peaks,pks,x);
plot(x,yshift,"r");
strain_3 = strain - yshift;
plot(x,strain_3,"m");
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [locs, pks]=peakseek(x,minpeakdist,minpeakh)
% FEX : https://fr.mathworks.com/matlabcentral/fileexchange/26581-peakseek?s_tid=srchtitle
% x is a vector input (generally a timecourse)
% minpeakdist is the minimum desired distance between peaks (optional, defaults to 1)
% minpeakh is the minimum height of a peak (optional)
%
% (c) 2010
% Peter O'Connor
% peter<dot>ed<dot>oconnor .AT. gmail<dot>com
if size(x,2)==1, x=x'; end
% Find all maxima and ties
locs=find(x(2:end-1)>=x(1:end-2) & x(2:end-1)>=x(3:end))+1;
if nargin<2, minpeakdist=1; end % If no minpeakdist specified, default to 1.
if nargin>2 % If there's a minpeakheight
locs(x(locs)<=minpeakh)=[];
end
if minpeakdist>1
while 1
del=diff(locs)<minpeakdist;
if ~any(del), break; end
pks=x(locs);
[garb, mins]=min([pks(del) ; pks([false del])]); %#ok<ASGLU>
deln=find(del);
deln=[deln(mins==1) deln(mins==2)+1];
locs(deln)=[];
end
end
if nargout>1
pks=x(locs);
end
end
  7 comentarios
Mathieu NOE
Mathieu NOE el 14 de Jun. de 2023
hello again
I have some trouble unzipping your file - does it work on your side ?
Mathieu NOE
Mathieu NOE el 14 de Jun. de 2023
maybe you could reduce the amount of data and send me only the first half , so you don't have to zip it
that should be enough data to fix the code

Iniciar sesión para comentar.

Más respuestas (2)

Maria Inês
Maria Inês el 14 de Jun. de 2023
Hi,
I had no problems but I attach a file with less data.
  1 comentario
Mathieu NOE
Mathieu NOE el 14 de Jun. de 2023
I am tryng to find a robust method that works both for the first data file you provided and then this new one - but they show very different look
your first file (provete_15_seco.xlsx) was a clean almost triangular shape signal with no artifacts or noise. also we can see the distance between peaks are only a few samples (blue dots on the curve).
with such a clean signal peakseek would work nicely even without to give any extra parameter values about minimal peak distance and height.
the "new" data file (5x250_CF_alterado.xlsx) gives a very different figure :
  • lots of data points between peaks - if I look at the negative peaks that are a bit more evident to recognize , I will see more than 1000 samples between 2 successive negative peaks, like this measurement has been made with a much higher sampling rate (or the test is done at a lower frequency)
  • signal quite a bit noisy and distorded on the positive side
  • peakseek will have trouble selecting the only valid peaks if we do not help him by defining an appropriate value for minpeakdist,minpeakh - now the risk is that we may have to tune those parameters depending of what signal we have , for example what distance between peaks we have and if the signal quality is like the first file or the second data file
  • so it's going to be messy to tweak too many parameters depending of what the data looks like , we need something simple and robust
a zoom on the top
so my job now is to find the "magic" tool that can deal with both data sets without requiring to "tune" too many parameters....

Iniciar sesión para comentar.


Maria Inês
Maria Inês el 14 de Jun. de 2023
Hi,
Okay, I understand. I can't put the filter of the first data file I sent in this second file because the data is different.
How can I help? What kind of parameters do you need to know to get the magic formula?
If it's simpler, you can just find the magic formula for these data (5x250_CF_alterado.xlsx) but with the same goal, ie take the peaks and set them to zero.
There is another issue that I don't know if you've seen, Ch2 will have symmetrical values to that of CH1. The filter must also be able to make this adjustment when the peak values are negative and positive.
I don't know if I made myself clear...
Any questions, just say.
  2 comentarios
Mathieu NOE
Mathieu NOE el 14 de Jun. de 2023
I was about to ask if you have some more data files to share , so I can see what kind of signals we have , but in the mean time i figured out / tested other options and , at least for the two files we have today , I could find a simple and more robust solution
basically you only need to replace peakseek with another function that is better working on noisy signals (here comes peakfinder , see attachment)
so it seems to work for both data files , and or the last file, I tested on channel 2 and 3 and it's ok
sorry if I have a bit messed up your code , but I think you can easily copy / paste the new lines , or simply uncomment your lines I have commented
also I beleive it is better to remove NaN values (they are generated by readmatrix when you have header lines in your excel file but you don't ask readmatrix to ignore them)
ok, so finally this is the new code , please have a ook and try it and let me know !
if you want to send me some more data files , I can also continue to test the code on my side
% [name,path]=uigetfile('.xlsx','Select a file'); % your code
% my code for fast testing
path = pwd;
% files i want to test
% name = 'provete_15_secoB.xlsx'; % 1st file
name = '5x250_CF_alterado.xlsx'; % 2 nd file (test Channel 2 and 3 !)
% main code
file=fullfile(path,name);
data_2=readmatrix(file,"Sheet","Untitled");
x=data_2(:,1);
strain=data_2(:,2); % choose which strain channel you want
% better remove NaN's first (they come from excel file header lines)
i1 = ~isnan(x);
i2 = ~isnan(strain);
i3 = i1&i2;
x=x(i3);
strain=strain(i3);
% plot(app.UIAxes,x,strain,"b"); % your code
plot(x,strain,"b");
% yline(0); % your code
% yline(-2800); % your code
hold on
% shift strain so that it positive peaks are on the y = 0 line
[locs] = peakfinder(strain); % more noise resistant than peakseek
yshift = interp1(x(locs),strain(locs),x);
plot(x,yshift,"k"); % just for fun (debug)
strain_3 = strain - yshift;
% plot(app.UIAxes_2,x,strain_3,"b", x,yshift,"r"); % your code
plot(x,strain_3,"r");
hold off
Mathieu NOE
Mathieu NOE el 14 de Jun. de 2023
forgot the attachment (peakfinder )
now you have it !

Iniciar sesión para comentar.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by