Matlab: Converting Timestamps to Readable Format given the Reference Date-Time - matlab

I have a text file that contains timestamps out of a camera that captures 50 frames per second .. The data are as follows:
1 20931160389
2 20931180407
3 20931200603
4 20931220273
5 20931240360
.
.
50 20932139319
... and so on.
It gives also the starting time of capturing like
Date: **02.03.2012 17:57:01**
The timestamps are in microseconds not in milliseconds, and MATLAB can support only till milliseconds but its OK for me.
Now I need to know the human format of these timestamps for each row..like
1 20931160389 02.03.2012 17:57:01.045 % just an example
2 20931180407 02.03.2012 17:57:01.066
3 20931200603 02.03.2012 17:57:01.083
4 20931220273 02.03.2012 17:57:01.105
5 20931240360 02.03.2012 17:57:01.124
and so on
I tried this:
%Refernce Data
clc; format longg
refTime = [2012,03,02,17,57,01];
refNum = datenum(refTime);
refStr = datestr(refNum,'yyyy-mm-dd HH:MM:SS.FFF');
% Processing data
dn = 24*60*60*1000*1000; % Microseconds! I have changed this equation to many options but nothing was helpful
for i = 1 : size(Data,1)
gzTm = double(Data{i,2}); %timestamps are uint64
gzTm2 = gzTm / dn;
gzTm2 = refNum + gzTm2;
gzNum = datenum(gzTm2);
gzStr = datestr(gzNum,'yyyy-mm-dd HH:MM:SS.FFF'); % I can't use 'SS.FFFFFF'
fprintf('i = %d\t Timestamp = %f\t TimeStr = %s\n', i, gzTm, gzStr);
end;
But I got always strange outputs like
i = 1 Timestamp = 20931160389.000000 TimeStr = **2012-03-08 13:29:28.849**
i = 2 Timestamp = 20931180407.000000 TimeStr = **2012-03-08 13:29:29.330**
i = 3 Timestamp = 20931200603.000000 TimeStr = **2012-03-08 13:29:29.815**
The output time is about some hours late/earlier than the Referenced Time. The day is different.
The time gap between each entry in the array should be nearly 20 seconds..since I have 50 frames per second(1000 millisecond / 50 = 20) ..and the year,month, day,hour,minute and seconds should also indicate the initial time given as reference time because it is about some seconds earlier.
I expect something like:
% just an example
1 20931160389 02.03.2012 **17:57:01.045**
2 20931180407 02.03.2012 **17:57:01.066**
Could one help me please..! Where is my mistake?

It looks like you can work out the number of microseconds between a record and the first record:
usecs = double(Data{i,2}) - double(Data{1,2});
convert that into seconds:
secsDiff = usecs / 1e6;
then add that to the initial datetime you'd calculated:
matDateTime = refNum + secsDiff / (24*60*60);

Related

Changing variable in ode15s [duplicate]

I have a code that uses ode15s to solve. This is my semester question and I am not really good on Matlab but tried to solve the problem like traditional programming way but couldn't achieve success.
The thing I want to achieve is I would like to change the value of Xxc depends on time
Initially Xxc value is 20, but when time will reach 10 then I want to update Xxc to 30 (1.5 times higher) and after that when time is 30 then I want to update Xxc to 40(2.0 times)
There are 2 files
adm1init.m (Initial values)
function ret=adm1init()
global Xxc......
.....
Xxc = 20;
......
time=0:0.2:70;
[t,dX]=ode15s('adm1sys', time, [Ssu Saa Sfa Sva Sbu Spro Sac Sh2 Sch4 SIC SIN SI Xxc Xch Xpr Xli Xsu Xaa Xfa Xc4 Xpro Xac Xh2 XI Scat San Shva Shbu Shpro...
Shac Shco3 Snh3 S_H_ion S_gas_h2 S_gas_ch4 S_gas_co2 q_gas Xhomo XCE Slac Sca]);
ret = dX
These are the only lines that I guess corelated.
Then the calculation file is adm1sys.m
function dX=adm1sys(t,X)
...
rho(1) = k_dis * X(13);
...
rho(13) = k_dec_Xsu * X(17);
rho(14) = k_dec_Xaa * X(18);
rho(15) = k_dec_Xfa * X(19);
rho(16) = k_dec_Xc4 * X(20);
rho(17) = k_dec_Xpro * X(21);
rho(18) = k_dec_Xac * X(22);
rho(19) = k_dec_Xh2 * X(23);
dX(13) = (q_in/V_liq) * (Xxc - X(13)) - rho(1) + sum(rho(13:19));
...
X0(13) = Xxc;
...
I just want to update Xxc value in formula of dX(13) depends on time
if t is 10 just Xxc == 30
if t is 30 just Xxc == 50
But instead of making t >= 10 I just want to apply this patch once.
I can provide other variables depends on formulas if needed.
Thanks

