How to convert decimal hour and calculate the average every 5 min? - matlab

I'm a beginner at Matlab and I need to solve a problem. First, I need to convert the UT columm from decimal hour to hour:minute:seconds. Then, I need to calculate every 5 minutes on average the ROT collumn and show the reply in a new matrix (hour:min:sec,rot mean).
Data
UT (column 1) A matrix
5.4
5.404
5.408
ROT (column2) A matrix
0.22
0.123
0.129
e.g. UT (5.404)=0.404*60=24.252; 0.252*60=15.12 ,then UT(5.404)=5:24:15 hours:min:sec
Thanks in advance
Marcelo

First convert decimal hour dates into serial dates where unity is a day:
serdates = [5.4;5.404;5.408]/24;
Then convert to string with datestr (this is however a cosmetic operation):
datestr(serdates,'HH:MM:SS')
Group observation in 5 minute bins (lb <= x < up):
ymdhms = datevec(serdates);
[~,minbins] = histc(ymdhms(:,5),[0:5:60])
Group then by year, day, month, hour and 5 minute bins:
[untime,~,subs] = unique([ymdhms(:,1:4) minbins*5],'rows')
Accumulate rot:
rot5min = accumarray(subs,[0.22;0.123;0.129]);
And for fancier presentation collect into dataset with datestrings
dataset({ cellstr(datestr(datenum([untime,zeros(size(untime,1),1)]),31)),'Datetime'}, {rot5min 'ROT5min'})
ans =
Datetime ROT5min
'0000-01-00 05:05:00' 0.472

This will do. Cheers.
function v=myfunction(ut,rot)
% ut is a vector of decimal hours
% rot is a vector of the same length as ut
% v is a matrix with rows of the form (hour, min, sec, rot5) where
% rot5 is an average of rot over 5 min interval from 2.5 min in the past
% to 2.5 min to the future.
m=numel(ut);
% input validation
assert(isvector(ut) && isvector(rot) && numel(rot)==m);
% array initialization
v=zeros(m,4);
utCopy=ut;
for i=1:m
% calculate hour from decimal hour
v(i,1)=floor(utCopy(i));
% calculate minute from decimal hour
utCopy(i)=(utCopy(i)-v(i,1))*60;
v(i,2)=floor(utCopy(i));
% calculate second from decimal hour, round to nearest integer
utCopy(i)=(utCopy(i)-v(i,2))*60;
v(i,3)=round(utCopy(i));
% calculate 5 mins central average of rot
% to get forward average just replace the logical indexing with
% ut>=ut(i) & ut<=ut(i)+1/12
v(i,4)=mean(rot(ut>=ut(i)-1/24 & ut<=ut(i)+1/24));
end
end

Related

Matlab - calculating sum of all molecules produced in the interval time

I am struggling with the code for calculating the sum of molecules produced in an interval and I think the issue is with establishing the interval the sum is being taken at.
prod_time_seq = total_time as a vector
bin_interval= 1;
number_min= 720;
prod_per_min= zeros(bin_interval,number_min);
for i=2:number_min
int(i) = 1 + ceil((prod_time_seq(i)-prod_time_seq(1))./60); %time interval
prod_per_min(i) = sum(int(i)); %sum of the molecules of each array
end
Assuming that you are trying to calculate the sum of the elements in each interval, this can be a solution (adding zero as the initial point in the interval of summation):
for i=1:number_min
int(i) = 1 + ceil((prod_time_seq(i)-prod_time_seq(1))./60); %time interval
prod_per_min(i) = sum(0:int(i)); %sum of the molecules of each array
end
In your case, int(i) is a single value and summation will return the value itself. But to be able to create an interval for each case, you need to define a starting point such as 0:int(i), which means the values from zero up to int(i).

Cumulative sum computation from hourly rainfall data MATLAB

I have a hourly rainfall timeseries from 1970 to 2003. I want to calculate:
n-hour values, n = 2,3,6,12,24 & 48 hr. 24-hr rainfall data can be calculated by accumulating 24 consecutive 1-hr data.
Similarly, 48-hr rainfall can be calculated by adding 2-day rainfall values.
From n-hr timeseries, I want to calculate maximum rainfall value for each year.
Likewise, I can compute for other accumulation periods. However, I need suggestions for calculation of annual maximum rainfall value from n-hrly data (aggregated time series), which can be calculated from maximum value of yearly n-hourly rainfall information. For example, from 1970 to 2003, I want to extract 34 annual maxima values correspond to 2,...24 hrs and 19 annual maxima values for 48-hr. Please find sample dataset here:
https://docs.google.com/document/d/1e8g54c6KDw8lwdQ53xi0Bs9fJmasTqbIk2n4LbKA-gM/edit
The frist, second, third & fourth column indicates year, month, day & values respectively.
I tried this code:
ny_p = []; Ann_Max = [];grp_pr = [];
for yr = 1970:1975
i = yr - 1969;
matched = ismember(Precip_Final(:,1), yr, 'rows');
grp_pr = Precip_Final(matched,4); % extracting hourly value of the same year
[nrow,ncol] = size(grp_pr);
for row = 6:nrow % to get 6~ hourly sum
p_new = sum(grp_pr(row-5:row));
ny_p(end+1) = p_new;
end
Max_p = max(ny_p);
Ann_Max = [Ann_Max;Max_p];
clear matched; clear grp_pr; clear i; clear Max_p;
end
I edited my code. Now the problem is: in the matrix ny_p, the earlier years' value also getting stored while running. I want to get an array of maximum n-hrly value of each year in the matrix Ann_Max.

