def noise_error_ps(nu_c, k, t, **kwargs):
    '''
    Calculate the system noise error on the
    power spectrum, using the analytical expression in 
    Mellema et al 2013 (equation 11). If no arguments are given,
    the noise is calculated for LOFAR-like parameters
    with delta k = k, and a bandwidth of 10 MHz.
    
    Parameters:
        * nu_c (float): the central observing frequency
        * k (float or array-like): the k mode(s)
        * t (float): the observing time in hours
        
    Valid kwargs:
        * Rmax (float): the radius of the array in meters
        * Aeff (float or function): the effective area. Can be a 
            function of nu.
        * Nstat (int): the number of stations
        * Tsys (float or function): the system temperature. Can be a
            function of nu.
        * B (float): the bandwidth in MHz
        * epsilon (float): the width of the k bins in terms of k
        * multipole (int): if this is zero (default), the 
            noise is calculated for the monopole (spherially-averaged).
            Otherwise it is calculated for the given multipole moment
            of the power spectrum.
    
    Returns:
        The system noise error in mK^2

    '''
    wavel = const.c / nu_c * 1.e-3
    t = t * 60. * 60.  #s
    Rmax = kwargs.get('Rmax', 1500.)
    Acore = Rmax**2 * np.pi  #m^2
    Aeff = kwargs.get('Aeff', lambda nu: 526. * (nu / 150.)**(-2))
    if hasattr(Aeff, '__call__'):
        Aeff_val = Aeff(nu_c)
    else:
        Aeff_val = Aeff
    Nstat = kwargs.get('Nstat', 48)
    Acoll = Nstat * Aeff_val
    B = kwargs.get('B', 10.)
    Dc = cm.nu_to_cdist(nu_c)
    deltaDc = np.abs(Dc - cm.nu_to_cdist(nu_c + B))
    OmegaFoV = wavel**2 / Aeff_val
    Tsys = kwargs.get('Tsys', lambda nu: (140. + 60. *
                                          (nu / 300.)**(-2.55)) * 1000.)
    if hasattr(Tsys, '__call__'):
        Tsys_val = Tsys(nu_c)
    else:
        Tsys_val = Tsys
    epsilon = kwargs.get('epsilon', 1)
    multipole = kwargs.get('multipole', 0)
    multipole_factor = np.sqrt(2 * multipole + 1)
    Delta_noise = (2. / np.pi) * k**(3. / 2.) * np.sqrt(
        Dc**2 * deltaDc * OmegaFoV) * (Tsys_val / np.sqrt(B * 1.e6 * t))**2 * (
            Acore * Aeff_val / (Acoll**2)) / np.sqrt(epsilon)

    return Delta_noise * multipole_factor
def noise_error_ps(nu_c, k, t, **kwargs):
    '''
    Calculate the system noise error on the
    power spectrum, using the analytical expression in 
    Mellema et al 2013 (equation 11). If no arguments are given,
    the noise is calculated for LOFAR-like parameters
    with delta k = k, and a bandwidth of 10 MHz.
    
    Parameters:
        * nu_c (float): the central observing frequency
        * k (float or array-like): the k mode(s)
        * t (float): the observing time in hours
        
    Valid kwargs:
        * Rmax (float): the radius of the array in meters
        * Aeff (float or function): the effective area. Can be a 
            function of nu.
        * Nstat (int): the number of stations
        * Tsys (float or function): the system temperature. Can be a
            function of nu.
        * B (float): the bandwidth in MHz
        * epsilon (float): the width of the k bins in terms of k
        * multipole (int): if this is zero (default), the 
            noise is calculated for the monopole (spherially-averaged).
            Otherwise it is calculated for the given multipole moment
            of the power spectrum.
    
    Returns:
        The system noise error in mK^2

    '''
    wavel = const.c/nu_c*1.e-3
    t = t*60.*60. #s
    Rmax = kwargs.get('Rmax', 1500.)
    Acore = Rmax**2*np.pi #m^2
    Aeff = kwargs.get('Aeff', lambda nu: 526.*(nu/150.)**(-2))
    if hasattr(Aeff, '__call__'):
        Aeff_val = Aeff(nu_c)
    else:
        Aeff_val = Aeff
    Nstat = kwargs.get('Nstat', 48)
    Acoll = Nstat*Aeff_val
    B = kwargs.get('B', 10.)
    Dc = cm.nu_to_cdist(nu_c)
    deltaDc = np.abs(Dc - cm.nu_to_cdist(nu_c+B))
    OmegaFoV = wavel**2/Aeff_val
    Tsys = kwargs.get('Tsys', lambda nu: (140. + 60.*(nu/300.)**(-2.55))*1000.)
    if hasattr(Tsys, '__call__'):
        Tsys_val = Tsys(nu_c)
    else:
        Tsys_val = Tsys
    epsilon = kwargs.get('epsilon', 1)
    multipole = kwargs.get('multipole', 0)
    multipole_factor = np.sqrt(2*multipole+1)
    Delta_noise = (2./np.pi)*k**(3./2.)*np.sqrt(Dc**2*deltaDc*OmegaFoV)*(Tsys_val/np.sqrt(B*1.e6*t))**2*(Acore*Aeff_val/(Acoll**2))/np.sqrt(epsilon)
    
    return Delta_noise*multipole_factor
