for my project, I need to calculate TOW (Time of week) in Simulink. I know this can be achieved through conversion of UTC time to GPS time.
I have written a simple m-file in Matlab which does the action for me in Matlab as follow:
date_gps_int = 10000*y + 100*m + d
date_gps_str = int2str(date_gps_int)
date_gps_str_to_serial = datenum(date_gps_str,'yyyymmdd')
date_str_format = datestr(date_gps_str_to_serial,'dd-mmmm-yyyy')
Num_Days = daysact('06-jan-1980',date_str_format)
Num_Weeks = Num_Days/7
TOW = Num_Weeks - 1024
My first intention was to use this as a function in simulink. But apparently because of 'datenum' and 'datestr' it is not possible, since simulink does not handle strings.
Now I am wondering if anyone can help me with this issue. Is there any way to calculate TOW from the UTC date in Matlab without using those predefined functions?
I also tried to write an algorithm for calculating number of days since '6 January 1980' and then calculating number of weeks by dividing that by 7. But since I am not very familiar with leap year calculation and I don't really know the formula for these kinds of calculations, my result differs from real TOW.
I would appreciate if anybody can help me on this.
There are three formats handled by Matlab for time: formatted date strings - what datestr outputs -, serial date - scalar double, what datenum outputs - and date vectors (see datevec). Conversion functions work with these three, and the most convenient way to convert individual variables (year, month, etc) to a date is to build a date vector [yyyy mm dd HH MM SS].
date_gps_str_to_serial = datenum([y m d 0 0 0]); % midnight on day y-m-d
date_Jan_6_1980 = datenum([1980 01 06 0 0 0]); % midnight on Jan 6th, 1980
Num_Days = date_gps_str_to_serial - date_Jan_6_1980;
Now, beware of leap seconds...
GPS time is computed form the time elapsed since Jan 6th 1980. Take the number of seconds elapsed since that day, as measured by the satellites' atomic clocks, divide by (24*3600) to get a number of days, the remainder is the time of the day (in seconds since midnight).
But, once in a while, the International Earth Rotation and Reference Systems Service will decide that a day will last one second longer to accommodate for the slowing of Earth rotation. It may happen twice a year, on June 30th or December 31st. The calculation of GPS time is wrong, because it does not take into account that some days last 86401 seconds (so dividing by 24*3600 does not work) and will advance by 1 second with respect to UTC each time this happens. There has been 18 such days since Jan 6th 1980, so one should subtract 18 seconds from GPS time to find UTC time. The next time a leap second may be added is June 2019.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am trying to create a season variable from a date variable so if the date is 09/09/2010 then the season would be "Fall".
Can anyone help?
Thanks
Assuming this is based on the month/day calculation. It depends on the exact logic, but something like this would work.
Use MONTH() to calculate the month of the year and then use that to assign the season. If you need to account for specific days, ie Winter is Dec 22 to Mar 22 then you can also use the DAY() function to get the day of the month.
data want;
set sashelp.stocks (where = stocks='IBM');
length Season $10.;
if month(date) in (3, 4, 5) then season = 'Spring';
else if month(date) in (6, 7, 8) then season = 'Fall';
else if ....;
else if ....;
else season = 'CHECK ME';
run;
Almost all SAS installations ship with the SASHELP library so you should be able to run this automatically.
You probably want to create a custom format based on a table of season start dates downloaded from the interwebs.
Or you could use a web api such as https://www.timeanddate.com/services/api/holiday-api.html
Or if you are a computational masochist, deal with the computed equinox based on lat and long.
From "https://aa.usno.navy.mil/faq/docs/GAST.php" (the page has a security certificate error)
Sidereal time is a system of timekeeping based on the rotation of
the Earth with respect to the fixed stars in the sky. More
specifically, it is the measure of the hour angle of the vernal
equinox. If the hour angle is measured with respect to the true
equinox, apparent sidereal time is being
measured. If the hour angle is measured with respect to the mean
equinox, mean sidereal time is being
measured. When the measurements are made with respect to the meridian
at Greenwich, the times are referred to as Greenwich mean sidereal
time (GMST) and Greenwich apparent sidereal time (GAST).
Given below is a simple algorithm for computing apparent sidereal
time to an accuracy of about 0.1 second, equivalent to about
1.5 arcseconds on the sky. The input time required by the algorithm is represented as a Julian date (
Julian dates can be used to determine
Universal Time.)
Let JD be the Julian date of the time of interest. Let
JD0 be the Julian date of the previous
midnight (0h) UT (the value of
JD0 will end in .5 exactly), and let H
be the hours of UT elapsed since that time. Thus we have
JD = JD0 + H/24.
For both of these Julian dates, compute the number of days and
fraction (+ or -) from 2000 January 1, 12h UT, Julian date 2451545.0:
D = JD - 2451545.0
D0 = JD0 - 2451545.0
Then the Greenwich mean sidereal time in hours is
GMST = 6.697374558 + 0.06570982441908 D0 + 1.00273790935 H + 0.000026 T2
where T = D/36525 is the number of centuries since the year 2000;
thus the last term can be omitted in most applications. It will be
necessary to reduce GMST to the range 0h to 24h.
Setting H = 0 in the above formula yields the Greenwich mean sidereal
time at 0h UT, which is tabulated in
The Astronomical Almanac.
The following alternative formula can be used with a loss of
precision of 0.1 second per century:
GMST = 18.697374558 + 24.06570982441908 D
where,
as above, GMST must be reduced to the range 0h to 24h.
The equations for GMST given above are adapted from those given in
Appendix A of USNO
Circular No. 163 (1981).
The Greenwich apparent sidereal time is obtained by adding a
correction to the Greenwich mean sidereal time computed above. The
correction term is called the nutation in right ascension or
the equation of the equinoxes. Thus,
GAST = GMST + eqeq.
The equation of the equinoxes
is given as eqeq = Δψ cos ε where Δψ, the nutation in longitude, is given
in hours approximately by
Δψ ≈ -0.000319 sin Ω - 0.000024 sin 2L
with Ω, the Longitude of the ascending node of the Moon, given as
Ω = 125.04 - 0.052954 D,
and L,
the Mean Longitude of the Sun, given as
L = 280.47 + 0.98565 D.
ε is the obliquity and is given as
ε = 23.4393 - 0.0000004 D.
The above expressions for Ω, L, and ε are all expressed
in degrees.
The mean or apparent sidereal time locally is found by
obtaining the local longitude in degrees, converting it to hours by
dividing by 15, and then adding it to or subtracting it from the
Greenwich time depending on whether the local position is east (add)
or west (subtract) of Greenwich.
If you need apparent sidereal time to better than 0.1 second
accuracy on a regular basis, consider using the Multiyear Interactive
Computer Almanac,
MICA.
MICA
provides very accurate almanac data in tabular form for a range of
years.
NOTES ON ACCURACY
The maximum error resulting from the use of the above formulas for
sidereal time over the period 2000-2100 is 0.432 seconds; the RMS
error is 0.01512 seconds. To obtain sub-second accuracy in
sidereal time, it is important to use the form of Universal Time
called UT1 as the basis for the input
Julian date.
The maximum value of the equation of the equinoxes is about 1.1
seconds, so if an error of ~1 second is unimportant, the last
series of formulas can be skipped entirely. In this case set
eqeq = 0 and GAST = GMST, and use either UT1 or UTC as the Universal Time basis for the
input Julian date.
I'm attempting to extract years from the timestamp, as indicated below:
const int timestamp = 1499477613;
int hours = timestamp/3600;
int days = hours/24;
int years = days/356;
printf("years=%i\n", years);
However after executing the program, I get an output saying:
years=48
Which is different from the expected value 2017.
What's wrong with the code?
https://en.wikipedia.org/wiki/Unix_time
Unix time (also known as POSIX time or epoch time) is a system for
describing instants in time, defined as the number of seconds that
have elapsed since 00:00:00 Coordinated Universal Time (UTC),
Thursday, 1 January 1970.
That result tells you that (approximately) 48 years has passed since that time. 1970 + 48 = 2018.
The reason you don't get an accurate value is precision you lose in each calculation. You're using ints to encode something that may return a floating point. (And what I assume to be a typo: days/356 should be days/365)
It's commonplace even outside of software to communicate time or date intervals in a truncated manner. For example: 1h10m translates to "One hour and ten minutes."
This could be abstracted to a set of rules. For instance: A date interval is represented as a combination of _h, _m, (and so on), where _ characters represent non-negative integers or floats, which are summed into one date interval object.
Mixing days, hours, minutes are allowed. For example, 0.5d1h60m would be a synonym for 14h.
Is there a standard defined out there anywhere that resembles this?
The standard for this is a Duration, defined by ISO 8601.
Note that an Interval is a different concept (also defined by the same ISO), although both are closely related:
A Duration defines an amount of time (like "1 hour and 10 minutes" or "2 years, 3 months and 4 days"). But it doesn't tell you when it starts or ends ("1 hours and 10 minutes" relative to what?). It's just the amount of time, by itself.
An Interval (quoting wikipedia) is "the intervening time between two time points". It has a defined start and end dates, but you can use a Duration to define it, as it can have 4 different formats:
Start and end, such as 2007-03-01T13:00:00Z/2008-05-11T15:30:00Z
Start and duration, such as 2007-03-01T13:00:00Z/P1Y2M10DT2H30M
Duration and end, such as P1Y2M10DT2H30M/2008-05-11T15:30:00Z
Duration only, such as P1Y2M10DT2H30M, with additional context information
Cases 1, 2 and 3 are equivalent (all have the same start and end dates). The only difference is that in cases 2 and 3, the duration P1Y2M10DT2H30M is used to calculate the other date (in case 2, you add it to the start date, and in case 3 you subtract it from the end date).
As you can notice above, the standard format for a Duration is P[n]Y[n]M[n]DT[n]H[n]M[n]S, where:
P is the duration designator (for period) placed at the start of the duration representation.
Y is the year designator that follows the value for the number of years.
M is the month designator that follows the value for the number of months.
W is the week designator that follows the value for the number of weeks.
D is the day designator that follows the value for the number of days.
T is the time designator that precedes the time components of the representation.
H is the hour designator that follows the value for the number of hours.
M is the minute designator that follows the value for the number of minutes.
S is the second designator that follows the value for the number of seconds.
So, "1 year and 10 months" is represented as P1Y10M and "1 hour and 10 minutes" is PT1H10M (note that the T is required to resolve the potencial ambiguity between 1 month (P1M) and 1 minute (PT1M), as they use the same letter M as designator).
As #MattJohnson commented, the math with dates it's not always obvious, so the equivalence between different durations can't be what we normally expect.
For the examples below, I'm using Java 8 (just to show how durations can be tricky). Note that the java.time API uses 2 different classes (Period and Duration), but the idea for both is the same (they're both amounts of time).
A duration of 1 month is equivalent to how many days? It depends:
// one month period
Period oneMonth = Period.parse("P1M");
// January 1st
LocalDate jan = LocalDate.of(2016, 1, 1);
System.out.println(jan); // 2016-01-01
// January 1st plus 1 month period = February 1st
LocalDate feb = jan.plus(oneMonth);
System.out.println(feb); // 2016-02-01
// February 1st plus 1 month period = March 1st
LocalDate mar = feb.plus(oneMonth);
System.out.println(mar); // 2016-03-01
// difference between Jan 1st and Feb 1st = 31 days
System.out.println(ChronoUnit.DAYS.between(jan, feb)); // 31
// difference between Feb 1st and Mar 1st = 29 days (2016 is leap year)
System.out.println(ChronoUnit.DAYS.between(feb, mar)); // 29
So, adding 1 month to January 1st results in February 1st - in this case, 1 month is equivalent 31 days (A.K.A. adding a 1 month duration (P1M) is equivalent to adding a 31 days duration (P31D)), and adding 1 month to February 1st results in March 1st (in this case, 1 month = 29 days, because 2016 is a leap year).
1 day = 24 hours? Not always. If there's a Daylight Saving Time shift involved, you can get strange results:
// 1 day period
Period oneDay = Period.parse("P1D");
// 24 hours period
Duration twentyFourHours = Duration.parse("PT24H");
// in Sao Paulo, summer time starts at Oct 15, at midnight
// getting a date one day before DST change, at 10:00 AM
ZonedDateTime z = ZonedDateTime.of(2017, 10, 14, 10, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2017-10-14T10:00-03:00[America/Sao_Paulo]
// add 1 day - gets the same hour (10:00 AM)
System.out.println(z.plus(oneDay)); // 2017-10-15T10:00-02:00[America/Sao_Paulo]
// add 24 hours - gets 11:00 AM because of DST shift (at midnight, clocks moved forward 1 hour)
System.out.println(z.plus(twentyFourHours)); // 2017-10-15T11:00-02:00[America/Sao_Paulo]
In São Paulo, at October 15th, 2017, DST starts (clocks are moved forward by 1 hour), so:
If you add 24 hours to October 14th at 10 AM, you'll get October 15th at 11 AM
But if you add 1 day, you'll get October 15th at 10 AM
So, in this case, 1 day = 23 hours - it means that adding a 1 day duration (P1D) is equivalent to adding a 23 hours duration (PT23H)
When DST ends, is the opposite: clocks move back 1 hour, and 1 day will be equivalent to 25 hours.
So, the standard defines the format and meaning of the amounts of time concepts, but the equivalence between different durations will depend on the context (although it might sound non-intuitive that 1 day is not always 24 hours, but date/time math is not as obvious as we'd like).
You can use moment: http://momentjs.com/docs/#/durations/
moment.duration(100); // 100 milliseconds
moment.duration(60000).humanize(); // a minute
Read more in the above linked docs. And to get all unit values you may want to use the ISO8601 Format:
moment.duration(1, 'd').toISOString() // "P1D"
For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".
Read more directly under http://momentjs.com/docs/#/durations/as-iso-string/
This question already has answers here:
Counting values by day/hour with timeseries in MATLAB
(3 answers)
Closed 6 years ago.
I have a year's worth of data, the data is recorded one minute intervals each day of the year.
The date and time was imported from excel (in form 243.981944, then by adding 42004 (so will be for 2015) and formatting to date it becomes 31.8.15 23:34:00).
Importing to MATLAB it becomes
'31/08/2015 23:34:00'
I require the data for each day of the year to be at hourly intervals, so I need to sum the data recorded in each hour and divide that by the number of data recorded for that hour, giving me the hourly average.
For some reason the data in August actually increments in 2 minute intervals, data for every other month increments in one minute intervals.
ie
...
31/07/2015 23:57:00
31/07/2015 23:58:00
31/07/2015 23:59:00
31/08/2015 00:00:00
31/08/2015 00:02:00
31/08/2015 00:04:00
...
I'm not sure how I can find all the values for a specific date and hour in order to work out the averages. I was thinking of using a for loop to find the values on each day, but when I got down to writing code realised this wouldn't work the way I was thinking.
I presume there must be some kind of functions available that would allow for data to be filtered by the date and time?
edit:
So I tried the following but I get these errors.
dates is a 520000x1 cell array containing the dates form = formatIn.
formatIn = 'DD/MM/YYYY HH:MM:SS';
[~,M,D,H] = datevec(dates, formatIn);
Error using cnv2icudf (line 131) Unrecognized minute format.
Format string: DD/MM/YYYY HH:MM:SS.
Error in datevec (line 112) icu_dtformat = cnv2icudf(varargin{isdateformat});`
Assuming your data is in a matrix or cell-array of strings called A, and your other data is in a vector X. Let's say all the data is in the same year (so we can ignore years)
[~,M,D,H] = datevec(A, 'dd/mm/yyyy HH:MM:SS');
mean_A = accumarray([M, D, H+1], X, [], #mean);
Then data from February will be in
mean_A(2,:,:)
To look at the data, you may find the squeeze() function useful, e.g.
squeeze(mean_A(2,1:10,13:24))
shows the average for the hours after midday (by column) for the first ten days (by row) of February.
See also:
Counting values by day/hour with timeseries in MATLAB
Assume the following timeseries (ts) with assigned values:
time val
15:00 4
15:45 7
17:12 2.3
17:50 2.9
Every value from a timestamp is valid until the next appears. Thus, from 15:00 to 15:45 the value is 4 or from 15:45 to 17:12 it is 2.3. Every new data point between these timestamps should have the same value. What i want is a new ts, with a constant time-interval and a pre-defined start point. Let's say the starting point is 15:00 and the interval should be 30 min. Normally, I could use the synchronize function - however, the function uses the interpolation method and this is not what i need here, since the values between the data points should not be interpolated, but be averaged if timestamps are overlapping.
The new ts should be like:
time val
15:00 4
15:30 5.5
16:00 7
16:30 7
17:00 4.18
The value for timestamp 15:30 is computed as = (4*15+7*15)/30, and so on. I have implemented a code, that is capable of fixing this by applying the trapz function with a lot of if statements. However, I was wondering if there are better/simpler solutions around, as a modified synchronize function, since I have more than 500.000 data points.
Thanks in advance
I managed to fix my problem by dividing all time steps into minute-values and afterwards applying the trapezoidal rule to get the sum of the area under the curve (AUC) and then the average by dividing with the applied minute interval.
AllValues = interp1(Time,Data,NewTime,'previous')';
[Xdata,Ydata] = stairs(NewTime,AllValues);
NewTS = timeseries(Xdata,Ydata);
TrapzSum = cumtrapz(NewTS.time,NewTS.data);
TrapzSum = TrapzSum(1:2:end);
NewResults = diff(TrapzSum(IndicesOfNewInterval))/MinInt;