SITCOMTN-098: TMA Event Generation

  • Merlin Fisher-Levine

Latest Revision: 2023-12-08

Note

This technote is a work-in-progress.

1 Abstract

A detailed description of what TMAEvents are, and how they’re made.

2 Introduction and definitions

This technote introduces the concept of the TMAEvent, and motivates their existence. The types of event are defined, and an explanation of how they are calculated is given.

There are two types of events: TRACKING and SLEWING, which are defined as follows:

  • SLEWING: a SLEW event is any movement of the TMA which contains no moments of sidereal tracking, and no moments of being stationary.

  • TRACKING: A TRACKING event is the exact period during which the TMA was only sidereally tracking.

These definitions are to be taken as definitional, i.e. the extent to which any given event is found not to be that, is because of either bugs in the generation code, or data missing from the EFD. In the case that EFD data is missing, correcting the events is fundamentally impossible, as events are derived from the data in the EFD and nothing else.

2.1 Side notes, caveats and cautions

Everywhere in this document that the phrase “sidereal tracking” is used, it actually needn’t be - TRACKING type events apply equally to any type of tracking. The reason the phrase “sideareal tracking” is used in these instances is to make clear that this is distinct from moving into position, because in some areas of the project, this is also referred to as “tracking”, and this leads to a lot of confusion in communication. What “sidereal tracking” actually means, in this context, is “both axes in the position they should be for the target of choice, and are moving at the correct rate in order to maintain contact with the intended target within some small error”. Clearly, this can therefore apply to non-sidereal targets, too, but it is also clear that there needs to be some shorthand for this notion to deal with the aforementioned confusion, and given that >99% of the tracking we will do will be sidereal, the phrase “sidereal tracking” was chosen for simplicity. (Footnote - this small error is defined by the low level TMA controller code, and I neither know what it is, nor have any control over it, but it must be very sub-arcsecond).

Because TMAEvents are derived data products generated from data in the EFD with code in summit_utils, bug fixes in the code which generates them could potentially cause a change in the parameters of a given event, or event numbering within a given day. Therefore, TMAEvents carry a .version property, which is incremented any time a code change is made which could potentially change definitions, and events only compare equal within a given version number. The “true” definition of event numbering is taken to be whatever the current code version number is, given the definitional nature of the event generation. It is intended that the versions stored in the Summit Database, and those displayed on RubinTV, will be kept up-to-date with the latest version.

2.2 Motivation

The EFD has no notion of “the TMA” as an entity, only of its constituent components. Furthermore, there is no API for getting the state of any of particular component at a given point in time. Finally, the correct physical interpretation of what a given component is doing at any time requires the logical combination of more than one EFD topic. This makes determining what the TMA was doing a very hard problem if the only mode of interaction is with the raw telemetry in the EFD. The concept of a TMAEvent was there introduced to solve several problems.

The intention here is twofold:

  • To create pythonic interfaces for querying the EFD for the time-series and event-like data for various components of interest during TMA testing and interacting with the events themselves.

  • To provide a conceptual framework to talk about the movements of the TMA.

3 Event Generation

3.1 Event Generation Overview

This section gives an overview of how events are generated. It refers to classes and concepts which are defined more rigorously later on. All event generation is done in terms of a given dayObs, and events are numbered with a seqNum, in keeping with observatory procedure for dataId s. The events are generated by the TMAEventMaker class. For a given dayObs:

  • Data is retrieved fr om the EFD by the TMAEventMaker for all the relevant topics for the entire dayObs.

  • The dataframe corresponding to each topic is then merged into one, to give a time-ordered series of component state changes.

  • These state changes are then replayed through the TMAStateMachine model to derive the overall state of the TMA at that point in time.

  • This time series of overall TMA states is then chunked into discrete TMAEvent objects.

  • Each of these TMAEvent objects is then augmented with data on the BLOCK that was being run at the time, if any.

3.2 The TMAStateMachine model

The physical TMA, in so far as event generation is concerned, has two components: the azimuth axis and the elevation axis. To determine the state of these components at a given point in time, three topics must be considered for each: the axis’ MotionState, InPosition status and SystemState. Therefore, the six topics which must be retrieved from from the EFD are:

lsst.sal.MTMount.logevent_azimuthMotionState
lsst.sal.MTMount.logevent_azimuthInPosition
lsst.sal.MTMount.logevent_azimuthSystemState
lsst.sal.MTMount.logevent_elevationMotionState
lsst.sal.MTMount.logevent_elevationInPosition
lsst.sal.MTMount.logevent_elevationSystemState

The <axis>MotionState is an AxisMotionState enum, which takes values of STOPPING, STOPPED, MOVING_POINT_TO_POINT, JOGGING, TRACKING, TRACKING_PAUSED. The <axis>InPosition is a boolean, and the <axis>SystemState is a PowerState enum, which takes values of OFF, ON, FAULT, TURNING_ON, TURNING_OFF, UNKNOWN.

