Пример #1
0
def save_fits(data, defocus_distance, center, choose):
    '''
    Save a fits with a simple header.

    Parameters
    ----------

    data : numpy array
        Image to save

    defocus_distance : float
        Information about the defocus distance to insert in the header

    center : tuple, array
        Invormation about the coordinate to insert in the header

    choose : int
        is a variable that determines the star used
    
    '''
    log.info(hist())
 
    name = ['Kolmogorov', 'Speckle_Sum', 'Simple_seeing']
    choose = choose-1
    hdul = fits.PrimaryHDU(data) #save the file
    hdr = hdul.header
    hdr['RA'] = (center[0], "Right Ascension in decimal hours" )
    hdr['DEC'] = (center[1], "Declination in decimal degrees")
    hdr['IMGTYPE'] = 'object'
    hdr['IMAGETYP'] = 'object'
    hdr['BZERO'] = 32768
    hdr['DEFOCUS'] = (defocus_distance, "[mm] Distance from focal plane")
    hdul.scale('int16', bzero=32768)
    hdul.writeto(f'try_{name[choose]}.fits', overwrite = True)
Пример #2
0
def atmospheric_attenuation(magnitudo, photo_filter, AirMass):
    '''
    This function takes the magnitudo of a star and gives back the same magnitudo attenuated by the atmosphere.
    It download the extinction coefficients calling data_loader

    Parameters
    ----------

    magnitudo : array (float elements)
        An element of magnitudo is the magnitudo of a star in a specific range (photo_filter)

    photo_filter : list (string elements)
        It is a list where a element is a string that identifies a filter, e.g. "U","R","I"

    AirMass : float
        The AirMass provide the thickness of the atmosphere crossed by the light 

    Output
    ------

    magnitudo : array
        The array contains the elements attenuated        
    '''
    log.debug(hist())

    sub = DATA["Extinction_coefficient"]
    extinction_coefficient = [sub[k] for k in photo_filter if k in sub]
    
    for i in range(len(magnitudo)-1):
        #if magnitudo[i] == 0:
         #   magnitudo[i] = 0
        #else:
         #   magnitudo[i] = magnitudo[i]-AirMass*extinction_coefficient[i]
        magnitudo[i] = magnitudo[i]+AirMass*extinction_coefficient[i]
    return magnitudo
Пример #3
0
def magnitudo_to_photons(magnitudo, photo_filter):
    '''
    This function convertes the magnitudo of a star in number of photons/second.
    It download informations calling data_loader

    Parameters
    ----------

    magnitudo : array (float elements)
        An element of magnitudo is the magnitudo of a star in a specific range (photo_filter)

    photo_filter : list (string elements)
        It is a list where a element is a string that identifies a filter, e.g. "U","R","I"

    Output
    ------

    photons : array
        The elements of the array are the number of photons for a specific range        
    '''
    log.debug(hist())
    
    sub = DATA["Central_wavelenght"]
    central_wavelenght = [sub[k] for k in photo_filter if k in sub]
    
    number = magnitudo   
    for i in range(len(magnitudo)-1):
        if magnitudo[i] == 0:
            number[i] = 0
        else:
            exp = 6.74-0.4*magnitudo[i]
            number[i] = (10**exp)#/(central_wavelenght[i])
    return number
Пример #4
0
def photons_to_electrons(photons, photo_filter):
    '''
    This function takes the number of photons/sec and converts them in number of electron/sec on the CCD.
    It calls data_loader to download the quantum efficiency of the CCD

    Parameters
    ----------

    photons : array
        The elements of the array are the number of photons for a specific range

    photo_filter : list (string elements)
        It is a list where a element is a string that identifies a filter, e.g. "U","R","I"

    Output

    electron : array
        The elements of the array are the number of electrons for a specific range 
    '''
    log.debug(hist())

    sub = DATA["Quantum_efficiency"]
    quantum_efficiency = [sub[k] for k in photo_filter if k in sub]
    
    electrons = photons
    for i in range(len(photons)-1):
        electrons[i] = photons[i]*quantum_efficiency[i]

    return electrons
Пример #5
0
def saturation_controll(image):
    '''
    The value of a pixel can't overcome the maximum value of a 16bit memory (65535) and it is
    called saturated. This function will controll that no pixel would surpass this value and,
    if it does, this function will reset its value to 65535

    Parameter
    ---------

    image : numpy ndarray
        It is the image to controll

    Output
    ------

    image : numpy ndarray
        The image controlled and adjusted
    '''

    log.info(hist())

    size = image.shape

    for i in range(size[0]):
        for j in range(size[1]):
            if image[i, j] >= 65535:
                image[i, j] = 65535
    return image
