docs: def azel2radec(az_deg: float, el_deg: float,
                 lat_deg: float, lon_deg: float,
                 time: datetime) -> Tuple[float, float]:
      """
      converts azimuth, elevation to right ascension, declination
  
      Parameters
      ----------
  
      az_deg : float or numpy.ndarray of float
          azimuth (clockwise) to point [degrees]
  
      el_deg : float or numpy.ndarray of float
          elevation above horizon to point [degrees]
  
      lat_deg : float
          observer WGS84 latitude [degrees]
  
      lon_deg : float
          observer WGS84 longitude [degrees]
  
      time : datetime.datetime
          time of observation
  
      Results
      -------
  
      ra_deg : float or numpy.ndarray of float
          right ascension to target [degrees]
  
      dec_deg : float or numpy.ndarray of float
          declination of target [degrees]
  
      from D.Vallado Fundamentals of Astrodynamics and Applications
      p.258-259
      """
      az = atleast_1d(az_deg)
      el = atleast_1d(el_deg)
      lat = atleast_1d(lat_deg)
      lon = atleast_1d(lon_deg)
  
      if az.shape != el.shape:
          raise ValueError('az and el must be same shape ndarray')
      if not(lat.size == 1 and lon.size == 1):
          raise ValueError('need one observer and one or more  (az,el).')
      if ((lat < -90) | (lat > 90)).any():
          raise ValueError('-90 <= lat <= 90')
  
      az = radians(az)
      el = radians(el)
      lat = radians(lat)
      lon = radians(lon)
  # %% Vallado "algorithm 28" p 268
      dec = arcsin(sin(el) * sin(lat) + cos(el) * cos(lat) * cos(az))
  
      lha = arctan2(-(sin(az) * cos(el)) / cos(dec),
                    (sin(el) - sin(lat) * sin(dec)) / (cos(dec) * cos(lat)))
  
      lst = datetime2sidereal(time, lon)  # lon, ra in RADIANS
  
      """ by definition right ascension [0, 360) degrees """
      return degrees(lst - lha) % 360, degrees(dec)