Main Content

Add Event Table from External Data to Timetable

To find and label events in a timetable, attach an eventtable to it. An event table is a timetable of events. An event consists of an event time (when something happened), often an event length or event end time (how long it happened), often an event label (what happened), and sometimes additional information about the event. When you attach an event table to a timetable, it enables you to find and label rows in the timetable that occur during events. By associating timetable rows with events, you can more easily analyze and plot the data that they contain.

This example shows how you can add events to your timetable using data that comes from an external data source. In the example, import a timetable of measurements of the Earth's rotation rate from 1962 to the present. The rotation rate varies as a function of time, causing changes in the excess length-of-day to accumulate. Whenever the cumulative excess becomes too large, a leap second is inserted. This example analyzes the excess length-of-day over time and treats leap seconds added since 1972 as a set of external events. To analyze these data with event tables, use the eventtable, eventfilter, and syncevents functions. (A related workflow is to find and label events within your timetable. For more information about that workflow, see Find Events in Timetable Using Event Table.)

Import Timetable with Length-of-Day Measurements

By definition, a day is 86,400 seconds long, where the second has a precise definition in the International System of Units (SI). However, the length of a day actually varies due to several physical causes. It varies with the seasons by as much as 30 seconds over and 21 seconds under the SI definition because of the eccentricity of Earth's orbit and the tilt of its axis. Averaging these seasonal effects enables the definition of the mean solar day, which does not vary in length over a year.

Also, there is a very long-term slowing in the rotational speed of the Earth due to tidal interaction with the moon; a smaller, opposite, shorter-term component believed to be due to melting of continental ice sheets; very short-term cycles on the order of decades; and unpredictable fluctuations due to geological events and other causes. Because of those effects, the length of a mean solar day might increase or decrease. In recent decades, it has fluctuated up and down, but has mostly been 1–3 milliseconds longer than 86,400 seconds. That difference is known as the excess Length of Day, or excess LOD.

For this example, create a timetable that contains the excess LOD for every day from January 1, 1962, to the present. The International Earth Rotation and Reference Systems Service (IERS) collects and publishes this data. However, this data needs preprocessing before storing in a MATLAB timetable because the dates are modified Julian dates. To read the IERS data into a table, use the readtable function. Rename the two variables of interest to MJD and ExcessLOD.

file = "https://datacenter.iers.org/data/latestVersion/223_EOP_C04_14.62-NOW.IAU1980223.txt";
IERSdata = readtable(file,NumHeaderLines=14);
IERSdata.Properties.VariableNames([4 8]) = ["MJD","ExcessLOD"];

To store the excess LOD values in a timetable, convert the modified Julian dates to datetime values. Use the datetime function with the ConvertFrom="mjd" name-value argument. Convert the excess LOD values to duration values by using the seconds function. Then convert IERSdata from a table to a timetable using the table2timetable function.

IERSdata.Date = datetime(IERSdata.MJD,ConvertFrom="mjd");
IERSdata.ExcessLOD = seconds(IERSdata.ExcessLOD);
IERSdata = table2timetable(IERSdata(:,["Date","ExcessLOD"]))
IERSdata=22458×1 timetable
       Date         ExcessLOD  
    ___________    ____________
    01-Jan-1962    0.001723 sec
    02-Jan-1962    0.001669 sec
    03-Jan-1962    0.001582 sec
    04-Jan-1962    0.001496 sec
    05-Jan-1962    0.001416 sec
    06-Jan-1962    0.001382 sec
    07-Jan-1962    0.001413 sec
    08-Jan-1962    0.001505 sec
    09-Jan-1962    0.001628 sec
    10-Jan-1962    0.001738 sec
    11-Jan-1962    0.001794 sec
    12-Jan-1962    0.001774 sec
    13-Jan-1962    0.001667 sec
    14-Jan-1962     0.00151 sec
    15-Jan-1962    0.001312 sec
    16-Jan-1962    0.001112 sec
      ⋮

Plot the excess LOD as a function of time. The excess LOD is currently decreasing on average but has remained positive except during very brief periods.

plot(IERSdata.Date,IERSdata.ExcessLOD,"b-");
xlabel("Date");
ylabel("Excess LOD");