Beispiel #3
0
def observational_lightcone_to_physical(observational_lightcone, input_freqs,
                                        input_dtheta):
    '''
    Interpolate a lightcone volume measured in observational (angle/frequency)
    units into  physical (length) units. The output resolution will be set
    to the coarest one, as determined either by the angular or the frequency
    resolution. The lightcone must have the LoS as the last index, with 
    frequencies decreasing along the LoS.
    
    Parameters:
        * observational_lightcone (numpy array): the input lightcone volume
        * input_freqs (numpy array): the frequency in MHz of each slice along the 
            line of sight of the input
        * input_dheta (float): the angular size of a cell in arcmin
        
    Returns:
        * The output volume
        * The redshifts along the LoS of the output
        * The output cell size in Mpc
    '''
    assert input_freqs[0] > input_freqs[-1]
    assert observational_lightcone.shape[0] == observational_lightcone.shape[1]

    #Determine new cell size - set either by frequency or angle.
    #The FoV size in Mpc is set by the lowest redshift
    dnu = input_freqs[0] - input_freqs[1]
    z_low = cm.nu_to_z(input_freqs[0])
    fov_deg = observational_lightcone.shape[0] * input_dtheta / 60.
    fov_mpc = fov_deg / cm.angular_size_comoving(1., z_low)
    cell_size_perp = fov_mpc / observational_lightcone.shape[0]
    cell_size_par = cm.nu_to_cdist(input_freqs[-1]) - cm.nu_to_cdist(
        input_freqs[-2])
    output_cell_size = max([cell_size_par, cell_size_perp])
    hf.print_msg('Making physical lightcone with cell size %.2f Mpc' %
                 output_cell_size)
    #Go through each slice along frequency axis. Cut off excess and
    #interpolate down to correct resolution
    n_cells_perp = int(fov_mpc / output_cell_size)
    output_volume_par = np.zeros(
        (n_cells_perp, n_cells_perp, observational_lightcone.shape[2]))
    for i in range(output_volume_par.shape[2]):
        z = cm.nu_to_z(input_freqs[i])
        output_volume_par[:,:,i] = angular_slice_to_physical(observational_lightcone[:,:,i],\
                                                    z, slice_size_deg=fov_deg, output_cell_size=output_cell_size,\
                                                    output_size_mpc=fov_mpc, order=2)
    #Bin along frequency axis
    output_volume, output_redshifts = bin_lightcone_in_mpc(output_volume_par, \
                                                input_freqs, output_cell_size)

    return output_volume, output_redshifts, output_cell_size
Beispiel #4
0
def bin_lightcone_in_mpc(lightcone, frequencies, cell_size_mpc):
    '''
    Bin a lightcone in Mpc slices along the LoS
    '''
    distances = cm.nu_to_cdist(frequencies)
    n_output_cells = (distances[-1] - distances[0]) / cell_size_mpc
    output_distances = np.arange(distances[0], distances[-1], cell_size_mpc)
    output_lightcone = np.zeros(
        (lightcone.shape[0], lightcone.shape[1], n_output_cells))

    #Bin in Mpc by smoothing and indexing
    smooth_scale = np.round(len(frequencies) / n_output_cells)

    tophat3d = np.ones((1, 1, smooth_scale))
    tophat3d /= np.sum(tophat3d)
    lightcone_smoothed = scipy.signal.fftconvolve(lightcone,
                                                  tophat3d,
                                                  mode='same')

    for i in range(output_lightcone.shape[2]):
        idx = hf.find_idx(distances, output_distances[i])
        output_lightcone[:, :, i] = lightcone_smoothed[:, :, idx]

    output_redshifts = cm.cdist_to_z(output_distances)

    return output_lightcone, output_redshifts