REXX codin with CSV input

Im new to coding with REXX and I need to make a program to find the Max, min and avg temperature for every month.
The input is Comma separated like below:
DAY/MONTH,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
1st,25.9,25.4,31.3,22.4,8.1,7.3,12.9,13.1,11.3,15.2,19.2,21
2nd,27.2,22.3,18,14.6,10.2,10.9,10.9,13.5,15.9,24.9,26.2,17.2
3rd,34.9,16.6,19.1,20.8,10.6,10.7,7,11.1,14.5,25.1,28.9,22.9
4th,24.4,19.8,21.7,12.6,11.5,13,10.5,7.3,13.1,22.5,16.8,21.7
5th,14.1,21.8,18.9,14.4,15.4,11.7,10.5,8.4,14,11.4,13.8,23.4
... etc
I need to create REXX code to find the the Max, Min and Mean temperature for each month and present it like below
User,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Max,34.9,16.6,19.1,20.8,10.6,10.7,7,11.1,14.5,25.1,28.9,22.9
Min,24.4,19.8,21.7,12.6,11.5,13,10.5,7.3,13.1,22.5,16.8,21.7
Mean,14.1,21.8,18.9,14.4,15.4,11.7,10.5,8.4,14,11.4,13.8,23.4
Any help in creating the REXX code, or any literature/direction on it would be greatly appreciated.
So far my code is
/*REXX*/
/* TRACE ?I */
ADDRESS SYSCALL "READFILE /u/inputdata RECS."
IF RC <> 0 THEN DO
SAY "ERROR READING FILE"
EXIT
END
FS=","; MAXTEMP=""; MINTEMP=""; AVGTEMP=""
DO I = 2 TO RECS.0
PARSE VAR RECS.I DAY","JAN","FEB","MAR","APR","JUN","JUL","AUG","SEP","OCT","NOV,"DEC
DO J = 2 TO RECS.I
MAXTEMP = MAX(RECS.I) /*Needs to add another VAR into Maxtemp*/
MINTEMP = MIN(RECS.I) /*same but Min */
AVGTEMP = SUM(RECS.I)/COUNT(RECS.I) /*Total/The amount of days*/
END
END
SAY user, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
SAY MAX, MAXTEMP /*MAX for each month fill out*/
SAY MIN, MINTEMP /*Min */
SAY MEAN, AVGTEMP /*Avg */
END
Im trying to make a variable for MaxTemp, MinTemp and MeanTemp adding the months on as the loop goes.
Here is a possible implementation. It runs over each record as you did; this is the outer loop (loop variable ii). Then the current temperature for each month is
compared to the current maximum for that month, and stored if greater
compared to the current minimum for that month, and stored if lower
added to the average sum-up field for the month
This is the inner loop (lop variable jj). Note that the code inside this inner loop takes care not to process values for days beyond the maximum number of days per month.
Since the year for the data doesn't seem to be known, the correct number of days for February cannot be calculated. You would need to add that, if the year is known.
/*REXX*/
/* TRACE ?I */
address syscall "readfile /u/inputdata Recs."
if RC <> 0
then do
say "ERROR READING FILE"
exit 16
end
ifs = "," /* Field separator for parsing input records */
ofs = "," /* field separator for writing output records */
/* Initialize arrays to aggregate temperature data by month */
MaxTemp. = 0
MinTemp. = 99999
AvgTemp. = 0
/* Initialize array of number of days per month */
/* We do not know the year, so we cannot calculate whether February has 28 or 29 days */
DaysPerMonth.1 = 31
DaysPerMonth.2 = 28 /* Need to be adjusted for leap years */
DaysPerMonth.3 = 31
DaysPerMonth.4 = 30
DaysPerMonth.5 = 31
DaysPerMonth.6 = 30
DaysPerMonth.7 = 31
DaysPerMonth.8 = 31
DaysPerMonth.9 = 30
DaysPerMonth.10 = 31
DaysPerMonth.11 = 30
DaysPerMonth.12 = 31
/* Split (parse) each input record and fill the DayTemp array with daily temperatures by month */
do ii = 2 to Recs.0
parse var Recs.ii DayNum (ifs) DayTemp.1 (ifs) DayTemp.2 (ifs) DayTemp.3 (ifs) DayTemp.4 ,
(ifs) DayTemp.5 (ifs) DayTemp.6 (ifs) DayTemp.7 (ifs) DayTemp.8 ,
(ifs) DayTemp.9 (ifs) DayTemp.10 (ifs) DayTemp.11 (ifs) DayTemp.12 .
/* For each month, adjust min and max values, and sum up for building average later on */
do jj = 1 to 12
/* Don't process values for day numbers greater that number of days in month */
if ( ii - 1 ) <= DaysPerMonth.jj
then do
if MaxTemp.jj < DayTemp.jj
then MaxTemp.jj = DayTemp.jj
if MinTemp.jj > DayTemp.jj
then MinTemp.jj = DayTemp.jj
AvgTemp.jj = AvgTemp.jj + DayTemp.jj
end /* if ( ii - 1 ) ... */
end /* do jj = 1 to 12 */
end /* do ii = 1 to 12 */
Heading = "User,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
Maxima = "Max"
Minima = "Min"
Means = "Mean"
/* Build the min, max and average records by appending value by value */
do ii = 1 to 12
Maxima = Maxima || ofs || format( MaxTemp.ii, 2, 1 )
Minima = Minima || ofs || format( MinTemp.ii, 2, 1 )
Means = Means || ofs || format( ( AvgTemp.ii / DaysPerMonth.ii ), 2, 1 )
end
/* Write heading, min, max, and average records */
say Heading
say Maxima
say Minima
say Means
Tip: Don't use single letter variable names, since you cannot search, or search-and-replace such names. I always use double letter variable names for loop variables, or temporary variables, such as ii, jj, kk, etc. These (most probably) never appear in the code in any other context, so searching for, and replacing can be easily done.