Figure contains an axes object. The axes object with xlabel Date, ylabel Excess LOD contains an object of type line.

Calculate Cumulative Excess Length of Day

A clock that defines a day as 86,400 SI seconds is effectively running fast with respect to the Earth's rotation, gaining time with respect to the sun each day. A few extra milliseconds per day might seem unimportant, but the excess LOD since 1962 accumulates.

Add the cumulative excess LOD to IERSdata as another table variable. To calculate the cumulative sum of the excess LOD, use the cumsum function. Then use the stackedplot function to plot excess LOD and cumulative excess LOD together. This plot shows that the shift due to the accumulated excess LOD since the 1960s has been less than one minute.

IERSdata.CumulativeELOD = [0; cumsum(IERSdata.ExcessLOD(1:end-1))];
stackedplot(IERSdata,["ExcessLOD","CumulativeELOD"])

Figure contains an object of type stackedplot.

Store Leap Seconds in Event Table

At midnight on January 1, 1972, the current version of the system of time known as Coordinated Universal Time (UTC) was enacted, which uses 86,400 SI seconds per day. On that date, UTC was defined to be roughly in sync with solar time at the Greenwich Meridian, or more precisely, with the time known as UT1. However, timekeeping based on exactly 86,400 SI seconds per day would drift away from our physical experience of solar time because of accumulated excess LOD. So, when needed, an extra leap second adjustment is inserted to keep UTC approximately in sync with solar time. Without these leap second adjustments after 1972, accumulated excess LOD would have caused UTC to drift away from UT1 over the years. Within decades, the difference would have grown to tens of seconds.

Show the difference since 1972. First, select the post-1971 excess LOD data by subscripting into IERSdata with a time range starting on January 1, 1972. To create that time range, use the timerange function.

IERSdata1972 = IERSdata(timerange("1972-01-01",Inf),"ExcessLOD")
IERSdata1972=18806×1 timetable
       Date         ExcessLOD  
    ___________    ____________
    01-Jan-1972    0.002539 sec
    02-Jan-1972    0.002708 sec
    03-Jan-1972    0.002897 sec
    04-Jan-1972    0.003065 sec
    05-Jan-1972    0.003177 sec
    06-Jan-1972     0.00322 sec
    07-Jan-1972    0.003201 sec
    08-Jan-1972    0.003137 sec
    09-Jan-1972    0.003033 sec
    10-Jan-1972    0.002898 sec
    11-Jan-1972    0.002772 sec
    12-Jan-1972    0.002672 sec
    13-Jan-1972    0.002621 sec
    14-Jan-1972    0.002642 sec
    15-Jan-1972     0.00274 sec
    16-Jan-1972    0.002937 sec
      ⋮

Add another variable with the unadjusted difference since 1972. Start with the cumulative excess LOD on January 1, 1972, which was 0.0454859 second. For every date that follows, calculate the unadjusted difference. By the beginning of 2017, the unadjusted difference would have grown to about 26 seconds. Display IERSdata1972 using a time range that includes the start of 2017.

DiffUT1_1972 = seconds(0.0454859);
IERSdata1972.UnadjustedDiff = DiffUT1_1972 + [0; cumsum(IERSdata1972.ExcessLOD(1:end-1))];
IERSdata1972(timerange("2016-12-29","2017-01-04"),:)
ans=6×2 timetable
       Date          ExcessLOD      UnadjustedDiff
    ___________    _____________    ______________
    29-Dec-2016    0.0008055 sec      26.402 sec  
    30-Dec-2016    0.0008525 sec      26.402 sec  
    31-Dec-2016    0.0009173 sec      26.403 sec  
    01-Jan-2017     0.001016 sec      26.404 sec  
    02-Jan-2017    0.0011845 sec      26.405 sec  
    03-Jan-2017    0.0013554 sec      26.406 sec  

This drift is what leap seconds are designed to mitigate. You can think of each leap second that is inserted into the UTC timeline as an event. These events are not part of the LOD data. However, in MATLAB the leapseconds function lists each leap second that has occurred since 1972. (The leap seconds listed by leapseconds come from another data set provided by the IERS.) The timetable returned by leapseconds contains a timestamp, a description of each event (+ for leap second insertions, - for removals), and the cumulative number of leap seconds up to and including the event. To date, there have been 27 leap second events, and they have all been insertions.