MATLAB: How to access 'Duration' datatype

Consider the following example
xDATA = data_timestamp;
[~,~,Days,Hour,Min,~] = datevec(xDATA(2:end) - xDATA(1:end - 1));
BadSamplingTime = find((Days)> 0 | (Hour)> 0 |(Min)> 5 );
In which xData contains a vector of time stamps and I am trying to find the samples with sampling time greater than 5 mins in between , the algorithm works fine but it creates 3 extra vectors for the data as big as my timestamp vector(the size to time stamp vector is pretty huge) whereas if I do this
DurationTime = xDATA(2:end) - xDATA(1:end - 1);
Instead of the second line it will just create one vector of same length of 'duration' data type which will be much easier to handle because but the problem I cant seem to access each index of the duration data type
for example
DurationTime(5,1)
ans =
26:00:01
I need to access this 26 hours part , does anyone have any idea how to do that ? or a better suggestion
You can create a duration-object and then use it to compare it with the duration vector DurationTime. The result of a>b is a logical vector that can be directly used to index the elements of DurationTime and thus giving you all the values where the duration is greater than 5 minutes.
Sidenote: You can calculate the difference/duration directly with diff.
Code:
% create example data
xDATA = (([0:4,4+26*60,4+26*60+1:4+26*60+5])/24/60+datetime('now')).';
% calculate the durations
DurationTime = xDATA(2:end) - xDATA(1:end-1); % as in the question
%DurationTime = diff(xDATA); % alternative
% get index and values of all durations greater than 5 minutes
ind = find(DurationTime>duration(0,5,0))
DurationTime(ind)
% get values of all durations greater than 5 minutes (direct solution, if no index needed)
DurationTime(DurationTime>duration(0,5,0));
Result:
ind =
5
ans =
26:00:00

How to create a matrix using a for loop MATLAB

I have three vectors of the same size, pressure, year and month. Basically I would like to create a matrix of pressure values that correspond with the months and years that they were measured using a for loop. It should be 12x100 in order to appear as 12 months going down and 100 years going left to right.
I am just unsure of how to actually create the matrix, besides creating the initial structure. So far I can only find pressure for a single month (below I did January) for all years.
A = zeros([12, 100]);
for some_years = 1900:2000
press = pressure(year == some_years & month == 1)
end
And I can only print the pressures for January for all years, but I would like to store all pressures for all months of the years in a matrix. If anyone can help it would be greatly appreciated. Thank You.
Starting with variables pressure, year, and month. I would do something like:
A fairly robust solution using for loops:
T = length(pressure); % get number of time periods. I will assume vectors same length
if(length(pressure) ~= T || length(month) ~= T)
error('length mismatch');
end
min_year = min(year); % this year will correspond to index 1
max_year = max(year);
A = NaN(max_year - min_year + 1, 12); % I like to initialize to NaN (not a number)
% this way missing values are NaN
for i=1:T
year_index = year(i) - min_year + 1;
month_index = month(i); % Im assuming months run from 1 to 12
A(year_index, month_index) = pressure(i);
end
If you're data is SUPER nicely formatted....
If your data has NO missing, duplicate, or out of order year month pairs (i.e. data is formatted like):
year month pressure
1900 1 ...
1900 2 ...
... ... ...
1900 12 ...
1901 1 ...
... ... ...
Then you could do the ONE liner:
A = reshape(pressure, 12, max(year) - min(year) + 1)';

Generating consistent arrays of datenums

Whenever I need to plot data vs time I generate the corresponding array of datenums so I can visualize a timeline on the plot by calling datetick.
Let's suppose I need all the datenums with a 1 minute interval between hours h_1 and h_2. This is how would I generate my array of datenums vd:
h_1 = [01 00]; % 01:00 AM
h_2 = [17 00]; % 17:00 PM
HH_1 = h_1(1); % Hour digits of h_1
MM_1 = h_1(2); % Minute digits of h_1
HH_2 = h_2(1); % Hour digits of h_2
MM_2 = h_2(2); % Minute digits of h_2
% Vector of 01:00 - 17:30 with 1 minute increments (24 hours a day, 1440 minutes a day)
vd = HH_1/24+MM_1/1440:1/1440:HH_2/24+MM_2/1440;
I learnt this technique reading this answer.
On the other hand, whenever I wish to generate a single datenum, I use the datenum function like this:
d = datenum('14:20','HH:MM');
Since 14:20 is comprised between the interval 01:00 - 17:30, its datenum should be too! Unfortunately this is not working as expected, since the number assigned to d is radically different to those values contained in vd. I think I might be missing something, probably something to do with setting up a reference date or similar.
So what would be the appropriate way to generate datenums consistently?
The reason is that the datenum function gives you a number of days from January 0, 0000.
So when calling
d = datenum('14:20','HH:MM');
you get a number about 735965, while the numbers in your vd array are between 0 and 1. In order to substruct the days between January 0, 0000 and today you can write
d = datenum('14:20','HH:MM') - datenum('00:00','HH:MM');
Then your code will look like
h_1 = [01 00]; % 01:00 AM
h_2 = [17 00]; % 17:00 PM
HH_1 = h_1(1); % Hour digits of h_1
MM_1 = h_1(2); % Minute digits of h_1
HH_2 = h_2(1); % Hour digits of h_2
MM_2 = h_2(2); % Minute digits of h_2
vd = HH_1/24 + MM_1/1440 : 1/1440 : HH_2/24+MM_2/1440;
d = datenum('14:20','HH:MM') - datenum('00:00','HH:MM');
display(d);
display(vd(801));
And the result:
d = 0.5972
ans = 0.5972