Wednesday, June 8, 2011

Automated Astrophotography with Python - Part 2b

THE SKY6 UTILITIES
The next major functionality to add to the 'cMount' class is the ability to perform various calculations related to equatorial coordinates. All these functions are found in the UTILS class of the Sky6. As in previous posts, instead of showing the complete 'cMount' class listing, here I show only the changes to the listing presented in the previous post. The first listing shows the one new line that must be added to the class constructor ('__init__' method) to create an instance of the Sky6 UTILS class. Here is the listing for that change:
self.__UTIL = win32com.client.Dispatch("TheSky6.Utils")

The next listing shows the six new methods added to 'cMount' that call methods from the Sky6 UTILS class:
def getAngularSeparation(self,RA1,Dec1,RA2,Dec2):
    """Returns results of "ComputeAngularSeparation" method of UTILS"""
    return self.__UTIL.ComputeAngularSeparation(RA1,Dec1,RA2,Dec2)
    
def getPositionAngle(self,RA1,Dec1,RA2,Dec2):
    """Returns results of "ComputePositionAngle" method of UTILS"""
    return self.__UTIL.ComputePositionAngle(RA1,Dec1,RA2,Dec2)

def getAngleToDMS(self,angle):
    """Returns results of "ConvertAngleToDMS" method of UTILS"""
    return self.__UTIL.ConvertAngleToDMS(angle)

def get2000ToNow(self,RA,Dec):
    """Returns results of "Precess2000ToNow" method of UTILS"""
    return self.__UTIL.Precess2000ToNow(RA,Dec)

def getNowTo2000(self,RA,Dec):
    """Returns results of "PrecessNowTo2000" method of UTILS"""
    return self.__UTIL.PrecessNowTo2000(RA,Dec)

def getRADecToAzAlt(self,RA,Dec):
    """Returns results of "ConvertRADecToAzAlt" method of UTILS"""
    return self.__UTIL.ConvertRADecToAzAlt(RA,Dec)
The first two methods are used to compute the angular separation (in degrees) between two equatorial coordinates and to compute the position angle (measured counter-clockwise from true North) from one coordinate to the other. The method 'getAngleToDMS()' is used to compute the degrees, minutes, and seconds from an angle expressed as a float value. The next two methods are used to precess an equatorial coordinate between the current epoch and the year 2000 epoch or vice-versa. Finally, the 'getRADecToAzAlt()' method is used to generate altitude and azimuth for the Sky6's current time and location from an equatorial coordinate. Many more methods are available in the UTILS class and descriptions can be found in the Sky6's help section under 'Scripted Operation'.