lsEvents = leapseconds()
lsEvents=27×2 timetable
       Date        Type    CumulativeAdjustment
    ___________    ____    ____________________
    30-Jun-1972     +              1 sec       
    31-Dec-1972     +              2 sec       
    31-Dec-1973     +              3 sec       
    31-Dec-1974     +              4 sec       
    31-Dec-1975     +              5 sec       
    31-Dec-1976     +              6 sec       
    31-Dec-1977     +              7 sec       
    31-Dec-1978     +              8 sec       
    31-Dec-1979     +              9 sec       
    30-Jun-1981     +             10 sec       
    30-Jun-1982     +             11 sec       
    30-Jun-1983     +             12 sec       
    30-Jun-1985     +             13 sec       
    31-Dec-1987     +             14 sec       
    31-Dec-1989     +             15 sec       
    31-Dec-1990     +             16 sec       
      ⋮

To treat the leap seconds as events, convert lsEvents to an event table by using the eventtable function.

lsEvents = eventtable(lsEvents)
lsEvents = 27×2 eventtable
  Event Labels Variable: <unset>
  Event Lengths Variable: <instantaneous>
       Date        Type    CumulativeAdjustment
    ___________    ____    ____________________
    30-Jun-1972     +              1 sec       
    31-Dec-1972     +              2 sec       
    31-Dec-1973     +              3 sec       
    31-Dec-1974     +              4 sec       
    31-Dec-1975     +              5 sec       
    31-Dec-1976     +              6 sec       
    31-Dec-1977     +              7 sec       
    31-Dec-1978     +              8 sec       
    31-Dec-1979     +              9 sec       
    30-Jun-1981     +             10 sec       
    30-Jun-1982     +             11 sec       
    30-Jun-1983     +             12 sec       
    30-Jun-1985     +             13 sec       
    31-Dec-1987     +             14 sec       
    31-Dec-1989     +             15 sec       
    31-Dec-1990     +             16 sec       
    30-Jun-1992     +             17 sec       
    30-Jun-1993     +             18 sec       
    30-Jun-1994     +             19 sec       
    31-Dec-1995     +             20 sec       
    30-Jun-1997     +             21 sec       
    31-Dec-1998     +             22 sec       
    31-Dec-2005     +             23 sec       
    31-Dec-2008     +             24 sec       
    30-Jun-2012     +             25 sec       
    30-Jun-2015     +             26 sec       
    31-Dec-2016     +             27 sec       

At this point, the main LOD data is in the IERSdata1972 timetable. The leap second events are in the lsEvents event table. To find and label rows that occur during leap seconds in the LOD data, attach lsEvents to IERSdata1972. Assign lsEvents to its Events property.

IERSdata1972.Properties.Events = lsEvents;
IERSdata1972.Properties
ans = 
  TimetableProperties with properties:
             Description: ''
                UserData: []
          DimensionNames: {'Date'  'Variables'}
           VariableNames: {'ExcessLOD'  'UnadjustedDiff'}
    VariableDescriptions: {}
           VariableUnits: {}
      VariableContinuity: []
                RowTimes: [18806×1 datetime]
               StartTime: 01-Jan-1972
              SampleRate: NaN
                TimeStep: 1d
                  Events: [27×2 eventtable]
        CustomProperties: No custom properties are set.
      Use addprop and rmprop to modify CustomProperties.

Use Event Timestamps to Select Data

Add the unadjusted difference, or cumulative excess LOD, at each date in lsEvents. To find the unadjusted differences on these dates, index into the UnadjustedDiff variable of IERSdata1972 and select the unadjusted difference at the timestamps from lsEvents. Then append those differences to each event in lsEvents as additional information about the event.

First, create an event filter using the eventfilter function. It uses the event table attached to a timetable to create a row subscript. You can use subscript into timetables rows using matching values from the event table. Subscript into IERSdata1972 and return an array of unadjusted differences on the dates when leap seconds were added.

EF = eventfilter(IERSdata1972)
EF = 
  eventfilter with no constraints and no selected variables

    <unconstrained>

  VariableNames: Date, Type, CumulativeAdjustment