Пример #6
0
def physical_CCD(CCD_structure):
    '''
    Generates a CCD with a given structure

    Parameters
    ----------

    CCD_structure : array
        The varies entries must have the measure on the CCD
        [0] : int, float; the x length of the CCD in mm
        [1] : int, float; the y length of the CCD in mm
        [2] : float     ; the length of a pixel in mm

    Outputs
    -------

    CCD : numpy ndarray
        The image of the CCD

    x : numpy ndarray
        The x variable on the CCD

    y : numpy ndarray
        The y variable on the CCD   
    '''
    log.info(hist())
        
    len_y = int(CCD_structure[0]/CCD_structure[2])//2
    len_x = int(CCD_structure[1]/CCD_structure[2])//2
    x, y = np.mgrid[-len_x:len_x,-len_y:len_y]
    r = np.sqrt(x**2+y**2)
    CCD = np.piecewise(r, [r], [0])
    return CCD    
Пример #7
0
def intensity_aberration(aperture, scale, modes, pupil):
    '''Creates the amplitude atmospheric aberration.

    Parameters
    ----------

    aperture : int
        The aperture of the telescope in mm

    scale : int
        The scale of the image generated

    modes : int
        Number of zernikle terms to use 

    pupil : numpy ndarray
        The image of the aperture


    Output
    ------

    zernike : numpy ndarray
        The image of the aberration overlapped with the image of the aperture
    '''

    log.info(hist())
        
    nx_size= aperture//scale
    zernike = []
    zernike_array = ZA(modes, nx_size)
    for i in range(modes):
        zernike.append(reshape_aber(zernike_array[i], scale, pupil))
    return zernike
Пример #8
0
def defocus(pupil, defocus_distance, r, wavelenght):
    '''
    Takes the image and created the FT at some distance

    Parameters
    ----------

    pupil : numpy ndarray
        The image of the aperture to transform

    defocus_distance : float
        The distance of the defocus in mm in range(-2.5,2.5)

    r : numpy ndarray
        The radial variable on the pupil

    wavelenght : float
        The center wavelength in mm

    Output
    ------

    image : numpy ndarray
        The FT of the pupil at defocus_distance from the focus plane, AKA the PSF
    '''
    log.info(hist())
        
    phaseAngle = 1j*defocus_distance*10*np.sqrt((2*np.pi/wavelenght)**2-r**2+0j) #unnecessary 0j but keeping it for complex reasons
    kernel = np.exp(phaseAngle)
    defocusPupil = pupil * kernel
    defocusPSFA = fft.fftshift(fft.fft2(defocusPupil))
    image = np.abs(defocusPSFA)
    return image
Пример #9
0
def reshape_aber(image, scale, pupil):
    '''
    Adapt the aberration to the pupil size

    Parameters
    ----------

    image : int
        The aperture of the telescope in mm

    scale : int
        The scale of the image generated

    pupil : numpy ndarray
        The image of the aperture


    Output
    ------

    image : numpy ndarray
        The image of the aberration with the right shape to be combinated
        with the aperture    
    '''

    log.info(hist())
        
    image = np.repeat(np.repeat(image, scale, axis = 0), scale, axis = 1)
    units= int((np.shape(pupil)[0]-np.shape(image)[0])/2)
    image = np.pad(image,(units), mode = 'constant')
    return image
Пример #10
0
def VEGA_to_AB(magnitudo, photo_filter):
    '''
    This function takes the magnitudo of a star in the VEGA system and converts it in the AB system.
    It download the conversion table calling data_loader

    Parameters
    ----------

    magnitudo : array (float elements)
        An element of magnitudo is the magnitudo of a star in a specific range (photo_filter)

    photo_filter : list (string elements)
        It is a list where a element is a string that identifies a filter, e.g. "U","R","I"

    Output
    ------

    magnitudo : array
        The array contains the elements converted        
    '''

    log.debug(hist(photo_filter))

    sub = DATA["Convertion_table"]
    convertion_table = [sub[k] for k in photo_filter if k in sub]
    for i in range(len(magnitudo)-1):
        if magnitudo[i]== 0:
            magnitudo[i]= 40
        else:
            magnitudo[i] = magnitudo[i] - convertion_table[i]
        magnitudo[i] = magnitudo[i] - convertion_table[i]
    return magnitudo
Пример #11
0
def radius_sky_portion(CCD_structure):
    '''
    This function uses the information on the CCD to estimate the radius of the portion of the sky visualized

    Parameters
    ----------

    CCD_structure : array (float elements)
        This object contains the information about the measure of the CCD
        [0] : the length of the CCD on the x axis in mm
        [1] : the length of the CCD on the y axis in mm
        [2] : the length of a single pixel in mm

    Output
    ------
     radius : astropy.units.quantity.Quantity
         it is the radius in an astropy undestandable format
    '''
    log.debug(hist())
    
    pixel_on_x = CCD_structure[0]/CCD_structure[2]
    pixel_on_y = CCD_structure[1]/CCD_structure[2]
    diagonal_diameter = np.sqrt((pixel_on_x)**2+(pixel_on_y)**2)
    radius_on_pixel = diagonal_diameter/2
    radius = radius_on_pixel*CCD_structure[3]/60
    radius = (radius/60)*u.deg
    return radius