def observational_lightcone_to_physical(observational_lightcone, input_freqs, input_dtheta):
    '''
    Interpolate a lightcone volume measured in observational (angle/frequency)
    units into  physical (length) units. The output resolution will be set
    to the coarest one, as determined either by the angular or the frequency
    resolution. The lightcone must have the LoS as the last index, with 
    frequencies decreasing along the LoS.
    
    Parameters:
        * observational_lightcone (numpy array): the input lightcone volume
        * input_freqs (numpy array): the frequency in MHz of each slice along the 
            line of sight of the input
        * input_dheta (float): the angular size of a cell in arcmin
        
    Returns:
        * The output volume
        * The redshifts along the LoS of the output
        * The output cell size in Mpc
    '''
    assert input_freqs[0] > input_freqs[-1]
    assert observational_lightcone.shape[0] == observational_lightcone.shape[1]
    
    #Determine new cell size - set either by frequency or angle.
    #The FoV size in Mpc is set by the lowest redshift
    dnu = input_freqs[0]-input_freqs[1]
    z_low = cm.nu_to_z(input_freqs[0])
    fov_deg = observational_lightcone.shape[0]*input_dtheta/60.
    fov_mpc = fov_deg/cm.angular_size_comoving(1., z_low)
    cell_size_perp = fov_mpc/observational_lightcone.shape[0]
    cell_size_par = cm.nu_to_cdist(input_freqs[-1])-cm.nu_to_cdist(input_freqs[-2])
    output_cell_size = max([cell_size_par, cell_size_perp])
    hf.print_msg('Making physical lightcone with cell size %.2f Mpc' % output_cell_size)
    #Go through each slice along frequency axis. Cut off excess and 
    #interpolate down to correct resolution
    n_cells_perp = int(fov_mpc/output_cell_size)
    output_volume_par = np.zeros((n_cells_perp, n_cells_perp, observational_lightcone.shape[2]))
    for i in range(output_volume_par.shape[2]):
        z = cm.nu_to_z(input_freqs[i])
        output_volume_par[:,:,i] = angular_slice_to_physical(observational_lightcone[:,:,i],\
                                                    z, slice_size_deg=fov_deg, output_cell_size=output_cell_size,\
                                                    output_size_mpc=fov_mpc, order=2)
    #Bin along frequency axis
    output_volume, output_redshifts = bin_lightcone_in_mpc(output_volume_par, \
                                                input_freqs, output_cell_size)
    
    return output_volume, output_redshifts, output_cell_size
Beispiel #6
0
def bin_lightcone_in_frequency(lightcone, z_low, box_size_mpc, dnu):
    '''
    Bin a lightcone in frequency bins.
    
    Parameters:
        * lightcone (numpy array): the lightcone in length units
        * z_low (float): the lowest redshift of the lightcone
        * box_size_mpc (float): the side of the lightcone in Mpc
        * dnu (float): the width of the frequency bins in MHz
        
    Returns:
        The lightcone, binned in frequencies with high frequencies first
        The frequencies along the line of sight in MHz
    '''
    #Figure out dimensions and make output volume
    cell_size = box_size_mpc / lightcone.shape[0]
    distances = cm.z_to_cdist(z_low) + np.arange(
        lightcone.shape[2]) * cell_size
    input_redshifts = cm.cdist_to_z(distances)
    input_frequencies = cm.z_to_nu(input_redshifts)
    nu1 = input_frequencies[0]
    nu2 = input_frequencies[-1]
    output_frequencies = np.arange(nu1, nu2, -dnu)
    output_lightcone = np.zeros((lightcone.shape[0], lightcone.shape[1], \
                                 len(output_frequencies)))

    #Bin in frequencies by smoothing and indexing
    max_cell_size = cm.nu_to_cdist(output_frequencies[-1]) - cm.nu_to_cdist(
        output_frequencies[-2])
    smooth_scale = np.round(max_cell_size / cell_size)
    if smooth_scale < 1:
        smooth_scale = 1

    hf.print_msg('Smooth along LoS with scale %f' % smooth_scale)
    tophat3d = np.ones((1, 1, smooth_scale))
    tophat3d /= np.sum(tophat3d)
    lightcone_smoothed = scipy.signal.fftconvolve(lightcone,
                                                  tophat3d,
                                                  mode='same')

    for i in range(output_lightcone.shape[2]):
        nu = output_frequencies[i]
        idx = hf.find_idx(input_frequencies, nu)
        output_lightcone[:, :, i] = lightcone_smoothed[:, :, idx]

    return output_lightcone, output_frequencies
