Data may be taken over periods of time at a set of discrete point, spatial locations called stations (see also discussion in 9.1).  The set of elements at a particular station is referred to as a timeSeries feature and a data variable may contain a collection of such features. The instance dimension in the case of timeSeries specifies the number of time series in the collection and is also referred to as the station dimension. The instance variables, which have just this dimension, including latitude and longitude for example, are also referred to as station variables and are considered to contain information describing the stations. The station variables may contain missing values, allowing one to reserve space for additional stations that may be added at a later time, as discussed in section 9.6. In addition,

All the representations described in section 9.3 can be used for time series. The global attribute featureType=”timeSeries” (case-insensitive) must be included.

H.2.1. Orthogonal multidimensional array representation of time series

If the time series instances have the same number of elements and the time values are identical for all instances, you may use the orthogonal multidimensional array representation. This has either a one-dimensional coordinate variable, time(time), provided the time values are ordered monotonically, or a one-dimensional auxiliary coordinate variable, time(o), where o is the element dimension. In the former case, listing the time variable in the coordinates attributes of the data variables is optional.

Example H.2. Timeseries with common element times in a time coordinate variable using the orthogonal multidimensional array representation.

   dimensions:
     station = 10 ;  // measurement locations
     time = UNLIMITED ;
   variables:
     float humidity(station,time) ;
       humidity:standard_name = "specific humidity" ;
       humidity:coordinates = "lat lon alt" ;
     double time(time) ; 
       time:standard_name = "time";
       time:long_name = "time of measurement" ;
       time:units = "days since 1970-01-01 00:00:00" ;
     float lon(station) ; 
       lon:standard_name = "longitude";
       lon:long_name = "station longitude";
       lon:units = "degrees_east";
     float lat(station) ; 
       lat:standard_name = "latitude";
       lat:long_name = "station latitude" ;
       lat:units = "degrees_north" ; 
     float alt(station) ;
       alt:long_name = "vertical distance above the surface" ;
       alt:standard_name = "height" ;
       alt:units = "m";
       alt:positive = "up";
       alt:axis = "Z";
     char station_name(station, name_strlen) ;
       station_name:long_name = "station name" ;
       station_name:cf_role = "timeseries_id";
   attributes:
       :featureType = "timeSeries";

In this example, humidity(i,o) is element o of time series i, and associated with the coordinate values time(o), lat(i), and lon(i). Either the instance (station) or the element (time) dimension may optionally be the netCDF unlimited dimension.

H.2.2. Incomplete multidimensional array representation of time series

Much of the simplicity of the orthogonal multidimensional representation can be preserved even in cases where individual time series have different time coordinate values.  All time series must be allocated the amount of staorage needed by the longest, so the use of this representation will trade off simplicity against storage space in some cases.  

Example H.3. Timeseries of station data in the incomplete multidimensional array representation.    

   dimensions:
      station = UNLIMITED ;
      obs = 13 ;

   variables:
      float lon(station) ; 
          lon:standard_name = "longitude";
          lon:long_name = "station longitude";
          lon:units = "degrees_east";
      float lat(station) ; 
          lat:standard_name = "latitude";
          lat:long_name = "station latitude" ;
          lat:units = "degrees_north" ;
      float alt(station) ;
          alt:long_name = "vertical distance above the surface" ;
          alt:standard_name = "height" ;
          alt:units = "m";
          alt:positive = "up";
          alt:axis = "Z";
      char station_name(station, name_strlen) ;
          station_name:long_name = "station name" ;
          station_name:cf_role = "timeseries_id";
      int station_info(station) ;
          station_info:long_name = "any kind of station info" ;
      float station_elevation(station) ;
          station_elevationalt:long_name = "height above the geoid" ;
          station_elevationalt:standard_name = "surface_altitude" ;
          station_elevationalt:units = "m";

      double time(station, obs) ; 
          time:standard_name = "time";
          time:long_name = "time of measurement" ;
          time:units = "days since 1970-01-01 00:00:00" ;
          time:missing_value = -999.9;
      float humidity(station, obs) ;
          humidity:standard_name = “specific_humidity” ;
          humidity:coordinates = "time lat lon alt" ;
          humidity:_FillValue = -999.9;
      float temp(station, obs) ;
          temp:standard_name = “air_temperature” ;
          temp:units = "Celsius" ;
          temp:coordinates = "time lat lon alt" ;
          temp:_FillValue = -999.9;

   attributes:
          :featureType = "timeSeries";

