Example #1
0
    def compute(self, freq, time, ra=None, dec=None):
        """ Compute UVW for a given time with an array phased
            towards (ra, dec).
            If ra and dec are None, local zenith is assumed.

            If uvw has already been calculated, the new values
            are stacked to the previous ones, as for a tracking.

            Parameters
            ----------
            ra : float
                Right Ascension in degrees
            dec : float
                Declination in degrees
            time : `astropy.time.Time`
                Time at which observation happened
            freq : float
                Frequency in MHz 

            Returns
            -------
            self.uvw : `np.ndarray`
                Shape (time, freq, nant*nant, 3)
        """
        if (ra is None) and (dec is None):
            ra, dec = eq_zenith(time=time, location=self.instru.array_position)

        self.wavel = wavelength(freq)

        uvw = np.zeros((1, self.wavel.size, self.bsl.shape[0], 3))

        # Prepare the transformation matrices
        rot_cel = self._celestial()
        rot_uvw = self._uvwplane(time=time, ra=ra, dec=dec)

        # Initialize the UVW array
        uvw = np.zeros((1, self.instru.n_ant, self.instru.n_ant, 3))

        # Perform UVW computation for each baseline and frequency
        xi = self.instru.tri_x
        yi = self.instru.tri_y
        dpos = self.positions[xi] - self.positions[yi]
        xyz = rot_cel * np.matrix(dpos).T
        uvw_k = rot_uvw * xyz
        uvw[0, xi, yi, :] = uvw_k.T
        uvw[0, yi, xi, :] = -uvw_k.T
        # uvw = uvw[:, np.newaxis, ...] /\
        #     self.wavel[:, np.newaxis, np.newaxis, np.newaxis]
        uvw = uvw[:, np.newaxis, ...]
        # Stack the UVW coordinates by time
        if self.uvw is None:
            self.uvw = uvw
        else:
            self.uvw = np.vstack((self.uvw, uvw))

        return
Example #2
0
 def freq(self, f):
     if f is not None:
         if isinstance(f, np.ndarray):
             pass
         elif isinstance(f, list):
             f = np.array(f)
         else:
             f = np.array([f])
         self._freq = f
         self.wavel = wavelength(f)
     else:
         self._freq = None
     return
Example #3
0
 def _uvplot(self, freq=None):
     """ Return UV for plotting purposes
     """
     if freq is None:
         fid = 0
     else:
         fid = np.argmin(np.abs(self.wavel - wavelength(freq)))
     uvw_f = self.uvw[:, fid, ...]
     # dont show autocorrelations
     mask = (uvw_f[..., 0] != 0.) & (uvw_f[..., 1] != 0.)
     u = uvw_f[..., 0][mask]
     v = uvw_f[..., 1][mask]
     #u = np.hstack((-u, u))
     #v = np.hstack((-v, v))
     return u, v
Example #4
0
 def uvw_lambda(self, frequencies):
     """
     """
     if self.uvw is None:
         raise Exception('Run compute() before.')
     if self._uvw.shape[1] != 1:
         warnings.warn('uvw_lambda() has previously been computed.')
         return
     if isinstance(frequencies, (int, np.integer))\
         or isinstance(frequencies, (float, np.inexact)):
         frequencies = [frequencies]
     if not isinstance(frequencies, np.ndarray):
         frequencies = np.array(frequencies)
     self.wavel = wavelength(frequencies)
     self._uvw = self._uvw / self.wavel[np.newaxis, :, np.newaxis,
                                        np.newaxis, np.newaxis]
     return
Example #5
0
 def wave_vector(self, frequency):
     """ Compute the wave vector k = 2 pi / lambda
     """
     k = 2. * np.pi / wavelength(frequency)
     return k