Beispiel #7
0
def get_lightcone_subvolume(lightcone, redshifts, central_z, \
                            depth_mhz=None, depth_mpc=None, odd_num_cells=True, \
                            subtract_mean=True, fov_Mpc=None):
    '''
    Extract a subvolume from a lightcone, at a given central redshift,
    and with a given depth. The depth can be specified in Mpc or MHz.
    You must give exactly one of these parameters.
    
    Parameters:
        * ligthcone (numpy array): the lightcone
        * redshifts (numpy array): the redshifts along the LOS
        * central_z (float): the central redshift of the subvolume
        * depth_mhz (float): the depth of the subvolume in MHz
        * depth_mpc (float): the depth of the subvolume in Mpc
        * odd_num_cells (bool): if true, the depth of the box will always 
                be an odd number of cells. This avoids problems with 
                power spectrum calculations.
        * subtract_mean (bool): if true, subtract the mean of the signal (Default: True)
        * fov_Mpc (float): the FoV size in Mpc
        
    Returns:
        Tuple with (subvolume, dims) where dims is a tuple
        with the dimensions of the subvolume in Mpc
    '''
    
    assert len(np.nonzero([depth_mhz, depth_mpc])) == 1
    
    if fov_Mpc == None:
        fov_Mpc = conv.LB
        
    central_nu = cm.z_to_nu(central_z)
    if depth_mpc != None: #Depth is given in Mpc
        central_dist = cm.nu_to_cdist(central_nu)
        low_z = cm.cdist_to_z(central_dist-depth_mpc/2.)
        high_z = cm.cdist_to_z(central_dist+depth_mpc/2.)
    else: #Depth is given in MHz
        low_z = cm.nu_to_z(central_nu+depth_mhz/2.)
        high_z = cm.nu_to_z(central_nu-depth_mhz/2.)
        
    if low_z < redshifts.min():
        raise Exception('Lowest z is outside range')
    if high_z > redshifts.max():
        raise Exception('Highest z is outside range')
        
    low_n = int(find_idx(redshifts, low_z))
    high_n = int(find_idx(redshifts, high_z))
    
    if (high_n-low_n) % 2 == 0 and odd_num_cells:
        high_n += 1
    
    subbox = lightcone[:,:,low_n:high_n]
    if subtract_mean:
        subbox = st.subtract_mean_signal(subbox, los_axis=2)
    box_depth = float(subbox.shape[2])/lightcone.shape[1]*fov_Mpc
    box_dims = (fov_Mpc, fov_Mpc, box_depth)
    
    return subbox, box_dims
Beispiel #8
0
def get_lightcone_subvolume(lightcone, redshifts, central_z, \
                            depth_mhz=None, depth_mpc=None, odd_num_cells=True, \
                            subtract_mean=True, fov_Mpc=None):
    '''
    Extract a subvolume from a lightcone, at a given central redshift,
    and with a given depth. The depth can be specified in Mpc or MHz.
    You must give exactly one of these parameters.
    
    Parameters:
        * ligthcone (numpy array): the lightcone
        * redshifts (numpy array): the redshifts along the LOS
        * central_z (float): the central redshift of the subvolume
        * depth_mhz (float): the depth of the subvolume in MHz
        * depth_mpc (float): the depth of the subvolume in Mpc
        * odd_num_cells (bool): if true, the depth of the box will always 
                be an odd number of cells. This avoids problems with 
                power spectrum calculations.
        * subtract_mean (bool): if true, subtract the mean of the signal (Default: True)
        * fov_Mpc (float): the FoV size in Mpc
        
    Returns:
        Tuple with (subvolume, dims) where dims is a tuple
        with the dimensions of the subvolume in Mpc
    '''

    assert len(np.nonzero([depth_mhz, depth_mpc])) == 1

    if fov_Mpc == None:
        fov_Mpc = conv.LB

    central_nu = cm.z_to_nu(central_z)
    if depth_mpc != None:  #Depth is given in Mpc
        central_dist = cm.nu_to_cdist(central_nu)
        low_z = cm.cdist_to_z(central_dist - depth_mpc / 2.)
        high_z = cm.cdist_to_z(central_dist + depth_mpc / 2.)
    else:  #Depth is given in MHz
        low_z = cm.nu_to_z(central_nu + depth_mhz / 2.)
        high_z = cm.nu_to_z(central_nu - depth_mhz / 2.)

    if low_z < redshifts.min():
        raise Exception('Lowest z is outside range')
    if high_z > redshifts.max():
        raise Exception('Highest z is outside range')

    low_n = int(find_idx(redshifts, low_z))
    high_n = int(find_idx(redshifts, high_z))

    if (high_n - low_n) % 2 == 0 and odd_num_cells:
        high_n += 1

    subbox = lightcone[:, :, low_n:high_n]
    if subtract_mean:
        subbox = st.subtract_mean_signal(subbox, los_axis=2)
    box_depth = float(subbox.shape[2]) / lightcone.shape[1] * fov_Mpc
    box_dims = (fov_Mpc, fov_Mpc, box_depth)

    return subbox, box_dims