Пример #12
0
def read_out_noise(image, amount, gain=1.0):
    '''
    This function provides the errors introduced with the readout of the CCD
    
    Parameters
    ----------

    image : numpy ndarray  #can be changed with the only shape 
        The image of the CCD, used by the function to extract the shape

    amount : float, int
        The central value of the distribution of the errors, it should be
        related with the background (the sqrt)

    gain : float, optional
        The value of the gain used by the CCD

    Output
    ------

    noise : numpy ndarray
        The image of the CCD with the readout noise generated
    '''

    log.info(hist())

    shape = image.shape
    noise = np.random.normal(scale=amount / gain, size=shape)

    return noise
Пример #13
0
def converter_to_pixel(CCD_resolution, focal_lenght, quantity_to_convert):  #TO REVISIONATE
    '''Convert a quantity on the aperture to pixels on CCD '''
    log.info(hist())
        
    converter_rad_arc = 180*3600/np.pi
    quantity_to_convert = quantity_to_convert
    quantity_angle = np.arctan(quantity_to_convert/focal_lenght) * converter_rad_arc
    Q_on_CCD = quantity_angle / CCD_resolution
    return Q_on_CCD
Пример #14
0
def sensitivity_variations(image, vignetting=True, dust=True):
    '''
    The sensivity isn't constant, but can vary over the CCD, tipically
    with a gaussian trend and can be worsen by the presence of the dust.
    This function provides for this, creating the flat frame
    

    Parameters
    ----------

    image : numpy ndarray  #can be changed with the only shape nect
        The image of the CCD, used by the function to extract the shape

    vignetting : bool, optional
        If True, the gaussian figure is created on a image with the shape
        of the CCD

    dust : bool, optional
        If True, there will be added the donut generated by the dust on the
        CCD image


    Output
    ------

    sensitivity :numpy ndarray
        The image of the CCD with a big gaussuan curve
        to simulate the variability of the sensivity
    '''
    log.info(hist())

    sensitivity = np.zeros_like(image) + 1.0
    shape = np.array(sensitivity.shape)

    if dust or vignetting:
        # I don't know why, but y,x not x,y
        y, x = np.indices(sensitivity.shape)

    if vignetting:  #TODO, centro gaussiana da spostare
        # Generate very wide gaussian centered on the center of the image,
        # multiply the sensitivity by it.
        #narrowing = np.random.randint(5,10)
        vign_model = Gaussian2D(amplitude=1,
                                x_mean=shape[0] / 2,
                                y_mean=shape[1] / 2,
                                x_stddev=2 * (shape.max()),
                                y_stddev=2 * (shape.max()))
        vign_im = vign_model(x, y)
        sensitivity *= vign_im

    if dust:
        dust_im = add_donuts(image, number=20)
        dust_im = dust_im / dust_im.max()
        sensitivity *= dust_im

    return sensitivity
Пример #15
0
def load_measure():
    '''
    Load the basic data of the telescope and the CCD from a JSON file

    Outputs
    -------
    telescope_structure : list
        a list that contains the information about the telescope
        telescope_structure[0] = f_l : int
            It is the focal length of the telescope in mm            
        telescope_structure[1] = ape : int
            It is the aperture of the telescope in mm
        telescope_structure[2] = obs : int
            It is the central obstruction of the telescope in mm
        telescope_structure[3] = wav : float
            It is the central wavelength of the sensible spectrum of the CCD in mm

    ccd_structure : array
        a array that contains the information about the CCD
        ccd_structure[0] = C_x : float
            It is the length of the CCD along the x axis in mm
        ccd_structure[0] = C_y : float
            It is the length of the CCD along the y axis in mm
        ccd_structure[0] = pix : float
            It is the lenght of a single pixel in mm

    ccd_data : list
        a list that cointains information about the errors generated in the CCD
        ccd_data[0] = gain : float
            the gain of the CCD
        ccd_data[1] = read_out_electrons : float
            the electrons that generate the read out noise
    '''
    log.info(hist())

    #filename = "Antola_data.json"
    #filename = "San_Pedro_data.json"
    filename = "San_Pedro_data_CCD2.json"
    f = open(filename, "r")
    data = json.load(f)
    Telescope = data['Telescope']
    f_l = Telescope['focal_lenght']
    ape = Telescope['aperture']
    obs = Telescope['obstruction']
    wav = Telescope['wavelenght']
    CCD = data['CCD']
    C_x = CCD['CCD_x']
    C_y = CCD['CCD_y']
    pix = CCD['pixels']
    gain = CCD['gain']
    read_out_electrons = CCD["read_out_electrons"]
    f.close()
    telescope_structure = (f_l, ape, obs, wav)
    ccd_structure = [C_x, C_y, pix]
    ccd_data = (gain, read_out_electrons)
    return telescope_structure, ccd_structure, ccd_data
