find positive calendarDurations in matlab - matlab

AIM:
I need to synchronize the animation of two plots in Matlab.
PROBLEM:
The data of the two plots has been acquired with a variable sample rate.
SOLUTION:
I converted the time-stamps of the two datasets in duration objects (relative to the beginning of the streaming).
Now I want to plot the two datasets in a for loop.
For each loop, I want to show the datasets samples whose durations are within the elapsed time.
QUESTION:
How do I determine if the duration of a specific sample already happened or not?
CODE EXAMPLE:
here I simulate and sort 10 random durations (d1), and 1 random elapsed time (et). I want to find which durations are past the elapsed time.
`
% simulate elapsed time
et = calendarDuration(round(rand(1,6)*10));
% simulate data for plot 1
data_for_plot1 = rand(10,1);
% simulate durations for the samples in plot1
d1 = calendarDuration(sortrows(round(rand(10,6)*10)));
% find index of durations which are before the elapsed time
is_past = (d1-et)>0;
% plot the data
plot(data_for_plot1(is_past))
`
ERROR MESSAGE
is_past = (d1-et)>0;
Undefined operator '>' for input arguments of type 'calendarDuration'.
ALTERNATIVE SOLUTIONS:
It's my first time with duration and date objects, and I am hating every bit of it. If you have alternative solutions I would love to hear them.
Mind that the timestamps of data1 come as strings ('yyyy-MM-dd HH:mm:ss.SSS') and the timestamps of data2 come as double (eg: 42.525, 42 s and 525 ms).
Thank you for your help

You can use split function for this purpose.
Use is_past = split((d1-et),'time')> 0; instead of is_past = (d1-et)>0;

Related

Saving parfor loop data in workspace (Matlab)

Good evening,
May I please get help with a script I'm writing? I have a parfor loop nested within a for loop. The goal is to iterate over a set of data that consists of 10 data subsets generated from an earlier parsim simulink analysis (it's labeled as 1x10 SimulationOutput). Each data subset is 24 rows deep, and a variable length of columns (usually about 200,000 to 300,000 columns of data). Part of the process is to find the maximum or minimum values in each data set. Once that is done, it is to be put into a table, appending data to that table. Ideally, I should have a 6x10 table by the end of it. See below for the code:
% Run Time
tic
% Preallocate memory to increase speed
b=zeros(24,1); %Make space for this array.
c=zeros(500000,1);
d=zeros(500000,1);
e=zeros(500000,1);
f=zeros(500000,1);
g=zeros(500000,1);
h=zeros(500000,1);
%table=[];
for j = 1:length(out(1,:)) %iterate over each run
parfor i = 1:length(out(1,j).PN.time) % Set length of vector
b=out(1,j).PN.signals.values(:,i); % Find the values to work on
c(i)=b(19,:); % Distance to target (m)
d(i)=b(20,:); % Lat. Accelerations, integrated twice (m)
e(i)=b(21,:); % Long. Acceleration, integrated twice (m)
f(i)=b(22,:); % Lat. Guidance Error
g(i)=b(23,:); % Long. Guidance Error
h(i)=b(24,:); % time to target (sec)
end
%For c_min, there's extranous zeros popping up, exclude them
tc = c;
tc(tc <= 0) = nan;
[c_min, I_1] = min(tc);
% [c_min,I_1]=min(c(c>0)); % Collect the closest missile/target approach (most
critical value)
[d_max,I_2]=max(d); % We need to find the max value per run, but wish for the min value
%over all runs.
[e_max,I_3]=max(e); % We need to find the max value per run, but wish for the min value
%over all runs.
[f_min,I_4]=min(f); % We just want the minimum value here.
[g_min,I_5]=min(g); % We just want the minimum value here.
[h_max,I_6]=max(h); % The minimum time is 2nd most critical value, after distance to
%target.
table(:,j)=[ c_min d_max e_max f_min g_min h_max]; %d_max e_max f_min g_min h_max
end
toc
The issue that I am having is that, while I can input the correct data sets in the correct locations in the table if I set a constant j value (example: if j = 7, then the 7th column in the table gets the correct data) I can't seem to get all the values inputted correctly. What I mean is that, the outputted table (6x10) will have repeated values across columns, values from one column in another column, and so on). It is as if the script cannot differentiate between columns anymore, so values just go wherever.
If anyone has any advice, I'd greatly appreciate it. Thank you,

I want advice about how to optimize my code. It takes too long for execution

