示例#1
0
def ampBiasLevel(filepath):
    file = fits.open(filepath)

    exp = geom.Exposure()
    exp.image = file[1].data
    exp.header = file[0].header
    exp = geom.Exposure(exp)
    ampIms, osIms, _ = exp.splitImage(doTrim=False)
    return [np.median(amp) for amp in ampIms]
示例#2
0
def imStats(im,
            asBias=False,
            rowTrim=(5, 5),
            colTrim=(5, 5),
            osColTrim=(3, 1)):

    exp = geom.Exposure(im)
    expTime = exp.expTime

    ampIms, osIms, _ = exp.splitImage()

    stats = []

    ampRows = slice(rowTrim[0],
                    None if rowTrim[-1] in {0, None} else -rowTrim[1])
    ampCols = slice(colTrim[0],
                    None if colTrim[-1] in {0, None} else -colTrim[1])

    osRows = ampRows
    osCols = slice(osColTrim[0],
                   None if osColTrim[-1] in {0, None} else -osColTrim[1])

    for a_i in range(8):
        stats1 = ampStats(ampIms[a_i][ampRows, ampCols],
                          osIms[a_i][osRows, osCols],
                          exp.header,
                          exptime=exp.header['EXPTIME'],
                          asBias=asBias)
        stats1['amp'] = a_i
        stats.append(stats1)

    return expTime, ampIms, osIms, stats
