def make_psf(uu, vv, ww, freq, fov, im_size): imager = Imager('single') wave_length = 299792458.0 / freq uu_ = uu / wave_length vv_ = vv / wave_length ww_ = ww / wave_length amp = numpy.ones(uu.shape, dtype='c16') weight = numpy.ones(uu.shape, dtype='f8') image = imager.make_image(uu_, vv_, ww_, amp, weight, fov, im_size) cell = math.degrees(imager.fov_to_cellsize(math.radians(fov), im_size)) lm_max = math.sin(0.5 * math.radians(fov)) lm_inc = (2.0 * lm_max) / im_size return {'image': image, 'fov': fov, 'im_size': im_size, 'cell': cell, 'lm_max': lm_max, 'lm_inc': lm_inc}
def make_psf(uu, vv, ww, ra, dec, freq, fov, im_size, file_name): imager = Imager("single") wave_length = 299792458.0 / freq uu_ = uu / wave_length vv_ = vv / wave_length ww_ = ww / wave_length amp = numpy.ones(uu.shape, dtype="c16") weight = numpy.ones(uu.shape, dtype="f8") image = imager.make_image(uu_, vv_, ww_, amp, weight, fov, im_size) cell = math.degrees(imager.fov_to_cellsize(math.radians(fov), im_size)) lm_max = math.sin(0.5 * math.radians(fov)) lm_inc = (2.0 * lm_max) / im_size off = lm_inc / 2.0 extent = [-lm_max - off, lm_max - off, -lm_max + off, lm_max + off] fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111, aspect="equal") divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.07) im = ax.imshow(image, interpolation="nearest", extent=extent, cmap="inferno") cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize="small") t = numpy.linspace(image.min(), image.max(), 7) ax.figure.colorbar(im, cax=cax, ticks=t, format="%.2f") ax.set_xlabel("l", fontsize="small") ax.set_ylabel("m", fontsize="small") ax.tick_params(axis="both", which="major", labelsize="small") ax.tick_params(axis="both", which="minor", labelsize="x-small") pyplot.savefig(file_name + "_%05.2f_%04i_image_lin.png" % (fov, im_size)) pyplot.close(fig) fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111, aspect="equal") divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.07) # http://matplotlib.org/api/colors_api.html im = ax.imshow( image, interpolation="nearest", extent=extent, cmap="inferno", norm=SymLogNorm(vmin=-0.01, vmax=1.0, linthresh=0.005, linscale=0.75), ) cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize="small") ax.figure.colorbar(im, cax=cax) ax.set_xlabel("l", fontsize="small") ax.set_ylabel("m", fontsize="small") ax.tick_params(axis="both", which="major", labelsize="small") ax.tick_params(axis="both", which="minor", labelsize="x-small") pyplot.savefig(file_name + "_%05.2f_%04i_image_log.png" % (fov, im_size)) pyplot.close(fig) # x = numpy.arange(-image.shape[0]/2, image.shape[0]/2) * lm_inc # x, y = numpy.meshgrid(x, x[::-1]) # r = (x**2 + y**2)**0.5 # x_ = r.flatten() # y_ = image.flatten() # sort_idx = numpy.argsort(x_) # x_ = x_[sort_idx] # y_ = y_[sort_idx] # y_ = numpy.abs(y_) # y_max = numpy.nanmax(y_) # norm_y = y_ / y_max # y_db = 10.0 * numpy.log10(norm_y) # num_bins = 200 # y_mean = numpy.zeros(num_bins) # y_std = numpy.zeros(num_bins) # x_bin = numpy.zeros(num_bins) # bin_inc = (image.shape[0]/2.0 * lm_inc) / float(num_bins) # for i in range(num_bins): # r0 = i * bin_inc # r1 = r0 + bin_inc # x_bin[i] = r0 + (r1 - r0) / 2.0 # idx = numpy.where(numpy.logical_and(x_ > r0, x_ <= r1)) # y_bin = y_db[idx] # y_mean[i] = y_bin.mean() # y_std[i] = y_bin.std() # fig = pyplot.figure(figsize=(8, 8)) # ax = fig.add_subplot(111) # ax.plot(x_, y_db, 'k.', alpha=0.01, ms=2.0) # ax.plot(x_bin, y_mean, 'r-') # # ax.plot(x_bin, y_mean + y_std, 'b-', lw=1.0, alpha=0.5) # # ax.plot(x_bin, y_mean - y_std, 'b-', lw=1.0, alpha=0.5) # ax.fill_between(x_bin, y_mean - y_std, y_mean + y_std, # edgecolor='blue', facecolor='blue', alpha=0.6) # ax.set_ylim(-40, 0) # ax.set_xlim(0.0, image.shape[0] / 2 * lm_inc) # ax.set_title(file_name) # ax.set_xlabel('Radius') # ax.set_ylabel('Decibels') # pyplot.savefig(file_name + '_%05.2f_%04i_log_r_ave.png' % (fov, im_size)) # pyplot.close(fig) # ============== x = numpy.arange(-image.shape[0] / 2, image.shape[0] / 2) * lm_inc x, y = numpy.meshgrid(x, x[::-1]) r = (x ** 2 + y ** 2) ** 0.5 x_ = r.flatten() y_ = image.flatten() sort_idx = numpy.argsort(x_) x_ = x_[sort_idx] y_ = y_[sort_idx] # y_ = numpy.abs(y_) num_bins = 200 y_mean = numpy.zeros(num_bins) y_std = numpy.zeros(num_bins) x_bin = numpy.zeros(num_bins) bin_inc = (image.shape[0] / 2.0 * lm_inc) / float(num_bins) for i in range(num_bins): r0 = i * bin_inc r1 = r0 + bin_inc x_bin[i] = r0 + (r1 - r0) / 2.0 idx = numpy.where(numpy.logical_and(x_ > r0, x_ <= r1)) y_bin = y_[idx] y_mean[i] = y_bin.mean() y_std[i] = y_bin.std() fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111) # ax.plot(x_, y_, 'k.', alpha=0.01, ms=2.0) ax.plot(x_bin, y_mean, "r-") ax.fill_between(x_bin, y_mean - y_std, y_mean + y_std, edgecolor="blue", facecolor="blue", alpha=0.6) ax.set_ylim(-0.005, 0.05) ax.set_xlim(0.0, image.shape[0] / 2 * lm_inc) # ax.set_yscale('symlog', linthreshy=0.00005) # ax.set_yscale('symlog') ax.set_title(file_name) ax.set_xlabel("Radius") ax.grid() # ax.set_ylabel('Decibels') pyplot.savefig(file_name + "_%05.2f_%04i_lin_r_ave.png" % (fov, im_size)) pyplot.close(fig) # ================== # ============== x = numpy.arange(-image.shape[0] / 2, image.shape[0] / 2) * lm_inc x, y = numpy.meshgrid(x, x[::-1]) r = (x ** 2 + y ** 2) ** 0.5 x_ = r.flatten() y_ = image.flatten() sort_idx = numpy.argsort(x_) x_ = x_[sort_idx] y_ = y_[sort_idx] # y_ = numpy.abs(y_) num_bins = 200 y_mean = numpy.zeros(num_bins) y_std = numpy.zeros(num_bins) x_bin = numpy.zeros(num_bins) bin_inc = (image.shape[0] / 2.0 * lm_inc) / float(num_bins) for i in range(num_bins): r0 = i * bin_inc r1 = r0 + bin_inc x_bin[i] = r0 + (r1 - r0) / 2.0 idx = numpy.where(numpy.logical_and(x_ > r0, x_ <= r1)) y_bin = y_[idx] y_mean[i] = y_bin.mean() y_std[i] = y_bin.std() fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111) # ax.plot(x_, y_, 'k.', alpha=0.01, ms=2.0) ax.plot(x_bin, y_mean, "r-") ax.fill_between(x_bin, y_mean - y_std, y_mean + y_std, edgecolor="blue", facecolor="blue", alpha=0.6) # ax.set_ylim(-0.005, 0.05) ax.set_xlim(0.0, image.shape[0] / 2 * lm_inc) # ax.set_yscale('symlog', linthreshy=0.1) ax.set_yscale("symlog") # ax.set_yscale('log', noposy='clip') ax.set_title(file_name) ax.set_xlabel("Radius") ax.grid() # ax.set_ylabel('Decibels') pyplot.savefig(file_name + "_%05.2f_%04i_log_r_ave.png" % (fov, im_size)) pyplot.close(fig)
def eval_psf(self, im_size=None, fov_deg=None, plot2d=False, plot1d=True): if self.uu_m is None: self.gen_uvw_coords() # Evaluate grid size and fov if needed. if im_size is None: b_max = self.r_uv_m.max() grid_size = int(ceil(b_max / self.grid_cell_size_m)) * 2 + \ self.station_diameter_m if grid_size % 2 == 1: grid_size += 1 else: grid_size = im_size wavelength = const.c.value / self.freq_hz if fov_deg is None: cellsize_wavelengths = self.grid_cell_size_m / wavelength fov_rad = Imager.uv_cellsize_to_fov(cellsize_wavelengths, grid_size) fov_deg = degrees(fov_rad) else: fov_deg = fov_deg uu = self.uu_m / wavelength vv = self.vv_m / wavelength ww = self.ww_m / wavelength amp = np.ones_like(uu, dtype='c8') psf = Imager.make_image(uu, vv, ww, np.ones_like(uu, dtype='c8'), fov_deg, grid_size) extent = Imager.image_extent_lm(fov_deg, grid_size) self.psf = psf self.psf_fov_deg = fov_deg # --- Plotting ---- if plot2d: fig, ax = plt.subplots(figsize=(8, 8)) norm = SymLogNorm(linthresh=0.05, linscale=1.0, vmin=-0.05, vmax=0.5, clip=False) opts = dict(interpolation='nearest', origin='lower', cmap='gray_r', extent=extent, norm=norm) im = ax.imshow(psf, **opts) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.03) cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize='small') ax.set_xlabel('l') ax.set_ylabel('m') plt.savefig('psf.png') plt.show() plt.close(fig) if plot1d: l, m = Imager.image_pixels(self.psf_fov_deg, grid_size) r_lm = (l**2 + m**2)**0.5 r_lm = r_lm.flatten() idx_sorted = np.argsort(r_lm) r_lm = r_lm[idx_sorted] psf_1d = self.psf.flatten()[idx_sorted] psf_hwhm = (wavelength / (r_lm[-1] * 2.0)) / 2 fig, ax = plt.subplots(figsize=(8, 8)) ax.plot(r_lm, psf_1d, 'k.', ms=2, alpha=0.1) ax.set_xscale('log') ax.set_yscale('log') fig.savefig('TEST_psf1d.png') plt.close(fig) num_bins = 100 # FIXME(BM) make this a function arg psf_1d_mean = np.zeros(num_bins) psf_1d_abs_mean = np.zeros(num_bins) psf_1d_abs_max = np.zeros(num_bins) psf_1d_min = np.zeros(num_bins) psf_1d_max = np.zeros(num_bins) psf_1d_std = np.zeros(num_bins) bin_edges = np.linspace(r_lm[0], r_lm[-1], num_bins + 1) # bin_edges = np.logspace(log10(r_lm[1]), log10(r_lm[-1]), # num_bins + 1) psf_1d_bin_r = (bin_edges[1:] + bin_edges[:-1]) / 2 bin_idx = np.digitize(r_lm, bin_edges) for i in range(1, num_bins + 1): values = psf_1d[bin_idx == i] if values.size > 0: psf_1d_mean[i - 1] = np.mean(values) psf_1d_abs_mean[i - 1] = np.mean(np.abs(values)) psf_1d_abs_max[i - 1] = np.max(np.abs(values)) psf_1d_min[i - 1] = np.min(values) psf_1d_max[i - 1] = np.max(values) psf_1d_std[i - 1] = np.std(values) fig, ax = plt.subplots(figsize=(8, 8)) ax.plot(psf_1d_bin_r, psf_1d_abs_mean, '-', c='b', lw=1, label='abs mean') ax.plot(psf_1d_bin_r, psf_1d_abs_max, '-', c='r', lw=1, label='abs max') ax.plot(psf_1d_bin_r, psf_1d_std, '-', c='g', lw=1, label='std') # ax.set_ylim(-0.1, 0.5) # ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) # ax.set_xscale('log') ax.set_yscale('log') ax.set_ylim(1e-4, 1) ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) ax.set_xlabel('PSF radius (direction cosines)') # ax.set_ylabel('PSF amplitude') ax.set_title('Azimuthally averaged PSF (FoV: %.2f)' % fov_deg) ax.legend() plt.show() plt.close(fig)
def eval_psf(self, im_size=None, fov_deg=None, plot2d=False, plot1d=True, filename_root=None, num_bins=100): """Evaluate and plot the PSF.""" if self.uu_m is None: self.gen_uvw_coords() # Work out a usable grid size. if im_size is None: b_max = self.r_uv_m.max() grid_size = int(ceil(b_max / self.grid_cell_size_m)) * 2 + \ self.station_diameter_m if grid_size % 2 == 1: grid_size += 1 else: grid_size = im_size # Work out the FoV wavelength = const.c.value / self.freq_hz if fov_deg is None: cellsize_wavelengths = self.grid_cell_size_m / wavelength fov_rad = Imager.uv_cellsize_to_fov(cellsize_wavelengths, grid_size) fov_deg = degrees(fov_rad) else: fov_deg = fov_deg uu = self.uu_m / wavelength vv = self.vv_m / wavelength ww = self.ww_m / wavelength amp = np.ones_like(uu, dtype='c8') # _r = (uu**2 + vv**2)**0.5 * wavelength # amp[_r <= 1e3] = 0.0 psf = Imager.make_image(uu, vv, ww, amp, fov_deg, grid_size, weighting='Natural') extent = Imager.image_extent_lm(fov_deg, grid_size) self.psf = psf self.psf_fov_deg = fov_deg # --- Plotting ---- if plot2d: fig, ax = plt.subplots(figsize=(8, 8)) norm = SymLogNorm(linthresh=0.005, linscale=1.0, vmin=-0.005, vmax=1.0, clip=False) opts = dict(interpolation='nearest', origin='lower', cmap='inferno', extent=extent, norm=norm) # opts = dict(interpolation='nearest', origin='lower', cmap='gray_r', # extent=extent) im = ax.imshow(psf, **opts) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.03) cbar = ax.figure.colorbar(im, cax=cax) cbar.ax.tick_params(labelsize='small') ax.set_xlabel('l') ax.set_ylabel('m') if filename_root: label = '' if 'ska1_v5' in filename_root: label = 'SKA1 v5' if 'model' in filename_root: label = 'Model ' + str( re.search(r'\d+', os.path.basename(filename_root)).group()) ax.text(0.02, 0.95, label, color='white', weight='bold', transform=ax.transAxes) plt.savefig('%s_2d_%.1f.png' % (filename_root, fov_deg)) else: plt.show() plt.close(fig) if plot1d: l, m = Imager.image_pixels(self.psf_fov_deg, grid_size) r_lm = (l**2 + m**2)**0.5 r_lm = r_lm.flatten() idx_sorted = np.argsort(r_lm) r_lm = r_lm[idx_sorted] psf_1d = self.psf.flatten()[idx_sorted] psf_hwhm = (wavelength / (r_lm[-1] * 2.0)) / 2 # fig, ax = plt.subplots(figsize=(8, 8)) # ax.plot(r_lm, psf_1d, 'k.', ms=2, alpha=0.1) # ax.set_xscale('log') # ax.set_yscale('log') # fig.savefig('TEST_psf1d.png') # plt.close(fig) psf_1d_mean = np.zeros(num_bins) psf_1d_abs_mean = np.zeros(num_bins) psf_1d_abs_max = np.zeros(num_bins) psf_1d_min = np.zeros(num_bins) psf_1d_max = np.zeros(num_bins) psf_1d_std = np.zeros(num_bins) psf_1d_rms = np.zeros(num_bins) bin_edges = np.linspace(r_lm[0], r_lm[-1] * 2**(-0.5), num_bins + 1) # bin_edges = np.logspace(log10(r_lm[1]), log10(r_lm[-1]), # num_bins + 1) psf_1d_bin_r = (bin_edges[1:] + bin_edges[:-1]) / 2 bin_idx = np.digitize(r_lm, bin_edges) for i in range(1, num_bins + 1): values = psf_1d[bin_idx == i] if values.size > 0: psf_1d_mean[i - 1] = np.mean(values) psf_1d_abs_mean[i - 1] = np.mean(np.abs(values)) psf_1d_abs_max[i - 1] = np.max(np.abs(values)) psf_1d_min[i - 1] = np.min(values) psf_1d_max[i - 1] = np.max(values) psf_1d_std[i - 1] = np.std(values) psf_1d_rms[i - 1] = np.mean(values**2)**0.5 self.psf_1d['r'] = psf_1d_bin_r self.psf_1d['min'] = psf_1d_min self.psf_1d['max'] = psf_1d_max self.psf_1d['mean'] = psf_1d_mean self.psf_1d['std'] = psf_1d_std self.psf_1d['rms'] = psf_1d_rms self.psf_1d['abs_mean'] = psf_1d_abs_mean self.psf_1d['abs_max'] = psf_1d_abs_max fig, ax = plt.subplots(figsize=(8, 8)) ax.plot(psf_1d_bin_r, psf_1d_abs_mean, '-', c='b', lw=1, label='abs mean') ax.plot(psf_1d_bin_r, psf_1d_abs_max, '-', c='r', lw=1, label='abs max') ax.plot(psf_1d_bin_r, psf_1d_std, '-', c='g', lw=1, label='std') # ax.set_ylim(-0.1, 0.5) # ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) # ax.set_xscale('log') ax.set_yscale('log') ax.set_ylim(1e-4, 1) ax.set_xlim(0, psf_1d_bin_r[-1] / 2**0.5) ax.set_xlabel('PSF radius (direction cosines)') # ax.set_ylabel('PSF amplitude') ax.set_title('Azimuthally averaged PSF (FoV: %.2f)' % fov_deg) ax.legend() if filename_root: plt.savefig('%s_1d_%.1f.png' % (filename_root, fov_deg)) else: plt.show() plt.close(fig)
def main(): # Options # ========================================================================= # Telescope model lon, lat = 116.63128900, -26.69702400 # degrees station_d = 35.0 # m telescope_radius_cut = 1000 # m (Remote stations in the telescope > this) eta = 1.0 # System efficiency # Observation settings az0, el0, date0 = 0.0, 90.0, '2016/7/14 10:30' # Midpoint coordinates #start_freqs = 50e6 + np.array([0, 6, 12, 18]) * 8e6 # start_freqs = [50e6] start_freqs = 50e6 + np.array([6, 12, 18]) * 8e6 num_channels, freq_inc = 80, 100e3 obs_length_h, noise_obs_length_h = 5, 1000 t_acc = 60.0 # Time resolution of visibility coordinates, in seconds. # Image settings im_size = 512 algorithm = 'w-projection' weights = 'uniform' lambda_cut = True w_planes = 64 # Results directory results_dir = 'noise_cubes_%s_%s' % (weights, algorithm.lower()) if algorithm.lower().startswith('w') and w_planes > 0: results_dir += '_%i' % w_planes # ========================================================================= # Calculate observation equatorial coordinates and start MJD of the # specified target field obs = ephem.Observer() obs.lon, obs.lat, obs.elevation = radians(lon), radians(lat), 0.0 obs.date = str(date0) ra, dec = obs.radec_of(radians(az0), radians(el0)) ra, dec = degrees(ra), degrees(dec) mjd_mid = ephem.julian_date(b'2016/02/25 10:30') - 2400000.5 mjd_start = mjd_mid - obs_length_h / (2 * 24.0) # Load telescope model and generate uvw coordinates, in metres coords_file = join(results_dir, 'uvw_m.npz') x, y, z = load_telescope(telescope_radius_cut, station_d, lon, lat, join(results_dir, 'telescope.eps')) num_stations = x.shape[0] uu, vv, ww, num_times = generate_uvw_coords_m(x, y, z, obs_length_h, mjd_mid, t_acc, ra, dec, join(results_dir, 'uvw')) t0 = time.time() np.savez(coords_file, uu=uu, vv=vv, ww=ww, x=x, y=y, z=z, num_times=num_times) print('- No. stations = %i' % num_stations) print('- Saved uvw coordinates in %.2f s' % (time.time() - t0)) # Evaluate radial uv co-ordinate range (needed for lambda cut) r_uvw = (uu**2 + vv**2)**0.5 r_uvw_min = r_uvw.min() r_uvw_max = r_uvw.max() # Allocate image cubes. noise_cube = np.zeros((num_channels, im_size, im_size)) psf_cube = np.zeros((num_channels, im_size, im_size)) # Loop over cube start frequency. for i, start_freq in enumerate(start_freqs): print() print('- Freq = %.1f MHz (+%i x %0.1f kHz)' % (start_freq / 1e6, num_channels, freq_inc/1e3)) # Array of cube frequency channels freqs = (start_freq + (np.arange(num_channels) * freq_inc + freq_inc / 2)) # Calculate image FoV and lambda cuts fov_deg = 1.5 * degrees((const.c.value / start_freq) / station_d) print('- FoV = %.2f deg.' % fov_deg) # Generate file names of image cube and noise outputs. if lambda_cut: l_cut_inner = ceil(r_uvw_min / (const.c.value / freqs[-1])) l_cut_outer = floor(r_uvw_max / (const.c.value / freqs[0])) print('- lambda cut = %.0f, %.0f' % (l_cut_inner, l_cut_outer)) suffix = ('%05.1fMHz_lcut_%04i_%04i_%s_%s' % (start_freq / 1e6, l_cut_inner, l_cut_outer, weights, algorithm.lower())) else: suffix = ('%05.1fMHz_%s_%s' % (start_freq / 1e6, weights, algorithm.lower())) if algorithm.lower().startswith('w') and w_planes > 0: suffix += '_%i' % w_planes l_cut = [l_cut_inner, l_cut_outer] if lambda_cut else None noise_cube_file = join(results_dir, 'noise_' + suffix + '.fits') noise_cube_file_k = join(results_dir, 'noise_' + suffix + '_K.fits') psf_cube_file = join(results_dir, 'psf_' + suffix + '.fits') noise_sigma_file = join(results_dir, 'noise_sigma_' + suffix + '.npz') t0 = time.time() # Option to load existing image cubes (used to skip directly to fitting # the psf and converting to K) if os.path.exists(noise_cube_file): noise_cube = fits.getdata(noise_cube_file) psf_cube = fits.getdata(psf_cube_file) # Simulate / image the noise cube (in Jy/beam) and PSF cube. else: sigma_pq, sigma_im = np.zeros(num_channels), np.zeros(num_channels) num_coords = np.zeros(num_channels, dtype='i8') progress_bar = ProgressBar(maxval=num_channels, widgets=[ Bar(marker='='), Counter(format='%03i'), '/%03i ' % num_channels, Percentage(), ' ', Timer(), ' ', ETA()]).start() # Loop over frequencies in the cube for j, freq in enumerate(freqs): # Convert coordinates wavelength and apply lambda cut wavelength = const.c.value / freq uu_l = (uu / wavelength) vv_l = (vv / wavelength) ww_l = (ww / wavelength) if lambda_cut: r_uv = (uu_l**2 + vv_l**2)**0.5 idx = np.where(np.logical_and(r_uv >= l_cut_inner, r_uv <= l_cut_outer)) uu_l, vv_l, ww_l = uu_l[idx], vv_l[idx], ww_l[idx] num_coords[j] = uu_l.shape[0] # Evaluate visibility noise (and predicted image noise) sigma_pq[j] = evaluate_scaled_noise_rms( freq, num_times, freq_inc, eta, noise_obs_length_h) sigma_im[j] = sigma_pq[j] / num_coords[j]**0.5 # Make the noise image amp = (randn(num_coords[j]) + 1j * randn(num_coords[j])) * sigma_pq[j] noise_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) # Make the psf amp = np.ones(uu_l.shape[0], dtype='c16') psf_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) progress_bar.update(j) progress_bar.finish() # Save noise values and cube images in Jy/beam np.savez(noise_sigma_file, freqs=freqs, sigma_pq=sigma_pq, sigma_im=sigma_im, num_coords=num_coords) write_fits_cube(noise_cube, noise_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) write_fits_cube(psf_cube, psf_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) print('- Time taken = %.2f s (image cube)' % (time.time() - t0)) # Fit the PSF with a gaussian to evaluate the beam area (in arcmin^2) t0 = time.time() r_uv_max_l = l_cut_outer if lambda_cut else \ r_uvw_max / (const.c.value / start_freq) area_arcmin2 = eval_beam_area(psf_cube, r_uv_max_l, fov_deg, freqs, start_freq, results_dir, weights, plot=False) print('- Time taken = %.2f s (fit area)' % (time.time() - t0)) # Convert cube from Jy/beam to K t0 = time.time() for j, freq in enumerate(freqs): image = noise_cube[j, :, :] area_sr = (area_arcmin2[j] / 3600.0) * (pi / 180)**2 image /= area_sr image *= (1e-26 * const.c.value**2) / (2 * const.k_B.value * freq**2) write_fits_cube(noise_cube, noise_cube_file_k, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm, bunit='K') print('- Time taken = %.2f s (convert to K)' % (time.time() - t0)) print()
def main(): # Options # ========================================================================= # Telescope model lon, lat = 116.63128900, -26.69702400 # degrees station_d = 35.0 # m telescope_radius_cut = 1000 # m (Remote stations in the telescope > this) eta = 1.0 # System efficiency # Observation settings az0, el0, date0 = 0.0, 90.0, '2016/7/14 10:30' # Midpoint coordinates #start_freqs = 50e6 + np.array([0, 6, 12, 18]) * 8e6 # start_freqs = [50e6] start_freqs = 50e6 + np.array([6, 12, 18]) * 8e6 num_channels, freq_inc = 80, 100e3 obs_length_h, noise_obs_length_h = 5, 1000 t_acc = 60.0 # Time resolution of visibility coordinates, in seconds. # Image settings im_size = 512 algorithm = 'w-projection' weights = 'uniform' lambda_cut = True w_planes = 64 # Results directory results_dir = 'noise_cubes_%s_%s' % (weights, algorithm.lower()) if algorithm.lower().startswith('w') and w_planes > 0: results_dir += '_%i' % w_planes # ========================================================================= # Calculate observation equatorial coordinates and start MJD of the # specified target field obs = ephem.Observer() obs.lon, obs.lat, obs.elevation = radians(lon), radians(lat), 0.0 obs.date = str(date0) ra, dec = obs.radec_of(radians(az0), radians(el0)) ra, dec = degrees(ra), degrees(dec) mjd_mid = ephem.julian_date(b'2016/02/25 10:30') - 2400000.5 mjd_start = mjd_mid - obs_length_h / (2 * 24.0) # Load telescope model and generate uvw coordinates, in metres coords_file = join(results_dir, 'uvw_m.npz') x, y, z = load_telescope(telescope_radius_cut, station_d, lon, lat, join(results_dir, 'telescope.eps')) num_stations = x.shape[0] uu, vv, ww, num_times = generate_uvw_coords_m(x, y, z, obs_length_h, mjd_mid, t_acc, ra, dec, join(results_dir, 'uvw')) t0 = time.time() np.savez(coords_file, uu=uu, vv=vv, ww=ww, x=x, y=y, z=z, num_times=num_times) print('- No. stations = %i' % num_stations) print('- Saved uvw coordinates in %.2f s' % (time.time() - t0)) # Evaluate radial uv co-ordinate range (needed for lambda cut) r_uvw = (uu**2 + vv**2)**0.5 r_uvw_min = r_uvw.min() r_uvw_max = r_uvw.max() # Allocate image cubes. noise_cube = np.zeros((num_channels, im_size, im_size)) psf_cube = np.zeros((num_channels, im_size, im_size)) # Loop over cube start frequency. for i, start_freq in enumerate(start_freqs): print() print('- Freq = %.1f MHz (+%i x %0.1f kHz)' % (start_freq / 1e6, num_channels, freq_inc / 1e3)) # Array of cube frequency channels freqs = (start_freq + (np.arange(num_channels) * freq_inc + freq_inc / 2)) # Calculate image FoV and lambda cuts fov_deg = 1.5 * degrees((const.c.value / start_freq) / station_d) print('- FoV = %.2f deg.' % fov_deg) # Generate file names of image cube and noise outputs. if lambda_cut: l_cut_inner = ceil(r_uvw_min / (const.c.value / freqs[-1])) l_cut_outer = floor(r_uvw_max / (const.c.value / freqs[0])) print('- lambda cut = %.0f, %.0f' % (l_cut_inner, l_cut_outer)) suffix = ('%05.1fMHz_lcut_%04i_%04i_%s_%s' % (start_freq / 1e6, l_cut_inner, l_cut_outer, weights, algorithm.lower())) else: suffix = ('%05.1fMHz_%s_%s' % (start_freq / 1e6, weights, algorithm.lower())) if algorithm.lower().startswith('w') and w_planes > 0: suffix += '_%i' % w_planes l_cut = [l_cut_inner, l_cut_outer] if lambda_cut else None noise_cube_file = join(results_dir, 'noise_' + suffix + '.fits') noise_cube_file_k = join(results_dir, 'noise_' + suffix + '_K.fits') psf_cube_file = join(results_dir, 'psf_' + suffix + '.fits') noise_sigma_file = join(results_dir, 'noise_sigma_' + suffix + '.npz') t0 = time.time() # Option to load existing image cubes (used to skip directly to fitting # the psf and converting to K) if os.path.exists(noise_cube_file): noise_cube = fits.getdata(noise_cube_file) psf_cube = fits.getdata(psf_cube_file) # Simulate / image the noise cube (in Jy/beam) and PSF cube. else: sigma_pq, sigma_im = np.zeros(num_channels), np.zeros(num_channels) num_coords = np.zeros(num_channels, dtype='i8') progress_bar = ProgressBar(maxval=num_channels, widgets=[ Bar(marker='='), Counter(format='%03i'), '/%03i ' % num_channels, Percentage(), ' ', Timer(), ' ', ETA() ]).start() # Loop over frequencies in the cube for j, freq in enumerate(freqs): # Convert coordinates wavelength and apply lambda cut wavelength = const.c.value / freq uu_l = (uu / wavelength) vv_l = (vv / wavelength) ww_l = (ww / wavelength) if lambda_cut: r_uv = (uu_l**2 + vv_l**2)**0.5 idx = np.where( np.logical_and(r_uv >= l_cut_inner, r_uv <= l_cut_outer)) uu_l, vv_l, ww_l = uu_l[idx], vv_l[idx], ww_l[idx] num_coords[j] = uu_l.shape[0] # Evaluate visibility noise (and predicted image noise) sigma_pq[j] = evaluate_scaled_noise_rms( freq, num_times, freq_inc, eta, noise_obs_length_h) sigma_im[j] = sigma_pq[j] / num_coords[j]**0.5 # Make the noise image amp = (randn(num_coords[j]) + 1j * randn(num_coords[j])) * sigma_pq[j] noise_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) # Make the psf amp = np.ones(uu_l.shape[0], dtype='c16') psf_cube[j, :, :] = Imager.make_image(uu_l, vv_l, ww_l, amp, fov_deg, im_size, weights, algorithm, wprojplanes=w_planes) progress_bar.update(j) progress_bar.finish() # Save noise values and cube images in Jy/beam np.savez(noise_sigma_file, freqs=freqs, sigma_pq=sigma_pq, sigma_im=sigma_im, num_coords=num_coords) write_fits_cube(noise_cube, noise_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) write_fits_cube(psf_cube, psf_cube_file, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm) print('- Time taken = %.2f s (image cube)' % (time.time() - t0)) # Fit the PSF with a gaussian to evaluate the beam area (in arcmin^2) t0 = time.time() r_uv_max_l = l_cut_outer if lambda_cut else \ r_uvw_max / (const.c.value / start_freq) area_arcmin2 = eval_beam_area(psf_cube, r_uv_max_l, fov_deg, freqs, start_freq, results_dir, weights, plot=False) print('- Time taken = %.2f s (fit area)' % (time.time() - t0)) # Convert cube from Jy/beam to K t0 = time.time() for j, freq in enumerate(freqs): image = noise_cube[j, :, :] area_sr = (area_arcmin2[j] / 3600.0) * (pi / 180)**2 image /= area_sr image *= (1e-26 * const.c.value**2) / (2 * const.k_B.value * freq**2) write_fits_cube(noise_cube, noise_cube_file_k, ra, dec, mjd_start, start_freq, freq_inc, fov_deg, l_cut, weights, algorithm, bunit='K') print('- Time taken = %.2f s (convert to K)' % (time.time() - t0)) print()
def main(): """ 1. Generate a large-ish core of stations using random generator. a. overlap some stations in the core to have a very dense station region 2. After core area start using arms but generate some randomness in the arms by placing antennas randomly near the outer stations keeping them along the spiral 3. Remove radius redundancy in the spiral arms """ # ========================================================================= # ====== Core seed = 1 num_tries = 10 num_core_stations = (1 + 5 + 11 + 17) * 6 + (3 * 6) core_radius_m = 480.0 inner_core_radius_m = 280.0 station_radius_m = 35.0 / 2.0 sll = -28 # ====== Core arms num_arms = 3 core_arm_count = 4 stations_per_arm_cluster = 6 arm_cluster_radius = 75.0 # a = 300.0 # b = 0.513 a = 300.0 b = 0.513 delta_theta = math.radians(37.0) arm_offsets = numpy.radians([35.0, 155.0, 270.0]) num_core_arm_stations = num_arms * core_arm_count * stations_per_arm_cluster # ====== Outer arms outer_arm_count = 12 stations_per_outer_cluster = 6 num_clusters_outer = outer_arm_count * num_arms v4a_ss_enu_file = 'v7ska1lowN1v2rev3R.enu.94x4.fixed.txt' outer_arm_cluster_radius = 80.0 # ===== uvw coordinate generation. lon = radians(116.63128900) lat = radians(-26.69702400) alt = 0.0 ra = radians(68.698903779331502) dec = radians(-26.568851215532160) mjd_mid = 57443.4375000000 obs_length = 0.0 mjd_start = mjd_mid dt_s = 0.0 num_times = 1 obs_length = 2.0 * 3600.0 # seconds num_times = int(obs_length / (3.0 * 60.0)) dt_s = obs_length / float(num_times) mjd_start = mjd_mid - ((obs_length / 2.0) / 3600.0 * 24.0) print('num times = %i' % num_times) out_dir = 'v5c-2h' # ========================================================================= if not os.path.isdir(out_dir): os.makedirs(out_dir) # Generate core stations x_core, y_core, weights, r_weights = \ generate_random_core(num_core_stations, core_radius_m, inner_core_radius_m, sll, station_radius_m, num_tries, seed) # Core arms x_arm, y_arm, cx_arm, cy_arm = \ generate_core_arms(num_arms, core_arm_count, stations_per_arm_cluster, arm_cluster_radius, station_radius_m, a, b, delta_theta, arm_offsets, num_tries) # Outer stations. x_arm_outer, y_arm_outer, cx_outer, cy_outer = \ generate_outer_arms(v4a_ss_enu_file, num_clusters_outer, stations_per_outer_cluster, outer_arm_cluster_radius, station_radius_m, num_tries) # Plotting plot_layout(x_core, y_core, x_arm, y_arm, x_arm_outer, y_arm_outer, cx_arm, cy_arm, cx_outer, cy_outer, station_radius_m, inner_core_radius_m, core_radius_m, arm_cluster_radius, outer_arm_cluster_radius, out_dir) plot_core_thinning_profile(r_weights, weights, core_radius_m, inner_core_radius_m, out_dir) if uvwsim_found: x = numpy.hstack((x_core, x_arm, x_arm_outer)) y = numpy.hstack((y_core, y_arm, y_arm_outer)) print('total stations = %i' % x.shape[0]) num_stations = x.shape[0] z = numpy.zeros_like(x) num_baselines = num_stations * (num_stations - 1) / 2 x, y, z = convert_enu_to_ecef(x, y, z, lon, lat, alt) uu, vv, ww = generate_baseline_uvw(x, y, z, ra, dec, num_times, num_baselines, mjd_start, dt_s) plot_hist(uu, vv, join(out_dir, 'uv_hist_%.2fh.png' % (obs_length/3600.0)), 'v5c %.2f h' % (obs_length/3600.0)) plot_uv_dist(uu, vv, station_radius_m, join(out_dir, 'uv_%.2fh' % (obs_length/3600.0))) # TODO-BM see ALMA memo for plots? # TODO-BM Plot of azimuthal variation # TODO-BM movie of uv coverage histogram improvement with time? # TODO-BM convolve uv response with station beam?! print('making image...') imager = Imager('single') fov = 1.0 im_size = 2048 freq = 150.0e6 wavelength = 299792458.0 / freq uu /= wavelength vv /= wavelength ww /= wavelength amp = numpy.ones(uu.shape, dtype='c16') weight = numpy.ones(uu.shape, dtype='f8') image = imager.make_image(uu, vv, ww, amp, weight, fov, im_size) fig = pyplot.figure(figsize=(8, 8)) ax = fig.add_subplot(111, aspect='equal') ax.imshow(image, interpolation='nearest') pyplot.show() cell = math.degrees(imager.fov_to_cellsize(math.radians(fov), im_size)) save_fits_image_2(join(out_dir, 'psf.fits'), image, cell, math.degrees(ra), math.degrees(dec), freq)