cMOUNT UNIT TEST
The following listing shows the unit test code for this version of the 'cMount' class. After creating an instance of the class, the test attempts to locate 'Pollux' in the database. If successful, the equatorial coordinates for the star are found and the RA and Dec for both the current epoch and for the year 2000 epoch are printed out in Hours or Degrees, minutes, and seconds. This operation is repeated for 'Castor' then the separation and position angle between the two stars is found and printed to screen. Next, the object 'M95' is located and the the RA and DEC (epoch 2000) is found and printed to screen. The current epoch coordinates is then found and printed using the 'get2000ToNow()' method. The object's altitude and azimuth is then computed and printed out. As a final test the object 'M65' is located and the the RA and DEC (current epoch) is found and printed. The year 2000 epoch coordinates is then found and printed using the 'getNowTo2000()' method. The object's altitude and azimuth is then computed and printed out.
if __name__ == "__main__":
    
    # create an instance of the cMount object
    testMount = cMount()

    # test getAngleToDMS()
    obj1 = 'Pollux'
    if not testMount.findObject(obj1):
        coords1 = testMount.getCoordinates()
        print
        DMScoords = testMount.getAngleToDMS(coords1['RA Now'])
        print "%s RA  (current epoch) = %02.0fh %02.0fm %03.1fs" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords1['DEC Now'])
        print "%s Dec (current epoch) = %02.0fd %02.0f' %03.1f\"" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords1['RA J2000'])
        print "%s RA     (epoch 2000) = %02.0fh %02.0fm %03.1fs" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords1['DEC J2000'])
        print "%s Dec    (epoch 2000) = %02.0fd %02.0f' %03.1f\"" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])
    else:
        print "%s could not be found." % obj1

    obj2 = 'Castor'
    if not testMount.findObject(obj2):
        coords2 = testMount.getCoordinates()
        print
        DMScoords = testMount.getAngleToDMS(coords2['RA Now'])
        print "%s RA  (current epoch) = %02.0fh %02.0fm %03.1fs" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords2['DEC Now'])
        print "%s Dec (current epoch) = %02.0fd %02.0f' %03.1f\"" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords2['RA J2000'])
        print "%s RA     (epoch 2000) = %02.0fh %02.0fm %03.1fs" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords2['DEC J2000'])
        print "%s Dec    (epoch 2000) = %02.0fd %02.0f' %03.1f\"" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])
    else:
        print "%s could not be found." % obj2

    # test getAngularSeparation()
    separation = testMount.getAngularSeparation(coords1['RA Now'],
                    coords1['DEC Now'],coords2['RA Now'],coords2['DEC Now'])
    separation = testMount.getAngleToDMS(separation)
    print
    print "The separation between %s and %s is %02.0f deg %02.0f min" % \
          (obj1,obj2,separation[0],separation[1])

    # test getPositionAngle()
    angle = testMount.getPositionAngle(coords2['RA Now'],coords2['DEC Now'],
                                       coords1['RA Now'],coords1['DEC Now'])
    angle = testMount.getAngleToDMS(angle)
    print
    print "The postion angle from %s to %s is %02.0f deg %02.0f min" % \
          (obj1,obj2,angle[0],angle[1])

    obj1 = 'm95'
    if not testMount.findObject(obj1):
        # test get2000ToNow()
        coords1 = testMount.getCoordinates()
        print
        DMScoords = testMount.getAngleToDMS(coords1['RA J2000'])
        print "%s RA     (epoch 2000) = %02.0fh %02.0fm %02.0fs" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords1['DEC J2000'])
        print "%s Dec    (epoch 2000) = %02.0fd %02.0f' %02.0f\"" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])


        coords2 = testMount.get2000ToNow(coords1['RA J2000'],coords1['DEC J2000'])
        DMScoords = testMount.getAngleToDMS(coords2[0])
        print "%s RA  (current epoch) = %02.0fh %02.0fm %02.0fs" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords2[1])
        print "%s Dec (current epoch) = %02.0fd %02.0f' %02.0f\"" % (obj1,
                DMScoords[0],DMScoords[1],DMScoords[2])

        # test getRADecToAzAlt()
        print
        azAlt = testMount.getRADecToAzAlt(coords1['RA J2000'],
                                          coords1['DEC J2000'])
        azimuth = testMount.getAngleToDMS(azAlt[0])
        print "%s Azimuth  = %02.0fd %02.0fm %02.0fs" % (obj1,
                azimuth[0],azimuth[1],azimuth[2])
        altitude = testMount.getAngleToDMS(azAlt[1])
        print "%s Altitude = %02.0fd %02.0fm %02.0fs" % (obj1,
                altitude[0],altitude[1],altitude[2])
        print
    else:
        print "%s could not be found." % obj1

    obj2 = 'm65'
    if not testMount.findObject(obj2):
        # test getNowTo2000()
        coords1 = testMount.getCoordinates()
        print
        DMScoords = testMount.getAngleToDMS(coords1['RA Now'])
        print "%s RA  (current epoch) = %02.0fh %02.0fm %02.0fs" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords1['DEC Now'])
        print "%s Dec (current epoch) = %02.0fd %02.0f' %02.0f\"" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])


        coords2 = testMount.getNowTo2000(coords1['RA Now'],coords1['DEC Now'])
        DMScoords = testMount.getAngleToDMS(coords2[0])
        print "%s RA     (epoch 2000) = %02.0fh %02.0fm %02.0fs" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])
        DMScoords = testMount.getAngleToDMS(coords2[1])
        print "%s Dec    (epoch 2000) = %02.0fd %02.0f' %02.0f\"" % (obj2,
                DMScoords[0],DMScoords[1],DMScoords[2])

        # test getRADecToAzAlt()
        print
        azAlt = testMount.getRADecToAzAlt(coords2[0],coords2[1])
        azimuth = testMount.getAngleToDMS(azAlt[0])
        print "%s Azimuth  = %02.0fd %02.0fm %02.0fs" % (obj2,
                azimuth[0],azimuth[1],azimuth[2])
        altitude = testMount.getAngleToDMS(azAlt[1])
        print "%s Altitude = %02.0fd %02.0fm %02.0fs" % (obj2,
                altitude[0],altitude[1],altitude[2])
        print
    else:
        print "%s could not be found." % obj2
RUNNING THE SCRIPT
As before, testing this version of the 'cMount' class is simply a matter of loading the source code into the Python IDE and running the module by hitting the F5 key. If the Sky6 is not already running, it will be loaded before the unit test executes. The source listing for 'cMount' can be downloaded from cMount_2b.zip. Experiment with the script by running it multiple times and selecting different objects for The Sky6 to locate and display information about.

WHAT'S NEXT?
In the next post I will complete the 'cMount' class by introducing methods that allow the script to control pointing of the telescope and syncing the the scope with a particular point in the sky. I will also create a new unit test listing to verify correct operation of the features added to this class.

CLICK HERE FOR NEXT POST IN THIS SERIES

No comments:

Post a Comment