UnadjustedDiff = IERSdata1972{EF.Date,"UnadjustedDiff"}
UnadjustedDiff = 27×1 duration
   0.63494 sec
    1.1864 sec
    2.2976 sec
     3.289 sec
    4.2718 sec
    5.3334 sec
    6.3469 sec
     7.398 sec
    8.3526 sec
    9.6281 sec
    10.389 sec
    11.249 sec
    12.451 sec
    13.634 sec
    14.669 sec
    15.379 sec
    16.556 sec
    17.399 sec
    18.216 sec
    19.442 sec
    20.472 sec
    21.282 sec
    22.659 sec
    23.589 sec
    24.583 sec
    25.671 sec
    26.403 sec

Add the array as a new variable to the event table. In this way, you can add more information about events after you have attached an event table to a timetable.

IERSdata1972.Properties.Events.UnadjustedDiff = UnadjustedDiff
IERSdata1972=18806×2 timetable
           Date         ExcessLOD      UnadjustedDiff
        ___________    ____________    ______________
        01-Jan-1972    0.002539 sec     0.045486 sec 
        02-Jan-1972    0.002708 sec     0.048025 sec 
        03-Jan-1972    0.002897 sec     0.050733 sec 
        04-Jan-1972    0.003065 sec      0.05363 sec 
        05-Jan-1972    0.003177 sec     0.056695 sec 
        06-Jan-1972     0.00322 sec     0.059872 sec 
        07-Jan-1972    0.003201 sec     0.063092 sec 
        08-Jan-1972    0.003137 sec     0.066293 sec 
        09-Jan-1972    0.003033 sec      0.06943 sec 
        10-Jan-1972    0.002898 sec     0.072463 sec 
        11-Jan-1972    0.002772 sec     0.075361 sec 
        12-Jan-1972    0.002672 sec     0.078133 sec 
        13-Jan-1972    0.002621 sec     0.080805 sec 
        14-Jan-1972    0.002642 sec     0.083426 sec 
        15-Jan-1972     0.00274 sec     0.086068 sec 
        16-Jan-1972    0.002937 sec     0.088808 sec 
      ⋮

Plot Events Against Data

The event table shows that at each event, the IERS inserted a leap second whenever the excess LOD accumulated by roughly one additional second. To confirm this observation visually, plot the LOD data overlaid with the instantaneous leap second events. Use the stackedplot function. If the input is a timetable with an attached event table, then stackedplot automatically plots events from the event table on top of the data from the timetable. It plots instantaneous events as vertical lines.

stackedplot(IERSdata1972)

Figure contains an object of type stackedplot.

The stackedplot function plots all events using the same default style. To plot events using different styles, use the plot function and specify colors, markers, line styles, and so on. For example, plot the leap second events on the unadjusted differences using red crosses instead of vertical lines.

plot(IERSdata1972,"UnadjustedDiff");
hold on
plot(lsEvents.Date,IERSdata1972.UnadjustedDiff(lsEvents.Date),"r+");
hold off

Figure contains an axes object. The axes object with xlabel Date, ylabel UnadjustedDiff contains 2 objects of type line. One or more of the lines displays its values using only markers

Copy Event Data to State Variable in Timetable

The leap seconds are instantaneous events recorded in an event table. Another way to represent them is by using a state variable appended to the original LOD data. A state variable describes the "state" of the process being measured at each time point rather than tagging a specific instant. One possible state variable for this leap second data is an indicator variable that records an adjustment on each event date, with missing values on all the other dates. This approach works because all timestamps from the event table are also timestamps in IERSdata1972.

To copy the cumulative adjustments from the attached event table to the timetable, use the syncevents function. The function automatically fills the other elements of the new CumulativeAdjustment variable with missing values. Display the timetable rows around the 27th leap second.