Difference between two date time stamp in Intersystems Cache

I would like to find out the number of hours and minutes between two date time stamp.
if for example
sDateTime = 2016-01-01 01:00
eDateTime = 2016-01-03 02:30
I would like it to output it as 49:30 (49hours and 30minutes)
I am unable to figure a method to work this out.
what I have so far:
Set oMNOF=##class(MNOF.MNOF).%OpenId(Id)
Set zstartDt=oMNOF.sDateTime
Set startDt=$PIECE(zstartDt,",",1)
Set startTime=$PIECE(zstartDt,",",2)
Set zendDt=oMNOF.eDateTime
Set endDt=$PIECE(zendDt,",",1)
Set endTime=$PIECE(zendDt,",",2)
set dateDiff=((endDt - startDt)) //2 days
set timeDiff=(endTime - startTime) //outputs 5400 seconds
set d = (dateDiff * 24 * 60 * 60)
set h = ((timeDiff - d) / 60)
set m = timeDiff - (d) - (h * 60)
Thank you for the help.
Another option:
USER>set mm=$system.SQL.DATEDIFF("mi","2016-01-02 01:00","2016-01-03 02:30")
USER>write "hours=", mm \ 60
hours=25
USER>write "minutes=", mm # 60
minutes=30
Hi thanks to all for the help.
I managed to come up with the below, appreciate if someone can improve on this.
<script language="cache" method="MGetData" arguments="pStartDt:%String,pEndDt:%String,pTimeField:%String" returntype="%Library.String">
set val1="00"
//HOUR: check if length equals 1
if $LENGTH($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600))=1{
//add leading zero
set val1 ="0"_$SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)
}
else{
//get without leading zero
set val1 = $SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)
}
//MINUTES: check if length equals 1
if $LENGTH($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/60) - ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)*60))=1{
//add leading zero
set val2 ="0"_($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/60) - ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)*60))
}
else{
//get without leading zero
set val2 = ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/60) - ($SYSTEM.SQL.FLOOR($system.SQL.DATEDIFF("ss",pStartDt,pEndDt)/3600)*60))
}
//insert result data into the time field
Write "document.getElementById('"_pTimeField_"').value='"_val1_":"_val2_"';"
//Write "alert('"_val1_"^"_val2_"');"
QUIT 1

Matlab Code for weekdays and weekends [duplicate]

This question already has an answer here:
Weekend extraction in Matlab
(1 answer)
Closed 6 years ago.
I were able to successfully made a schedule in which the output is 1 if time is between 7 AM-5PM and otherwise 0, time is based on my computer. However the day Monday-Sunday is based on my computer as well.. I cant find the solution to put an output 1 on Monday-Saturday and output 0 on Sunday. The code I have is below
function y = IsBetween5AMand7PM
coder.extrinsic('clock');
time = zeros(1,6);
time = clock;
current = 3600*time(4) + 60*time(5) + time(6); %seconds passed from the beginning of day until now
morning = 3600*7; %seconds passed from the beginning of day until 7AM
evening = 3600*17; %seconds passed from the beginning of day until 5PM
y = current > morning && current < evening;
end
Now the time here is correct already what I need is for the day (Monday-Sunday) to have my needed output. Also this matlab code is inside a matlab function on Simulink block.
If you use weekday like this, you can generate a 0/1 value as you specified for today's date:
if (weekday(now) > 1)
day_of_week_flag = 1;
else
day_of_week_flag = 0;
or if you like, this one-liner does the same thing, but may not be as easy to read if you're not familiar with the syntax:
day_of_week_flag = ( weekday(now) > 1);
You can also use date-strings like this to convert other dates:
day_of_week_flag = ( weekday('01-Mar-2016') > 1 )
Finally, if you have a numeric array of date/time values, like [2016 3 3 12 0 0], you first need to convert to a serial date using datenum, then use weekday:
time = clock;
day_of_week_flag = ( weekday(datenum(time)) > 1);
An alternate way to check without using weekday is the following:
time = clock;
day_of_week = datestr(time, 8);
if (day_of_week == 'Sun')
day_of_week_flag = 0;
else
day_of_week_flag = 1;

