Tutorial¶
For the impatient, see the Quickstart section below. To take full advantage of all the capabilities of annie, continue on through the rest of the tutorial as well.
Quickstart¶
The very simplest way to run an annie simulation is to take some or all
of the simulation parameters from an existing or planned observation via the starcheck
catalog. This is done with the run_from_starcheck()
function:
>>> from annie import run_from_starcheck
>>> obsid = 20201
>>> stop = 200 # seconds. Can also do `stop = 200 * u.s` with astropy units.
>>> sc = run_from_starcheck(obsid, verbose=True, stop=stop)
Running annie with:
{'att_cmd': [193.228633, -63.884565, 39.69144],
'ccd_bgd_data': '2018:051:02:57:08.203',
'dither': {'pitch_ampl': 8.0,
'pitch_period': 707.1,
'pitch_phase': 0.0,
'yaw_ampl': 8.0,
'yaw_period': 1000.0,
'yaw_phase': 0.0},
'starcat': <Table length=12>
sc_id obsid idx slot id idnote ... yang zang dim res halfw pass notes
int64 int64 int64 int64 int64 object ... int64 int64 int64 int64 int64 str2 str2
----- ----- ----- ----- ---------- ------ ... ----- ----- ----- ----- ----- ---- -----
2116 20201 1 0 1 None ... 919 -844 1 1 25 -- --
2116 20201 2 1 5 None ... -1828 1053 1 1 25 -- --
2116 20201 3 2 6 None ... 385 1697 1 1 25 -- --
2116 20201 4 3 1178736784 None ... 2004 -622 28 1 160 a2 --
2116 20201 5 4 1178737152 None ... 775 1438 32 1 180 -- --
2116 20201 6 5 1178737496 None ... 1219 123 32 1 180 -- --
2116 20201 7 6 1179259616 None ... -2112 -1949 28 1 160 a2 --
2116 20201 8 7 1178736896 None ... 2420 -905 1 1 25 -- --
2116 20201 9 7 1179257400 None ... 33 544 32 1 180 -- --
2116 20201 10 0 1179257016 None ... -8 -2234 29 1 165 -- --
2116 20201 11 1 1179257288 None ... 942 -257 28 1 160 a2 --
2116 20201 12 2 1179127856 None ... -1782 -21 28 1 160 a2 --,
'stop': 200,
't_ccd': -11.4}
>>>
The run_from_starcheck()
function can also take as input the starcheck
dict returned from get_starcheck_catalog(),
or the text copied from the starcheck report. In the latter case one could easily update
catalog parameters to evaluate a potential catalog update.
In addition one can override any of the track_stars_setup()
parameters for the observation, for instance simulate this observation at a higher CCD
temperature:
>>> sc = run_from_starcheck(obsid, t_ccd=-5.0, stop=stop)
Now to look at the results, see the section on Exploring annie’s telemetry.
Creating spacecraft subsystems¶
All spacecraft subsystems required to run a simulation are created using the Spacecraft
master controller:
>>> from annie.annie import Spacecraft
>>> sc = Spacecraft()
The main s/c subsystems include the Clock
, Sky
, ACA
,
CCD
, PCAD
and Telem
objects:
>>> sc.__dict__
{'aca': <annie.aca.ACA at 0x7f50a85ca630>,
'ccd': <annie.aca.CCD at 0x7f50a85c4198>,
'clock': <Clock secs=0.000 ticks=0>,
'logger': <Logger root (CRITICAL)>,
'loglevel': 50,
'pcad': <annie.pcad.PCAD at 0x7f50a85ca7f0>,
'sky': <annie.sky.Sky at 0x7f50a85ca390>,
'start': 0,
'stop': 100,
'telem': <annie.telem.Telem at 0x7f50a85ca438>}
Internal clock¶
The annie clock units are as follows:
Name |
Attribute |
Ticks |
Seconds |
---|---|---|---|
Clock tick |
|
1 |
0.016015625 |
Minor cycle |
|
1 |
0.016015625 |
Minor frame |
|
16 |
0.25625 |
Frame |
|
64 |
1.025 |
Major frame |
|
2048 |
32.8 |
One frame lasts 1.025 seconds and there are 64 clock ticks per frame:
>>> from annie.clock import TICKS_PER_FRAME
>>> print(TICKS_PER_FRAME)
64
The relative durations of these clock units is available in the TICKS_PER
module dictionary:
>>> from annie.clock import TICKS_PER
>>> print(TICKS_PER.keys())
dict_keys(['mnc', 'mnf', 'mjf', 'frame', 'sec'])
>>> print(TICKS_PER['mnf'])
16
>>> print(TICKS_PER['sec'])
62.43902439024391
The clock module contains two classes, ClockTime
and Clock
.
ClockTime¶
The ClockTime
class provides functionality to convert Date or DateTime objects
into the internal annie clock time:
>>> from annie.clock import ClockTime
>>> import astropy.units as u
>>> ct = ClockTime(15) # Initialize in ticks
>>> ct
<ClockTime secs=0.240, ticks=15>
>>> ClockTime(32.8 * u.s) # Initialize in seconds
<ClockTime secs=32.800, ticks=2048>
>>> ClockTime('2017:001') # Absolute date
<ClockTime secs=599616069.191 ticks=37439442369>
It also provides functionality to manipulate the internal time, e.g. derive the time at the next unit:
>>> ct.at_next('frame')
<ClockTime secs=1.025, ticks=64>
or derive the number of ticks that have passed since the start of a given unit:
>>> ct = ClockTime(41 * u.s)
>>> ct
<ClockTime secs=41, ticks=2560>
>>> ct.ticks_mod('mjf')
512 # 2560 - 2048
or perform arithmetic operations on the ClockTime
objects:
>>> ct_delta = ClockTime(2)
>>> ct + ct_delta
<ClockTime secs=41.032, ticks=2562>
Clock¶
The Clock
class controls the internal clock. It inherits from the ClockTime
class. It also inherits from the SubSystem
class, and thus annie’s clock is one of the
spacecraft subsystems created within the Spacecraft
master controller for the simulation:
>>> from annie.clock import Clock
>>> from annie.annie import Spacecraft
>>> import astropy.units as u
>>> sc = Spacecraft()
>>> c = sc.clock
>>> c.start = 0 # ticks
>>> c # Clock object
<Clock secs=0.000, ticks=0>
>>> c.start # ClockTime object
<ClockTime secs=0.00, ticks=0>
The end of the simulation is specified by setting the stop
attribute:
>>> c.stop = 100 * u.s # Ticks or delta time via astropy units
The simulation progresses via successive calls to the tick()
method until the stop
time is reached, at which point the method returns False
.
>>> # The first tick() method call initializes/starts the clock
>>> c.tick()
True
>>> c
<Clock secs=0.000, ticks=0>
>>>
>>> # The next and following tick() calls move the clock by 1 tick
>>> c.tick()
True
>>> c
<Clock secs=0.016, ticks=1>
Scheduling actions¶
Tasks¶
In each subsystem there are certain tasks that are executed regularly by the generic
subsystem processing called every tick (annie.subsystem.SubSystem.process()
,
see annie.annie.Spacecraft.run()
and Running an annie simulation). Information about
these tasks can be accessed through the tasks attribute, which is a list of tuples containing
method, time unit, and tick offset within this time unit.
For example, the PCAD subsystem performs attitude updates at the start of every minor frame and main processing at the start of every frame, while the ACA subsystem performs main processing one tick (one minor cycle) after the start of each frame:
>>> sc.pcad.tasks
[('update_att', 'mnf', 0), ('main_processing', 'frame', 0)]
>>> sc.aca.tasks
[('main_processing', 'frame', 1)]
Commands¶
Commands executed by the subsystems are scheduled using the subsystem’s
command()
method which adds the new commands
to the subsystem’s commands
dictionary:
>>> sc.pcad.commands
defaultdict(list, {})
>>> sc.pcad.pending_commands
[]
>>> sc.pcad.command('set_att_cmd', 0 * u.s, att=[0., 0., 0.])
>>> sc.pcad.command('set_att_cmd', 100 * u.s, att=[10., 20., 0.])
>>> sc.pcad.commands
defaultdict(list,
{<ClockTime secs=0.016 ticks=1>: [('set_att_cmd',
{'att': [0.0, 0.0, 0.0]})],
<ClockTime secs=100.018 ticks=6245>: [('set_att_cmd',
{'att': [10.0, 20.0, 0.0]})]})
>>> sc.pcad.pending_commands
[]
>>> print(sc.pcad.att_record.att_cmd)
None
The commands to be executed at this time are then added to the subsystem’s
pending_commands
list by the generic
subsystem processing called every tick (process()
,
see Running an annie simulation):
>>> sc.clock
<Clock secs=0.016, ticks=1>
>>> sc.pcad.process()
>>> sc.pcad.commands
defaultdict(list,
{<ClockTime secs=0.016 ticks=1>: [('set_att_cmd',
{'att': [0.0, 0.0, 0.0]})],
<ClockTime secs=100.018 ticks=6245>: [('set_att_cmd',
{'att': [10.0, 20.0, 0.0]})]})
>>> sc.pcad.pending_commands
[('set_att_cmd', {'att': [0.0, 0.0, 0.0]})]
>>> print(sc.pcad.att_record.att_cmd)
None
Finally, the commands are executed at their scheduled time as part of the subsystem’s
regularly scheduled tasks (e.g. annie.pcad.PCAD.main_processing()
which calls
subsystem’s execute_pending_commands()
method).
This removes the command from the pending commands list. However, the command is kept
in the commands list which acts as a log of commands scheduled during the simulation:
>>> sc.pcad.main_processing()
>>> sc.pcad.commands
defaultdict(list,
{<ClockTime secs=0.016 ticks=1>: [('set_att_cmd',
{'att': [0.0, 0.0, 0.0]})],
<ClockTime secs=100.018 ticks=6245>: [('set_att_cmd',
{'att': [10.0, 20.0, 0.0]})]})
>>> sc.pcad.pending_commands
[]
>>> print(sc.pcad.att_record.att_cmd)
<Quat q1=0.00000000 q2=-0.00000000 q3=0.00000000 q4=1.00000000>
The next scheduled command gets processed and executed when the clock reaches its scheduled time:
>>> sc.clock.ticks = 6245
>>> sc.pcad.process()
>>> sc.pcad.commands
defaultdict(list,
{<ClockTime secs=0.016 ticks=1>: [('set_att_cmd',
{'att': [0.0, 0.0, 0.0]})],
<ClockTime secs=100.018 ticks=6245>: [('set_att_cmd',
{'att': [10.0, 20.0, 0.0]})]})
>>> sc.pcad.pending_commands
[('set_att_cmd', {'att': [10.0, 20.0, 0.0]})]
>>> sc.pcad.main_processing()
>>> sc.pcad.commands
defaultdict(list,
{<ClockTime secs=0.016 ticks=1>: [('set_att_cmd',
{'att': [0.0, 0.0, 0.0]})],
<ClockTime secs=100.018 ticks=6245>: [('set_att_cmd',
{'att': [10.0, 20.0, 0.0]})]})
>>> sc.pcad.pending_commands
[]
>>> print(sc.pcad.att_record.att_cmd)
<Quat q1=0.01513444 q2=-0.17298739 q3=0.08583165 q4=0.98106026>
Events¶
Events to be executed at a given time are added to the subsystem’s events queue
(annie.subsystem.SubSystem.events
) using the subsystem’s
annie.subsystem.SubSystem.add_event()
method:
>>> # Schedule a `flush` event (change the ccd status to `flush`)
>>> sc.clock.ticks = 0 # reset the clock for the purpose of this example
>>> sc.ccd.events
defaultdict(list, {})
>>> sc.ccd.add_event('flush', sc.clock + 1 * u.mnc)
>>> sc.ccd.events
defaultdict(list, {<ClockTime secs=0.016 ticks=1>: [('flush', {})]})
The events in the events queue are executed at their scheduled time by the generic
subsystem processing called every tick (annie.subsystem.SubSystem.process()
,
see Running an annie simulation). The execution of the event does not remove
the event from the events list which acts as a log of events scheduled for a given
subsystem in the course of the simulation:
>>> sc.ccd.status
`idle`
>>> sc.clock.tick()
>>> sc.clock
<Clock secs=0.016 ticks=1>
>>> sc.ccd.process()
>>> sc.ccd.status
`flush`
>>> sc.ccd.events
defaultdict(list, {<ClockTime secs=0.016 ticks=1>: [('flush', {})]})
Setting up an annie simulation¶
Setting up an annie simulation requires providing a number of subsystem
parameters and issuing relevant commands. This is most conveniently done
using the annie.annie.Spacecraft.track_stars_setup()
method. By convention, simulations normally start at time=0,
and the end of the simulation is defined with a stop parameter (which then
also corresponds to the duration).
Once the parameters are set, the track_stars_setup()
method calls PCAD’s annie.pcad.PCAD.track_guide_stars()
method which commands
ACA to search for the guide stars and start guiding.
- The simulation parameter fall into four categories:
Stars (sky and catalog),
Attitude,
Conditions,
Image and image processing.
|
|
|
|
|
|
|
Background setup examples:
>>> # No background, will use ccd_bgd_data = 0.
>>> bgd_algorithm = 'Constant'
>>> ccd_bgd_source = None
>>> # Constant background
>>> bgd_algorithm = 'Constant'
>>> ccd_bgd_source = 'Constant'
>>> ccd_bgd_data = 20.
>>> # Flight algorithm and bgd data
>>> bgd_algorithm = 'FlightBgd'
>>> ccd_bgd_source = 'telemetry'
>>> ccd_bgd_data = <list of telemetered BGDAVG values>
>>> # Flight algorithm and ACA DCC bgd data
>>> bgd_algorithm = 'FlightBgd'
>>> ccd_bgd_source = 'DCC'
>>> ccd_bgd_data = '2017:100' # fetch the ACA DCC nearest to this date
>>> # Dynamic bgd algorithm and ACA DCC bgd data
>>> bgd_algorithm = 'DynamBgd'
>>> % ccd_bgd_source = 'DCC' # use the default setting for ccd_bgd_data = the date of the simulation
>>> # Dynamic bgd algorithm and custom 1024x1024 DCC map scaled with temperature
>>> bgd_algorithm = 'DynamBgd'
>>> ccd_bgd_source = 'Custom_1024x1024'
>>> ccd_bgd_data = <custom 1024x1024 ndarray or ACAImage>
>>> t_ccd_ref = -14 # indicate that the custom bgd map was computed at -14C
>>> t_ccd = -5 # scale it with temperature to -5C
Running an annie simulation¶
Once all parameters are set and the stars are found and identified,
the simulation is ready to be performed. This is done using the
annie.annie.Spacecraft.run()
method, which initializes the
annie clock and processes all the s/c subsystems at each clock tick,
until the clock reaches the stop time specified by the user.
- The minimal setup requires the following settings:
the stop time of the simulation (stop parameter), and
a star catalog (an astropy Table, starcat parameter)
a commanded attitude.
With this minimum setup, the system will perform a full simulation (image and attitude data will be simulated). Image processing will be performed assuming the ACA DCC background taken at the date closest to the date of the simulation, and the flight algorithm will be used to subtract the background (average bgd value derived from the eight corner pixels):
>>> # Example 1 (This uses the get_att, get_starcat, and get_dither helper methods from mica.starcheck)
>>> from annie.annie import Spacecraft
>>> import astropy.units as u
>>> from mica.starcheck import get_att, get_starcheck, get_dither
>>> sc = Spacecraft()
>>> stop = 20 * u.s
>>> obsid = 8008
>>> sc.track_stars_setup(stop=stop,
att_cmd=get_att(obsid),
starcat=get_starcat(obsid),
dither=get_dither(obsid))
>>> sc.run()
or:
>>> # Example 2
>>> from annie.annie import Spacecraft
>>> import astropy.units as u
>>> from astropy.table import Table
>>> sc = Spacecraft()
>>> stop = 20 * u.s
>>> starcat = Table.read("""
slot type sz mag maxmag yang zang halfw
0 BOT 8x8 10.1 11.5 0.0 0.0 120
1 BOT 8x8 10.1 11.5 1000.0 0.0 120
2 BOT 8x8 10.1 11.5 0.0 1000.0 120
3 BOT 8x8 10.1 11.5 -1000.0 0.0 120
""", format='ascii', guess=False)
>>> sc.track_stars_setup(stop=stop,
starcat=starcat,
stars_source='table',
stars_data=starcat,
att_cmd=[0., 0., 0.])
>>> sc.run()
Exploring annie’s telemetry¶
Telemetry is collected by the telem
module by the
means of regularly executed tasks
defined for the Telem
class.
These tasks include (see Telemetry):
main_processing()
which is called every frame; it collects
the
SlotRecord
telemetry for each slot and stores it inannie.telem.Telem.slot_records
,the
StarDataRecord
telemetry for each slot and stores it inannie.telem.Telem.star_data_records
,
attitude_processing()
which is called every minor frame; it collects theAttitudeRecord
telemetry and stores it inannie.telem.Telem.att_records
.
Telemetry tables¶
The spacecraft telem
object has three sub-attributes that contain most of the
useful output from an annie simulation. These are mostly just tabularized versions
the full telemetry described above.
sc.telem.aca_slots
: dict of ACAStarDataRecord
tables keyed by slot
sc.telem.pcad_slots
: dict of PCAD starSlotRecord
info tables () keyed by slot
sc.telem.pcad_att
: PCADAttitudeRecord
info table
These attributes are the recommended way to access the annie simulation results.
The example below shows how to access these attributes to plot the y-angle centroids.
In most cases the telemetry from the first 8.2 seconds of simulation are
not interesting (where acquisition occurs), so we can just clip that using the
clip()
method:
>>> from annie import run_from_starcheck
>>> sc = run_from_starcheck(20201, stop=700)
>>> sc.telem.clip()
Now let’s plot the telemetry:
>>> import matplotlib.pyplot as plt
>>> %matplotlib
>>> aca_slot = sc.telem.aca_slots[3]
>>> plt.plot(aca_slot['time'], aca_slot['zag'])
>>> plt.xlabel('Time (sec)')
>>> plt.grid()
>>> plt.title('Z-angle (arcsec)')
The next example shows how to compute the offsets between the true and estimated attitudes:
>>> times = sc.telem.pcad_att['time']
>>> atts_true = sc.telem.pcad_att['att_true']
>>> atts_est = sc.telem.pcad_att['att_est']
>>> dr = []
>>> dp = []
>>> dy = []
>>> for att_true, att_est in zip(atts_true, atts_est):
>>> dq = att_true.dq(att_est)
>>> dr.append(dq.roll0 * 3600)
>>> dy.append(dq.yaw * 3600)
>>> dp.append(dq.pitch * 3600)
>>>
>>> plt.plot(times, dr)
>>> plt.ylabel('offset (arcsec)')
>>> plt.xlabel('Time (s)')
>>> plt.grid()
>>> plt.title('Delta roll')
Slot records¶
The telemetry records are dictionaries keyed by slot number, with values
that are lists containing the relevant records ordered by time. The example
below shows how to access the slot record telemetry that stores the
GS_loss_count
counter Kalman status, star residuals,
star magnitude, slot number, ACA function and a time stamp for each frame:
>>> sc.telem.slot_records.keys()
dict_keys([3, 4, 5, 6, 7])
>>> # The first two slot records for slot number 3
>>> sc.telem.slot_records[3][:2]
[<SlotRecord: slot=3 time=0.0 F_image=NULL_IMAGE>,
<SlotRecord: slot=3 time=1.025 F_image=NULL_IMAGE>]
>>> # Explore the content of an individual slot record
>>> sr = sc.telem.slot_records[3][10] # 10th record for slot number 3
>>> print(sr)
{'F_image': 'STAR',
'GS_loss_count': 0,
'Kalman_ok': True,
'clock': <ClockTime secs=10.250 ticks=640>,
'delta_y': 0.040003284291393326,
'delta_z': 0.076399486542315209,
'function': 'TRAK',
'mag': 9.2567258517843527,
'slot': 3,
'time': 10.249999999999998}
Plot the image function for slot number 7:
>>> import numpy as np
>>> F_images = np.array([sr.F_image for sr in sc.telem.slot_records[7]])
>>> times = np.array([sr.time for sr in sc.telem.slot_records[7]])
>>> state_codes = [(0, 'NULL_IMAGE'), (1, 'STAR')]
>>> vals = np.zeros_like(F_images)
>>> for state_code in state_codes:
... ok = F_images == state_code[1]
... vals[ok] = state_code[0]
>>> from Ska.Matplotlib import plot_cxctime
>>> plot_cxctime(times, vals, 'o--', state_codes=state_codes)
Star data records¶
To explore the star data use star_data_records
. Note
that the star data record telemetry starts at t = 1.025 sec
, as opposed
to the slot record telemetry that starts at t = 0 sec
:
>>> # Explore star data telemetry resulting from Example 1 above
>>> sc.telem.star_data_records.keys()
dict_keys([3, 4, 5, 6, 7])
>>> # The first two star data records for slot number 3
>>>sc.telem.star_data_records[3][:2]
[<StarDataRecord: slot=3 time=1.025 row0=46 col0=222>,
<StarDataRecord: slot=3 time=2.05 row0=511 col0=511>]
>>> # Explore the content of an individual slot record
>>> sdr = sc.telem.star_data_records[3][10] # 10th record for slot number 3
>>> print(sdr)
{'bgd': 17.0,
'bgd_avg': 17.0,
'bgd_rms': 13.714108945658715,
'bgd_status': array([ True, False, True, True, True, True, True, False], dtype=bool),
'brightest': True,
'clock': <ClockTime secs=11.275 ticks=704>,
'col': 245.49913455685868,
'col1': 250,
'fid': False,
'function': 'TRAK',
'halfwidth': 120,
'image': <ACAImage row0=66 col0=242
array([[ 8, 45, 5, 35, 119, 7, 5, 5],
[ 27, 89, 7, 5, 13, 5, 30, 35],
[ 41, 6, 23, 56, 121, 39, 17, 3],
[ 95, 12, 161, 479, 461, 198, 14, 11],
[ 6, 17, 188, 833, 863, 220, 44, 22],
[ 51, 12, 107, 397, 412, 108, 70, 165],
[ 28, 23, 43, 161, 69, 56, 40, 69],
[ 44, 35, 25, 9, 12, 24, 18, 37]])>,
'img_sum': 4753.3399205036621,
'last_sdr': <weakref at 0x7fa1325a6db8; to 'StarDataRecord' at 0x7fa1325b37b8>,
'mag': 9.2567258524020062,
'maxmag': 10.859,
'min_img_sum': 543.32441108392015,
'rate_c': 0.027156531569687559,
'rate_r': -0.023609485876363578,
'repeat_count': 0,
'row': 69.972698185568873,
'row1': 74,
'search_count': 4,
'size': 6,
'slot': 3,
'threshold': 10.859,
'time': 11.274999999999999,
'yag': -318.80588100432664,
'yag_cat': -318.30117934550685,
'zag': 1202.8794098096994,
'zag_cat': 1202.290747547197}
Plot the ACA function for slot number 3:
>>> import numpy as np
>>> funcs = np.array([sdr.function for sdr in sc.telem.star_data_records[3]])
>>> times = np.array([sdr.time for sdr in sc.telem.star_data_records[3]])
>>> state_codes = [(0, 'NONE'), (1, 'TRAK'), (2, 'SRCH'), (3, 'RACQ')]
>>> vals = np.zeros_like(funcs)
>>> for state_code in state_codes:
ok = funcs == state_code[1]
vals[ok] = state_code[0]
>>> from Ska.Matplotlib import plot_cxctime
>>> plot_cxctime(times, vals, 'o--', state_codes=state_codes)
Attitude records¶
The att_records
attribute is a list containing
an AttitudeRecord
for each minor frame. It allows for exploration
of the spacecraft attitude during the simulation. It contains the
time history of the commanded, true and estimated attitudes, their yaw,
pitch and roll components, and dither, true and estimated rates:
>>> # Access the 10th attitude record
>>> ar = sc.telem.attitude_records[10]
>>> print(ar)
{'att_cmd': <Quat q1=0.14961427 q2=0.49089671 q3=0.83147065 q4=0.21282047>,
'att_est': <Quat q1=0.14961408 q2=0.49089675 q3=0.83147077 q4=0.21282004>,
'att_true': <Quat q1=0.14961406 q2=0.49089675 q3=0.83147078 q4=0.21281999>,
'clock': <ClockTime secs=2.562 ticks=160>,
'last_att_record': <weakref at 0x7fa1325800e8; to 'AttitudeRecord' at 0x7fa1325e3ac8>,
'pitch_cmd': 0.0,
'pitch_dither': 0.18214420697121447,
'pitch_dither_rate': 0.071068381251204654,
'pitch_err': -0.018200254323126025,
'pitch_est': 0.16394395264808845,
'pitch_est_rate': 0.07108680873629852,
'pitch_true': 0.18401325204517213,
'pitch_true_rate': 0.071978393967360957,
'roll_cmd': 0.0,
'roll_dither': 0.0,
'roll_dither_rate': 0.0,
'roll_err': 0.0,
'roll_est': 0.0,
'roll_est_rate': 0.0,
'roll_true': 0.0,
'roll_true_rate': 0.0,
'time': 2.5624999999999996,
'yaw_cmd': 0.0,
'yaw_dither': 0.12879973380786744,
'yaw_dither_rate': 0.050258967404293226,
'yaw_err': -0.0128749648904041,
'yaw_est': 0.11592476891746334,
'yaw_est_rate': 0.05026548245743669,
'yaw_true': 0.13012066185289703,
'yaw_true_rate': 0.050902715648813428}
Kalman tracking¶
The Kalman status and the number of Kalman stars are collected
for each frame and stored in annie.telem.Telem.Kalman_status
and
annie.telem.Telem.n_Kalman_stars
. The example below illustrates that
there were enough Kalman stars in each slot and for each frame once the ACA
function changed from ‘SRCH’ to ‘TRAK’ (Kalman_status = True
;
see Star data records to learn how to access the ACA function data),
and that the actual number of Kalman stars for each fo these frames was
n_Kalman_stars = 5
:
>>> # Explore telemetry resulting from Example 1 above
>>> # Frame no. 7 is the last frame with ACA function equal 'SRCH'
>>> # while frame no. 8 is the first frame with ACA function equal 'TRAK'
>>> sc.telem.Kalman_status[7:9]
>>> [[False, False, False, False, False], [True, True, True, True, True]]
>>> # The number of Kalman stars was 5 in all frames
>>> # with ACA function equal 'TRAK'
>>> sc.telem.n_Kalman_stars
>>> [0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]