Ejemplo n.º 1
0
def test_hocoord():
    # Float and string inputs
    altaz = ho_coord(alt=90, az=180, time='2020-04-01 12:00:00')
    # Quantity and Time inputs
    altaz = ho_coord(alt=90 * u.deg,
                     az=180 * u.deg,
                     time=Time('2020-04-01 12:00:00'))
    assert isinstance(altaz, AltAz)
    assert altaz.az.deg == 180.0
    assert altaz.alt.deg == 90.0
Ejemplo n.º 2
0
 def beam_values(self, coords, time):
     """
         :param coords:
         :type coords: :class:`~astropy.coordinates.ICRS` or 
             :class:`~astropy.coordinates.SkyCoord`
         :param time:
         :type time: :class:`~astropy.time.Time`
     """
     if not isinstance(coords, (ICRS, SkyCoord)):
         raise TypeError('coords should be ICRS or SkyCoord object')
     if not isinstance(time, Time):
         raise TypeError('time should be Time object')
     # Real pointing
     if self.beamsquint:
         el = desquint_elevation(elevation=self.elana,
                                 opt_freq=self.squint_freq)
     else:
         el = self.elana.copy()
     az, el = analog_pointing(self.azana, el)
     log.info('Effective analog pointing=({}, {})'.format(az, el))
     # Array factor
     phase_center = ho_coord(az=az, alt=el, time=time)
     altazcoords = toAltaz(skycoord=coords, time=time)
     arrfac = self.array_factor(phase_center=phase_center,
                                coords=altazcoords,
                                antpos=ma_antpos(rot=self._rot))
     # Antenna Gain
     antgain = self.ant_gain(coords=coords, time=time)
     anagain = arrfac * antgain
     log.info('Anabeam (rot {}) computed for {} pixels.'.format(
         self._rot % 60, anagain.size))
     return anagain
Ejemplo n.º 3
0
def test_toradec():
    with pytest.raises(TypeError):
        radec = to_radec(1.)
    altaz = ho_coord(alt=90, az=180, time='2020-04-01 12:00:00')
    radec = to_radec(altaz)
    assert isinstance(radec, ICRS)
    assert radec.ra.deg == pytest.approx(12.22, 1e-2)
    assert radec.dec.deg == pytest.approx(47.27, 1e-2)
Ejemplo n.º 4
0
    def beam_values(self, coords, time):
        """
            :param coords:
            :type coords: :class:`~astropy.coordinates.ICRS` or 
                :class:`~astropy.coordinates.SkyCoord`
            :param time:
            :type time: :class:`~astropy.time.Time`
        """
        if not isinstance(coords, (ICRS, SkyCoord)):
            raise TypeError('coords should be ICRS or SkyCoord object')
        if not isinstance(time, Time):
            raise TypeError('time should be Time object')

        # Build the Mini-Array 'summed' response
        abeams = {}
        for ma in self.ma:
            rot = ma_info['rot'][ma_info['ma'] == ma][0]
            if str(rot % 60) not in abeams.keys():
                ana = ABeam(freq=self.freq,
                            polar=self.polar,
                            azana=self.azana,
                            elana=self.elana,
                            ma=ma)
                ana.beamsquint = self.beamsquint
                anavals = ana.beam_values(coords=coords, time=time)
                abeams[str(rot % 60)] = anavals.copy()
            if not 'summa' in locals():
                summa = abeams[str(rot % 60)]
            else:
                summa += abeams[str(rot % 60)]
        # Array factor
        phase_center = ho_coord(az=self.azdig, alt=self.eldig, time=time)
        altazcoords = toAltaz(skycoord=coords, time=time)
        arrfac = self.array_factor(phase_center=phase_center,
                                   coords=altazcoords,
                                   antpos=ma_pos[np.isin(
                                       ma_info['ma'], self.ma)])
        # Arrayfactor * summed MA response
        digigain = arrfac * summa
        log.info('Digibeam computed for {} pixels.'.format(digigain.size))
        return digigain
