Extracting data from a signal
21 views (last 30 days)
Show older comments
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 Comments
Adam Danz
on 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.
Accepted Answer
Adam Danz
on 9 Mar 2020
Edited: Adam Danz
on 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 Comments
Adam Danz
on 10 Mar 2020
Edited: Adam Danz
on 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.
More Answers (1)
Hank
on 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.
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!