Converting Epoch to Date in Matlab

I have an array of Epoch milliseconds (array of numbers) in Matlab. I would like to convert these into UTC date-time format, such as DD-MM-YYYY HH:MM.
Is there a pre-defined Matlab way to do this or will I have to write my own function?
Suppose, you start with a vector time_unix, then:
>> time_unix = 1339116554872; % example time
>> time_reference = datenum('1970', 'yyyy');
>> time_matlab = time_reference + time_unix / 8.64e7;
>> time_matlab_string = datestr(time_matlab, 'yyyymmdd HH:MM:SS.FFF')
time_matlab_string =
20120608 00:49:14.872
Notes:
1) See the definition of matlab's time.
2) 8.64e7 is number of milliseconds in a day.
3) Matlab does not apply any time-zone shifts, so the result is the same UTC time.
4) Example for backward transformation:
>> matlab_time = now;
>> unix_time = round(8.64e7 * (matlab_time - datenum('1970', 'yyyy')))
unix_time =
1339118367664
To summarize, here are two functions:
function tm = unix2matlab(tu)
tm = datenum('1970', 'yyyy') + tu / 864e5;
end
function tu = matlab2unix(tm)
tu = round(864e5 * (tm - datenum('1970', 'yyyy')));
end
The matlab time here is numeric. You can always convert it to string using datestr()
Update for nanoseconds
time_unix_nanos = 1339116554872666666;
millis = round(time_unix_nanos / 1e6);
nanos = time_unix_nanos - 1e6 * millis;
time_matlab = unix2matlab(millis);
s = [datestr(time_matlab, 'yyyymmdd HH:MM:SS.FFF'), num2str(nanos)];
s =
20120608 00:49:14.872666666
I tried the above code, but the results were wrong. I realised the main error is related to the awkward definition of the Unix time (epoch time). Unix time (epoch time) is defined as the number of seconds after 1-1-1970, 00h:00, not the number of **milli**seconds (http://en.wikipedia.org/wiki/Unix_time). With this definition, the Unix time should therefore be divided by 8.64e5 instead of 8.64e7.
In addition, datenum('1970', 'yyyy') does not seem to result in the desired reference time of 1-1-1970, 00h:00.
Here's my improved code:
tMatlab = datenum (1970,1,1,0,0) + tUnix / 86400;
Serg's answer is what I normally use, when I'm working in MATLAB. Today I found myself wanting to do the conversion to date in MATLAB as the title says - without the datestring conversion  specified in the question body - and output the date number from the shell.
Here is what I settled on for the rounded date number:
TODAY_MATLAB="$[719529 + $[`date +%s` / 24/60/60]]"
This is really just the bash equivalent of what you would expect: 719529 is the datenum of the epoch (1970-01-01 or datenum(1970,1,1) in MATLAB). I'm also fumbling through ksh lately and it seems this can be done there with:
TODAY_EPOCH=`date +%s`
TODAY_MATLAB=`expr $TODAY_EPOCH / 24 / 60 / 60 + 719529`
As a side exercise, I added the decimal portion back onto the date in bash - I didn't bother in ksh, but it's only arithmetic and goes similarly:
N_DIGITS=7
FORMAT=$(printf "%%d.%%0%dd" $N_DIGITS)
NOW_EP_SEC=`date +%s`
SEC_PER_DAY=$(( 24*60*60 ))
NOW_EP_DAY=$(( $NOW_EP /$SEC_PER_DAY ))
SEC_TODAY=$(( $NOW_EP_SEC - $NOW_EP_DAY*$SEC_PER_DAY ))
TODAY_MATLAB="$(( NOW_EP_DAY+719529 ))"
FRACTION_MATLAB="$( printf '%07d' $(( ($SEC_TODAY*10**$N_DIGITS)/SEC_PER_DAY )) )"
MATLAB_DATENUM=$( printf $FORMAT $TODAY_MATLAB $FRACTION_MATLAB )
echo $MATLAB_DATENUM