Ejemplo n.º 5
0
    def array_factor(self, az, el, antpos, freq):
        r""" Computes the array factor :math:`\mathcal{A}` (i.e.
            the far-field radiation pattern obtained for an array
            of :math:`n_{\rm ant}` radiators).

            .. math::
                \mathcal{A} = \left| \sum_{n_{\scriptscriptstyle \rm ant}} e^{2 \pi i \frac{\nu}{c} (\varphi_0 - \varphi)} \right|^2

            .. math::
                \varphi = \underset{\scriptstyle n_{\scriptscriptstyle \rm ant}\, \times\, 3}{\mathbf{P}_{\rm ant}} \cdot \pmatrix{
                    \cos(\phi)\cos(\theta)\\
                    \sin(\phi)\cos(\theta)\\
                    \sin(\theta)
                }

            .. math::
                \varphi_0 = \underset{\scriptstyle n_{\scriptscriptstyle \rm ant}\, \times\, 3}{\mathbf{P}_{\rm ant}} \cdot \pmatrix{
                    \cos(\phi_0)\cos(\theta_0)\\
                    \sin(\phi_0)\cos(\theta_0)\\
                    \sin(\theta_0)
                }

            :math:`\mathbf{P}_{\rm ant}` is the antenna position
            matrix, :math:`\phi` and :math:`\theta` are the sky
            local coordinates (azimuth and elevation respectively)
            gridded on a HEALPix representation, whereas 
            :math:`\phi_0` and :math:`\theta_0` are the pointing
            direction in local coordinates.

            :param az:
                Pointing azimuth (in degrees if `float`)
            :type az: `float` or :class:`~astropy.units.Quantity`
            :param el:
                Pointing elevation (in degrees if `float`)
            :type el: `float` or :class:`~astropy.units.Quantity`
            :param antpos:
                Antenna positions shaped as (n_ant, 3)
            :type antpos: :class:`~numpy.ndarray`
            :param freq:
                Frequency (in MHz if `float`)
            :type freq: `float` or :class:`~astropy.units.Quantity`

            :returns: Array factor
            :rtype: :class:`~numpy.ndarray`

        """
        def get_phi(az, el, antpos):
            """ az, el in radians
            """
            xyz_proj = np.array(
                [np.cos(az) * np.cos(el),
                 np.sin(az) * np.cos(el),
                 np.sin(el)])
            antennas = np.array(antpos)
            phi = np.dot(antennas, xyz_proj)
            return phi

        if not isinstance(az, u.Quantity):
            az *= u.deg
        if not isinstance(el, u.Quantity):
            el *= u.deg

        self.phase_center = to_radec(ho_coord(az=az, alt=el, time=self.time))

        phi0 = get_phi(az=[az.to(u.rad).value],
                       el=[el.to(u.rad).value],
                       antpos=antpos)
        phi_grid = get_phi(az=self.ho_coords.az.rad,
                           el=self.ho_coords.alt.rad,
                           antpos=antpos)
        nt = ne.set_num_threads(ne._init_num_threads())
        delay = ne.evaluate('phi_grid-phi0')
        coeff = 2j * np.pi / wavelength(freq).value

        if self.ncpus == 1:
            # Normal
            af = ne.evaluate('sum(exp(coeff*delay),axis=0)')
        # elif self.ncpus == 'numba':
        #     af = perfcompute(coeff * delay)
        else:
            # Multiproc
            af = np.sum(mp_expo(self.ncpus, coeff, delay), axis=0)

        #return np.abs(af * af.conjugate())
        return np.real(af * af.conjugate())