Example #6
0
    def make_nearfield(self, filename='', radius=300, npix=128):
        """
            :param radius:
                Radius of nearfield in meters
            :type radius: float, optional
            :param npix:
                Size in pixels of the image
            :type npix: int, optional
        """
        import matplotlib.pyplot as plt
        from matplotlib.colorbar import ColorbarBase
        from matplotlib.ticker import LinearLocator
        from matplotlib.colors import Normalize
        from matplotlib.cm import get_cmap
        from mpl_toolkits.axes_grid1.inset_locator import inset_axes
        antpos = self.array.ma_enu.copy()

        # Compute the delays at the ground
        z = np.average(antpos[:, 2]) + 1
        x = np.linspace(-radius, radius, npix)
        y = np.linspace(-radius, radius, npix)
        posx, posy = np.meshgrid(x, y)
        delay = (antpos[:, 0][:, None, None] - posx[None]) ** 2 \
            + (antpos[:, 1][:, None, None] - posy[None]) ** 2 \
            + (antpos[:, 2][:, None, None] - z) ** 2
        delay = np.sqrt(delay)

        # Compute delays between antenna pairs
        k = 0
        nant = self.array.antennas.size
        dd = np.zeros((int(nant * (nant - 1) / 2 + nant), npix, npix))
        for i in range(nant):
            for j in range(i, nant):
                dd[k] = np.array([delay[j] - delay[i]])
                k += 1

        # Multi-frequencies
        vis = np.mean(self.vis, axis=0)  # mean in time
        vis_i = 0.5 * (vis[..., 0] + vis[..., 3])
        j2pi = 2.j * np.pi
        nearfield = 0
        n = vis_i.shape[0]
        for j in range(n):
            v = vis_i[j, self.array.tri_x, self.array.tri_y][:, None, None]
            d = dd[None, ...]
            lamb = wavelength(self.freq[j])
            # Multiproc
            h = v * mp_expo_nf(npix, self.ncpus, d, lamb)
            # Slow
            # h = ne.evaluate('v*exp(j2pi*d/lamb)')
            nearfield += h
        nearfield = np.sum(np.abs(nearfield[0] / len(self.freq)),
                           axis=0)  # /mean

        # Plot
        loc_buildings_enu = np.array([[27.75451691, -51.40993459, 7.99973228],
                                      [20.5648047, -59.79299576, 7.99968629],
                                      [167.86485612, 177.89170175,
                                       7.99531119]])
        fig, ax = plt.subplots(figsize=(10, 10))
        nearfield_db = 10 * np.log10(nearfield)
        ax.imshow(np.fliplr(nearfield_db),
                  cmap='YlGnBu_r',
                  extent=[-radius, radius, -radius, radius])
        # Colorbar
        cax = inset_axes(
            ax,
            width='5%',
            height='100%',
            loc='lower left',
            bbox_to_anchor=(1.05, 0., 1, 1),
            bbox_transform=ax.transAxes,
            borderpad=0,
        )
        cb = ColorbarBase(cax,
                          cmap=get_cmap(name='YlGnBu_r'),
                          orientation='vertical',
                          norm=Normalize(vmin=np.min(nearfield_db),
                                         vmax=np.max(nearfield_db)),
                          ticks=LinearLocator())
        cb.solids.set_edgecolor('face')
        cb.set_label('dB')
        cb.formatter.set_powerlimits((0, 0))
        # Array info
        ax.scatter(self.array.ma_enu[:, 0],
                   self.array.ma_enu[:, 1],
                   color='tab:red')
        ax.scatter(loc_buildings_enu[:, 0],
                   loc_buildings_enu[:, 1],
                   color='tab:orange')
        for i in range(self.array.ant_names.size):
            ax.text(self.array.ma_enu[i, 0], self.array.ma_enu[i, 1],
                    ' ' + self.array.ant_names[i].replace('MR', ''))
        ax.set_xlabel(r'$\Delta x$ (m)')
        ax.set_ylabel(r'$\Delta y$ (m)')
        obstime = self.cross.time[0] + (self.cross.time[-1] -
                                        self.cross.time[0]) / 2.
        ax.set_title('{}'.format(obstime.isot))
        plt.savefig(filename, dpi=300, bbox_inches='tight')
        return