IERSdata1972 = syncevents(IERSdata1972,EventDataVariables="CumulativeAdjustment");
IERSdata1972(timerange("2016-12-29","2017-01-04"),:)
ans=6×3 timetable
                    Date          ExcessLOD      UnadjustedDiff    CumulativeAdjustment
                 ___________    _____________    ______________    ____________________
                 29-Dec-2016    0.0008055 sec      26.402 sec            NaN sec       
                 30-Dec-2016    0.0008525 sec      26.402 sec            NaN sec       
    <1 event>    31-Dec-2016    0.0009173 sec      26.403 sec             27 sec       
                 01-Jan-2017     0.001016 sec      26.404 sec            NaN sec       
                 02-Jan-2017    0.0011845 sec      26.405 sec            NaN sec       
                 03-Jan-2017    0.0013554 sec      26.406 sec            NaN sec       

Another possibility, more useful in this example, is to add a state variable that indicates the cumulative sum of leap seconds at any given date in the LOD data. Begin by removing the CumulativeAdjustment variable from the timetable.

IERSdata1972.CumulativeAdjustment = []; % remove the previous state variable

Then assign the attached event table to local variable in the workspace.

lsEvents = IERSdata1972.Properties.Events;

The data in IERSdata1972 begin on January 1, 1972, before the first leap second was added. So, add one more event to lsEvents, to cover the time before the first leap second.

lsEvents(IERSdata1972.Date(1),:) = {"+",seconds(0),seconds(0)};
lsEvents = sortrows(lsEvents)
lsEvents = 28×3 eventtable
  Event Labels Variable: <unset>
  Event Lengths Variable: <instantaneous>
       Date        Type    CumulativeAdjustment    UnadjustedDiff
    ___________    ____    ____________________    ______________
    01-Jan-1972     +              0 sec                  0 sec  
    30-Jun-1972     +              1 sec            0.63494 sec  
    31-Dec-1972     +              2 sec             1.1864 sec  
    31-Dec-1973     +              3 sec             2.2976 sec  
    31-Dec-1974     +              4 sec              3.289 sec  
    31-Dec-1975     +              5 sec             4.2718 sec  
    31-Dec-1976     +              6 sec             5.3334 sec  
    31-Dec-1977     +              7 sec             6.3469 sec  
    31-Dec-1978     +              8 sec              7.398 sec  
    31-Dec-1979     +              9 sec             8.3526 sec  
    30-Jun-1981     +             10 sec             9.6281 sec  
    30-Jun-1982     +             11 sec             10.389 sec  
    30-Jun-1983     +             12 sec             11.249 sec  
    30-Jun-1985     +             13 sec             12.451 sec  
    31-Dec-1987     +             14 sec             13.634 sec  
    31-Dec-1989     +             15 sec             14.669 sec  
    31-Dec-1990     +             16 sec             15.379 sec  
    30-Jun-1992     +             17 sec             16.556 sec  
    30-Jun-1993     +             18 sec             17.399 sec  
    30-Jun-1994     +             19 sec             18.216 sec  
    31-Dec-1995     +             20 sec             19.442 sec  
    30-Jun-1997     +             21 sec             20.472 sec  
    31-Dec-1998     +             22 sec             21.282 sec  
    31-Dec-2005     +             23 sec             22.659 sec  
    31-Dec-2008     +             24 sec             23.589 sec  
    30-Jun-2012     +             25 sec             24.583 sec  
    30-Jun-2015     +             26 sec             25.671 sec  
    31-Dec-2016     +             27 sec             26.403 sec  

Add event end times to transform the events into interval events. The end of each interval is the day before the next leap second was added. The last event end time is the last date in IERSdata1972.

endEvents = [lsEvents.Date(2:end) - 1 ; IERSdata1972.Date(end)];

Add the event end times to lsEvents as a new variable. Then assign the new variable to the EventEndsVariable property of lsEvents. Event tables have properties that specify which of their variables contain event labels, event lengths, or event end times.

