Plotting with respect to minutes as formatted time (min.sec) - matlab

I'm trying to plot some data with respect to minutes instead of seconds in Matlab as formatted time, i.e. min.sec.
I have real time data streaming in where with every sample received, its time in seconds is also sent. I then plot them with respect to time. Now, since my session is around 15 minutes long, I can't be plotting with respect to time. Therefore I wanted to plot it with respect to time (min.sec). I tried dividing the received time by 60 but this gives me minutes with 100 subdivisions instead of 60 (the minutes increment after 0.9999 instead of 0.59). How do I convert it so that I'm able to plot with respect to time in minutes?
Here is what I mean by 0.99 fractions of a minute instead of 0.59. A normal minute has 60 divisions not 100.
EDIT:
I tried m7913d's suggestions and here is what I got.
first I plot the signal with respect to time in seconds without changing the ticks ( A normal plot(t,v))
The I added datetick('x', 'mm:ss'); to the plot (Xtick format is not supported in Matlab 2015b)
Here is a screenshot of the results
The time in seconds was up to 80 seconds, when translated into minutes, it should give me 1 minutes and 20 seconds as the maximum x axis limit. But this is not the case. I tried to construct a t vector (i.e like t=0:seconds(3):minutes(3)) but I couldn't link it to my seconds vector which will be constantly updating as new samples are received from the serial port.
Thanks