Example #7
0
    def make_psf(self, npix=None, fi=None):
        """ Make the PSF regarding the UV distribution

            :param npix:
                Size in pixels of the image
            :type npix: int, optional
            :param fi:
                Frequency index
            :type fi: int, optional
        """
        from astropy.modeling.models import Gaussian2D
        from astropy.modeling.fitting import LevMarLSQFitter

        print('\tMaking PSF')
        if fi is None:
            fi = self._fi
        if npix is None:
            npix = self.npix * 2
        na = np.newaxis

        # Average over time
        uvw = np.mean(self.uvw, axis=0)
        # Flatten the array
        uvw = uvw[:, self.array.tri_y, self.array.tri_x, :]
        # Transform UVW in lambdas units, take fi frequency
        uvw = uvw[fi, ...] / wavelength(self.freq[fi, na, na])

        # Prepare l, m grid
        lm_psf = np.cos(np.radians(90 - self.fov))
        l = np.linspace(-lm_psf, lm_psf, npix)
        m = np.linspace(lm_psf, -lm_psf, npix)
        lg, mg = np.meshgrid(l, m)

        # Make the TF of UV distribution
        u = uvw[..., 0][:, na, na]
        v = uvw[..., 1][:, na, na]

        # Slow
        # expo = np.exp(
        #     2j * np.pi * (u * lg[na, ...] + v * mg[na, ...])
        # )
        # Faster
        # lg = lg[na, ...]
        # mg = mg[na, ...]
        # pi = np.pi
        # expo = ne.evaluate('exp(2j*pi*(u*lg+v*mg))')
        # psf = np.real(
        #     np.mean(
        #         expo,
        #         axis=0
        #     )
        # )
        # Mutliprocessing
        expo = mp_expo(npix, self.ncpus, lg, mg, u, v)
        psf = np.real(np.mean(expo, axis=0))
        self.psf = psf / psf.max()

        # Get clean beam
        print('\tComputing clean beam')
        # Put most of the PSF to 0 to help the fit
        simple_psf = self.psf.copy()
        simple_psf[self.psf <= np.std(self.psf)] = 0
        nsize = int(simple_psf.shape[0])
        fit_init = Gaussian2D(amplitude=1,
                              x_mean=npix / 2,
                              y_mean=npix / 2,
                              x_stddev=0.2,
                              y_stddev=0.2)
        fit_algo = LevMarLSQFitter()
        yi, xi = np.indices(simple_psf.shape)
        gaussian = fit_algo(fit_init, xi, yi, simple_psf)
        clean_beam = gaussian(xi, yi)
        clean_beam /= clean_beam.max()
        self.clean_beam = clean_beam[int(npix / 2 / 2):int(npix / 2 * 3 / 2),
                                     int(npix / 2 / 2):int(npix / 2 * 3 / 2)]
        return
Example #8
0
    def plot_dirty(self, output='plot', altazdir=None, **kwargs):
        """
        """
        obstime = self.cross.time[0] + (self.cross.time[-1] -
                                        self.cross.time[0]) / 2.

        if altazdir is not None:
            # Find pointing information to plot the beam
            from glob import glob
            from astropy.time import Time
            # Get hold of the pointing files
            pointings = sorted(glob(join(altazdir, '*.altazA')))
            # Parse the pointings
            time = []
            azimuth = []
            elevation = []
            for pointing in pointings:
                try:
                    t, b, az, el, az1, el1, f, el2 = np.loadtxt(fname=pointing,
                                                                dtype=str,
                                                                comments=';',
                                                                unpack=True)
                except:
                    # TESTANT-type files...
                    t, b, az, el, f, el2 = np.loadtxt(fname=pointing,
                                                      dtype=str,
                                                      comments=';',
                                                      unpack=True)
                time += t.tolist()
                azimuth += az.tolist()
                elevation += el.tolist()
            time = Time(np.array(time))
            azimuth = np.array(azimuth).astype(float)
            elevation = np.array(elevation).astype(float)
            # Remove unused files and keed the last one
            for pointing in sorted(pointings)[:-1]:
                remove(pointing)
            # Mini-Array beam width
            primarybeam = np.degrees(wavelength(np.mean(self.freq)) / 25)
            # Where NenuFAR was aiming
            ti = np.max(np.where((time - obstime).sec <= 0)[0])
            ra_point, dec_point = to_radec(alt=elevation[ti],
                                           az=azimuth[ti],
                                           time=obstime)
            circle = (ra_point, dec_point, primarybeam)
        else:
            circle = None

        astroplt = AstroPlot(image=np.real(np.flipud(self.dirty)),
                             center=self.phase_center,
                             resol=self.fov / self.npix)

        if output.lower() == 'plot':
            astroplt.plot(title='{}'.format(obstime.isot),
                          cblabel='Amplitude',
                          sources=True,
                          time=obstime,
                          circle=circle,
                          **kwargs)
        elif output.endswith('.png'):
            output = abspath(output)
            if isdir(dirname(output)):
                astroplt.plot(title='{}'.format(obstime.isot),
                              cblabel='Amplitude',
                              sources=True,
                              time=obstime,
                              filename=output,
                              circle=circle,
                              **kwargs)
        else:
            pass
        return