Пример #16
0
def Data_structure():
    '''
    This function simply creates the data structure used in query
    '''
    log.debug(hist())
    
    Coord_x = []
    Coord_y = []
    Flux_tot = []
    data = [Coord_x, Coord_y, Flux_tot]
    return data
Пример #17
0
def sky_background_aperture(focal_lenght, aperture, obstruction, trellis=True, atmosphere=False):
    '''
    Calls telescope, intensity_aberration and phase_aberration to create the optical
    figure at the aperure
    
    Parameters
    ----------

    focal_lenght : int
        The focal length of the telescope in mm

    aperture : int
        The aperture of the telescope in mm

    obstruction : int
        The central obstraction of the telescope in mm

    trellis : bool, optional
        If trellis == True the structure that hold on the obstruction is drawn,
        else the structure is not drawn

    atmosphere : bool, optional
        If atmosphere == True intensity_aberration and phase_aberration are called,
        else they are not

    Output
    ------

    pupil : numpy ndarray
        The image of the aperture with all the aberrations

    r : numpy ndarray
        The radial variable on the pupil
    '''
    log.info(hist())
        
    pupil, r = telescope(focal_lenght, aperture, obstruction, trellis)

    if atmosphere:
        #zer = intensity_aberration(aperture, scale, modes, pupil)
        #zernike = zer[0]

        #for i in range(modes-1):
        #    a = np.random.random()
        #    zernike += (a/5)*zer[i]

        phase = phase_aberration(aperture, scale, D, r0, L0, pupil) #Small aperture, long exposure, the kolmogorov turbulance on small scale are no
        #phase = np.sqrt(np.abs(phase))**2
        
        kernel = pupil * phase
        pupil = pupil * np.exp(1j*kernel+0j)
    return pupil, r
Пример #18
0
def Coordinator(coord, center, CCD_structure, catalog):
    '''
    The function takes the coordinates of a star and uses the WCS keywords
    to give back the position on the CCD in pixel

    Parameters
    ----------

    coord : SkyCoord
        It is the coordinates of the star already elaborated by astropy

    center : array
        It must contain the position of the center of the CCD and it is used to obtain
        the distance of the star from it

    CCD_res : float
        It is the resolution of the CCD in arcsec/pixel

    Outputs
    -------

    x : float
        It is the position of the star on the grid of the CCD along the axis x

    y : float
        It is the position of the star on the grid of the CCD along the axis y
    '''

    log.info(hist())
    if catalog == 'Simbad':
        offset_x = CCD_structure[0]/CCD_structure[2]
        offset_y = CCD_structure[1]/CCD_structure[2]
        w = wcs.WCS(naxis=2)
        w.wcs.crpix = [1, 1]
        w.wcs.crval = [center[0], center[1]]
        w.wcs.ctype = ["RA", "DEC"]    
        x,y = wcs.utils.skycoord_to_pixel(coord, w)
        x = ((x*3600)/CCD_structure[3]) + offset_x/2 #(deg*arc/sec*deg)*arc/sec*pixel+offset
        y = ((y*3600)/CCD_structure[3]) + offset_y/2
    elif catalog == 'Gaia':
        offset_x = CCD_structure[0]/CCD_structure[2]
        offset_y = CCD_structure[1]/CCD_structure[2]
        w = wcs.WCS(naxis=2)
        w.wcs.crpix = [1, 1]
        w.wcs.crval = [center[0], center[1]]
        w.wcs.ctype = ["RA", "DEC"]    
        x,y = wcs.utils.skycoord_to_pixel(coord, w)
        x = ((x*3600)/CCD_structure[3]) + offset_x/2 #(deg*arc/sec*deg)*arc/sec*pixel+offset
        y = ((y*3600)/CCD_structure[3]) + offset_y/2

    return y, x