The TMAStateMachine itself represents the overall state of the TMA at a given point in time, held in the with the TMAStateMachine.state property. This property is a TMAState enum, which can be one of: UNINITIALIZED, FAULT, OFF, STOPPED, TRACKING, SLEWING. It does this by holding the state of all the relevant components and combining them logically to give the overall state. It also has the ability to apply a new row of data from the merged dataframe, which is used to evolve the TMA’s state with time. It also has convenience properties to make the programmatic flow and logical statements easier to understand, for example isMoving, isNotMoving, isTracking, isSlewing, canMove.

3.2.1 The TMAState states

The following is a definition of the overall TMAStateMachine states:

  • TRACKING: as per the definition in the introduction, when the TMA is in the TRACKING state, both axes are powered on and not in fault and in motion and inPosition, i.e. it is in the state it would be when tracking an object across the sky.

  • SLEWING: as per the definition in the introduction, when the TMA is in the SLEWING state, at least one axis is powered on and not in fault and in motion. It is possible that the other axis may be also be in motion (in position or otherwise), or not. The other axis might also be in fault, or not.

  • STOPPED: Neither axis is in motion, and at least one of them is powered on and not in FAULT, i.e. the TMA canMove but is not moving right now.

  • OFF: Both axes are powered off, i.e. TMA.canMove == False

  • FAULT: Both axes are in fault.

  • UNINITIALIZED: this state is currently unused. The intention was to have this be the state the TMA is brought up in, and the state remains like this until each component has had its state set, as time evolves. However, in practice, because event generation currently starts from the start of a dayObs and doesn’t look back in time to find the previously set state, this doesn’t work as movements frequently begin before all topics have had their state set. If this turns out to cause problems in practice, then the solution is to simply look back in time from the start of the day to establish the state that the TMA was in, and then work forwards again from that point in time, but so far this has proven unnecessary and wasn’t worth the added complexity during the initial design and implementation.

3.3 Data Retrieval and Caching

Data is retrieved from the EFD for each of the six topics in turn, for the entire dayObs (note that this is the standard observatory definition of the dayObs, not the calendar day). If the day in question is in the past, and we can therefore be sure that new data is not going to land, the data is cached in the TMAEventMaker, as this increases performance of subsequent event operations for that day by orders of magnitude and the data itself is not large, even when working with multiple days. However, a call is made to eventMaker.getEvents(dayObs) where the dayObs is the current day, then the data is pulled again, and events are regenerated from scratch for all calls until the day rolls over.

The dataframe for each of the six topics is merged in time order, based on the private_efdStamp column. The merged dataframe being constructed to keep provenance for each row, so that it is known which component it contains data for. The retrieval is done by the _getEfdDataForDayObs() function, and the data is merged in _mergeData(), which together also handle the class’ behavior when no data is returned for one or more topics.

3.4 Event generation

The event generation itself works in three parts: state evolution through the state machine, state grouping, and event data augmentation. The augmentation happens as a post-processing step, and is explained in Section 3.

3.4.1 State evolution

For each row of the merged dataframe, the row is played through the state machine using the TMAStateMachine.apply() method, and the resulting state of the TMA recorded. The top-level function in charge of this is _calculateEventsFromMergedData(), which in turn calls out to _statesToEventTuples() to do the groupings.

Calculate the list of events from the merged data. Runs the merged data, row by row, through the TMA state machine (with tma.apply) to get the overall TMA state at each row, building a dict of these states, keyed by row number. This time-series of TMA states are then looped over (in _statesToEventTuples()), building a list of tuples representing the start and end of each event, the type of the event, and the reason for the event ending. This list of tuples is then passed to _makeEventsFromStateTuples(), which actually creates the TMAEvent objects.

3.4.2 State grouping and event creation

  • Event Detection

  • Detects events by grouping continuous rows with the same TMA state.

  • An event starts when the state changes from a non-moving state (STOPPED, OFF, or FAULT) to a moving state (TRACKING or SLEWING), and ends when it transitions back. - The event’s type and duration are determined based on these transitions.

3.5 Special Cases Handling

  • Handles cases like events spanning across the start or end of the day.

  • Identifies contiguous events and logs information accordingly.

4 Data augmentation

The BlockInfoParser itself.

4.1 BlockInfo integration

Links block data (observational data) with events for more detailed analysis.

4.2 ScriptState evolution

ScriptState which can be any ofUNKNOWN, UNCONFIGURED, CONFIGURED, RUNNING, PAUSED, ENDING, STOPPING, FAILING, DONE, STOPPED, FAILED, CONFIGURE_FAILED.

5 Additional Features

5.1 Event finding/lookup

  • findEvent

  • event.relatesTo()

5.2 Event printing

  • printTmaDetailedState

  • printFullDayStateEvolution

  • printEventDetails