Example #9
0
    def make_dirty(self, npix=256, fi=0, data='data', **kwargs):
        """ Make a dirty image from the visibilities

            :param npix:
                Size in pixels of the image
            :type npix: int, optional
            :param fi:
                Frequency index
            :type fi: int, optional
            :param data:
                Data type to be imaged, choose between `'data'`,
                `'corrected'` and `'predicted'`.
            :type data: str, optional
            :param output:
                Type of output `'plot'`,
                `'array'` and `'savefile'` (in .png).
            :type output: str, optional
        """
        self._selection(**kwargs)

        if fi >= self.freq.size:
            raise IndexError('Frequency index exceeds {}'.format(
                self.freq.size))
        self.npix = npix
        self._fi = fi

        na = np.newaxis

        # Average over time
        if data.lower == 'corrected':
            if not hasattr(self, 'corrected'):
                self.calibrate(fi=fi)
            vis = np.mean(self.corrected, axis=0)
        elif data.lower() == 'predicted':
            if not hasattr(self, 'predicted'):
                self.predict()
            vis = np.mean(self.predicted, axis=0)
        else:
            vis = np.mean(self.vis, axis=0)
        uvw = np.mean(self.uvw, axis=0)
        # Flatten the arrays
        vis = vis[:, self.array.tri_y, self.array.tri_x, :]
        uvw = uvw[:, self.array.tri_y, self.array.tri_x, :]
        # Get Stokes I
        vis = 0.5 * (vis[..., 0] + vis[..., 3])
        # # Transform UVW in lambdas units, take fi frequency
        # uvw = uvw[fi, ...] / wavelength(self.freq[fi, na, na])

        # # Prepare l, m grid
        # l = np.linspace(-self.lmax, self.lmax, npix)
        # m = np.linspace(self.mmax, -self.mmax, npix)
        # lg, mg = np.meshgrid(l, m)

        # # Make the TF of Visbilities
        # print('\tMaking dirty image')
        # u = uvw[:, 0][:, na, na]
        # v = uvw[:, 1][:, na, na]
        # # Slow:
        # # self.dirty = np.zeros([npix, npix], dtype=np.complex64)
        # # expo = np.exp(
        # #     2j * np.pi * (u * lg[na, ...] + v * mg[na, ...])
        # # )
        # # Faster :
        # # self.dirty = np.zeros([npix, npix], dtype=np.complex64)
        # # lg = lg[na, ...]
        # # mg = mg[na, ...]
        # # pi = np.pi
        # # expo = ne.evaluate('exp(2j*pi*(u*lg+v*mg))')
        # # self.dirty += np.mean(
        # #     vis[fi, :, na, na] * expo,
        # #     axis=0
        # # )
        # # Mutliprocessing
        # expo = mp_expo(self.npix, self.ncpus, lg, mg, u, v)
        # self.dirty = np.mean(
        #     vis[fi, :, na, na] * expo,
        #     axis=0
        # )

        # Transform UVW in lambdas units, take fi frequency
        uvw = uvw / wavelength(self.freq[:, na, na])

        # Prepare l, m grid
        l = np.linspace(-self.lmax, self.lmax, npix)
        m = np.linspace(self.mmax, -self.mmax, npix)
        lg, mg = np.meshgrid(l, m)

        # Make the TF of Visbilities
        print('\tMaking dirty image')
        self.dirty = 0
        for fi in range(self.freq.size):
            u = uvw[fi, :, 0][:, na, na]
            v = uvw[fi, :, 1][:, na, na]
            # Slow:
            # self.dirty = np.zeros([npix, npix], dtype=np.complex64)
            # expo = np.exp(
            #     2j * np.pi * (u * lg[na, ...] + v * mg[na, ...])
            # )
            # Faster :
            # self.dirty = np.zeros([npix, npix], dtype=np.complex64)
            # lg = lg[na, ...]
            # mg = mg[na, ...]
            # pi = np.pi
            # expo = ne.evaluate('exp(2j*pi*(u*lg+v*mg))')
            # self.dirty += np.mean(
            #     vis[fi, :, na, na] * expo,
            #     axis=0
            # )
            # Mutliprocessing
            expo = mp_expo(self.npix, self.ncpus, lg, mg, u, v)
            self.dirty += np.mean(vis[fi, :, na, na] * expo,
                                  axis=0) / self.freq.size
            break  # only compute image on first frequency
        return