lsEvents.EventEnds = endEvents;
lsEvents.Properties.EventEndsVariable = "EventEnds"
lsEvents = 28×4 eventtable
  Event Labels Variable: <unset>
  Event Ends Variable: EventEnds
       Date        Type    CumulativeAdjustment    UnadjustedDiff     EventEnds 
    ___________    ____    ____________________    ______________    ___________
    01-Jan-1972     +              0 sec                  0 sec      29-Jun-1972
    30-Jun-1972     +              1 sec            0.63494 sec      30-Dec-1972
    31-Dec-1972     +              2 sec             1.1864 sec      30-Dec-1973
    31-Dec-1973     +              3 sec             2.2976 sec      30-Dec-1974
    31-Dec-1974     +              4 sec              3.289 sec      30-Dec-1975
    31-Dec-1975     +              5 sec             4.2718 sec      30-Dec-1976
    31-Dec-1976     +              6 sec             5.3334 sec      30-Dec-1977
    31-Dec-1977     +              7 sec             6.3469 sec      30-Dec-1978
    31-Dec-1978     +              8 sec              7.398 sec      30-Dec-1979
    31-Dec-1979     +              9 sec             8.3526 sec      29-Jun-1981
    30-Jun-1981     +             10 sec             9.6281 sec      29-Jun-1982
    30-Jun-1982     +             11 sec             10.389 sec      29-Jun-1983
    30-Jun-1983     +             12 sec             11.249 sec      29-Jun-1985
    30-Jun-1985     +             13 sec             12.451 sec      30-Dec-1987
    31-Dec-1987     +             14 sec             13.634 sec      30-Dec-1989
    31-Dec-1989     +             15 sec             14.669 sec      30-Dec-1990
    31-Dec-1990     +             16 sec             15.379 sec      29-Jun-1992
    30-Jun-1992     +             17 sec             16.556 sec      29-Jun-1993
    30-Jun-1993     +             18 sec             17.399 sec      29-Jun-1994
    30-Jun-1994     +             19 sec             18.216 sec      30-Dec-1995
    31-Dec-1995     +             20 sec             19.442 sec      29-Jun-1997
    30-Jun-1997     +             21 sec             20.472 sec      30-Dec-1998
    31-Dec-1998     +             22 sec             21.282 sec      30-Dec-2005
    31-Dec-2005     +             23 sec             22.659 sec      30-Dec-2008
    31-Dec-2008     +             24 sec             23.589 sec      29-Jun-2012
    30-Jun-2012     +             25 sec             24.583 sec      29-Jun-2015
    30-Jun-2015     +             26 sec             25.671 sec      30-Dec-2016
    31-Dec-2016     +             27 sec             26.403 sec      27-Jun-2023

Attach lsEvents to IERSdata1972.

IERSdata1972.Properties.Events = lsEvents;

Copy the cumulative adjustments by calling syncevents. The attached event table has interval events, so syncevents fills in every row of IERSdata1972 with event data that occurs during the intervals. Every row of IERSdata1972 records the cumulative adjustment that occurred up to that time.

IERSdata1972 = syncevents(IERSdata1972,EventDataVariables="CumulativeAdjustment");
IERSdata1972(timerange("2016-12-29","2017-01-04"),:)
ans=6×3 timetable
                    Date          ExcessLOD      UnadjustedDiff    CumulativeAdjustment
                 ___________    _____________    ______________    ____________________
    <1 event>    29-Dec-2016    0.0008055 sec      26.402 sec             26 sec       
                 30-Dec-2016    0.0008525 sec      26.402 sec            NaN sec       
    <1 event>    31-Dec-2016    0.0009173 sec      26.403 sec             27 sec       
    <1 event>    01-Jan-2017     0.001016 sec      26.404 sec             27 sec       
    <1 event>    02-Jan-2017    0.0011845 sec      26.405 sec             27 sec       
    <1 event>    03-Jan-2017    0.0013554 sec      26.406 sec             27 sec       

The new state variable is just like all the other variables in IERSdata1972, with a value that is defined at each time. You can use it to compute the actual differences between UTC and UT1, given all the leap second adjustments, by subtracting it from the unadjusted difference. The convention is to compute the actual difference with the opposite sign as UT1 – UTC and denote it as DUT1.

IERSdata1972.DUT1 = IERSdata1972.UnadjustedDiff - IERSdata1972.CumulativeAdjustment;
IERSdata1972(timerange("2016-12-29","2017-01-04"),:)
ans=6×4 timetable
                    Date          ExcessLOD      UnadjustedDiff    CumulativeAdjustment        DUT1    
                 ___________    _____________    ______________    ____________________    ____________
    <1 event>    29-Dec-2016    0.0008055 sec      26.402 sec             26 sec            0.40159 sec
                 30-Dec-2016    0.0008525 sec      26.402 sec            NaN sec                NaN sec
    <1 event>    31-Dec-2016    0.0009173 sec      26.403 sec             27 sec           -0.59676 sec
    <1 event>    01-Jan-2017     0.001016 sec      26.404 sec             27 sec           -0.59584 sec
    <1 event>    02-Jan-2017    0.0011845 sec      26.405 sec             27 sec           -0.59482 sec
    <1 event>    03-Jan-2017    0.0013554 sec      26.406 sec             27 sec           -0.59364 sec

