UserContributedScripts: planetTracking.py

File planetTracking.py, 5.8 KB (added by jayce, 4 years ago)

Script to generate a planet tracking SDF.

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5Script to generate a STEPPED mode SDF to track a PyEphem Planet instance. 
6Valid targets are:
7 * Sun
8 * Mercury
9 * Venus
10 * Moon
11 * Mars
12 * Jupiter
13 * Saturn
14 * Uranus
15 * Neptune
16 * Pluto
17"""
18
19import os
20import re
21import sys
22import ephem
23import numpy
24import getopt
25
26from lsl.common import sdf
27from lsl.common.stations import lwa1
28
29
30def usage(exitCode=None):
31        print """planetTracking - Create a STEPPED mode observation to track a PyEphem
32Planet instance.  Valid targets are:
33 * Sun
34 * Mercury
35 * Venus
36 * Moon
37 * Mars
38 * Jupiter
39 * Saturn
40 * Uranus
41 * Neptune
42 * Pluto
43
44Usage: planetTracking.py [OPTIONS] Target YYYY/MM/DD HH:MM:SS.SSS
45
46Options:
47-h, --help                  Display this help information
48-u, --update-interval       Pointing update interval in seconds (Default = 60.0)
49-l, --obs-length            Duration of the observation in seconds (Default = 3600.0)
50-b, --beam                  Beam to use for the observation (Default = 2)
51-1, --frequency1            Frequency in MHz for Tuning #1 (Default = 37.9 MHz)
52-2, --frequency2            Frequency in MHz for Tuning #2 (Default = 74.0 MHz)
53-f, --filter                DRX filter code (Default = 7)
54-s, --spec-setup            Spectrometer setup to use, i.e., "32 6144{Stokes=IV}"
55                            (Default = do not use DR spectrometer)
56-o, --output                Filename to save the SDF to (Default = planetTracking.sdf)
57"""
58        if exitCode is not None:
59                sys.exit(exitCode)
60        else:
61                return True
62
63
64def parseOptions(args):
65        config = {}
66        # Command line flags - default values
67        config['update'] = 60.0
68        config['duration'] = 3600.0
69        config['beam'] = 2
70        config['freq1'] = 37.9e6
71        config['freq2'] = 74.0e6
72        config['filter'] = 7
73        config['spcSetup'] = [0, 0]
74        config['spcMetatag'] = ""
75        config['output'] = 'planetTracking.sdf'
76        config['args'] = []
77       
78        # Create the metatag regular expression to deal with spectrometer mode settings
79        metaRE = re.compile(r'\{.*\}')
80       
81        # Read in and process the command line flags
82        try:
83                opts, args = getopt.getopt(args, "hu:l:b:1:2:f:s:o:", ["help", "update-interval=", "obs-length=", "beam=", "frequency1=", "frequency2=", "filter=", "spec-setup=", "output="])
84        except getopt.GetoptError, err:
85                # Print help information and exit:
86                print str(err) # will print something like "option -a not recognized"
87                usage(exitCode=2)
88       
89        # Work through opts
90        for opt, value in opts:
91                if opt in ('-h', '--help'):
92                        usage(exitCode=0)
93                elif opt in ('-u', '--update-interval'):
94                        config['update'] = float(value)
95                elif opt in ('-l', '--obs-length'):
96                        config['duration'] = float(value)
97                elif opt in ('-b', '--beam'):
98                        config['beam'] = int(value)
99                elif opt in ('-1', '--frequency1'):
100                        config['freq1'] = float(value)*1e6
101                elif opt in ('-2', '--frequency2'):
102                        config['freq2'] = float(value)*1e6
103                elif opt in ('-f', '--filter'):
104                        config['filter'] = int(value)
105                elif opt in ('-s', '--spec-setup'):
106                        # Remove the ' marks
107                        value = value.replace("'", "")
108                        # Excise the metatags
109                        mtch = metaRE.search(value)
110                        if mtch is not None:
111                                metatag = mtch.group(0)
112                                value = metaRE.sub('', value)
113                        else:
114                                metatag = None
115                       
116                        config['spcSetup'] = [int(i) for i in value.lstrip().rstrip().split(None, 1)]
117                        config['spcMetatag'] = metatag
118                elif opt in ('-o', '--output'):
119                        config['output'] = value
120                else:
121                        assert False
122       
123        # Add in arguments
124        config['args'] = args
125       
126        # Validate
127        if config['beam'] not in (1, 2, 3, 4):
128                raise ValueError("Invalid beam assignment")
129        if config['freq1'] < 10e6 or config['freq1'] > 88e6:
130                raise ValueError("Invalid frequency assignment for tuning 1")
131        if config['freq2'] < 10e6 or config['freq2'] > 88e6:
132                raise ValueError("Invalid frequency assignment for tuning 2")
133        if config['filter'] not in (1, 2, 3, 4, 5, 6, 7):
134                raise ValueError("Invalid filter code")
135
136        # Return configuration
137        return config
138
139
140def main(args):
141        config = parseOptions(args)
142        target = config['args'][0]
143        if target in ('Sun', 'Mercury', 'Venus', 'Moon', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto'):
144                exec("pnt = ephem.%s()" % target)
145        else:
146                raise ValueError("Unknown target: %s" % target)
147       
148        # Observation start time
149        config['args'][1] = config['args'][1].replace('-', '/')
150        tStart = "%s %s" % (config['args'][1], config['args'][2])
151
152        # Create the SDF
153        observer = sdf.Observer("planetTracking.py Observer", 99)
154        session = sdf.Session("planetTracking.py Session", 1)
155        project = sdf.Project(observer, "planetTracking.py Project", 1, [session,])
156        obs1 = sdf.Stepped(target, target, tStart, config['filter'], RADec=False)
157        project.sessions[0].observations.append(obs1)
158        project.sessions[0].drxBeam = config['beam']
159        project.sessions[0].spcSetup = config['spcSetup']
160        project.sessions[0].spcMetatag = config['spcMetatag']
161
162        # Setup the observer to compute the position of the body
163        obs = lwa1.getObserver()
164        obs.date = tStart
165
166        # Go!
167        obs.date = tStart
168        pnt.compute(obs)
169        lastPos = (pnt.az*1.0, pnt.alt*1.0)
170       
171        tooFastWarning = True
172        for i in numpy.arange(0.0, config['duration'], config['update']):
173                obs.date = tStart
174                obs.date += (i + config['update']/2.0) / (3600.0*24.0)
175               
176                pnt.compute(obs)
177                az = float(pnt.az) * 180.0/numpy.pi
178                el = float(pnt.alt) *180.0/numpy.pi
179                if ephem.separation(lastPos, (pnt.az, pnt.alt)) > ephem.degrees('1:30:00'):
180                        if tooFastWarning:
181                                print "WARNING: Target has moved more than 1.5 degrees since last update"
182                                print "         Consider reducing the update interval"
183                                tooFastWarning = False
184                lastPos = (pnt.az*1.0, pnt.alt*1.0)
185               
186                stp = sdf.BeamStep(az, el, str(config['update']), config['freq1'], config['freq2'], RADec=False)
187                obs1.append(stp)
188       
189        # Write it out
190        if os.path.exists(config['output']):
191                raise RuntimeError("File '%s' already exists" % config['output'])
192        project.render(verbose=True)
193        fh = open(config['output'], 'w')
194        fh.write(project.render())
195        fh.close()
196
197
198if __name__ == "__main__":
199        main(sys.argv[1:])