Extracting data from a signal

21 vues (au cours des 30 derniers jours)
Rahim Yousefi
Rahim Yousefi le 9 Mar 2020
Modifié(e) : Adam Danz le 10 Mar 2020
my signal is a single column vector (I have attached an image how the signal looks like), I want to extract data from this vector from whenever the signal starts rising until it reaches the peak for each iteration and saving corresponding data from each iteration in a new separate column vector. Any suggestions?
  2 commentaires
Adam Danz
Adam Danz le 9 Mar 2020
Which one of these images (if any) indicate when the signal starts to rise?
In the first image, there are many tiny spike where the signal technically isn't monotonically rising.
Rahim Yousefi
Rahim Yousefi le 9 Mar 2020
@Adam Danz , thank you for the comment, the picture in the right hand side indcates where the signal rise

Connectez-vous pour commenter.

Réponse acceptée

Adam Danz
Adam Danz le 9 Mar 2020
Modifié(e) : Adam Danz le 10 Mar 2020
This segments the monotonically increasing part of each pulse, as depicted in the 2nd image in my comment under your question. See inline comments for details.
Input: signal (provided by your mat file)
Output: startIdx (the starting index of each rise), locs (the index of the peaks).
Method 1
This method is not recommended; see method 2 below.
% Get coordinates of peaks
% The first line below is another option
% [~, locs] = findpeaks(signal, 'MinPeakHeight', range(signal)*.4 + min(signal), 'MinPeakDistance', 200);
signalSmooth = smooth(signal,20);
[~, locs] = findpeaks(signalSmooth, 'MinPeakHeight', range(signal)*.4 + min(signal), 'MinPeakDistance', 200);
% Look for 4 consecutive increases
mm = movmean([inf;diff(signal)] > 0, [0,3]) == 1;
mmIdx = find(mm);
firstOnes = find([mm(1);diff(mmIdx)>1]);
startIdx = mmIdx(firstOnes);
clf()
plot(signal, 'b-')
hold on
plot(locs, signal(locs), 'r*')
plot(startIdx, signal(startIdx), 'mx', 'LineWidth',2)
% Now exact the segments and plot them separately
% Extract
segements = arrayfun(@(start,stop){signal(start:stop)},startIdx,locs);
figure()
hold on
cellfun(@(c)plot(c),segements)
Or, if you want to preserve the x-values,
% Extract
segements = arrayfun(@(start,stop){signal(start:stop)},startIdx,locs);
segement_xvalues = arrayfun(@(start,stop){start:stop},startIdx,locs);
figure()
hold on
cellfun(@(x,y)plot(x,y),segement_xvalues, segements)
Update: Method 2
New smoothing method; a new, more robust, method of finding the start of each rising segment that ends at a peak.
load('signal3.mat');
signal = s3;
% Get coordinates of peaks
signalSmooth = smoothdata(signal,'gaussian', 20);
% NOTE: You may have to play around with findpeak() options to optimize
% this to your data! See the documentation.
[~, locs] = findpeaks(signalSmooth, 'MinPeakHeight', range(signal)*.1 + min(signal), 'MinPeakDistance', 200);
% Determine which points are increasing releative to previous point
isIncrease = diff([inf; signalSmooth]) > 0 ;
notIncrIdx = find(~isIncrease);
% For each peak, find the closest previous point that isn't increasing.
idx = notIncrIdx(:) < locs(:).';
startIdx = arrayfun(@(col)find(idx(:,col),1,'last'),1:numel(locs));
startIdx = notIncrIdx(startIdx)+1;
clf()
plot(signal, 'b-')
hold on
% plot(signalSmooth, 'c-')
plot(locs, signal(locs), 'r*')
plot(startIdx, signal(startIdx), 'mx', 'LineWidth',2)
% Extract
segements = arrayfun(@(start,stop){signal(start:stop)},startIdx,locs);
segement_xvalues = arrayfun(@(start,stop){start:stop},startIdx,locs);
figure()
hold on
cellfun(@(x,y)plot(x,y),segement_xvalues, segements)
  6 commentaires
Rahim Yousefi
Rahim Yousefi le 10 Mar 2020
There is just one thing else, the second method is good for the peak detections, but the segments don’t really start from when the values are increasing (there is always some constant values before the rise) which will make problem for my further evaluations (for example when I want to calculate the area under each segment). I want the segments to look like the ones from method one (however method one was not working for the new signal). So should I extract the increasing part of the segments again with a separate code (easiest solution probably) or any other suggestions?
Adam Danz
Adam Danz le 10 Mar 2020
Modifié(e) : Adam Danz le 10 Mar 2020
When I zoom into a portion of the plot, the magenta x marks look reasonable. The flat lines at the beginning of your M2.png figure are due to the similar y-values clustered around the beginning of each segment. You can see this below. If that's a problem, you could offset the startIdx by a few values.

Connectez-vous pour commenter.

Plus de réponses (1)

Hank
Hank le 9 Mar 2020
Adam, I think the crosshairs in the first image are where the derivative becomes positive: the signal starts to rise. I would use this fact to cut the data programatically. First smooth the data and then take the derivative. The continguous regions where the derivative is positive are the regions you're looking for.
sig = load('signal'); % load
sig = sig(:); % column vector
sigsmooth = smooth(sig,100); % boxcar 100 smoothing
dsig = [0; diff(sig)]; % derivative, padded with 0 so the length doesn't change.
dsigrising = dsig>0; % this vector is true in the regions you want data.
Clustering the rising regions is not something I know how to do programatically, but maybe this could make the boundaries distinct enought that you could do it by hand.

Community Treasure Hunt

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

Start Hunting!

Translated by