Plot State Variable Against Data

The IERS makes leap second adjustments to keep UTC roughly in sync with UT1. To show how this adjustment works, plot the CumulativeAdjustment state variable as a piecewise-constant step function over time. The step function approximates the accumulated excess LOD, so subtracting it keeps DUT1 small. For visual confirmation, plot DUT1 along the same time axis by using the stackedplot function. Plot UnadjustedDiff and CumulativeAdjustment together along one y-axis, with a legend, and plot DUT1 along a second y-axis. Because the events in the attached event table were converted to interval events that cover the entire time range, it is redundant to plot events. So, specify the EventsVisible name-value argument as "off".

stackedplot(IERSdata1972,{["UnadjustedDiff","CumulativeAdjustment"],"DUT1"},EventsVisible="off")

Figure contains an object of type stackedplot.

Choose Events or State Variables

The two representations, a separate list of events and a state variable defined at all times, are conceptually different. In some cases, there might not be a useful definition of a "state" that corresponds to the periods between instantaneous events. But when there is, the two representations are equivalent and useful in similar ways. For example, to select all the data after the 22nd leap second but before the 23rd, you can use an event filter and timerange.

EF = eventfilter(IERSdata1972)
EF = 
  eventfilter with no constraints and no selected variables

    <unconstrained>

  VariableNames: Date, Type, CumulativeAdjustment, UnadjustedDiff, EventEnds

from22to23 = timerange(EF.CumulativeAdjustment == seconds(22),EF.CumulativeAdjustment == seconds(23),"openright");
data22to23 = IERSdata1972(from22to23,:)
data22to23=2557×4 timetable
                    Date          ExcessLOD      UnadjustedDiff    CumulativeAdjustment        DUT1    
                 ___________    _____________    ______________    ____________________    ____________
    <1 event>    31-Dec-1998    0.0010954 sec      21.282 sec             22 sec           -0.71811 sec
    <1 event>    01-Jan-1999    0.0009738 sec      21.283 sec             22 sec           -0.71702 sec
    <1 event>    02-Jan-1999     0.000888 sec      21.284 sec             22 sec           -0.71604 sec
    <1 event>    03-Jan-1999    0.0008605 sec      21.285 sec             22 sec           -0.71516 sec
    <1 event>    04-Jan-1999    0.0008798 sec      21.286 sec             22 sec           -0.71429 sec
    <1 event>    05-Jan-1999    0.0008935 sec      21.287 sec             22 sec           -0.71342 sec
    <1 event>    06-Jan-1999    0.0009693 sec      21.287 sec             22 sec           -0.71252 sec
    <1 event>    07-Jan-1999    0.0010658 sec      21.288 sec             22 sec           -0.71155 sec
    <1 event>    08-Jan-1999    0.0010857 sec       21.29 sec             22 sec           -0.71049 sec
    <1 event>    09-Jan-1999    0.0010715 sec      21.291 sec             22 sec            -0.7094 sec
    <1 event>    10-Jan-1999    0.0010519 sec      21.292 sec             22 sec           -0.70833 sec
    <1 event>    11-Jan-1999    0.0010021 sec      21.293 sec             22 sec           -0.70728 sec
    <1 event>    12-Jan-1999    0.0008986 sec      21.294 sec             22 sec           -0.70628 sec
    <1 event>    13-Jan-1999    0.0007891 sec      21.295 sec             22 sec           -0.70538 sec
    <1 event>    14-Jan-1999    0.0007236 sec      21.295 sec             22 sec           -0.70459 sec
    <1 event>    15-Jan-1999    0.0006842 sec      21.296 sec             22 sec           -0.70386 sec
      ⋮

As an alternative, you can create a logical subscript from the state variable that selects the same data.