Пример #19
0
def make_cosmic_rays(image, number, strength=10000):
    '''
    It can appens that during an acquisition of an image some pixel are "saturated"
    by the cosmic rays, this function provides for a CCD image with this effect

    Parameters
    ----------

    image : numpy ndarray  #can be changed with the only shape
        The image of the CCD, used by the function to extract the shape

    number : int
        This number is the number of cosmic ray within a single image

    strenght : int, optional
        This is the intensity of a cosmic ray on a pixel

    Output
    ------

    cosmic_image :numpy ndarray
        The image of the CCD with the pixel overflowed by the cosmic rays generated
    '''

    log.info(hist())

    cosmic_image = np.zeros_like(image)

    # Yes, the order below is correct. The x axis is the column, which
    # is the second index.
    max_y, max_x = cosmic_image.shape

    # Get the smallest dimension to ensure the cosmic rays are within the image
    maximum_pos = np.min(cosmic_image.shape)
    # These will be center points of the cosmic rays, which we place away from
    # the edges to ensure they are visible.
    xy_cosmic = np.random.randint(0.1 * maximum_pos,
                                  0.9 * maximum_pos,
                                  size=[number, 2])

    cosmic_length = 5  # pixels, a little big
    cosmic_width = 2
    theta_cosmic = 2 * np.pi * np.random.rand()
    apertures = EllipticalAperture(xy_cosmic, cosmic_length, cosmic_width,
                                   theta_cosmic)
    masks = apertures.to_mask(method='center')
    for mask in masks:
        cosmic_image += strength * mask.to_image(shape=cosmic_image.shape)

    return cosmic_image
Пример #20
0
def telescope_on_CCD(CCD_resolution, binning, telescope_structure, defocus_distance, trellis=True, atmosphere=False):
    '''
    This function calls sky_backgroud_aperture, defocus and image_processing to create the sample on the PSF on the CCD

    Parameters
    ----------

    CCD_resolution : float
        The resolution on the CCD in arcsec/pixel

    telescope_structure : list
        
        telescope_structure[0] = focal_lenght : int
            The focal length of the telescope in mm

        telescope_structure[1] = aperture : int
            The aperture of the telescope in mm

        telescope_structure[2] = obstruction : int
            The central obstraction of the telescope in mm

        telescope_structure[3] = wavelenght : float
            The center wavelength in mm

    defocus_distance : float
        The distance of the defocus in mm in range(-2.5,2.5)
    
    trellis : bool, optional
        If trellis == True the structure that hold on the obstruction is drawn,
        else the structure is not drawn

    atmosphere : bool, optional
        If atmosphere == True intensity_aberration and phase_aberration are called,
        else they are not

    Output
    ------

    image : numpy ndarray
        The image of the PSF
    '''
    log.info(hist())
        
    #units =  converter_to_pixel(CCD_resolution, focal_lenght, 1) #convert 1mm on the aperture in pixel on CCD
    units = CCD_resolution//0.12 #empiric value
    image, r = sky_background_aperture(telescope_structure[0], telescope_structure[1], telescope_structure[2], trellis, atmosphere) #creates the aperture 
    image = defocus(image, defocus_distance, r, telescope_structure[3]) #creates the image on the screen
    image = image_processing(image, binning, telescope_structure[1], atmosphere) 
    return image
Пример #21
0
def dark_current(image, current, exposure_time, gain=1.0, hot_pixels=False):
    '''
    This function creates a matrix with the shape of the CCD with the errors introduced
    by the dark current with a poissonian distribution. It also provide for the presence
    of hot pixels in the CCD

    Parameters
    ----------

    image : numpy ndarray  #can be changed with the only shape 
        The image of the CCD, used by the function to extract the shape

    current : float
        This is the value of the dark current for 1 second

    exposure_time : int
        The number of second used for obtainig the CCD's image

    gain : float, optional
        The value of the gain used in the CCD, more the gain, more the errors

    hot_pixel : bool, optional
        This flag allows to choose if there will by the hot pixels or not
        if True there will be hot pixels

    Output
    ------

    dark_bias : numpy ndarray
        The image of the CCD with the dark current noise generated
    '''

    log.info(hist())

    base_current = current * exposure_time / gain
    dark_bias = np.random.poisson(base_current, size=image.shape)

    if hot_pixels:
        '''set the probability of 0.01% of a pixel to be hot'''
        y_max, x_max = dark_bias.shape

        numb_hot = int(0.0001 * x_max * y_max)
        hot_x = np.random.randint(0, x_max, size=numb_hot)
        hot_y = np.random.randint(0, y_max, size=numb_hot)

        hot_current = 10000 * current
        dark_bias[[hot_y, hot_x]] = hot_current * exposure_time  #/gain

    return dark_bias