I wrote a MATLAB code for finding seismic signal (ex. P wave) from SAC(seismic) file (which is read via another code). This algorithm is called STA/LTA trigger algorithm (actually not that important for my question)
Important thing is that actually this code works well, but since my seismic file is too big (1GB, which is for two months), it takes almost 40 minutes for executing to see the result. Thus, I feel the need to optimize the code.
I heard that replacing loops with advanced functions would help, but since I am a novice in MATLAB, I cannot get an idea about how to do it, since the purpose of code is scan through the every time series.
Also, I heard that preallocation might help, but I have mere idea about how to actually do this.
Since this code is about seismology, it might be hard to understand, but my notes at the top might help. I hope I can get useful advice here.
Following is my code.
function[pstime]=classic_LR(tseries,ltw,stw,thresh,dt)
% This is the code for "Classic LR" algorithm
% 'ns' is the number of measurement in STW-used to calculate STA
% 'nl' is the number of measurement in LTW-used to calculate LTA
% 'dt' is the time gap between measurements i.e. 0.008s for HHZ and 0.02s for BHZ
% 'ltw' and 'stw' are long and short time windows respectively
% 'lta' and 'sta' are long and short time windows average respectively
% 'sra' is the ratio between 'sta' and 'lta' which will be each component
% for a vector containing the ratio for each measurement point 'i'
% Index 'i' denotes each measurement point and this will be converted to actual time
nl=fix(ltw/dt);
ns=fix(stw/dt);
nt=length(tseries);
aseries=abs(detrend(tseries));
sra=zeros(1,nt);
for i=1:nt-ns
if i>nl
lta=mean(aseries(i-nl:i));
sta=mean(aseries(i:i+ns));
sra(i)=sta/lta;
else
sra(i)=0;
end
end
[k]=find(sra>thresh);
if ~isempty(k)
pstime=k*dt;
else
pstime=0;
end
return;
If you have MATLAB 2016a or later, you can use movmean instead of your loop (this means you also don't need to preallocate anything):
lta = movmean(aseries(1:nt-ns),nl+1,'Endpoints','discard');
sta = movmean(aseries(nl+1:end),ns+1,'Endpoints','discard');
sra = sta./lta;
The only difference here is that you will get sra with no leading and trailing zeros. This is most likely to be the fastest way. If for instance, aseries is 'only' 8 MB than this method takes less than 0.02 second while the original method takes almost 6 seconds!
However, even if you don't have Matlab 2016a, considering your loop, you can still do the following:
Remove the else statement - sta(i) is already zero from the preallocating.
Start the loop from nl+1, instead of checking when i is greater than nl.
So your new loop will be:
for i=nl+1:nt-ns
lta = mean(aseries(i-nl:i));
sta = mean(aseries(i:i+ns));
sra(i)=sta/lta;
end
But it won't be so faster.

matlab: running fft on short time intervals in a for-loop for the length of data

I have some EEG data that I would like to break down into 30-second windows and run a fast Fourier transform on each window of data. I've tried to implement a for-loop and increment the index value by the number of samples in the time window. When I run this, I can see that (1) this works for the first window of data, but not the rest of them because (I think) the "number of samples minus one" leads to fewer elements than necessary for data_fft and thus doesn't have the same dimensions as f, which are both being plotted in a figure. (2) I tried to update the index value by adding the number of samples in a window, but after i = 1, it goes to i = 2 in my workspace and not to i = 7681 as I'd hoped. I've spent an embarrassingly long time on trying to figure out how to change this so it works correctly, so any advice is appreciated! Code is below. Let me know if I can clarify anything.
data_ch6 = data(:,6); % looking at just 1 electrode
tmax = 2*60; % total time in sec I want to analyze; just keeping it to 2 minutes for this exercise
tmax_window = 30; %30 sec window
times = tmax/tmax_window; % number of times fft should be run
Nsamps = tmax*hdr.SPR; % total # samples in tmax; sample rate is 256 hz
Nsamps_window = tmax_window*hdr.SPR; % # samples in time window
f = hdr.SPR*(0:((Nsamps_window-1)/2))/Nsamps_window; % frequency for plotting
for i = 1:Nsamps; % need to loop through data in 30 second windows in tmax
data_fft = abs(fft(data_ch6(i:i+Nsamps_window-1))); %run fft on data window
data_fft = data_fft(i:((i+Nsamps_window-1)/2)); %discard half the points
figure
plot(f, data_fft)
i = i+Nsamps_window;
end
Well there are a few things that are wrong in your code. First, let me start be saying that i is a very poor choice for a variable name since in matlab it usually stand for sqrt{-1}.
As for your code, I assume that you intend to perform windowed FFT without overlapping.
1) Your loop goes from 1 to Nsamps with an increment of 1. That means the each time you advance 1 sample. In other words you have Nsamps_window-1 overlap. You can use perhaps i=1:Nsamps_window:Nsamps-Nsamps_window-1 if you are not interested in overlapping.
2) The length of data_fft is Nsamps_window, so I think what you wanted to do is data_fft = data_fft(1:round(Nsamps_window/2));
3) When plotting FFT results, I suggest using dB: plot(20*log10(abs(data_fft)));
4) The line i = i+Nsamps_window; is meaningless since i is your loop variable (it has not effect).