In this example, the humidity(i,o) and temp(i,o) data for element o of time series i are associated with the coordinate values time(i,o), lat(i), lon(i) and alt(i). Either the instance (station) dimension or the element (obs) dimension could be the unlimited dimension of a netCDF file.  Any unused elements of the data and auxiliary coordinate variables must contain the missing data flag value(section 9.6).

H.2.3. Single time series, including deviations from a nominal fixed spatial location

When the intention of a data variable is to contain only a single time series, the preferred encoding is a special case of the multidimensional array representation.

Example H.4. A single timeseries.

   dimensions:
      time = 100233 ;
      name_strlen = 23 ;

   variables:
      float lon ; 
          lon:standard_name = "longitude";
          lon:long_name = "station longitude";
          lon:units = "degrees_east";
      float lat ; 
          lat:standard_name = "latitude";
          lat:long_name = "station latitude" ;
          lat:units = "degrees_north" ;
      float alt ;
          alt:long_name = "vertical distance above the surface" ;
          alt:standard_name = "height" ;
          alt:units = "m";
          alt:positive = "up";
          alt:axis = "Z";
      char station_name(name_strlen) ;
          station_name:long_name = "station name" ;
          station_name:cf_role = "timeseries_id";

      double time(time) ; 
          time:standard_name = "time";
          time:long_name = "time of measurement" ;
          time:units = "days since 1970-01-01 00:00:00" ;
          time:missing_value = -999.9;
      float humidity(time) ;
          humidity:standard_name = “specific_humidity” ;
          humidity:coordinates = "time lat lon alt" ;
          humidity:_FillValue = -999.9;
      float temp(time) ;
          temp:standard_name = “air_temperature” ;
          temp:units = "Celsius" ;
          temp:coordinates = "time lat lon alt" ;
          temp:_FillValue = -999.9;

   attributes:
          :featureType = "timeSeries";

While an idealized time series is defined at a single, stable point location, there are examples of time series, such as cabled ocean surface mooring measurements, in which the precise position of the observations varies slightly from a nominal fixed point.  In the following example we show how the spatial positions of such a time series should be encoded in CF.  Note that although this example shows only a single time series, the technique is applicable to all of the representations.

Example H.5. A single timeseries with time-varying deviations from a nominal point spatial location

   dimensions:
      time = 100233 ;
      name_strlen = 23 ;

   variables:
      float lon ; 
          lon:standard_name = "longitude";
          lon:long_name = "station longitude";
          lon:units = "degrees_east";
          lon:axis = “X”;
      float lat ; 
          lat:standard_name = "latitude";
          lat:long_name = "station latitude" ;
          lat:units = "degrees_north" ;
          lat: axis = “Y” ;
      float precise_lon (time); 
          precise_lon:standard_name = "longitude";
          precise_lon:long_name = "station longitude";
          precise_lon:units = "degrees_east";
      float precise_lat (time); 
          precise_lat:standard_name = "latitude";
          precise_lat:long_name = "station latitude" ;
          precise_lat:units = "degrees_north" ;
      float alt ;
          alt:long_name = "vertical distance above the surface" ;
          alt:standard_name = "height" ;
          alt:units = "m";
          alt:positive = "up";
          alt:axis = "Z";
      char station_name(name_strlen) ;
          station_name:long_name = "station name" ;
          station_name:cf_role = "timeseries_id";

      double time(time) ; 
          time:standard_name = "time";
          time:long_name = "time of measurement" ;
          time:units = "days since 1970-01-01 00:00:00" ;
          time:missing_value = -999.9;
      float humidity(time) ;
          humidity:standard_name = “specific_humidity” ;
          humidity:coordinates = "time lat lon alt precise_lon precise_lat" ;
          humidity:_FillValue = -999.9;
      float temp(time) ;
          temp:standard_name = “air_temperature” ;
          temp:units = "Celsius" ;
          temp:coordinates = "time lat lon alt precise_lon precise_lat " ;
          temp:_FillValue = -999.9;

   attributes:
          :featureType = "timeSeries";

H.2.4. Contiguous ragged array representation of time series

When the time series have different lengths and the data values for entire time series are available to be written in a single operation,  the contiguous ragged array representation is efficient.