Ejemplo n.º 6
0
def plotPointing(altaza=None, altazb=None, sourceName=None):
    """
    """
    fig, axs = plt.subplots(2 if sourceName is None else 3,
                            1,
                            sharex=True,
                            figsize=(15, 10))
    fig.subplots_adjust(hspace=0)

    if altaza is not None:
        if not altaza.endswith('.altazA'):
            raise TypeError('Wrong file format for altaza.')
        title = basename(altaza).replace('.altazA', '')
        aza = readPointing(altaza)
        azaTime = Time(aza['time'])
        tmin = azaTime[0]
        tmax = azaTime[-1]
        for abeam in np.unique(aza['anabeam']):
            mask = aza['anabeam'] == abeam
            axs[0].plot(
                azaTime[mask]
                [:-1].datetime,  # Do not show last pointing / back to zenith
                aza['az'][mask][:-1],
                linewidth='5.5',
                label=f'Analog requested (#{abeam})')
            axs[0].plot(azaTime[mask][:-1].datetime,
                        aza['az_cor'][mask][:-1],
                        linewidth='3',
                        label=f'Analog corrected (#{abeam})')
            axs[1].plot(azaTime[mask][:-1].datetime,
                        aza['el'][mask][:-1],
                        linewidth='5.5',
                        label=f'Analog requested (#{abeam})')
            axs[1].plot(azaTime[mask][:-1].datetime,
                        aza['el_cor'][mask][:-1],
                        linewidth='3',
                        label=f'Analog corrected (#{abeam})')
            axs[1].plot(azaTime[mask][:-1].datetime,
                        aza['el_eff'][mask][:-1],
                        linewidth='2',
                        label=f'Analog beamsquint corrected (#{abeam})')

    if altazb is not None:
        if not altazb.endswith('.altazB'):
            raise TypeError('Wrong file format for altazb.')
        title = basename(altazb).replace('.altazB', '')
        azb = readPointing(altazb)
        azbTime = Time(azb['time'])
        tmin = azbTime[0]
        tmax = azbTime[-1]
        for dbeam in np.unique(azb['digibeam']):
            mask = azb['digibeam'] == dbeam
            axs[0].plot(azbTime[mask].datetime,
                        azb['az'][mask],
                        linewidth='1',
                        label=f'Numeric (#{dbeam})')
            axs[1].plot(azbTime[mask].datetime,
                        azb['el'][mask],
                        linewidth='1',
                        label=f'Numeric (#{dbeam})')

    if (altaza is None) and (altazb is None):
        raise ValueError('At least one pointing file should be given.')

    if sourceName is not None:
        srcTime, srcAz, srcEl = altazProfile(sourceName=sourceName,
                                             tMin=tmin,
                                             tMax=tmax,
                                             dt=(tmax - tmin) / 20. -
                                             TimeDelta(0.5, format='sec'))
        axs[0].plot(srcTime.datetime,
                    srcAz,
                    color='black',
                    linestyle='--',
                    alpha=0.8,
                    label=f'{sourceName}')
        axs[1].plot(srcTime.datetime,
                    srcEl,
                    color='black',
                    linestyle='--',
                    alpha=0.8,
                    label=f'{sourceName}')

        if altaza is not None:
            for abeam in np.unique(aza['anabeam']):
                mask = aza['anabeam'] == abeam
                analog = ho_coord(alt=aza['el'][mask][:-1],
                                  az=aza['az'][mask][:-1],
                                  time=azaTime[mask][:-1])
                analog_cor = ho_coord(alt=aza['el_cor'][mask][:-1],
                                      az=aza['az_cor'][mask][:-1],
                                      time=azaTime[mask][:-1])
                analog_bscor = ho_coord(alt=aza['el_eff'][mask][:-1],
                                        az=aza['az_cor'][mask][:-1],
                                        time=azaTime[mask][:-1])
                source = toAltaz(skycoord=getSource(name=sourceName,
                                                    time=azaTime[mask][:-1]),
                                 time=azaTime[mask][:-1])
            axs[2].plot(azaTime[mask][:-1].datetime,
                        source.separation(analog).deg,
                        label=f'Analog (#{abeam})')
            axs[2].plot(azaTime[mask][:-1].datetime,
                        source.separation(analog_cor).deg,
                        label=f'Analog corrected (#{abeam})')
            axs[2].plot(azaTime[mask][:-1].datetime,
                        source.separation(analog_bscor).deg,
                        label=f'Analog beamsquint corrected (#{abeam})')

        if altazb is not None:
            for dbeam in np.unique(azb['digibeam']):
                mask = azb['digibeam'] == dbeam
                numeric = ho_coord(alt=azb['el'][mask],
                                   az=azb['az'][mask],
                                   time=azbTime[mask])
                source = toAltaz(skycoord=getSource(name=sourceName,
                                                    time=azbTime[mask]),
                                 time=azbTime[mask])
            axs[2].plot(azbTime[mask].datetime,
                        source.separation(numeric).deg,
                        label=f'Numeric (#{dbeam})')

        axs[2].set_ylabel(f'Separation from {sourceName} (deg)')
        axs[2].legend()
        axs[2].set_xlabel(f'UTC Time (since {tmin.iso})')
    else:
        axs[1].set_xlabel(f'UTC Time (since {tmin.iso})')

    axs[0].set_title('Pointing - ' + title)
    axs[0].set_ylabel('Azimuth (deg)')
    axs[0].legend()
    axs[1].set_ylabel('Elevation (deg)')
    axs[1].legend()
    plt.show()