Selecting certain time range in Matlab

I have a project to do and im facing some problems. Please help me. Im not so good at matlab yet.
Basically, I have a set of movement data (data.mat) which were recorded for 3 days non stop. And I need to:
1. select only certain certain moments (time range) of this whole set of data
2. divide these moments into small 2.56 seconds parts
3. make FFT of each small parts , to see the movement in frequency domain, and select only 5-25 Hz
4. find a few biggest frequency peaks
I wrote a code for making FFT and peaks for whole my data "Data.mat" and it is working.
This is my code:
load('Data.mat');
P=data1(,2); %
Fs=100
Ts=1/Fs
L=length(P)
t = (0:L-1)*Ts;
nfft = 256
figure(1) % raw signal plotting
plot(t,P);
y = fft(P,nfft)/L; % FFT
ymag = abs(y(1:length(y)/2+1));
ft = Fs/2*linspace(0,1,nfft/2+1);
figure(2) % FFT plotting
plot(ft,2*abs(y(1:nfft/2+1)))
indx=ft>= 5 & ft<= 25; % only 5-25Hz
ftsub=ft(indx);
ymagsub=ymag(indx);
% highest peaks
[pks,locs] = findpeaks(ymagsub,'MinPeakHeight',0.02)
plot(ftsub,ymagsub,ftsub(locs),pks,'rv','MarkerFaceColor','r')
Now Im trying to select only certain moments of the data but I have problems with it.
E.g. lets say, I want select only time range: 13-03-2013 9:20:00-9:45:00 AM
I have tried:
t_start =datenum('13-03-2013 9:20:00 AM', 'dd-mm-yyyy HH:MM:SS AM');
t_end = datenum('13-03-2013 9:45:00 AM', 'dd-mm-yyyy HH:MM:SS AM');
rows=find(P>= t_start & P<= t_end);
but I get answer:
rows=
Empty matrix: 0-by-1
Whats wrong? If this code is wrong, how to select certain time range then?
And how to select into 2.56 seconds ?
Please help me, Ive been trying to find the solution since weeks, im really depressed now.
For this line to work properly:
rows=find(P>= t_start & P<= t_end); P must be a series of times in MATLAB datenum format.
I'm guessing P is your actual data - so it doesn't work because find simply compares the numeric values in P against the numeric date values - your "P" values aren't date-tagged in MATLAB. The important things to remember is that the output of datenum is simply a number, so MATLAB will allow you to compare it against other numbers even if the result doesn't make real-world sense.
Your options are:
If your data contains a timestamp, load that, check that it is in the correct format (convert back with datestr for a sanity check). This may be the first column of your data. Perform the find on the time values and then use that to plot/extract the appropriate parts of P.
Construct a time vector - using what you know about the time of the first data point + the sampling rate, and do the same. Similar to your t but in datenums. This will also work if your data acquisition means you only have the times in time-since-start-of-file plus a start time.
Then it's just something like:
r=find(t>= t_start & t<= t_end);
plot(t(r),P(r);

Find a Binary Data Sequence in a Signal

Here's my goal:
I'm trying to find a way to search through a data signal and find (index) locations where a known, repeating binary data sequence is located. Then, because the spreading code and demodulation is known, pull out the corresponding chip of data and read it. Currently, I believe xcorr will do the trick.
Here's my problem:
I can't seem to interpret my result from xcorr or xcorr2 to give me what I'm looking for. I'm either having a problem cross-referencing from the vector location of my xcorr function to my time vector, or a problem properly identifying my data sequence with xcorr, or both. Other possibilities may exist.
Where I am at/What I have:
I have created a random BPSK signal that consists of the data sequence of interest and garbage data over a repeating period. I have tried processing it using xcorr, which is where I am stuck.
Here's my code:
%% Clear Variables
clc;
clear all, close all;
%% Create random data
nbits = 2^10;
ngarbage = 3*nbits;
data = randi([0,1],1,nbits);
garbage = randi([0,1],1,ngarbage);
stream = horzcat(data,garbage);
%% Convert from Unipolar to Bipolar Encoding
stream_b = 2*stream - 1;
%% Define Parameters
%%% Variable Parameters
nsamples = 20*nbits;
nseq = 5 %# Iterate stream nseq times
T = 10; %# Number of periods
Ts = 1; %# Symbol Duration
Es = Ts/2; %# Energy per Symbol
fc = 1e9; %# Carrier frequency
%%% Dependent Parameters
A = sqrt(2*Es/Ts); %# Amplitude of Carrier
omega = 2*pi*fc %# Frequency in radians
t = linspace(0,T,nsamples) %# Discrete time from 0 to T periods with nsamples samples
nspb = nsamples/length(stream) %# Number of samples per bit
%% Creating the BPSK Modulation
%# First we have to stretch the stream to fit the time vector. We can quickly do this using _
%# simple matrix manipulation.
% Replicate each bit nspb/nseq times
repStream_b = repmat(stream_b',1,nspb/nseq);
% Tranpose and replicate nseq times to be able to fill to t
modSig_proto = repmat(repStream_b',1,nseq);
% Tranpose column by column, then rearrange into a row vector
modSig = modSig_proto(:)';
%% The Carrier Wave
carrier = A*cos(omega*t);
%% Modulated Signal
sig = modSig.*carrier;
Using XCORR
I use xcorr2() to eliminate the zero padding effect of xcorr on unequal vectors. See comments below for clarification.
corr = abs(xcorr2(data,sig); %# pull the absolute correlation between data and sig
[val,ind] = sort(corr(:),'descend') %# sort the correlation data and assign values and indices
ind_max = ind(1:nseq); %# pull the nseq highest valued indices and send to ind_max
Now, I think this should pull the five highest correlations between data and sig. These should correspond to the end bit of data in the stream for every iteration of stream, because I would think that is where the data would most strongly cross-correlate with sig, but they do not. Sometimes the maxes are not even one stream length apart. So I'm confused here.
Question
In a three part question:
Am I missing a certain step? How do I use xcorr in this case to find where data and sig are most strongly correlated?
Is my entire method wrong? Should I not be looking for the max correlations?
Or should I be attacking this problem from another angle, id est, not use xcorr and maybe use filter or another function?
Your overall method is great and makes a lot of sense. The problem you're having is that you're getting some actual correlation with your garbage data. I noticed that you shifted all of your sream to be zero-centered, but didn't do the same to your data. If you zero-center the data, your correlation peaks will be better defined (at least that worked when I tried it).
data = 2*data -1;
Also, I don't recommend using a simple sort to find your peaks. If you have a wide peak, which is especially possible with a noisy signal, you could have two high points right next to each other. Find a single maximum, and then zero that point and a few neighbors. Then just repeat however many times you like. Alternatively, if you know how long your epoch is, only do a correlation with one epoch's worth of data, and iterate through the signal as it arrives.
With #David K 's and #Patrick Mineault's help I manage to track down where I went wrong. First #Patrick Mineault suggested I flip the signals. The best way to see what you would expect from the result is to slide the small vector along the larger, searched vector. So
corr = xcorr2(sig,data);
Then I like to chop off the end there because it's just extra. I did this with a trim function I made that simply takes the signal you're sliding and trims it's irrelevant pieces off the end of the xcorr result.
trim = #(x,s2) x(1:end - (length(s2) - 1));
trim(corr,data);
Then, as #David K suggests, you need to have the data stream you're looking for encoded the same as your searched signal. So in this case
data = 2*data-1;
Second, if you just have your data at it's original bit length, and not at it's stretched, iterated length, it can be found in the signal but it will be VERY noisy. To reduce the noise, simply stretch the data to match it's stretched length in the iterated signal. So
rdata = repmat(data',1,nspb/nseq);
rdata = repmat(rdata',1,nseq);
data = rdata(:)';
Now finally, we should have crystal clear correlations for this case. And to pull out the maxes that should correspond to those correlations I wrote
[sortedValues sortIndex] = sort(corr(:),'descend');
c = 0 ;
for r = 1 : length(sortedValues)
if sortedValues(r,:) == max(corr)
c = c + 1;
maxIndex(1,c) = sortIndex(r,:);
else break % If you don't do this, you get loop lock
end
end
Now c should end up being nseq for this case and you should have 5 index times where the corrs should be! You can easily pull out the bits with another loop and c or length(maxIndex). I've also made this into a more "real world" toy script, where there is a data stream, doppler, fading, and it's over a time vector in seconds instead of samples.
Thanks for the help!
Try flipping the signal, i.e.:
corr = abs(xcorr2(data,sig(end:-1:1));
Is that any better?