示例#3
0
def plotOffsetScans(fnames):
    import os.path

    for f in fnames:
        exp = geom.Exposure(f)
        m = exp.header['offset.ch0.2n']
        r = exp.header['offset.ch0.2p']
        expid = int(os.path.basename(f)[4:10], base=10)
        title = "%s\nexp %d ref=%s master=%s" % (f, expid, m, r)

        fim = exp.image
        plotAmpRows(fim,
                    cols=np.arange(10, fim.shape[1] // 8 - 10),
                    title=title)
示例#4
0
def tuneOffsets(ccd=None, feeControl=None):
    amps = list(range(8))
    feeControl.zeroOffsets(amps)

    im, fname = ccdFuncs.fullExposure('bias',
                                      ccd=ccd,
                                      feeControl=feeControl,
                                      nrows=300)
    exp = geom.Exposure(im)

    ampIms, osIms, _ = exp.splitImage(doTrim=False)

    means = []
    for a_i in range(8):
        reg = osIms[a_i][20:-20][2:-2]
        means.append(reg.mean())

    m, r = calcOffsets(1000, np.array(means))
    print("applying master: %s" % (m))
    print("applying refs  : %s" % (r))

    feeControl.setOffsets(amps, m, leg='n', doSave=False)
    feeControl.setOffsets(amps, r, leg='p', doSave=True)
    feeControl.setMode('offset')

    im, fname = ccdFuncs.fullExposure('bias',
                                      ccd=ccd,
                                      feeControl=feeControl,
                                      nrows=200)
    exp = geom.Exposure(im)

    ampIms, osIms, _ = exp.splitImage(doTrim=False)
    means = []
    for a_i in range(8):
        reg = osIms[a_i][20:-20][2:-2]
        means.append(reg.mean())
    print("final means: %s" % ' '.join(["%0.1f" % m for m in means]))
示例#5
0
def serialOverscanStats(image, readRows=(0, 4300)):
    """Calculate serial overscan levels and noise for all amplifiers.

    Parameters
    ----------
    image : `numpy.ndarray`
        Raw CCD Image

    Returns
    -------
    stats : `pd.DataFrame`
        DataFrame with stats for each amplifier.
    """
    exp = geom.Exposure()
    exp.image = image
    ampIms, osIms, _ = exp.splitImage()

    stats = [perAmpSerialOverScan(osIm[slice(*readRows)]) for osIm in osIms]
    return pd.DataFrame(stats, columns=['level', 'noise'])
示例#6
0
def flatStats(f1name, f2name):
    """ Return stats from two compatible flats.

    To calculate the gain and noise:

    Take two identical flats. Do
    stats in a standard central region, say 100x100.
    Find the median signal level in this region and
    subtract the median signal in the overscan. The
    average of these two is the SIGNAL, S

    Subtract them

    Find the quartiles in this same region. For
    gaussian noise, the sigma is .741*(3rdqt - 1stqt),
    but we have taken a difference, so
    Sig1 = (0.741/sqrt(2))*(3rdqt - 1stqt)

    is the `sigma' in the illuminated part. Also calculate
    the 3-sigma clipped standard deviation and divide it
    by sqrt(2). This is Trusig1.

    In the
    overscan region, do the same

    Sig2 = (0.741/sqrt(2))*(3rdqt - 1stqt),

    This is the read noise in ADU.

    calculate Trusig2 likewise.

    Then

    Sig = sqrt (Sig1^2 - Sig2^2)

    is the shot noise in the signal, and

    Trusig = sqrt(Trusig1^2 - Trusig2^2)

    is the `real' sigma. Compare.


    Then the inverse gain G in e-/ADU is

    G = S/(Sig^2). Calculate for both the
    sigma based on quartiles and the one
    based on moments.

    The noise in electrons is Sig2*G.

    """

    exp1 = geom.Exposure(f1name)
    exp2 = geom.Exposure(f2name)

    f1AmpIms, f1OsIms, _ = exp1.splitImage(doTrim=True)
    f2AmpIms, f2OsIms, _ = exp2.splitImage(doTrim=True)

    if (exp1.expType != 'flat' or exp2.expType != 'flat'
            or exp1.expTime != exp2.expTime):

        raise RuntimeError(
            "require matching flats (%s(%s) vs %s(%s)" %
            (exp1.expType, exp1.expTime, exp2.expType, exp2.expTime))

    stats = []
    diffAmpIms = []
    diffOsIms = []
    for a_i in range(8):
        stats1, ampIm1, osIm1 = ampDiffStats(f1AmpIms[a_i],
                                             f2AmpIms[a_i],
                                             f1OsIms[a_i],
                                             f2OsIms[a_i],
                                             exptime=exp1.expTime)
        stats1['amp'] = a_i
        stats.append(stats1)
        diffAmpIms.append(ampIm1)
        diffOsIms.append(osIm1)

    return diffAmpIms, diffOsIms, stats
示例#7
0
def CTEStats(flist, bias, amps=None, useCols=None):
    '''
    The algorithm is

    for either one flat or, better, a series of nominally identical flats prepared thus:

    adjust by adding a constant so that the median or mean OVERSCAN levels are the same

    median the frames pixel-by pixel and subtract a medianed bias, prepared the same way, and 
    also adjusted additively so that the median of the overscan area is the same as the frame--thus 
    the median of the overscan extents in the corrected frame is zero.

    let Ib be the median of the last illuminated row (for parallel CTE) or column (for serial), 
    (the last with level ~like the rest of the illuminated area.

    let Ic1 be the median of the next row or column, and Ic2 the median of
    the one after that, Ic3 the one after that, .... Let Ic be the sum of
    the first few (3?) of these

    Then if Ic1 << Ib, the CTE is

    1 - (Ic/Ib)/Npix

    Where Npix is the number of transfers to get to the edge you are
    investigating--512 for the serial CTE and 4xxx for the parallel.
    If Ic is not much less than Ib, the CTE is awful and it does not matter what you do.

    The last illuminated row or column is, of course, a property of the
    device, so determine it from the high flats and use the number
    for the low ones if it is unclear where it is for the low ones.
    '''

    flatExps = []

    allNormedOsCols = []
    allNormedOsRows = []
    allNormedCols = []
    allNormedRows = []

    allBiasOsRows = []
    allBiasOsCols = []
    allBiasRawAmps = []

    colCTEs = []
    rowCTEs = []

    expType = None
    expTime = None

    rowCteRowSlice = slice(100, None)
    colCteRowSlice = slice(150, -60)
    colSlice = slice(None, None)

    # preload the files
    for f_i, fname in enumerate(flist):
        exp = geom.Exposure(fname)

        if f_i == 0:
            expTime = exp.expTime

        if exp.expType != 'flat':
            raise RuntimeError("must use flats")
        if exp.expTime != expTime:
            raise RuntimeError("require matching flats (%s(%s) vs %s(%s)" %
                               (exp.header['IMAGETYP'], exp.header['EXPTIME'],
                                expType, expTime))
        flatExps.append(exp)

        print("%s %0.1f: %s" % (exp.expType, exp.expTime, fname))

    print()
    print("#amp    HCTE      VCTE   ampCol overCol  ampRow overRow")

    if amps is None:
        amps = list(range(exp.namps))
    biasexp = geom.Exposure(bias)
    for a_i in amps:

        # Load the bias parts once.
        biasOsRows = biasexp.overscanRowImage(a_i)[:, colSlice]
        biasOsCols = biasexp.overscanColImage(a_i)[colCteRowSlice, :]
        biasImg = biasexp.ampImage(a_i)

        allBiasOsRows.append(biasOsRows)
        allBiasOsCols.append(biasOsCols)
        allBiasRawAmps.append(biasImg)

        biasRowMed = np.median(biasOsRows)
        biasColMed = np.median(biasOsCols)

        ampOsCols = []
        ampOsRows = []
        ampRows = []
        ampCols = []
        for exp in flatExps:
            osRows = exp.overscanRowImage(a_i)[:, colSlice]
            osCols = exp.overscanColImage(a_i)[colCteRowSlice, :]
            ampImg = exp.ampImage(a_i)

            osRowMed = np.median(osRows)
            osColMed = np.median(osCols)

            ampOsCols.append((osCols - osColMed) - (biasOsCols - biasColMed))
            ampOsRows.append((osRows - osRowMed) - (biasOsRows - biasRowMed))
            ampCols.append((ampImg[colCteRowSlice, colSlice] - osColMed) -
                           (biasImg[colCteRowSlice, colSlice] - biasColMed))
            ampRows.append((ampImg[rowCteRowSlice, colSlice] - osRowMed) -
                           (biasImg[rowCteRowSlice, colSlice] - biasRowMed))

        normedOsCols = np.median(np.dstack(ampOsCols), axis=2)
        normedOsRows = np.median(np.dstack(ampOsRows), axis=2)
        normedCols = np.median(np.dstack(ampCols), axis=2)
        normedRows = np.median(np.dstack(ampRows), axis=2)

        allNormedOsCols.append(normedOsCols)
        allNormedOsRows.append(normedOsRows)
        allNormedCols.append(normedCols)
        allNormedRows.append(normedRows)

        if False:
            colCTE = 1 - (normedOsCols[:, :3].sum() /
                          normedCols[:, -1].sum()) / ampImg.shape[1]
            rowCTE = 1 - (normedOsRows[:3, :].sum() /
                          normedRows[-1, :].sum()) / ampImg.shape[0]
        elif useCols == 'b1':
            osCol = normedOsCols[:, 0]
            ampCol = normedCols[:, -1]

            osRow = normedOsRows[2, :]
            ampRow = np.mean(normedOsRows[0:2, :], axis=0)
        else:
            osCol = normedOsCols[:, 0]
            ampCol = normedCols[:, -1]
            osRow = normedOsRows[0, :]
            ampRow = normedRows[-1, :]

        colCTE = 1 - (np.mean(osCol * ampCol) /
                      np.mean(ampCol * ampCol)) / ampImg.shape[1]
        rowCTE = 1 - (np.mean(osRow * ampRow) /
                      np.mean(ampRow * ampRow)) / ampImg.shape[0]

        colCTEs.append(colCTE)
        rowCTEs.append(rowCTE)

        print("%d: %0.7f %0.7f  %7.2f %7.3f %7.2f %7.3f" %
              (a_i, colCTE, rowCTE, np.mean(ampCol), np.mean(osCol),
               np.mean(ampRow), np.mean(osRow)))

    return (colCTEs, rowCTEs, allNormedCols, allNormedOsCols, allNormedRows,
            allNormedOsRows, allBiasOsCols, allBiasOsRows)