Example H.6. Timeseries of station data in the contiguous ragged array representation.

   dimensions:
      station = 23 ;
      obs = 1234 ;

   variables:
      float lon(station) ; 
          lon:standard_name = "longitude";
          lon:long_name = "station longitude";
          lon:units = "degrees_east";
      float lat(station) ; 
          lat:standard_name = "latitude";
          lat:long_name = "station latitude" ;
          lat:units = "degrees_north" ;
      float alt(station) ;
          alt:long_name = "vertical distance above the surface" ;
          alt:standard_name = "height" ;
          alt:units = "m";
          alt:positive = "up";
          alt:axis = "Z";
      char station_name(station, name_strlen) ;
          station_name:long_name = "station name" ;
          station_name:cf_role = "timeseries_id";
      int station_info(station) ;
          station_info:long_name = "some kind of station info" ;
      int row_size(station) ;
          row_size:long_name = "number of observations for this station " ;
          row_size:sample_dimension = "obs" ;

      double time(obs) ; 
          time:standard_name = "time";
          time:long_name = "time of measurement" ;
          time:units = "days since 1970-01-01 00:00:00" ;
      float humidity(obs) ;
          humidity:standard_name = “specific_humidity” ;
          humidity:coordinates = "time lat lon alt" ;
          humidity:_FillValue = -999.9;
      float temp(obs) ;
          temp:standard_name = “air_temperature” ;
          temp:units = "Celsius" ;
          temp:coordinates = "time lat lon alt" ;
          temp:_FillValue = -999.9;

   attributes:
          :featureType = "timeSeries";

The data humidity(o) and temp(o) are associated with the coordinate values time(o), lat(i), lon(i), and alt(i), where i indicates which time series. Time series i comprises the data elements from

   rowStart(i) to rowStart(i) + row_size(i) - 1

where

      rowStart(i) = 0 if i = 0      
      rowStart(i) = rowStart(i-1) + row_size(i-1) if i > 0

The variable, row_size, is the count variable containing the length of each time series feature.   It is identified by having an attribute with name sample_dimension whose value is name of the sample dimension (obs in this example). The sample dimension could optionally be the netCDF unlimited dimension. The variable bearing the sample_dimension attribute must have the instance dimension (station in this example) as its single dimension, and must be of type integer.   This variable implicitly partitions into individual instances all variables that have the sample dimension. The auxiliary coordinate variables lat, lon, alt and station_name are station variables.

H.2.5. Indexed ragged array representation of time series

When time series with different lengths are written incrementally, the indexed ragged array representation is efficient.

Example H.7. Timeseries of station data in the indexed ragged array representation.

   dimensions:
      station = 23 ;
      obs = UNLIMITED ;

   variables:
      float lon(station) ; 
          lon:standard_name = "longitude";
          lon:long_name = "station longitude";
          lon:units = "degrees_east";
      float lat(station) ; 
          lat:standard_name = "latitude";
          lat:long_name = "station latitude" ;
          lat:units = "degrees_north" ;
      float alt(station) ;
          alt:long_name = "vertical distance above the surface" ;
          alt:standard_name = "height" ;
          alt:units = "m";
          alt:positive = "up";
          alt:axis = "Z";
      char station_name(station, name_strlen) ;
          station_name:long_name = "station name" ;
          station_name:cf_role = "timeseries_id";
      int station_info(station) ;
          station_info:long_name = "some kind of station info" ;

      int stationIndex(obs) ;
          stationIndex:long_name = "which station this obs is for" ;
          stationIndex:instance_dimension= "station" ;
      double time(obs) ; 
          time:standard_name = "time";
          time:long_name = "time of measurement" ;
          time:units = "days since 1970-01-01 00:00:00" ;
      float humidity(obs) ;
          humidity:standard_name = “specific_humidity” ;
          humidity:coordinates = "time lat lon alt" ;
          humidity:_FillValue = -999.9;
      float temp(obs) ;
          temp:standard_name = “air_temperature” ;
          temp:units = "Celsius" ;
          temp:coordinates = "time lat lon alt" ;
          temp:_FillValue = -999.9;

   attributes:
          :featureType = "timeSeries";

The humidity(o) and temp(o) data are associated with the coordinate values time(o), lat(i), lon(i), and alt(i), where i = stationIndex(o) is a zero-based index indicating which time series. Thus, time(0), humidity(0) and temp(0) belong to the element of the station dimension that is indicated by stationIndex(0); time(1), humidity(1) and temp(1) belong to element stationIndex(1) of the station dimension, etc.

The variable, stationIndex , is identified as the index variable by having an attribute with name of instance_dimension whose value is the instance dimension (station in this example).  The variable bearing the instance_dimension attribute must have the sample dimension (obs in this example) as its single dimension, and must be type integer. This variable implicitly assigns the station to each value of any variable having the sample dimension. The sample dimension need not be the netCDF unlimited dimension, though it commonly is.