Пример #22
0
def image_processing(image, m, aperture, atmosphere):
    '''
    This function takes an image and some parameters to obtain the same image cut and strechetd to fit the CCD.
    Also, this function takes only the essentioal information thus reducing the total weight of the final image 

    Parameters
    ----------

    image : numpy ndarray
        The image, usually the PSF

    m : int
        The binnig, used to re-sum the PSF pixels

    aperture : int
        The aperture of the telescope in mm

    atmosphere : bool
        To the long exposure 

    Output
    ------

    new_image : numpy ndarray
        The image cleaned with only the good parts and with the right measure
    '''
    log.info(hist())
    image = (np.abs(image))**2
    size = image.shape
    if atmosphere:
        m = m*4
    new_size = (size[0]//m, size[1]//m)
    new_image = np.zeros(new_size)
    
    if m==1:
        new_image = image
    elif m>=2:
        for i in range(new_size[0]):
            for j in range(new_size[1]):
                new_image[[i],[j]] = sum_image(image, i, j, m)    
    else:
        print('binning problem, PSF binnig ignored')
        new_image = image
    new_image = (new_image/(np.sum(new_image)))*0.2

    new_image = rotate(new_image, angle=45)
    return new_image  
Пример #23
0
def phase_aberration(aperture, scale, D, r0, L0, pupil):
    '''
    Creates an image with the Kolmogorov algorithm
    with the phase atmospheric aberration.
    This function works but usually is not used
    because the telescope is limited by the seeing.

    Parameters
    ----------

    aperture : int
        The aperture of the telescope in mm

    scale : int
        The scale of the image generated

    D : int #inutile e rindondante con aperture, da cambiare e togliere

    r0 : float
        The Fried parameter of the 'seeing'

    L0 : float, int
        The outer scale of the 'seeing'

    pupil : numpy ndarray
        The image of the aperture


    Output
    ------

    phase_screen : numpy ndarray
        The image of the turbolence overlapped with the image of the aperture
    '''

    log.info(hist())
    nx_size= aperture//scale
    plx_scale = D/nx_size
    phase_screen = PhaseScreenKolmogorov(nx_size, plx_scale, r0, L0)
    phase_screen.add_row()
    phase_screen = phase_screen.scrn
    phase_screen = reshape_aber(phase_screen, scale, pupil)
    return phase_screen
Пример #24
0
def magnitudo_to_electrons(magnitudo, photo_filters, AirMass, exposure_time, Controll):
    '''
    This functions calls VEGA_to_AB, atmospheric_attenuation, magnitudo_to_photons, photons_to_electrons
    to obtain the total electrons generated in a CCD by the light of a star
    
    Parameters
    ----------

    magnitudo : array (float elements)
        An element of magnitudo is the magnitudo of a star in a specific range (photo_filter)

    photo_filter : list (string elements)
        It is a list where a element is a string that identifies a filter, e.g. "U","R","I"

    AirMass : float
        The AirMass provide the thickness of the atmosphere crossed by the light

    exposure_time : int
        It is the exposure time used to obtain the image, it is in seconds

    Output
    ------

    tot : float
        It is the total number of electrons generated by the star on the CCD
    '''
    log.debug(hist())
    magnitudo = VEGA_to_AB(magnitudo, photo_filters)
    magnitudo = atmospheric_attenuation(magnitudo, photo_filters, 1)
    photons = magnitudo_to_photons(magnitudo, photo_filters)
    electrons = photons_to_electrons(photons, photo_filters)
    
    if Controll:
        for n, i in enumerate(photo_filters):
            if i == "V":
                if electrons[n] <= 3e-4:
                    electrons[n] = electrons[-1]
        tot = (sum(electrons)-electrons[-1])*exposure_time
    else:
        tot = sum(electrons)*exposure_time
    return tot
Пример #25
0
def sky_brightness(plate_scale, x_pix, y_pix, photo_filters, exposure_time, moon_phase=3):
    
    log.info(hist())
    '''
    moon_phase = int, optional
        moon_phase can go to 0 (new moon) to 3 (full moon) with intermedian phases 1 (7 day from new moon) and 2 (10 day from new moon)
    '''
    sub = DATA["Sky_brightness"]
    for n, i in enumerate(photo_filters):
        if i == "g":
            photo_filters[n] = "V"
    sky_brightness = [sub[k] for k in photo_filters if k in sub]
    x_arcsec = plate_scale * x_pix
    y_arcsec = plate_scale * y_pix
    Area = x_arcsec * y_arcsec
    magnitudo_ab_sky = []
    magnitudo_ab_sky.append(sky_brightness[0][moon_phase] - 2.5*np.log10(Area))
    photons = magnitudo_to_photons(magnitudo_ab_sky, photo_filters)
    electrons = photons_to_electrons(photons, photo_filters)
    tot = sum(electrons)*exposure_time
    return tot
Пример #26
0
def bias(image, value, realistic=False):
    '''
    This function creates a matrix with the shape of the CCD with the bias and
    some bad colums
    
    Parameters
    ----------

    image : numpy ndarray  #can be changed with the only shape 
        The image of the CCD, used by the function to extract the shape

    value: int
        It is the bias level to add at the CCD

    realistic : bool, optional
        If True there will be add some bad columns at the CCD

    Output
    ------

    bias_image : numpy ndarray
        The image of the CCD with the bais generated
    '''

    log.info(hist())

    bias_image = np.zeros_like(image) + value

    if realistic:
        shape = image.shape
        number_of_columns = np.random.randint(1, 6)
        columns = np.random.randint(0, shape[1], size=number_of_columns)
        col_pattern = np.random.randint(0, int(
            0.1 * value), size=shape[0])  #add a little pseudo-random noise

        for c in columns:
            bias_image[:, c] = value + col_pattern

    return bias_image
Пример #27
0
def make_one_donut(center, diameter=10, amplitude=0.25):
    '''
    This fuction is pretty eavy, it uses 3 mathematical fuction creates the
    image of a single donut to by added to the flat image

    Parameters
    ----------

    center : numpy array
        center[0] : the position along the x axis of the center of the donut
        center[1] : the position along the y axis of the center of the donut

    diameter : int, float
        Can be interpreted as the diameter in pixel of the donut.
        In reality it is 2sigma of the Gaussian and RickerWavelet (ex MexicaHat)
        functions used to simulate the donut

    amplitude : float, optional
        The peak intensity of the aforementioned functions

    Output
    ------

    Const2D(amplitude=1) + (mh - gauss) : numpy array
        It is a image of the donut created 
    '''
    log.info(hist())

    sigma = diameter / 2
    mh = RickerWavelet2D(amplitude=amplitude,
                         x_0=center[0],
                         y_0=center[1],
                         sigma=sigma)
    gauss = Gaussian2D(amplitude=amplitude,
                       x_mean=center[0],
                       y_mean=center[1],
                       x_stddev=sigma,
                       y_stddev=sigma)
    return Const2D(amplitude=1) + (mh - gauss)
Пример #28
0
def telescope(focal_lenght, aperture, obstruction, trellis=True):
    '''
    Creates the figures of the telescope

    Parameters
    ----------

    focal_lenght : int
        The focal length of the telescope in mm

    aperture : int
        The aperture of the telescope in mm

    obstruction : int
        The central obstraction of the telescope in mm

    trellis : bool, optional
        If trellis == True the structure that hold on the obstruction is drawn,
        else the structure is not drawn

    Output
    ------

    pupil : numpy ndarray
        The image of the aperture

    r : numpy ndarray
        The radial variable on the pupil   
    '''
    log.info(hist())

    x,y = np.mgrid[-aperture/2:aperture/2, -aperture/2:aperture/2] # creates the 2D grid for the 2D function *4
    r = np.sqrt(x**2+y**2)
    pupil = np.piecewise(r, [r < aperture/2, r > aperture/2, r < obstruction/2], [1, 0, 0]) #creates the aperture
    if trellis:
        structure_x = np.piecewise(x, [x, x>1, x<0], [0,1,1]) #creates the structure that keep the obstruction
        structure_y = np.piecewise(y, [y, y>1, y<0], [0,1,1])
        pupil = pupil*(structure_x*structure_y)
    return pupil, r
Пример #29
0
def synthetic_ccd(shape):
    '''
    Given a shape this function will creates an empty image with that shape

    Parameters
    ----------

    shape: tuple
        shape[0] : int, the shape of the CCD along the x axis in number of pixel
        shape[1] : int, the shape of the CCD along the y axis in number of pixel

    Output
    ------

    ccd_image : numpy ndarray
        The empy image with the choosen shape
    '''

    log.info(hist())

    ccd_image = np.zeros(shape)

    return ccd_image
Пример #30
0
def main():
    '''
    This is the main function of the system, it coordinates the Telescope_mod, the ccd_mod and the Query_mod.
    First it calls load_measure to obtain some data for Telescope_mod and Query_mod, the uses Telescope_mod
    with some additional parameters in input to create the PSF with the right measure for the telescope and the CCD.
    
    At this point the function calls again the Telescope_mod to creats an empty image of the CCD, and the Query_mod
    to obtain information about the position and the flux of the stars in a specific reagion of the sky,
    the center of that is an imput from the operator.

    The function uses the information of Query_mod to "light_up" some pixel on the CCD's image in position where shoud be the stars
    and then convolve this updated CCD with the calculated PSF from Telescope_mod obtainig the CCD with the stars drawn.

    If the value of realistic is True, the main calls the ccd_mod to creates the bias frame, the dark frame, the read out noise,
    the backround noise and the flat frame and then combines all the frames to obtain a more realistic image on the CCD.    
    '''
    log.info(hist())

    binning = 2
    #photo_filters = ['U', 'B', 'V', 'R', 'I']
    photo_filters = ['V']
    
    default_coordinates = "07 59 08.445 +15 24 42.00"
    default_defocus = 0.0 #mm
    default_exptime = 60
    default_seeing = 3
    default_method = 3 # gaussian approx
    default_catalog = 1
    
    coordinates = input(f'Coordinates. Default: {default_coordinates}. ') or default_coordinates
    defocus_distance = float(input(f'Defocus distance [mm]. Default: {default_defocus}. ') or default_defocus)
    exposure_time = float(input(f'Exptime [s]. Default: {default_exptime}. ') or default_exptime) 
    seeing = float(input(f'Seeing [arcsec]. Default: {default_seeing}. ') or default_seeing) 
    choose = int(input(f'Method. Kolmogorov (1), spekles (2), gaussian approximation(3). Default: {default_method}. ') or default_method)
    catalogue = default_catalog # int(input(f'Catalog. Gaia(1) or Simbad(2). Default Catalog: {default_catalog}') or default_catalog )
    if catalogue == 1:
        catalogue = 'Gaia'
        log.warning('This catalog uses its own passband, simulated results can be different from the real ones')
        
    else:
        catalogue = 'Simbad'
    telescope_structure, ccd_structure, ccd_data = load_measure()

    #Standard data for the noise formation 
    realistic = True
    dark = 1.04
    bias_level = 0 #760 # 2000
    
    gain = ccd_data[0]
    read_noise_electrons = ccd_data[1]

    ccd_structure[2] = ccd_structure[2] * binning
    ccd_structure.append(Tm.plate_scale(ccd_structure[2], telescope_structure[0])) #calculate the resolution of the CCD arcsec/pixel
    if choose == 1:
        CCD_sample = Tm.telescope_on_CCD(ccd_structure[3], binning, telescope_structure, defocus_distance, True, True)
    else:
        CCD_sample = Tm.telescope_on_CCD(ccd_structure[3], binning, telescope_structure, defocus_distance, True, False) #generates the sample of a star with the right measure

    CCD = Tm.physical_CCD(ccd_structure) #generate the CCD
    size = CCD.shape

    if choose == 2:
        CCD_seeing = seeing/(ccd_structure[3]*2)
        number_of_spekle = 100 * exposure_time
        seeing_image = Tm.main_spekle(number_of_spekle, CCD_seeing)
        seeing_image = seeing_image/number_of_spekle
    elif choose == 3:
        CCD_seeing = seeing/(ccd_structure[3]*2)
        seeing_image = Tm.seeing(CCD_seeing)

    sky, center = Qm.query(coordinates, photo_filters, ccd_structure, exposure_time, catalogue) #call a function that gives back positions, fluxs of the stars and a data for the header
    sky_counts = Qm.sky_brightness(ccd_structure[3], size[0], size[1], photo_filters, exposure_time, 3)

    photons_collection_area = (np.pi/400)*(telescope_structure[1]**2-telescope_structure[2]**2)

    if choose == 1:
        multiplier = 2 * gain * photons_collection_area *0.05
    else:
        multiplier = 1 * gain * photons_collection_area *0.05 #photons_collection_area * gain * binning**2 #* 200 #I don't know where 200 cames from I'm investigating
                                    #the flux is in ph cm^-2 so it has to be multiplied for the effective area of the aperure in cm^2

    for i in range(len(sky[0])):
        if sky[0][i] >=0 and sky[0][i] <=size[0]:
            if sky[1][i] >=0 and sky[1][i] <=size[1]:
                CCD[int(sky[0][i])][int(sky[1][i])] = sky[2][i] * multiplier

    

    CCD = signal.fftconvolve(CCD, CCD_sample, mode='same')  #convolve the position with the sample

    if choose == 2 or choose == 3:
        CCD = signal.fftconvolve(CCD, seeing_image, mode='same')   

    lines = False
    dust = False
    gaussian_vignetting = False
    
    if realistic: 

        flat = ccd_mod.sensitivity_variations(CCD, gaussian_vignetting, dust)
        if bias_level == 0:
            bias_only = 0
        else:
            bias_only = ccd_mod.bias(CCD, bias_level, lines)
        noise_only = ccd_mod.read_out_noise(CCD, read_noise_electrons, gain) 
        dark_only = ccd_mod.dark_current(CCD, dark, exposure_time, gain)
        sky_only = ccd_mod.sky_background(CCD, sky_counts, gain)
        #cosmic_rays = ccd_mod.make_cosmic_rays(CCD, np.random.randint(10,30))

        CCD = bias_only + noise_only + dark_only + flat * (sky_only + CCD)
        CCD = ccd_mod.saturation_controll(CCD)
    
    save_fits(CCD, defocus_distance, center, choose) #save the fits