def bin_lightcone_in_frequency(lightcone, z_low, box_size_mpc, dnu):
    '''
    Bin a lightcone in frequency bins.
    
    Parameters:
        * lightcone (numpy array): the lightcone in length units
        * z_low (float): the lowest redshift of the lightcone
        * box_size_mpc (float): the side of the lightcone in Mpc
        * dnu (float): the width of the frequency bins in MHz
        
    Returns:
        The lightcone, binned in frequencies with high frequencies first
        The frequencies along the line of sight in MHz
    '''
    #Figure out dimensions and make output volume
    cell_size = box_size_mpc/lightcone.shape[0]
    distances = cm.z_to_cdist(z_low) + np.arange(lightcone.shape[2])*cell_size
    input_redshifts = cm.cdist_to_z(distances)
    input_frequencies = cm.z_to_nu(input_redshifts)
    nu1 = input_frequencies[0]
    nu2 = input_frequencies[-1]
    output_frequencies = np.arange(nu1, nu2, -dnu)
    output_lightcone = np.zeros((lightcone.shape[0], lightcone.shape[1], \
                                 len(output_frequencies)))
    
    #Bin in frequencies by smoothing and indexing
    max_cell_size = cm.nu_to_cdist(output_frequencies[-1])-cm.nu_to_cdist(output_frequencies[-2])
    smooth_scale = np.round(max_cell_size/cell_size)
    if smooth_scale < 1:
        smooth_scale = 1

    hf.print_msg('Smooth along LoS with scale %f' % smooth_scale)
    tophat3d = np.ones((1,1,smooth_scale))
    tophat3d /= np.sum(tophat3d)
    lightcone_smoothed = fftconvolve(lightcone, tophat3d)
    
    for i in range(output_lightcone.shape[2]):
        nu = output_frequencies[i]
        idx = hf.find_idx(input_frequencies, nu)
        output_lightcone[:,:,i] = lightcone_smoothed[:,:,idx]

    return output_lightcone, output_frequencies
Beispiel #10
0
def bin_lightcone_in_mpc(lightcone, frequencies, cell_size_mpc):
    '''
    Bin a lightcone in Mpc slices along the LoS
    '''
    distances = cm.nu_to_cdist(frequencies)
    n_output_cells = (distances[-1]-distances[0])/cell_size_mpc
    output_distances = np.arange(distances[0], distances[-1], cell_size_mpc)
    output_lightcone = np.zeros((lightcone.shape[0], lightcone.shape[1], n_output_cells))
    
    #Bin in Mpc by smoothing and indexing
    smooth_scale = np.round(len(frequencies)/n_output_cells)

    tophat3d = np.ones((1,1,smooth_scale))
    tophat3d /= np.sum(tophat3d)
    lightcone_smoothed = fftconvolve(lightcone, tophat3d, mode='same')
    
    for i in range(output_lightcone.shape[2]):
        idx = hf.find_idx(distances, output_distances[i])
        output_lightcone[:,:,i] = lightcone_smoothed[:,:,idx]
    
    output_redshifts = cm.cdist_to_z(output_distances)
        
    return output_lightcone, output_redshifts