Source code for sofia_redux.scan.simulation.scan_patterns.lissajous

# Licensed under a 3-clause BSD style license - see LICENSE.rst

from astropy import units
import numpy as np

from sofia_redux.scan.coordinate_systems.coordinate_2d import Coordinate2D
from sofia_redux.scan.coordinate_systems.equatorial_coordinates import (
    EquatorialCoordinates)
from sofia_redux.scan.simulation.scan_patterns.constant_speed import (
    to_constant_speed)

__all__ = ['lissajous_offset', 'lissajous_pattern_equatorial']


[docs] def lissajous_offset(width, height, t_interval, ratio=np.sqrt(2), delta=np.pi * units.Unit('radian') / 2, n_oscillations=20, oscillation_period=10 * units.Unit('second'), constant_speed=False): """ Create a Lissajous scan pattern in offset coordinates. The two-dimensions Lissajous pattern is of the following form:: x = width.sin(a + delta) y = height.sin(b + delta) a = 2.pi.t/oscillation_period b = 2.pi.ratio.t/oscillation_period The distance between samples (speed) is maximal at the origin and minimal near the edges of the box, which also means the map is under-sampled near the center. An approximation of the pattern using a constant speed for all samples can be achieved by setting `constant_speed` to `True`. Parameters ---------- width : units.Quantity The angular spatial width of the scan. height : units.Quantity The angular spatial height of the scan. t_interval : units.Quantity The time interval between sampling points. ratio : float, optional Determines the number of "lobes" in the lissajous curves relating to width/height. For example 5/4 produces a curve with 5 lobes in the x-direction, and 4 in the y-direction. Irrational numbers result in perfect coverage over a long time span. delta : units.Quantity, optional The angular value giving the apparent rotation as if viewed from a third axis. Any non-zero value results in curve rotated to the left-right or up-down depending on `ratio`. n_oscillations : int or float, optional The number of curve oscillations. oscillation_period : units.Quantity, optional The time for the curve to complete a single oscillation. Note that the scan length (time) will be `n_oscillations` * `oscillation_period`. constant_speed : bool, optional If `True`, return a pattern where the speed between each sample point is equal. Returns ------- pattern : Coordinate2D The elevation/cross-elevation scan pattern sampled at `t_interval`. """ fx = 1.0 fy = ratio * fx period_distance = 2 * np.pi * units.Unit('radian') scan_time = n_oscillations * oscillation_period nt = int(np.ceil((scan_time / t_interval).decompose().value)) t = np.arange(nt) * t_interval rt = period_distance / oscillation_period ax = rt * fx * t ay = rt * fy * t x = width * np.sin(ax + delta) / 2 y = height * np.sin(ay + delta) / 2 pattern = Coordinate2D(np.stack([x, y])) if constant_speed: pattern = to_constant_speed(pattern) return pattern
[docs] def lissajous_pattern_equatorial(center, t_interval, **kwargs): """ Create a Lissajous scan pattern in equatorial coordinates. Please see :func:`lissajous_offset` for a description of the available Lissajous parameters. Parameters ---------- center : units.Quantity or EquatorialCoordinates The center of the pattern in equatorial coordinates. t_interval : units.Quantity The sampling interval between output points. kwargs : dict, optional A list of optional keyword arguments to pass into :func:`lissajous_offset`. Returns ------- pattern : EquatorialCoordinates The equatorial scan pattern sampled at `t_interval`. """ if 'width' in kwargs: width = kwargs['width'] else: width = 2 * units.Unit('arcmin') if 'height' in kwargs: height = kwargs['height'] else: height = 2 * units.Unit('arcmin') if 'delta' in kwargs: delta = kwargs['delta'] else: delta = np.pi * units.Unit('radian') / 2 if 'ratio' in kwargs: ratio = kwargs['ratio'] else: ratio = np.sqrt(2) if 'n_oscillations' in kwargs: n_oscillations = kwargs['n_oscillations'] else: n_oscillations = 20 if 'oscillation_period' in kwargs: oscillation_period = kwargs['oscillation_period'] else: oscillation_period = 10 * units.Unit('second') if 'constant_speed' in kwargs: constant_speed = kwargs['constant_speed'] else: constant_speed = False equatorial_offset = lissajous_offset(width, height, t_interval, ratio=ratio, delta=delta, n_oscillations=n_oscillations, oscillation_period=oscillation_period, constant_speed=constant_speed) equatorial = EquatorialCoordinates(center) equatorial.add(equatorial_offset) return equatorial