from22to23 = (IERSdata1972.CumulativeAdjustment == seconds(22));
data22to23 = IERSdata1972(from22to23,:)
data22to23=2556×4 timetable
                    Date          ExcessLOD      UnadjustedDiff    CumulativeAdjustment        DUT1    
                 ___________    _____________    ______________    ____________________    ____________
    <1 event>    31-Dec-1998    0.0010954 sec      21.282 sec             22 sec           -0.71811 sec
    <1 event>    01-Jan-1999    0.0009738 sec      21.283 sec             22 sec           -0.71702 sec
    <1 event>    02-Jan-1999     0.000888 sec      21.284 sec             22 sec           -0.71604 sec
    <1 event>    03-Jan-1999    0.0008605 sec      21.285 sec             22 sec           -0.71516 sec
    <1 event>    04-Jan-1999    0.0008798 sec      21.286 sec             22 sec           -0.71429 sec
    <1 event>    05-Jan-1999    0.0008935 sec      21.287 sec             22 sec           -0.71342 sec
    <1 event>    06-Jan-1999    0.0009693 sec      21.287 sec             22 sec           -0.71252 sec
    <1 event>    07-Jan-1999    0.0010658 sec      21.288 sec             22 sec           -0.71155 sec
    <1 event>    08-Jan-1999    0.0010857 sec       21.29 sec             22 sec           -0.71049 sec
    <1 event>    09-Jan-1999    0.0010715 sec      21.291 sec             22 sec            -0.7094 sec
    <1 event>    10-Jan-1999    0.0010519 sec      21.292 sec             22 sec           -0.70833 sec
    <1 event>    11-Jan-1999    0.0010021 sec      21.293 sec             22 sec           -0.70728 sec
    <1 event>    12-Jan-1999    0.0008986 sec      21.294 sec             22 sec           -0.70628 sec
    <1 event>    13-Jan-1999    0.0007891 sec      21.295 sec             22 sec           -0.70538 sec
    <1 event>    14-Jan-1999    0.0007236 sec      21.295 sec             22 sec           -0.70459 sec
    <1 event>    15-Jan-1999    0.0006842 sec      21.296 sec             22 sec           -0.70386 sec
      ⋮

Both representations have their uses. For example, while each event can be plotted as a point, the state variable is the more convenient form for highlighting regions between events in a plot. To highlight the region between the 22nd and 23rd leap second, use the from22to23 logical subscript created from CumulativeAdjustment.

plot(IERSdata1972,"UnadjustedDiff");
hold on
plot(IERSdata1972(from22to23,:),"UnadjustedDiff",Color="r",LineWidth=4);
hold off

Figure contains an axes object. The axes object with xlabel Date, ylabel UnadjustedDiff contains 2 objects of type line.

You can switch between the two representations. In this case, to get the leap second event dates from CumulativeAdjustment, find the locations where the adjustment changes, and subtract one day. The eventTimes output represents the dates on which leap seconds were added, which are instantaneous events.

eventTimes = IERSdata1972.Date(diff(IERSdata1972.CumulativeAdjustment) ~= 0) + caldays(1)
eventTimes = 55×1 datetime
   29-Jun-1972
   30-Jun-1972
   30-Dec-1972
   31-Dec-1972
   30-Dec-1973
   31-Dec-1973
   30-Dec-1974
   31-Dec-1974
   30-Dec-1975
   31-Dec-1975
   30-Dec-1976
   31-Dec-1976
   30-Dec-1977
   31-Dec-1977
   30-Dec-1978
   31-Dec-1978
   30-Dec-1979
   31-Dec-1979
   29-Jun-1981
   30-Jun-1981
   29-Jun-1982
   30-Jun-1982
   29-Jun-1983
   30-Jun-1983
   29-Jun-1985
   30-Jun-1985
   30-Dec-1987
   31-Dec-1987
   30-Dec-1989
   31-Dec-1989
      ⋮

To represent events, you can use event tables, with either instantaneous events or interval events, or state variables in timetables. The representation you use depends on which one is more convenient and useful for the data analysis that you plan to conduct. You might even switch between representations as you go. All these representations are useful ways to add information about events to your timestamped data in a timetable.

See Also

| | | | | | | | |

Related Topics