Source code for scanner

# -*- coding: utf-8 -*-
"""
Scanner class implementation in Python

:Authors: LucaZampieri (2018)
         mdelvallevaro (2018)
"""

# # Imports
# Global imports
import numpy as np
import time
from scipy import optimize
import quaternion
# Local imports
import constants as const
import frame_transformations as ft
from satellite import Satellite
from source import Source
import helpers
from agis_functions import *


# fonctions used in the loop
[docs]def eta_angle(t, sat, source, FoV='centered'): """ | Function to minimize in the scanner. | See :meth:`agis_functions.observed_field_angles` :param FoV: [string] specify which Field of View to use """ Gamma_c = const.Gamma_c Cu_unit = source.unit_topocentric_function(sat, t) Su = ft.lmn_to_xyz(sat.func_attitude(t), Cu_unit) Su_x, Su_y, Su_z = Su[:] phi = np.arctan2(Su_y, Su_x) field_index = np.sign(phi) if FoV == 'centered': eta = phi elif FoV == 'preceding': eta = phi + Gamma_c / 2 elif FoV == 'following': eta = phi - Gamma_c / 2 else: raise ValueError('incorrect FoV argument.') return eta
[docs]def get_etas_from_phis(phi_a, phi_b, FoV): """ Tranform phis into etas using the field of view parameter :param phi_a: phi at the beginning of the interval :param phi_b: phi at the end of the interval :param FoV: [string] specify which Field of View we are using :returns: eta at the beginning and end of the inteval """ Gamma_c = const.Gamma_c if FoV == 'following': eta_a, eta_b = (phi_a - Gamma_c / 2, phi_b - Gamma_c / 2) elif FoV == 'preceding': eta_a, eta_b = (phi_a + Gamma_c / 2, phi_b + Gamma_c / 2) elif FoV == 'centered': eta_a, eta_b = (phi_a, phi_b) else: raise ValueError('Invalid FoV parameter') return eta_a, eta_b
[docs]def violated_contraints(eta_a, zeta_a, eta_b, zeta_b, zeta_limit): """ :returns: True if the contraints are violated and False otherwise """ if eta_a*eta_b >= 0: # check if f changes sign in [a,b] return True if np.abs(zeta_a + zeta_b)/2 > zeta_limit: # ~ |zeta|<= 0.5° return True if (np.abs(eta_a) > np.pi/2) & (np.abs(eta_b) > np.pi/2): return True return False
# Scanner class
[docs]class Scanner:
[docs] def __init__(self, zeta_limit=np.radians(0.5), double_telescope=True): """ :param zeta_limit: [rads] limitation of the Field of View in the across scan direction :param double_telescope: [bool] if true implements the scanner version with two telescopes (gaia-like) """ # Parameters self.zeta_limit = zeta_limit self.double_telescope = double_telescope # bool that indicates if there is the second telescope self.FoVs = ['preceding', 'following'] if double_telescope else ['centered'] # fields of view of scanner # Products self.obs_times = [] self.obs_times_FFoV = [] self.obs_times_PFoV = [] self.root_messages = [] self.eta_scanned = [] self.zeta_scanned = []
[docs] def reset(self, verbose=False): """ :action: empty all attribute lists from scanner before beginning new scanning period. :param verbose: [bool] If true will print messages """ self.obs_times.clear() self.obs_times_FFoV.clear() self.obs_times_PFoV.clear() self.root_messages.clear() self.eta_scanned.clear() self.zeta_scanned.clear() if verbose: print('Cleared variables!')
# Scan function
[docs] def scan(self, sat, source, ti, tf): """ Find the exact time in which the source is seen. :action: Find the observation time of the sources :param sat: [Satellite object] :param source: [Source object] :param ti & tf: [days] initial and end dates :returns: [float] time it took for the scan """ # print('Starting scan with time from {} to {} days'.format(ti, tf)) self.reset() t0 = time.time() # for timer time_step = sat.time_of_revolution/6 # need <= 6th of revolution time # Get list on which to loop if (tf - ti) > 10: day_list = get_interesting_days(ti, tf, sat, source, self.zeta_limit) t_list = generate_scanned_times_intervals(day_list, time_step) else: t_list = np.arange(ti, tf, time_step) t_old = 0 # Looping for t in t_list: # Check constraints if (t == t_old) & (t_old > 0): # print(t) phi_a, zeta_a = (phi_b, zeta_b) else: phi_a, zeta_a = observed_field_angles(source, sat.func_attitude(t), sat, t, double_telescope=False) phi_b, zeta_b = observed_field_angles(source, sat.func_attitude(t+time_step), sat, t+time_step, double_telescope=False) for FoV in self.FoVs: eta_a, eta_b = get_etas_from_phis(phi_a, phi_b, FoV) if violated_contraints(eta_a, zeta_a, eta_b, zeta_b, self.zeta_limit): continue x0, r = optimize.brentq(f=eta_angle, a=t, b=t+time_step, args=(sat, source, FoV), xtol=2e-20, rtol=8.881784197001252e-16, maxiter=100, full_output=True, disp=False) self.obs_times.append(x0) """if FoV == 'preceding': self.obs_times_PFoV.append(x0) elif FoV == 'following': self.obs_times_FFoV.append(x0) else: pass""" t_old = t+time_step # self.obs_times = list(np.sort(self.obs_times)) return time.time()-t0 # Total measured time
[docs] def compute_angles_eta_zeta(self, sat, source): """ Compute angles and remove 'illegal' observations (:math:`|zeta| > zeta_lim`) """ for t in self.obs_times: eta, zeta = observed_field_angles(source, sat.func_attitude(t), sat, t, self.double_telescope) if np.abs(zeta) >= self.zeta_limit: continue self.eta_scanned.append(eta) self.zeta_scanned.append(zeta)
[docs] def scanner_error(self): """ :return: mean error in the Along-scan direction """ if not self.eta_scanned: raise ValueError('No scanned angles in the scanner! Please scan' + ' and call compute_angles_eta_zeta(sat, source)') return np.mean(self.eta_scanned)
# End of file