Search code examples
astropy

Astropy: Inititializing a user-defined Coordinate Frame


I am developing an application for Raspberry Pi to control an amateur telescope on AltAzimutal mount.

The azimutal axis is not perfectly aligned with the zenith. In this case one can point onto 2 or 3 stars and find the transformation matrix between apparent telescope and equatorial coordinates. The method can be seen here. I want to implement this method with astropy, but I don't understand how I can define the reference frame of the tilted telescope.

I calculate the transformatin matrix and give it as an argument for the new frame. But I get an error.

Here is the code:

 # coding: utf-8

 """ Astropy coordinate class for the tilted telescope coordinate system """

from __future__ import division, print_function

# Third-party
import numpy as np
from numpy import cos, sin

from astropy.coordinates import frame_transform_graph
from astropy.coordinates.angles import rotation_matrix

import astropy.coordinates as coord
import astropy.units as u


__all__ = ["MyFrame"]


import astropy.coordinates as coord


class MyFrame(coord.BaseCoordinateFrame):
    """
    A topocentric spherical coordinate system defined by the telescope on tilted Altzimutal mount
     http://www.geocities.jp/toshimi_taki/aim/aim.htm    

    Parameters
    ----------
    matrix: the transformation matrix obtained by 2 stars method ( http://www.geocities.jp/toshimi_taki/aim/aim.htm)  
    representation : `BaseRepresentation` or None
        A representation object or None to have no data (or use the other keywords)
    Lambda : `Angle`, optional, must be keyword
        The longitude-like angle corresponding to Sagittarius' orbit.
    Beta : `Angle`, optional, must be keyword
        The latitude-like angle corresponding to Sagittarius' orbit.

    """
    default_representation = coord.UnitSphericalRepresentation

    frame_specific_representation_info = {
        'spherical': [coord.RepresentationMapping('lon', 'az'),
                      coord.RepresentationMapping('lat', 'alt'),
                      coord.RepresentationMapping('distance', 'distance')],
        'unitspherical': [coord.RepresentationMapping('lon', 'az'),
                          coord.RepresentationMapping('lat', 'alt')]
    }


    def __init__(self,matrix,*args, **kwargs):
        super(MyFrame, self).__init__(*args, **kwargs)
        self.matrix=matrix


# equatorial (ICRS )  to tilted telescope AltAz coordinates
@frame_transform_graph.transform(coord.FunctionTransform, coord.ICRS, MyFrame)
def equatorial_to_telescope(icrs_frame, telescope_frame):
    """ Compute the transformation from icrs spherical to
        topocentric telescope coordinates.
    """
    matrix=np.matrix(([1,0,0],[0,1,0],[0,0,1]))
    C0=icrs_frame.represent_as(coord.CartesianRepresentation).xyz.value

    l0=matrix.dot(C0)

    altAZ=coord.SkyCoord(x=l0[0,0],y=l0[0,1],z=l0[0,2],frame='altaz',representation='cartesian').represent_as(coord.UnitSphericalRepresentation)

    return MyFrame(az=altAZ.lon.to(u.deg),  alt=altAZ.lat.to(*u.deg))

Here is the call of this class:

import myFrame as fr
import astropy.coordinates as coord
import astropy.units as u
import numpy as np

matrix=np.matrix(([1,0,0],[0,1,0],[0,0,1]))

m=fr.MyFrame()
icrs = coord.ICRS(152.88572*u.degree, 11.57281*u.degree)
mfr=icrs.transform_to(m)

Here is the error code:

TypeError                                 Traceback (most recent call last)
<ipython-input-14-33f2cd1fa087> in <module>()
----> 1 mfr=icrs.transform_to(m)

/home/maksim/MyPython/astropy/coordinates/baseframe.pyc in transform_to(self, new_frame)
    839             msg = 'Cannot transform from {0} to {1}'
    840             raise ConvertError(msg.format(self.__class__, new_frame.__class__))
--> 841         return trans(self, new_frame)
    842 
    843     def is_transformable_to(self, new_frame):

/home/maksim/MyPython/astropy/coordinates/transformations.pyc in __call__(self, fromcoord, toframe)
    915                     frattrs[inter_frame_attr_nm] = attr
    916 
--> 917             curr_toframe = t.tosys(**frattrs)
    918             curr_coord = t(curr_coord, curr_toframe)
    919 

TypeError: __init__() takes at least 2 arguments (1 given)

I understand the error message: the definition of my constructor does not correspond to expectation of astropy BaseFrame.

How can I transfer extern matrix to BaseCoordinateFrame instance?


Solution

  • You don't need or want to override the __init__ on your frame class to include the transformation matrix as an argument. Instead, because an specific frame defined in your frame class depends on this matrix it should be defined as a FrameAttribute as demonstrated in the example in the docs: http://docs.astropy.org/en/stable/coordinates/frames.html#defining-a-new-frame

    Looking at those docs I can see that the purpose of defining frame attributes is not as clear as it could be. But in short, merely adding an __init__ argument tells the coordinate machinery nothing about the purpose of that argument / attribute--it doesn't in any way indicate that this is a defining parameter of frames in this class of frames. That's information that the framework needs to know about and keep track of.

    When you define matrix as a frame attribute on your class it will automatically set up an accessor for the attribute (i.e. self.matrix) and will also accept the matrix as an argument to the frame's initializer.

    One thing that I'm not sure this immediately supports is a FrameAttribute that is required to initialize the frame (usually each attribute has a default value). This could be implemented by a simple wrapper around the base __init__ though it also might not be a bad idea for a feature request.