You can use xtickformat to specify the desired format of your x labels as follows:
% generate a random signal (in seconds)
t = 0:5:15*60;
y = rand(size(t));
plot(seconds(t),y) % plot your signal, making it explicit that the t is expressed in seconds
xtickformat('mm:ss') % specify the desired format of the x labels
Note that I used the seconds methods, which returns a duration object, to indicate to Matlab that t is expressed in seconds.
The output of the above script is (the right image is a zoomed version of the left image):
Pre R2016b
One can use datetime instead of xtickformat as follows:
datetimes = datetime(0,0,0,0,0,t); % convert seconds to datetime
plot(datetimes,y)
datetick('x', 'MM:SS'); % set the x tick format (Note that you should now use capital M and S in the format string
xlim([min(datetimes) max(datetimes)])

Related

Resample time based column array as per sampling time in Matlab

I need to run a simulation with sample time of
tsample = 0.01 ; % seconds
I have a table such as below
I need to resample each column in input table such that value of the input Time vector gets equally spaced based on tsample values.
For the [Time] column I achieved this by following code
simTime = max(tests.(test_names{i}).Times); % Seconds
% Interpolate the time and frequency values as per sample time
numSteps = simTime/tsample;
time = tsample * [0:(numSteps-1)]';
What I need to do now is resize the frequency (f) values such that it shall be filled with previous values until a new value is found in column;
Time
f
0
50
....
50
4.99
50
5.00
49.65
....
49.65
19.99
49.65
20.00
49.80
I am confused whether I should use fillmissing or resample or interp1.
The examples I am following for these seem kind of different than what I wish to achieve here.
Any help would be really appreciated.
Thank you.
Ok,
I tried experimenting with more examples for interp1 and this solved my issue.
freq = interp1(tests.Times, tests.fHz, time, 'previous');
I was earlier unaware of the 'previous' option
Should have searched the documentation more extensively.

How do I take an n-day average of data in Matlab to match another time series?

I have daily time series data and I want to calculate 5-day averages of that data while also retrieving the corresponding start date for each of the 5-day averages. For example:
x = [732099 732100 732101 732102 732103 732104 732105 732106 732107 732108];
y= [1 5 3 4 6 2 3 5 6 8];
Where x and y are actually size 92x1.
Firstly, how do I compute the 5-day mean when this time series data is not divisible by 5? Ultimately, I want to compute the 'jumping mean', where the average is not computed continuously (e.g., June 1-5, June 6-10, and so on).
I've tried doing the following:
Pentad_avg = mean(reshape(y(1:90),5,[]))'; %manually adjusted to be divisible by 5
Pentad_dt = x(1:5:90); %select every 5th day for time
However, Pentad_dt gives me dates 01-Jun-2004 and 06-Jun-2004 as output. And, that brings me to my second point.
I am looking to find 5-day averages for x and y that correspond to 5-day averages of another time series. This second time series has 5-day averaged data starting from 15-Jun-2004 until 29-Aug-2004 (instead of starting at 01-Jun-2004). Ultimately, how do I align the dates and 5-day averages between these two time series?
Synchronization between two time series can be accomplished using the timeseries object. Placing your data into an object allows Matlab to intelligently process it. The most useful thing is adds for your usage is the synchronize method.
You'll want to make sure to properly set the time vector on each of the timeseries objects.
An example of what this might look like is as follows:
ts1 = timeseries(y,datestr(x));
ts2 = timeseries(OtherData,OtherTimes);
[ts1 ts2] = synchronize(ts1,ts2,'Uniform','Interval',5);
This should return to you each timeseries aligned to be with the same times. You could also specify a specific time vector to align a timeseries to using the resample method.

Plotting multiple datasets in MATLAB

I have voltage and current signals from multiple days. The time vector is in seconds of the day (SOD), and the voltage and current vectors are in volts and amps respectively. However, the vector data from each day is different lengths. For example Mondays data might be 1x100000 for both time and voltage/current, and Tuesdays might be 1x50000 for both time and voltage/current. I was asked to plot the different days of data on the same figure for comparison purposes. I have tried using the plot(x1,y1,x2,y2) method but that obviously didn't work due to different vector lengths. I tried interpolating to the larger data set, but then realized that I will get all NaNs on the result since there is no overlap in time. I ran out of ideas and am desperately in need of help.
EDIT:
I guess I forgot to mention that somehow I would like to overlay them one on top of the other in the same figure and not using a subplot.
It sounds like you want a data vector of length n to span, I'm guessing, 24 hours = 86400 seconds, for any n (e.g. n=100000 or n=50000). Assuming the original data is uniformly sampled, this should do the trick:
x1=linspace(0,86400,length(x1));
x2=linspace(0,86400,length(x2));
plot(x1,y1,'r-',x2,y2,'b-');
If it is not uniformly sampled, we can still make it work:
t1=linspace(0,86400,length(x1));
t2=linspace(0,86400,length(x2));
newy1 = spline(x1,y1,t1);
newy2 = spline(x2,y2,t2);
plot(t1,newy1,'r-',t2,newy2,'b-');

Iterate for loop by hour in MATLAB

I am writing a for loop to average 10 years of hourly measurements made on the hour. The dates of the measurements are recorded as MATLAB datenums.
I am trying to iterate through using 0.0417 as it is the datenum for 1AM 00/00/00 but it is adding in a couple of seconds of error each time I iterate.
Can anyone recommend a better way for me to iterate by hour?
date = a(:,1);
load = a(:,7);
%loop for each hour of the year
for i=0:0.0417:366
%set condition
%condition removes year from current date
c = date(:)-datenum(year(date(:)),0,0)==i;
%evaluate condition on load vector and find mean
X(i,2)=mean(load(c==1));
end
An hour has a duration of 1/24 day, not 0.0417. Use 1/24 and the precision is sufficient high for a year.
For an even higher precision, use something like datenum(y,1,1,1:24*365,0,0) to generate all timestamps.
To avoid error drift entirely, specify the index using integers, and divide the result down inside the loop:
for hour_index=1:365*24
hour_datenum = (hour_index - 1) / 24;
end

Timestamp Processing Brain Teaser

I am processing 1Hz timestamps (variable 'timestamp_1hz') from a logger which doesn't log exactly at the same time every second (the difference varies from 0.984 to 1.094, but sometimes 0.5 or several seconds if the logger burps). The 1Hz dataset is used to build a 10 minute averaged dataset, and each 10 minute interval must have 600 records. Because the logger doesn't log exactly at the same time every second, the timestamp slowly drifts through the 1 second mark. Issues come up when the timestamp cross the 0 mark, as well as the 0.5 mark.
I have tried various ways to pre-process the timestamps. The timestamps with around 1 second between them should be considered valid. A few examples include:
% simple
% this screws up around half second and full second values
rawseconds = raw_1hz_new(:,6)+(raw_1hz_new(:,7)./1000);
rawsecondstest = rawseconds;
rawsecondstest(:,1) = floor(rawseconds(:,1))+ rawseconds(1,1);
% more complicated
% this screws up if there is missing data, then the issue compounds because k+1 timestamp is dependent on k timestamp
rawseconds = raw_1hz_new(:,6)+(raw_1hz_new(:,7)./1000);
A = diff(rawseconds);
numcheck = rawseconds(1,1);
integ = floor(numcheck);
fract = numcheck-integ;
if fract>0.5
rawseconds(1,1) = rawseconds(1,1)-0.5;
end
for k=2:length(rawseconds)
rawsecondstest(k,1) = rawsecondstest(k-1,1)+round(A(k-1,1));
end
I would like to pre-process the timestamps then compare it to a contiguous 1Hz timestamp using 'intersect' in order to find the missing, repeating, etc data such as this:
% pull out the time stamp (round to 1hz and convert to serial number)
timestamp_1hz=round((datenum(raw_1hz_new(:,[1:6])))*86400)/86400;
% calculate new start time and end time to find contig time
starttime=min(timestamp_1hz);
endtime=max(timestamp_1hz);
% determine the contig time
contigtime=round([floor(mean([starttime endtime])):1/86400:ceil(mean([starttime endtime]))-1/86400]'*86400)/86400;
% find indices where logger time stamp matches real time and puts
% the indices of a and b
clear Ia Ib Ic Id
[~,Ia,Ib]=intersect(timestamp_1hz,contigtime);
% find indices where there is a value in real time that is not in
% logger time
[~,Ic] = setdiff(contigtime,timestamp_1hz);
% finds the indices that are unique
[~,Id] = unique(timestamp_1hz);
You can download 10 days of the raw_1hz_new timestamps here. Any help or tips would be much appreciated!
The problem you have is that you can't simply match these stamps up to a list of times, because you could be expecting a set of datapoints at seconds = 1000, 1001, 1002, but if there was an earlier blip you could have entirely legitimate data at 1000.5, 1001.5, 1002.5 instead.
If all you want is a list of valid times/their location in your series, why not just something like (times in seconds):
A = diff(times); % difference between times
n = find(abs(A-1)<0.1) % change 0.1 to whatever your tolerance is
times2 = times(n+1);
times2 should then be a list of all your timestamps where the previous timestamp was approximately 1 second ago - works on a small set of fake data I constructed, didn't try it on yours. (For future reference: it would be more help to provide a small subset of your data, e.g. just a few minutes worth, that you know contains a blip).
I would then take the list of valid timestamps and split it up into 10 minute sections for averaging, counting how many valid timestamps were obtained in each section. If it's working, you should end up with no more than 600 - but not much less if the blips are occasional.