コード例 #1
0
ファイル: refcal_anal.py プロジェクト: sjyu1988/eovsa
def unrot_refcal(refcal_in):
    ''' Apply feed-rotation correction to data read with rd_refcal(), returning updated data in
        the same format for further processing.
    '''
    import dbutil as db
    import copy
    import chan_util_bc as cu
    import cal_header as ch
    from stateframe import extract
    refcal = copy.deepcopy(refcal_in)
    xml, buf = ch.read_cal(11, Time(refcal['times'][0][0], format='jd'))
    dph = extract(buf, xml['XYphase'])
    xi_rot = extract(buf, xml['Xi_Rot'])
    freq = extract(buf, xml['FGHz'])
    freq = freq[np.where(freq != 0)]
    band = []
    for f in freq:
        band.append(cu.freq2bdname(f))
    bds, sidx = np.unique(band, return_index=True)
    nbd = len(bds)
    eidx = np.append(sidx[1:], len(band))
    dxy = np.zeros((14, 34), dtype=np.float)
    xi = np.zeros(34, dtype=np.float)
    fghz = np.zeros(34)
    # average dph and xi_rot frequencies within each band, to convert to 34-band representation
    for b, bd in enumerate(bds):
        fghz[bd - 1] = np.nanmean(freq[sidx[b]:eidx[b]])
        xi[bd - 1] = np.nanmean(xi_rot[sidx[b]:eidx[b]])
        for a in range(14):
            dxy[a, bd - 1] = np.angle(np.sum(np.exp(1j * dph[a, sidx[b]:eidx[b]])))
    nscans = len(refcal['scanlist'])
    for i in range(nscans):
        # Read parallactic angles for this scan
        trange = Time([refcal['tstlist'][i].iso, refcal['tedlist'][i].iso])
        times, chi = db.get_chi(trange)
        tchi = times.jd
        t = refcal['times'][i]
        if len(t) > 0:
            vis = copy.deepcopy(refcal['vis'][i])
            idx = nearest_val_idx(t, tchi)
            pa = chi[idx]  # Parallactic angle for the times of this refcal.
            pa[:, [8, 9, 10, 12]] = 0.0
            nt = len(idx)  # Number of times in this refcal
            # Apply X-Y delay phase correction
            for a in range(13):
                a1 = lobe(dxy[a] - dxy[13])
                a2 = -dxy[13] - xi
                a3 = dxy[a] - xi + np.pi
                for j in range(nt):
                    vis[a, 1, :, j] *= np.exp(1j * a1)
                    vis[a, 2, :, j] *= np.exp(1j * a2)
                    vis[a, 3, :, j] *= np.exp(1j * a3)
            for j in range(nt):
                for a in range(13):
                    refcal['vis'][i][a, 0, :, j] = vis[a, 0, :, j] * np.cos(pa[j, a]) + vis[a, 3, :, j] * np.sin(pa[j, a])
                    refcal['vis'][i][a, 2, :, j] = vis[a, 2, :, j] * np.cos(pa[j, a]) + vis[a, 1, :, j] * np.sin(pa[j, a])
                    refcal['vis'][i][a, 3, :, j] = vis[a, 3, :, j] * np.cos(pa[j, a]) - vis[a, 0, :, j] * np.sin(pa[j, a])
                    refcal['vis'][i][a, 1, :, j] = vis[a, 1, :, j] * np.cos(pa[j, a]) - vis[a, 2, :, j] * np.sin(pa[j, a])
    return refcal
コード例 #2
0
ファイル: refcal_anal.py プロジェクト: binchensolar/eovsa
def unrot_refcal(refcal_in):
    ''' Apply feed-rotation correction to data read with rd_refcal(), returning updated data in
        the same format for further processing.
    '''
    import dbutil as db
    import copy
    import chan_util_bc as cu
    refcal = copy.deepcopy(refcal_in)
    blah = np.load('/common/tmp/Feed_rotation/20170702121949_delay_phase.npz')
    dph = blah['dph']
    band=[]
    for f in blah['fghz']:
        band.append(cu.freq2bdname(f))
    bds, sidx = np.unique(band, return_index=True)
    nbd = len(bds)
    eidx = np.append(sidx[1:], len(band))
    dxy = np.zeros((14, 34), dtype=np.float)
    fghz = np.zeros(34)
    # average dph frequencies within each band, to convert to 34-band representation
    for b, bd in enumerate(bds):
        fghz[bd - 1] = np.nanmean(blah['fghz'][sidx[b]:eidx[b]])
        for a in range(14):
            dxy[a,bd-1] = np.angle(np.sum(np.exp(1j*dph[a, sidx[b]:eidx[b]])))
    # Read parallactic angles for entire time range
    trange = Time([refcal['tstlist'][0].iso,refcal['tedlist'][-1].iso])
    times, chi = db.get_chi(trange)
    tchi = times.jd
    nscans = len(refcal['scanlist'])
    for i in range(nscans):
        t = refcal['times'][i]
        vis = copy.deepcopy(refcal['vis'][i])
        idx = nearest_val_idx(t,tchi)
        pa = chi[idx]   # Parallactic angle for the times of this refcal.
        pa[:,[8,9,10,12]] = 0.0
        nt = len(idx)   # Number of times in this refcal
        # Apply X-Y delay phase correction
        for a in range(13):
            a1 = lobe(dxy[a] - dxy[13])
            a2 = -dxy[13] + np.pi/2
            a3 = dxy[a] - np.pi/2
            for j in range(nt):
                vis[a,1,:,j] *= np.exp(1j*a1)
                vis[a,2,:,j] *= np.exp(1j*a2) 
                vis[a,3,:,j] *= np.exp(1j*a3)
        for j in range(nt):
            for a in range(13):
                refcal['vis'][i][a,0,:,j] = vis[a,0,:,j]*np.cos(pa[j,a]) + vis[a,3,:,j]*np.sin(pa[j,a])
                refcal['vis'][i][a,2,:,j] = vis[a,2,:,j]*np.cos(pa[j,a]) + vis[a,1,:,j]*np.sin(pa[j,a])
                refcal['vis'][i][a,3,:,j] = vis[a,3,:,j]*np.cos(pa[j,a]) - vis[a,0,:,j]*np.sin(pa[j,a])
                refcal['vis'][i][a,1,:,j] = vis[a,1,:,j]*np.cos(pa[j,a]) - vis[a,2,:,j]*np.sin(pa[j,a])  
    return refcal                
コード例 #3
0
ファイル: pipeline_cal.py プロジェクト: sjyu1988/eovsa
def allday_process(path=None):
    ''' Process an all day list of corrected data files to create total power 
        and baseline amplitude FITS spectrograms (planned for submission to
        NASA SDAC for support of the Parker Solar Probe).
        
        Fixed a problem when nans appear in the data--use nanmean() and nanmedian()
    '''
    import glob
    import read_idb as ri
    from xspfits2 import tp_writefits
    if path is None:
        path = './'
    files = glob.glob(path + 'IDB*')
    files.sort()
    for file in files:
        out = ri.read_idb([file])
        nant, npol, nf, nt = out['p'].shape
        nant = 13
        # Use only data from tracking antennas
        azeldict = get_sql_info(Time(out['time'], format='jd')[[0, -1]])
        idx = nearest_val_idx(out['time'], azeldict['Time'].jd)
        tracking = azeldict['TrackFlag'].T
        # Flag any data where the antennas are not tracking
        for i in range(nant):
            out['p'][i, :, :, ~tracking[i, idx]] = np.nan
        # Determine best 8 antennas
        med = np.nanmean(np.nanmedian(out['p'][:nant], 3), 1)  # size nant,nf
        medspec = np.nanmedian(med, 0)  # size nf
        p = np.polyfit(out['fghz'], medspec, 2)
        spec = np.polyval(p, out['fghz']).repeat(nant).reshape(
            nf, nant)  # size nf, nant
        stdev = np.std(med - np.transpose(spec), 1)  # size nant
        idx = stdev.argsort()[:8]  # List of 8 best-fitting antennas
        # Use list of antennas to get final median total power dynamic spectrum
        med = np.nanmean(np.nanmedian(out['p'][idx], 0), 0)
        # Write the total power spectrum to a FITS file
        tp_writefits(out, med.astype(np.float32), filestem='TP_', outpath='./')
        # Form sum of intermediate baselines
        baseidx = np.array([
            29, 30, 31, 32, 33, 34, 42, 43, 44, 45, 46, 54, 55, 56, 57, 65, 66,
            67, 75, 76, 84
        ])
        # Get uv distance for mid-time
        #uvdist = np.sqrt(out['uvw'][:,nt/2,0]**2 + out['uvw'][:,nt/2,1]**2 + out['uvw'][:,nt/2,2]**2)
        # Sort from low to high uv distance
        #bah = uvdist.argsort()
        # Use "intermediate" lengths, i.e. 20th to 39th in list, and sum amplitudes
        med = np.abs(np.nansum(np.nansum(out['x'][baseidx], 0), 0))
        # Write the baseline amplitude spectrum to a FITS file
        tp_writefits(out, med.astype(np.float32), filestem='XP_', outpath='./')
コード例 #4
0
ファイル: calwidget.py プロジェクト: donghaoliu/eovsa
def findscans(trange):
    '''Identify phasecal scans from UFDB files
    '''
    import dbutil
    import dump_tsys
    tstart, tend = trange.lv.astype(int).astype(str)
    cursor = dbutil.get_cursor()
    verstr = dbutil.find_table_version(cursor, tstart, True)
    query = 'select Timestamp,Project,SourceID from hV'+verstr+'_vD1 where left(Project,8) = "PHASECAL" and Timestamp between '+tstart+' and '+tend+' order by Timestamp'
    projdict, msg = dbutil.do_query(cursor, query)
    if msg != 'Success':
        return {'msg':msg}
    if projdict == {}:
        return {'msg':'No PHASECAL scans for this day'}
    tsint = projdict['Timestamp'].astype(int)
    # Check UFDB file to get duration
    ufdb = dump_tsys.rd_ufdb(Time(int(tstart),format='lv'))
    mjd0 = int(Time(int(tstart),format='lv').mjd)
    mjdnow = int(Time.now().mjd)
    if mjd0 < mjdnow:
        # The date is a previous day, so read a second ufdb file 
        # to ensure we have the whole local day
        try:
            ufdb2 = dump_tsys.rd_ufdb(Time(int(tstart)+86400.,format='lv'))
            for key in ufdb.keys():
                ufdb.update({key: np.append(ufdb[key], ufdb2[key])})
        except:
            # No previous day, so just skip it.
            pass
    ufdb_times = ufdb['ST_TS'].astype(float).astype(int)
    idx = nearest_val_idx(tsint,ufdb_times)
    fpath = '/data1/eovsa/fits/UDB/' + trange[0].iso[:4] + '/'
    dur = []
    file = []
    for i in idx:
        dur.append(((ufdb['EN_TS'].astype(float) - ufdb['ST_TS'].astype(float))[i])/60.)
        file.append(fpath+ufdb['FILE'][i])
    # Fix source ID to remove nulls
    srclist = np.array([str(i.replace('\x00','')) for i in projdict['SourceID']])
    return {'Timestamp': tsint, 'SourceID': srclist, 'duration': np.array(dur), 'filelist':np.array(file), 'msg': msg}
コード例 #5
0
def apply_attn_corr(data, tref=None):
    ''' Applys the attenuator state corrections to the given data dictionary,
        corrected to the gain-state at time given by Time() object tref.
        
        Inputs:
          data     A dictionary returned by udb_util.py's readXdata().
          tref     A Time() object with the reference time, or if None,
                     the gain state of the nearest earlier REFCAL is 
                     used.
        Output:
          cdata    A dictionary with the gain-corrected data.  The keys
                     px, py, and x, are updated.
                     
        NB: This is the same routine as in gaincal2.py, but modified
        to handle the different ordering/format of data from udb_util.py's
        readXdata() routine.
    '''
    from gaincal2 import get_gain_state
    from util import common_val_idx, nearest_val_idx
    import copy
    if tref is None:
        # No reference time specified, so get nearest earlier REFCAL
        trange = Time(data['time'][[0, -1]], format='jd')
        xml, buf = ch.read_cal(8, t=trange[0])
        tref = Time(stateframe.extract(buf, xml['Timestamp']), format='lv')
    # Get the gain state at the reference time (actually median over 1 minute)
    trefrange = Time([tref.iso, Time(tref.lv + 60, format='lv').iso])
    ref_gs = get_gain_state(trefrange)  # refcal gain state for 60 s
    # Get median of refcal gain state (which should be constant anyway)
    ref_gs['h1'] = np.median(ref_gs['h1'], 1)
    ref_gs['h2'] = np.median(ref_gs['h2'], 1)
    ref_gs['v1'] = np.median(ref_gs['v1'], 1)
    ref_gs['v2'] = np.median(ref_gs['v2'], 1)

    # Get timerange from data
    trange = Time([data['time'][0], data['time'][-1]], format='jd')
    # Get time cadence
    dt = np.int(
        np.round(np.median(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the gain state of the requested timerange
    src_gs = get_gain_state(trange,
                            dt)  # solar gain state for timerange of file
    nt = len(src_gs['times'])
    antgain = np.zeros((15, 2, 34, nt),
                       np.float32)  # Antenna-based gains vs. band
    for i in range(15):
        for j in range(34):
            antgain[i, 0, j] = src_gs['h1'][i] + src_gs['h2'][i] - ref_gs[
                'h1'][i] - ref_gs['h2'][i] + src_gs['dcmattn'][
                    i, 0, j] - ref_gs['dcmattn'][i, 0, j]
            antgain[i, 1, j] = src_gs['v1'][i] + src_gs['v2'][i] - ref_gs[
                'v1'][i] - ref_gs['v2'][i] + src_gs['dcmattn'][
                    i, 1, j] - ref_gs['dcmattn'][i, 1, j]

    cdata = copy.deepcopy(data)
    # Create giant array of baseline-based gains, translated to baselines and frequencies
    fghz = data['fghz']
    nf = len(fghz)
    blist = (fghz * 2 - 1).astype(
        int) - 1  # Band list corresponding to frequencies in data
    blgain = np.zeros((nf, 136, 4, nt),
                      float)  # Baseline-based gains vs. frequency
    for k, bl in enumerate(get_bl_order()):
        i, j = bl
        if i < 15 and j < 15:
            blgain[:, k,
                   0] = 10**((antgain[i, 0, blist] + antgain[j, 0, blist]) /
                             20.)
            blgain[:, k,
                   1] = 10**((antgain[i, 1, blist] + antgain[j, 1, blist]) /
                             20.)
            blgain[:, k,
                   2] = 10**((antgain[i, 0, blist] + antgain[j, 1, blist]) /
                             20.)
            blgain[:, k,
                   3] = 10**((antgain[i, 1, blist] + antgain[j, 0, blist]) /
                             20.)
    # Reorder antgain axes to put frequencies in first slot, to match data
    antgain = np.swapaxes(np.swapaxes(antgain, 1, 2), 0, 1)
    antgainf = 10**(antgain[blist] / 10.)

    idx = nearest_val_idx(data['time'], src_gs['times'].jd)
    # Correct the auto- and cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Reshape px and py arrays
    cdata['px'].shape = (134, 16, 3, nt)
    cdata['py'].shape = (134, 16, 3, nt)
    # Correct the power
    cdata['px'][:, :15, 0] *= antgainf[:, :, 0, idx]
    cdata['py'][:, :15, 0] *= antgainf[:, :, 1, idx]
    # Correct the power-squared
    cdata['px'][:, :15, 1] *= antgainf[:, :, 0, idx]**2
    cdata['py'][:, :15, 1] *= antgainf[:, :, 1, idx]**2
    # Reshape px and py arrays back to original
    cdata['px'].shape = (134 * 16 * 3, nt)
    cdata['py'].shape = (134 * 16 * 3, nt)
    return cdata
コード例 #6
0
def unrot(data, azeldict=None):
    ''' Apply the correction to differential feed rotation to data, and return
        the corrected data.

        Inputs:
          data     A dictionary returned by udb_util.py's readXdata().
          azeldict The dictionary returned from get_sql_info(), or if None, the appropriate
                     get_sql_info() call is done internally.

        Output:
          cdata    A dictionary with the phase-corrected data.  Only the key
                     x is updated.
    '''
    import copy
    from util import lobe
    trange = Time(data['time'][[0, -1]], format='jd')

    if azeldict is None:
        azeldict = get_sql_info(trange)
    chi = azeldict['ParallacticAngle']  # (nt, nant)
    # Correct parallactic angle for equatorial mounts, relative to Ant14
    for i in [8, 9, 10, 12, 13]:
        chi[:, i] -= chi[:, 13]

    # Ensure that nearest valid parallactic angle is used for times in the data
    good, = np.where(azeldict['ActualAzimuth'][0] != 0)
    tidx = nearest_val_idx(data['time'], azeldict['Time'][good].jd)

    # Read X-Y Delay phase from SQL database and get common frequencies
    xml, buf = ch.read_cal(11, t=trange[0])
    fghz = stateframe.extract(buf, xml['FGHz'])
    good, = np.where(fghz != 0.)
    fghz = fghz[good]
    dph = stateframe.extract(buf, xml['XYphase'])
    dph = dph[:, good]
    fidx1, fidx2 = common_val_idx(data['fghz'], fghz, precision=4)
    missing = np.setdiff1d(np.arange(len(data['fghz'])), fidx1)

    nf, nbl, npol, nt = data['x'].shape
    nf = len(fidx1)
    # Correct data for X-Y delay phase
    for k, bl in enumerate(get_bl_order()):
        i, j = bl
        if i < 14 and j < 14 and i != j:
            a1 = lobe(dph[i, fidx2] - dph[j, fidx2])
            a2 = -dph[j, fidx2] + np.pi / 2
            a3 = dph[i, fidx2] - np.pi / 2
            data['x'][fidx1, k, 1] *= np.repeat(np.exp(1j * a1),
                                                nt).reshape(nf, nt)
            data['x'][fidx1, k, 2] *= np.repeat(np.exp(1j * a2),
                                                nt).reshape(nf, nt)
            data['x'][fidx1, k, 3] *= np.repeat(np.exp(1j * a3),
                                                nt).reshape(nf, nt)

    # Correct data for differential feed rotation
    cdata = copy.deepcopy(data)
    for n in range(nt):
        for k, bl in enumerate(get_bl_order()):
            i, j = bl
            if i < 14 and j < 14 and i != j:
                dchi = chi[n, i] - chi[n, j]
                cchi = np.cos(dchi)
                schi = np.sin(dchi)
                cdata['x'][:, k, 0,
                           n] = data['x'][:, k, 0,
                                          n] * cchi + data['x'][:, k, 3,
                                                                n] * schi
                cdata['x'][:, k, 2,
                           n] = data['x'][:, k, 2,
                                          n] * cchi + data['x'][:, k, 1,
                                                                n] * schi
                cdata['x'][:, k, 3,
                           n] = data['x'][:, k, 3,
                                          n] * cchi - data['x'][:, k, 0,
                                                                n] * schi
                cdata['x'][:, k, 1,
                           n] = data['x'][:, k, 1,
                                          n] * cchi - data['x'][:, k, 2,
                                                                n] * schi
    # Set flags for any missing frequencies (hopefully this also works when missing is np.array([]))
    cdata[missing] = np.ma.masked
    return cdata
コード例 #7
0
ファイル: pipeline_cal.py プロジェクト: hayesla/eovsa
def apply_fem_level(data, gctime=None):
    ''' Applys the FEM level corrections to the given data dictionary.
        
        Inputs:
          data     A dictionary such as that returned by read_idb().
          gctime   A Time() object whose date specifies which GAINCALTEST
                     measurements to use.  If omitted, the date of the data
                     is used.

        Output:
          cdata    A dictionary with the level-corrected data.  The keys
                     p, x, p2, and a are all updated.
    '''
    from util import common_val_idx, nearest_val_idx, bl2ord
    import attncal as ac
    from gaincal2 import get_fem_level
    import copy

    # Get timerange from data
    trange = Time([data['time'][0], data['time'][-1]], format='jd')
    if gctime is None:
        gctime = trange[0]
    # Get time cadence
    dt = np.int(
        np.round(np.median(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the FEM levels of the requested timerange
    src_lev = get_fem_level(trange,
                            dt)  # solar gain state for timerange of file
    nf = len(data['fghz'])
    nt = len(src_lev['times'])
    attn = ac.read_attncal(
        gctime
    )[0]  # Reads attn from SQL database (returns a list, but use first, generally only, one)
    # attn = ac.get_attncal(gctime)[0]   # Analyzes GAINCALTEST (returns a list, but use first, generally only, one)
    antgain = np.zeros((15, 2, nf, nt),
                       np.float32)  # Antenna-based gains [dB] vs. frequency
    # Find common frequencies of attn with data
    idx1, idx2 = common_val_idx(data['fghz'], attn['fghz'], precision=4)
    # Currently, GAINCALTEST measures 8 levels of attenuation (16 dB).  I assumed this would be enough,
    # but the flare of 2017-09-10 actually went to 10 levels (20 dB), so we have no choice but to extend
    # to higher levels using only the nominal, 2 dB steps above the 8th level.  This part of the code
    # extends to the maximum 14 levels.
    a = np.zeros((14, 13, 2, nf), float)  # Extend attenuation to 14 levels
    a[:8, :, :, idx1] = attn[
        'attn'][:, :13, :,
                idx2]  # Use GAINCALTEST results in the first 8 levels
    for i in range(7, 13):
        # Extend to levels 9-14 by adding 2 dB to each previous level
        a[i + 1] = a[i] + 2.
    for i in range(13):
        for k, j in enumerate(idx1):
            antgain[i, 0, j] = a[src_lev['hlev'][i], i, 0, j]
            antgain[i, 1, j] = a[src_lev['vlev'][i], i, 0, j]
    cdata = copy.deepcopy(data)
    nblant = 136
    blgain = np.zeros((nf, nblant, 4, nt),
                      float)  # Baseline-based gains vs. frequency

    for i in range(14):
        for j in range(i, 14):
            k = bl2ord[i, j]
            blgain[:, k, 0] = 10**((antgain[i, 0] + antgain[j, 0]) / 20.)
            blgain[:, k, 1] = 10**((antgain[i, 1] + antgain[j, 1]) / 20.)
            blgain[:, k, 2] = 10**((antgain[i, 0] + antgain[j, 1]) / 20.)
            blgain[:, k, 3] = 10**((antgain[i, 1] + antgain[j, 0]) / 20.)
    # Reorder antgain axes to put frequencies in first slot, to match data
    antgain = np.swapaxes(np.swapaxes(antgain, 1, 2), 0, 1)
    antgainf = 10**(antgain / 10.)

    idx = nearest_val_idx(data['time'], src_lev['times'].jd)
    nt = len(idx)  # New number of times
    # Correct the auto- and cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Reshape px and py arrays
    cdata['px'].shape = (nf, 16, 3, nt)
    cdata['py'].shape = (nf, 16, 3, nt)
    # Correct the power
    cdata['px'][:, :15, 0] *= antgainf[:, :, 0, idx]
    cdata['py'][:, :15, 0] *= antgainf[:, :, 1, idx]
    # Correct the power-squared
    cdata['px'][:, :15, 1] *= antgainf[:, :, 0, idx]**2
    cdata['py'][:, :15, 1] *= antgainf[:, :, 1, idx]**2
    # Reshape px and py arrays back to original
    cdata['px'].shape = (nf * 16 * 3, nt)
    cdata['py'].shape = (nf * 16 * 3, nt)
    return cdata
コード例 #8
0
ファイル: pipeline_cal.py プロジェクト: hayesla/eovsa
def unrot(data, azeldict=None):
    ''' Apply the correction to differential feed rotation to data, and return
        the corrected data.  This also applies flags to data whose antennas are
        not tracking.

        Inputs:
          data     A dictionary returned by udb_util.py's readXdata().
          azeldict The dictionary returned from get_sql_info(), or if None, the appropriate
                     get_sql_info() call is done internally.

        Output:
          cdata    A dictionary with the phase-corrected data.  Only the key
                     x is updated.
    '''
    import copy
    from util import lobe, bl2ord
    trange = Time(data['time'][[0, -1]], format='jd')

    if azeldict is None:
        azeldict = get_sql_info(trange)
    chi = azeldict['ParallacticAngle'] * np.pi / 180.  # (nt, nant)
    # Correct parallactic angle for equatorial mounts, relative to Ant14
    chi[:,
        [8, 9, 10, 12, 13]] = 0  # Currently 0, but can be measured and updated

    # Which antennas are tracking
    track = azeldict['TrackFlag']  # True if tracking

    # Ensure that nearest valid parallactic angle is used for times in the data
    good = np.where(azeldict['ActualAzimuth'] != 0)
    tidx = []  # List of arrays of indexes for each antenna
    for i in range(14):
        gd = good[0][np.where(good[1] == i)]
        tidx.append(nearest_val_idx(data['time'], azeldict['Time'][gd].jd))

    # Read X-Y Delay phase from SQL database and get common frequencies
    xml, buf = ch.read_cal(11, t=trange[0])
    fghz = stateframe.extract(buf, xml['FGHz'])
    good, = np.where(fghz != 0.)
    fghz = fghz[good]
    dph = stateframe.extract(buf, xml['XYphase'])
    dph = dph[:, good]
    xi_rot = stateframe.extract(buf, xml['Xi_Rot'])
    xi_rot = xi_rot[good]
    fidx1, fidx2 = common_val_idx(data['fghz'], fghz, precision=4)
    missing = np.setdiff1d(np.arange(len(data['fghz'])), fidx1)

    nf, nbl, npol, nt = data['x'].shape
    nf = len(fidx1)
    # Correct data for X-Y delay phase
    for i in range(13):
        for j in range(i + 1, 14):
            k = bl2ord[i, j]
            a1 = lobe(dph[i, fidx2] - dph[j, fidx2])
            a2 = -dph[j, fidx2] - xi_rot[fidx2]
            a3 = dph[i, fidx2] - xi_rot[fidx2] + np.pi
            data['x'][fidx1, k, 1] *= np.repeat(np.exp(1j * a1),
                                                nt).reshape(nf, nt)
            data['x'][fidx1, k, 2] *= np.repeat(np.exp(1j * a2),
                                                nt).reshape(nf, nt)
            data['x'][fidx1, k, 3] *= np.repeat(np.exp(1j * a3),
                                                nt).reshape(nf, nt)

    # Correct data for differential feed rotation
    cdata = copy.deepcopy(data)
    for n in range(nt):
        for i in range(13):
            for j in range(i + 1, 14):
                k = bl2ord[i, j]
                ti = tidx[i][n]
                tj = tidx[j][n]
                if track[ti, i] and track[tj, j]:
                    dchi = chi[ti, i] - chi[tj, j]
                    cchi = np.cos(dchi)
                    schi = np.sin(dchi)
                    cdata['x'][:, k, 0,
                               n] = data['x'][:, k, 0,
                                              n] * cchi + data['x'][:, k, 3,
                                                                    n] * schi
                    cdata['x'][:, k, 2,
                               n] = data['x'][:, k, 2,
                                              n] * cchi + data['x'][:, k, 1,
                                                                    n] * schi
                    cdata['x'][:, k, 3,
                               n] = data['x'][:, k, 3,
                                              n] * cchi - data['x'][:, k, 0,
                                                                    n] * schi
                    cdata['x'][:, k, 1,
                               n] = data['x'][:, k, 1,
                                              n] * cchi - data['x'][:, k, 2,
                                                                    n] * schi
                else:
                    cdata['x'][:, k, :, n] = np.ma.masked

    # Set flags for any missing frequencies (hopefully this also works when "missing" is np.array([]))
    cdata['x'][missing] = np.ma.masked
    return cdata
コード例 #9
0
def apply_gain_corr(data, tref=None):
    ''' Applys the gain_state() corrections to the given data dictionary,
        corrected to the gain-state at time given by Time() object tref.
        
        Inputs:
          data     A dictionary such as that returned by read_idb().
          tref     A Time() object with the reference time, or if None,
                     the gain state of the nearest earlier REFCAL is 
                     used.
        Output:
          cdata    A dictionary with the gain-corrected data.  The keys
                     p, x, p2, and a are all updated.
    '''
    from util import fname2mjd, common_val_idx, nearest_val_idx
    import copy
    if tref is None:
        # No reference time specified, so get nearest PHASECAL scan (should guarantee femauto-off state)
        mjd = int(Time(data['time'][0], format='jd').mjd)
        trange = Time([mjd + 10. / 24., mjd + 1.], format='mjd')
        import pcal_anal as pa
        try:
            # Get filename of first PHASECAL on this day, and use it to get reference time
            scanfile = pa.findfile(trange)['scanlist'][0][0]
            tref = Time(
                fname2mjd(scanfile) + 60. / 86400,
                format='mjd')  # Add one minute to ensure scan is active
            # Get the gain state at the reference time (actually median over 1 minute)
            trefrange = Time([tref.iso, Time(tref.lv + 61, format='lv').iso])
            ref_gs = get_gain_state(trefrange)  # refcal gain state for 60 s
        except:
            # No phasecal in timerange, so just use an early time as reference
            tref = Time(trange[0].iso[:10] + ' 13:30')
            # Get the gain state at the reference time (actually median over 1 minute)
            trefrange = Time([tref.iso, Time(tref.lv + 61, format='lv').iso])
            ref_gs = get_gain_state(
                trefrange,
                relax=True)  # refcal gain state for 60 s after ref time
        if trange[0].mjd - tref.mjd > 2:
            # Reference calibration is too old, so just use an early time as reference
            tref = Time(trange[0].iso[:10] + ' 13:30')
            # Get the gain state at the reference time (actually median over 1 minute)
            trefrange = Time([tref.iso, Time(tref.lv + 61, format='lv').iso])
            ref_gs = get_gain_state(
                trefrange,
                relax=True)  # refcal gain state for 60 s after ref time

    # Get median of refcal gain state (which should be constant anyway)
    ref_gs['h1'] = np.median(ref_gs['h1'], 1)
    ref_gs['h2'] = np.median(ref_gs['h2'], 1)
    ref_gs['v1'] = np.median(ref_gs['v1'], 1)
    ref_gs['v2'] = np.median(ref_gs['v2'], 1)

    # Get timerange from data
    trange = Time([data['time'][0], data['time'][-1]], format='jd')
    # Get time cadence
    dt = np.int(
        np.round(np.median(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the gain state of the requested timerange
    src_gs = get_gain_state(trange,
                            dt)  # solar gain state for timerange of file
    nt = len(src_gs['times'])
    nbands = src_gs['dcmattn'].shape[2]
    if nbands != ref_gs['dcmattn'].shape[2]:
        # Reference gain state is incompatible with this one, so set to src gain state (no correction will be applied)
        ref_gs = src_gs
        print 'GAINCAL2 Warning: Data and reference gain states are not compatible. No correction applied!'
    antgain = np.zeros((15, 2, nbands, nt),
                       np.float32)  # Antenna-based gains vs. band
    for i in range(15):
        for j in range(nbands):
            antgain[i, 0, j] = src_gs['h1'][i] + src_gs['h2'][i] - ref_gs[
                'h1'][i] - ref_gs['h2'][i] + src_gs['dcmattn'][
                    i, 0, j] - ref_gs['dcmattn'][i, 0, j]
            antgain[i, 1, j] = src_gs['v1'][i] + src_gs['v2'][i] - ref_gs[
                'v1'][i] - ref_gs['v2'][i] + src_gs['dcmattn'][
                    i, 1, j] - ref_gs['dcmattn'][i, 1, j]

    cdata = copy.deepcopy(data)
    # Frequency list is provided, so produce baseline-based gain table as well
    # Create giant array of gains, translated to baselines and frequencies
    fghz = data['fghz']
    nf = len(fghz)
    blist = (fghz * 2 - 1).astype(int) - 1
    blgain = np.zeros((120, 4, nf, nt),
                      float)  # Baseline-based gains vs. frequency
    for i in range(14):
        for j in range(i + 1, 15):
            blgain[ri.bl2ord[i, j],
                   0] = 10**((antgain[i, 0, blist] + antgain[j, 0, blist]) /
                             20.)
            blgain[ri.bl2ord[i, j],
                   1] = 10**((antgain[i, 1, blist] + antgain[j, 1, blist]) /
                             20.)
            blgain[ri.bl2ord[i, j],
                   2] = 10**((antgain[i, 0, blist] + antgain[j, 1, blist]) /
                             20.)
            blgain[ri.bl2ord[i, j],
                   3] = 10**((antgain[i, 1, blist] + antgain[j, 0, blist]) /
                             20.)
    antgainf = 10**(antgain[:, :, blist] / 10.)

    #idx1, idx2 = common_val_idx(data['time'],src_gs['times'].jd)
    idx = nearest_val_idx(data['time'], src_gs['times'].jd)
    # Apply corrections (some times may be eliminated from the data)
    # Correct the cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Correct the power
    cdata['p'][:15] *= antgainf[:, :, :, idx]
    # Correct the autocorrelation
    cdata['a'][:15, :2] *= antgainf[:, :, :, idx]
    cross_fac = np.sqrt(antgainf[:, 0] * antgainf[:, 1])
    cdata['a'][:15, 2] *= cross_fac[:, :, idx]
    cdata['a'][:15, 3] *= cross_fac[:, :, idx]
    # Correct the power-squared -- this should preserve SK
    cdata['p2'][:15] *= antgainf[:, :, :, idx]**2
    # Remove any uncorrected times before returning
    #cdata['time'] = cdata['time'][idx1]
    #cdata['p'] = cdata['p'][:,:,:,idx1]
    #cdata['a'] = cdata['a'][:,:,:,idx1]
    #cdata['p2'] = cdata['p2'][:,:,:,idx1]
    #cdata['ha'] = cdata['ha'][idx1]
    #cdata['m'] = cdata['m'][:,:,:,idx1]
    return cdata
コード例 #10
0
ファイル: autocorrect_tp.py プロジェクト: sjyu1988/eovsa
def tp_bgnd_all(tpdata):
    ''' Create time-variable background from ROACH inlet temperature
        This version is far superior to the earlier, crude version, but
        beware that it works best for a long timerange of data, especially
        when there is a flare in the data.
        
        Inputs:
          tpdata   dictionary returned by read_idb()  NB: tpdata is not changed.
          
        Returns:
          bgnd     The background fluctuation array of size (nf,nt) to be 
                     subtracted from any antenna's total power (or mean of
                     antenna total powers)
    '''
    import dbutil as db
    from util import Time, nearest_val_idx
    outfghz = tpdata['fghz']
    try:
        outtime = tpdata['time']
        trange = Time(outtime[[0, -1]], format='jd')
    except:
        outtime = tpdata['ut_mjd']
        trange = Time(outtime[[0, -1]], format='mjd')

    nt = len(outtime)
    if nt < 1200:
        print 'TP_BGND: Error, timebase too small.  Must have at least 1200 time samples.'
        return None
    nf = len(outfghz)
    outpd = Time(outtime, format='jd').plot_date
    cursor = db.get_cursor()
    data = db.get_dbrecs(cursor, dimension=8, timestamp=trange)
    pd = Time(data['Timestamp'][:, 0].astype(int), format='lv').plot_date
    inlet = data['Sche_Data_Roac_TempInlet']  # Inlet temperature variation
    sinlet = np.sum(inlet.astype(float), 1)
    # Eliminate 0 values in sinlet by replacing with nearest good value
    bad, = np.where(sinlet == 0)
    good, = np.where(sinlet != 0)
    idx = nearest_val_idx(
        bad, good)  # Find locations of nearest good values to bad ones
    sinlet[bad] = sinlet[good[idx]]  # Overwrite bad values with good ones
    sinlet -= np.mean(
        sinlet)  # Remove offset, to provide zero-mean fluctuation
    sinlet = np.roll(
        sinlet,
        -110)  # Shift phase of variation by 110 s earlier (seems to be needed)
    # Interpolate sinlet values to the times in the data
    sint = np.interp(outpd, pd, sinlet)
    #    sint = np.roll(sint,-90)  # Shift phase of variation by 90 s earlier
    #    sint -= np.mean(sint)     # Remove offset, to provide zero-mean fluctuation
    sdev = np.std(sint)
    sint_ok = np.abs(sint) < 2 * sdev
    bgnd = np.zeros((13, 2, nf, nt), float)
    for ant in range(13):
        for pol in range(2):
            for i in range(nf):
                # Subtract smooth trend from data
                nt = len(tpdata['p'][ant, pol, i])
                wlen = min(nt, 2000)
                if wlen % 2 != 0:
                    wlen -= 1
                sig = tpdata['p'][ant, pol, i] - smooth(
                    tpdata['p'][ant, pol, i], wlen,
                    'blackman')[wlen / 2:-(wlen / 2 - 1)]
                # Eliminate the worst outliers and repeat
                stdev = np.nanstd(sig)
                good, = np.where(np.abs(sig) < 2 * stdev)
                if len(good) > nt * 0.1:
                    wlen = min(len(good), 2000)
                    if wlen % 2 != 0:
                        wlen -= 1
                    sig = tpdata['p'][ant, pol, i, good] - smooth(
                        tpdata['p'][ant, pol, i, good], wlen,
                        'blackman')[wlen / 2:-(wlen / 2 - 1)]
                    sint_i = sint[good]
                    stdev = np.std(sig)
                    # Final check for data quality
                    good, = np.where(
                        np.logical_and(sig < 2 * stdev, sint_ok[good]))
                    if len(good) > nt * 0.1:
                        p = np.polyfit(sint_i[good], sig[good], 1)
                    else:
                        p = [1., 0.]
                    # Apply correction for this frequency
                    bgnd[ant, pol, i] = sint * p[0] + p[1]
    return bgnd
コード例 #11
0
ファイル: gaincal2.py プロジェクト: donghaoliu/eovsa
def get_fem_level(trange, dt=None):
    ''' Get FEM attenuation levels for a given timerange.  Returns a dictionary
        with keys as follows:

        times:     A Time object containing the array of times, size (nt)
        hlev:      The FEM attenuation level for HPol, size (nt, 15) 
        vlev:      The FEM attenuation level for VPol, size (nt, 15)
        dcmattn:   The base DCM attenuations for 34 bands x 15 antennas x 2 Poln, size (34,30)
                      The order is Ant1 H, Ant1 V, Ant2 H, Ant2 V, etc.
        dcmoff:    If DPPoffset-on is 0, this is None (meaning there are no changes to the
                      above base attenuations).  
                   If DPPoffset-on is 1, then dcmoff is a table of offsets to the 
                      base attenuation, size (nt, 50).  The offset applies to all 
                      antennas/polarizations.
                      
        Optional keywords:
           dt      Seconds between entries to read from SQL stateframe database. 
                     If omitted, 1 s is assumed.
        
    '''
    if dt is None:
        tstart, tend = [str(i) for i in trange.lv]
    else:
        # Expand time by 1/2 of dt before and after
        tstart = str(np.round(trange[0].lv - dt / 2))
        tend = str(np.round(trange[1].lv + dt / 2))
    cursor = db.get_cursor()
    ver = db.find_table_version(cursor, trange[0].lv)
    # Get front end attenuator states
    query = 'select Timestamp,Ante_Fron_FEM_Clockms,' \
            +'Ante_Fron_FEM_HPol_Regi_Level,Ante_Fron_FEM_VPol_Regi_Level from fV' \
            +ver+'_vD15 where Timestamp >= '+tstart+' and Timestamp <= '+tend+' order by Timestamp'
    data, msg = db.do_query(cursor, query)
    if msg == 'Success':
        if dt:
            # If we want other than full cadence, get new array shapes and times
            n = len(data['Timestamp'])  # Original number of times
            new_n = (
                n / 15 / dt
            ) * 15 * dt  # Truncated number of times equally divisible by dt
            new_shape = (n / 15 / dt, dt, 15)  # New shape of truncated arrays
            times = Time(data['Timestamp'][:new_n].astype('int')[::15 * dt],
                         format='lv')
        else:
            times = Time(data['Timestamp'].astype('int')[::15], format='lv')
        hlev = data['Ante_Fron_FEM_HPol_Regi_Level']
        vlev = data['Ante_Fron_FEM_VPol_Regi_Level']
        ms = data['Ante_Fron_FEM_Clockms']
        nt = len(hlev) / 15
        hlev.shape = (nt, 15)
        vlev.shape = (nt, 15)
        ms.shape = (nt, 15)
        # Find any entries for which Clockms is zero, which indicates where no
        # gain-state measurement is available.
        for i in range(15):
            bad, = np.where(ms[:, i] == 0)
            if bad.size != 0 and bad.size != nt:
                # Find nearest adjacent good value
                good, = np.where(ms[:, i] != 0)
                idx = nearest_val_idx(bad, good)
                hlev[bad, i] = hlev[good[idx], i]
                vlev[bad, i] = vlev[good[idx], i]
        if dt:
            # If we want other than full cadence, find mean over dt measurements
            hlev = np.mean(hlev[:new_n / 15].reshape(new_shape), 1)
            vlev = np.mean(vlev[:new_n / 15].reshape(new_shape), 1)
        # Put results in canonical order [nant, nt]
        hlev = hlev.T
        vlev = vlev.T
    else:
        print 'Error reading FEM levels:', msg
        return {}
    # Get back end attenuator states
    xml, buf = ch.read_cal(2, t=trange[0])
    dcmattn = stf.extract(buf, xml['Attenuation'])
    dcmattn.shape = (34, 15, 2)
    # Put into canonical order [nant, npol, nband]
    dcmattn = np.moveaxis(dcmattn, 0, 2)
    # See if DPP offset is enabled
    query = 'select Timestamp,DPPoffsetattn_on from fV' \
            +ver+'_vD1 where Timestamp >= '+tstart+' and Timestamp <= '+tend+'order by Timestamp'
    data, msg = db.do_query(cursor, query)
    if msg == 'Success':
        dppon = data['DPPoffsetattn_on']
        if np.where(dppon > 0)[0].size == 0:
            dcm_off = None
        else:
            query = 'select Timestamp,DCMoffset_attn from fV' \
                    +ver+'_vD50 where Timestamp >= '+tstart+' and Timestamp <= '+tend+' order by Timestamp'
            data, msg = db.do_query(cursor, query)
            if msg == 'Success':
                otimes = Time(data['Timestamp'].astype('int')[::15],
                              format='lv')
                dcmoff = data['DCMoffset_attn']
                dcmoff.shape = (nt, 50)
                # We now have a time-history of offsets, at least some of which are non-zero.
                # Offsets by slot number do us no good, so we need to translate to band number.
                # Get fseqfile name at mean of timerange, from stateframe SQL database
                fseqfile = get_fseqfile(
                    Time(int(np.mean(trange.lv)), format='lv'))
                if fseqfile is None:
                    print 'Error: No active fseq file.'
                    dcm_off = None
                else:
                    # Get fseqfile from ACC and return bandlist
                    bandlist = fseqfile2bandlist(fseqfile)
                    # Use bandlist to covert nt x 50 array to nt x 34 band array of DCM attn offsets
                    # Note that this assumes DCM offset is the same for any multiply-sampled bands
                    # in the sequence.
                    dcm_off = np.zeros((nt, 34), float)
                    dcm_off[:, bandlist - 1] = dcmoff
                    # Put into canonical order [nband, nt]
                    dcm_off = dcm_off.T
                    if dt:
                        # If we want other than full cadence, find mean over dt measurements
                        new_nt = len(times)
                        dcm_off = dcm_off[:, :new_nt * dt]
                        dcm_off.shape = (34, dt, new_nt)
                        dcm_off = np.mean(dcm_off, 1)
            else:
                print 'Error reading DCM attenuations:', msg
                dcm_off = None
    else:
        print 'Error reading DPPon state:', msg
        dcm_off = None
    cursor.close()
    return {
        'times': times,
        'hlev': hlev.astype(int),
        'vlev': vlev.astype(int),
        'dcmattn': dcmattn,
        'dcmoff': dcm_off
    }
コード例 #12
0
ファイル: autocorrect_tp.py プロジェクト: donghaoliu/eovsa
def autocorrect(out, ant_str='ant1-13'):
    nt = len(out['time'])
    nf = len(out['fghz'])
    pfac1 = (out['p'][:, :, :, :-1] -
             out['p'][:, :, :, 1:]) / out['p'][:, :, :, :-1]
    trange = Time(out['time'][[0, -1]], format='jd')
    src_lev = gc.get_fem_level(trange)  # Read FEM levels from SQL
    # Match times with data
    tidx = nearest_val_idx(out['time'], src_lev['times'].jd)
    # Find attenuation changes
    for ant in range(13):
        for pol in range(2):
            if pol == 0:
                lev = src_lev['hlev'][ant, tidx]
            else:
                lev = src_lev['vlev'][ant, tidx]
            jidx, = np.where(abs(lev[:-1] - lev[1:]) == 1)
            for freq in range(nf):
                idx, = np.where(
                    np.logical_and(
                        abs(pfac1[ant, pol, freq]) > 0.05,
                        abs(pfac1[ant, pol, freq]) < 0.95))
                for i in range(len(idx - 1)):
                    if idx[i] in jidx or idx[i] in jidx - 1:
                        out['p'][ant, pol, freq, idx[i] +
                                 1:] /= (1 - pfac1[ant, pol, freq, idx[i]])
    calfac = pc.get_calfac(trange[0])
    tpcalfac = calfac['tpcalfac']
    tpoffsun = calfac['tpoffsun']
    hlev = src_lev['hlev'][:13, 0]
    vlev = src_lev['vlev'][:13, 0]
    attn_dict = ac.read_attncal(trange[0])[0]  # Read GCAL attn from SQL
    attn = np.zeros((13, 2, nf))
    for i in range(13):
        attn[i, 0] = attn_dict['attn'][hlev[i], 0, 0]
        attn[i, 1] = attn_dict['attn'][vlev[i], 0, 1]
        print 'Ant', i + 1, attn[i, 0, 20], attn[i, 1, 20]
    attnfac = 10**(attn / 10.)
    for i in range(13):
        print attnfac[i, 0, 20], attnfac[i, 1, 20]
    for i in range(nt):
        out['p'][:13, :, :,
                 i] = (out['p'][:13, :, :, i] * attnfac - tpoffsun) * tpcalfac
    antlist = ant_str2list(ant_str)
    med = np.mean(np.median(out['p'][antlist], 0), 0)
    bg = np.median(med[:, 0:300], 1).repeat(nt).reshape(nf, nt)
    med -= bg
    pdata = np.log10(med)
    f, ax = plt.subplots(1, 1)
    vmax = np.median(np.nanmax(pdata, 1))
    im = ax.pcolormesh(Time(out['time'], format='jd').plot_date,
                       out['fghz'],
                       pdata,
                       vmin=1,
                       vmax=vmax)
    plt.colorbar(im, ax=ax, label='Log Flux Density [sfu]')
    ax.xaxis_date()
    ax.xaxis.set_major_formatter(DateFormatter("%H:%M"))
    ax.set_ylim(out['fghz'][0], out['fghz'][-1])
    ax.set_xlabel('Time [UT]')
    ax.set_ylabel('Frequency [GHz]')
    return out, med
コード例 #13
0
def get_attncal(trange, do_plot=False, dataonly=False):
    ''' Finds GAINCALTEST scans from FDB files corresponding to the days
        present in trange Time() object (can be multiple days), calculates
        the attenuation differences for the various FEMATTN states 1-8 
        relative to FEMATTN state 0, and optionally plots the results for
        states 1 and 2 (the most commonly used).  To analyze only a single
        day, trange Time() object can have the same time repeated, or can
        be a single time.
        
        Returns a list of dictionaries, each pertaining to one of the days
        in trange, with keys defined as follows:
           'time':      The start time of the GAINCALTEST scan, as a Time() object
           'fghz':      The list of frequencies [GHz] at which attenuations are measured
           'attn':      The array of attenuations [dB] of size (nattn, nant, npol, nf), 
                           where nattn = 8, nant = 13, npol = 2, and nf is variable
           'rcvr':      The array of receiver noise level (raw units) of size 
                           (nant, npol, nf), where nant = 13, npol = 2, and nf is variable
           'rcvr_auto': Same as rcvr, but for auto-correlation (hence it is complex)
                           
        N.B.: Ignores days with other than one GAINCALTEST measurement, e.g. 0 or 2,
              the first is obvious, while the second is because there is no way to
              tell which of the 2 are good.
        
        The dataonly parameter tells the routine to skip calculating the attenuation
        and only return the IDB data from the (first) gaincal.
    '''
    from util import get_idbdir, fname2mjd, nearest_val_idx
    import socket
    import dbutil
    if type(trange.mjd) == np.float:
        # Interpret single time as both start and end time
        mjd1 = int(trange.mjd)
        mjd2 = mjd1
    else:
        mjd1, mjd2 = trange.mjd.astype(int)
    if do_plot:
        import matplotlib.pylab as plt
        f, ax = plt.subplots(4, 13)
        f.set_size_inches((14, 5))
        ax[0, 0].set_ylabel('Atn1X [dB]')
        ax[1, 0].set_ylabel('Atn1Y [dB]')
        ax[2, 0].set_ylabel('Atn2X [dB]')
        ax[3, 0].set_ylabel('Atn2Y [dB]')
        for i in range(13):
            ax[0, i].set_title('Ant ' + str(i + 1))
            ax[3, i].set_xlabel('Freq [GHz]')
            for j in range(2):
                ax[j, i].set_ylim(1, 3)
                ax[j + 2, i].set_ylim(3, 5)
    outdict = []
    for mjd in range(mjd1, mjd2 + 1):
        fdb = dt.rd_fdb(Time(mjd, format='mjd'))
        gcidx, = np.where(fdb['PROJECTID'] == 'GAINCALTEST')
        if len(gcidx) == 1:
            print fdb['FILE'][gcidx]
            gcidx = gcidx[0]
        else:
            for i, fname in enumerate(fdb['FILE'][gcidx]):
                print str(i) + ': GAINCALTEST File', fname
            idex = input('There is more than one GAINCALTEST. Select: ' +
                         str(np.arange(len(gcidx))) + ':')
            gcidx = gcidx[idex]

        datadir = get_idbdir(Time(mjd, format='mjd'))
        # Add date path if on pipeline
        # if datadir.find('eovsa') != -1: datadir += fdb['FILE'][gcidx][3:11]+'/'

        host = socket.gethostname()
        if host == 'pipeline': datadir += fdb['FILE'][gcidx][3:11] + '/'

        file = datadir + fdb['FILE'][gcidx]
        out = ri.read_idb([file])
        if dataonly:
            return out
        # Get time from filename and read 120 records of attn state from SQL database
        filemjd = fname2mjd(fdb['FILE'][gcidx])
        cursor = dbutil.get_cursor()
        d15 = dbutil.get_dbrecs(cursor,
                                dimension=15,
                                timestamp=Time(filemjd, format='mjd'),
                                nrecs=120)
        cursor.close()
        # Find time indexes of the 62 dB attn state
        # Uses only ant 1 assuming all are the same
        dtot = (d15['Ante_Fron_FEM_HPol_Atte_Second'] +
                d15['Ante_Fron_FEM_HPol_Atte_First'])[:, 0]
        # Use system clock day number to identify bad SQL entries and eliminate them
        good, = np.where(d15['Ante_Cont_SystemClockMJDay'][:, 0] != 0)
        #import pdb; pdb.set_trace()
        # Indexes into SQL records where a transition occurred.
        transitions, = np.where(dtot[good] - np.roll(dtot[good], 1) != 0)
        # Eliminate any zero-index transition (if it exists)
        if transitions[0] == 0:
            transitions = transitions[1:]
        # These now have to be translated into indexes into the data, using the times
        idx = nearest_val_idx(d15['Timestamp'][good, 0][transitions],
                              Time(out['time'], format='jd').lv)
        #import pdb; pdb.set_trace()
        vx = np.nanmedian(
            out['p'][:13, :, :, np.arange(idx[0] + 1, idx[1] - 1)], 3)
        va = np.mean(out['a'][:13, :2, :,
                              np.arange(idx[0] + 1, idx[1] - 1)], 3)
        vals = []
        attn = []
        for i in range(1, 10):
            vals.append(
                np.nanmedian(
                    out['p'][:13, :, :,
                             np.arange(idx[i] + 1, idx[i + 1] - 1)], 3) - vx)
            attn.append(np.log10(vals[0] / vals[-1]) * 10.)
        #vals = []
        #attna = []
        #for i in range(1,10):
        #    vals.append(np.median(out['a'][:13,:2,:,np.arange(idx[i],idx[i+1])],3) - va)
        #    attna.append(np.log10(vals[0]/vals[-1])*10.)

        if do_plot:
            for i in range(13):
                for j in range(2):
                    ax[j, i].plot(out['fghz'],
                                  attn[1][i, j],
                                  '.',
                                  markersize=3)
                    #ax[j,i].plot(out['fghz'],attna[1][i,j],'.',markersize=1)
                    ax[j + 2, i].plot(out['fghz'],
                                      attn[2][i, j],
                                      '.',
                                      markersize=3)
                    #ax[j+2,i].plot(out['fghz'],attna[2][i,j],'.',markersize=1)
        outdict.append({
            'time': Time(out['time'][0], format='jd'),
            'fghz': out['fghz'],
            'rcvr_auto': va,  # 'attna': np.array(attna[1:]), 
            'rcvr': vx,
            'attn': np.array(attn[1:])
        })
    return outdict
コード例 #14
0
ファイル: pipeline_cal.py プロジェクト: sjyu1988/eovsa
def apply_fem_level(data, gctime=None, skycal=None):
    ''' Applys the FEM level corrections to the given data dictionary.
        
        Inputs:
          data     A dictionary such as that returned by readXdata().
          gctime   A Time() object whose date specifies which GAINCALTEST
                     measurements to use.  If omitted, the date of the data
                     is used.
          skycal   Optional array of receiver noise from SKYCAL or GAINCAL
                     calibration.  Only the receiver noise is applied (subtracted)

        Output:
          cdata    A dictionary with the level-corrected data.  The keys
                     p, x, p2, and a are all updated.
    '''
    import attncal as ac
    from gaincal2 import get_fem_level
    import copy

    # Get timerange from data
    trange = Time([data['time'][0], data['time'][-1]], format='jd')
    if gctime is None:
        gctime = trange[0]
    # Get time cadence
    dt = np.int(
        np.round(np.nanmedian(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the FEM levels of the requested timerange
    src_lev = get_fem_level(trange,
                            dt)  # solar gain state for timerange of file
    nf = len(data['fghz'])
    nt = len(src_lev['times'])
    attn = ac.read_attncal(
        gctime
    )[0]  # Reads attn from SQL database (returns a list, but use first, generally only, one)
    # attn = ac.get_attncal(gctime)[0]   # Analyzes GAINCALTEST (returns a list, but use first, generally only, one)
    antgain = np.zeros((15, 2, nf, nt),
                       np.float32)  # Antenna-based gains [dB] vs. frequency
    # Find common frequencies of attn with data
    idx1, idx2 = common_val_idx(data['fghz'], attn['fghz'], precision=4)
    # Currently, GAINCALTEST measures 8 levels of attenuation (16 dB).  I assumed this would be enough,
    # but the flare of 2017-09-10 actually went to 10 levels (20 dB), so we have no choice but to extend
    # to higher levels using only the nominal, 2 dB steps above the 8th level.  This part of the code
    # extends to the maximum 16 levels.
    a = np.zeros((16, 13, 2, nf), float)  # Extend attenuation to 14 levels
    a[1:9, :, :, idx1] = attn[
        'attn'][:, :13, :,
                idx2]  # Use GAINCALTEST results in levels 1-9 (bottom level is 0dB)
    for i in range(8, 15):
        # Extend to levels 9-15 by adding 2 dB to each previous level
        a[i + 1] = a[i] + 2.
    a[15] = 62.  # Level 15 means 62 dB have been inserted.
    #print 'Attn list (dB) for ant 1, pol xx, lowest frequency:',a[:,0,0,0]
    if dt:
        # For this case, src_lev is an array of dictionaries where keys are levels and
        # values are the proportion of that level for the given integration
        for i in range(13):
            for k, j in enumerate(idx1):
                for m in range(nt):
                    for lev, prop in src_lev['hlev'][i, m].items():
                        antgain[i, 0, j, m] += prop * a[lev, i, 0, idx2[k]]
                    for lev, prop in src_lev['vlev'][i, m].items():
                        antgain[i, 1, j, m] += prop * a[lev, i, 1, idx2[k]]
    else:
        # For this case, src_lev is just an array of levels
        for i in range(13):
            for k, j in enumerate(idx1):
                antgain[i, 0, j] = a[src_lev['hlev'][i], i, 0, idx2[k]]
                antgain[i, 1, j] = a[src_lev['vlev'][i], i, 1, idx2[k]]
    cdata = copy.deepcopy(data)
    nblant = 136
    blgain = np.zeros((nf, nblant, 4, nt),
                      float)  # Baseline-based gains vs. frequency

    for i in range(14):
        for j in range(i, 14):
            k = bl2ord[i, j]
            blgain[:, k, 0] = 10**((antgain[i, 0] + antgain[j, 0]) / 20.)
            blgain[:, k, 1] = 10**((antgain[i, 1] + antgain[j, 1]) / 20.)
            blgain[:, k, 2] = 10**((antgain[i, 0] + antgain[j, 1]) / 20.)
            blgain[:, k, 3] = 10**((antgain[i, 1] + antgain[j, 0]) / 20.)
    # Reorder antgain axes to put frequencies in first slot, to match data
    antgain = np.swapaxes(np.swapaxes(antgain, 1, 2), 0, 1)
    antgainf = 10**(antgain / 10.)

    idx = nearest_val_idx(data['time'], src_lev['times'].jd)
    nt = len(idx)  # New number of times
    # If a skycal dictionary exists, subtract auto-correlation receiver noise before scaling (clip to 0)
    if skycal:
        sna, snp, snf = skycal['rcvr_bgd_auto'].shape
        bgd = skycal['rcvr_bgd_auto'].repeat(nt).reshape((sna, snp, snf, nt))
        bgd = bgd[:, :, idx2]  # Extract only frequencies matching the data
        # Reorder axes
        bgd = np.swapaxes(bgd, 0, 2)
        #        bslice = bgd[:,:,:,idx]
        for i in range(13):
            cdata['x'][:, bl2ord[i, i], 0] = np.clip(
                cdata['x'][:, bl2ord[i, i], 0] - bgd[:, 0, i], 0,
                None)  #bslice[:,0,i],0,None)
            cdata['x'][:, bl2ord[i, i], 1] = np.clip(
                cdata['x'][:, bl2ord[i, i], 1] - bgd[:, 1, i], 0,
                None)  #bslice[:,1,i],0,None)
    # Correct the auto- and cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Reshape px and py arrays
    cdata['px'].shape = (nf, 16, 3, nt)
    cdata['py'].shape = (nf, 16, 3, nt)
    # If a skycal dictionary exists, subtract total power receiver noise before scaling (clip to 0)
    # NB: This will break SK!
    if skycal:
        sna, snp, snf = skycal['rcvr_bgd'].shape
        bgd = skycal['rcvr_bgd'].repeat(nt).reshape((sna, snp, snf, nt))
        bgd = bgd[:, :, idx2]  # Extract only frequencies matching the data
        # Reorder axes
        bgd = np.swapaxes(bgd, 0, 2)
        #bslice = bgd[:,:,:,idx]
        #bgnd = np.rollaxis(bslice,3)
        cdata['px'][:, :13, 0] = np.clip(cdata['px'][:, :13, 0] - bgd[:, 0], 0,
                                         None)  #bslice[:,0],0,None)
        cdata['py'][:, :13, 0] = np.clip(cdata['py'][:, :13, 0] - bgd[:, 1], 0,
                                         None)  #bslice[:,1],0,None)
    # Correct the power
    cdata['px'][:, :15, 0] *= antgainf[:, :, 0, idx]
    cdata['py'][:, :15, 0] *= antgainf[:, :, 1, idx]
    # Correct the power-squared
    cdata['px'][:, :15, 1] *= antgainf[:, :, 0, idx]**2
    cdata['py'][:, :15, 1] *= antgainf[:, :, 1, idx]**2
    # Reshape px and py arrays back to original
    cdata['px'].shape = (nf * 16 * 3, nt)
    cdata['py'].shape = (nf * 16 * 3, nt)
    return cdata
コード例 #15
0
ファイル: calwidget.py プロジェクト: donghaoliu/eovsa
def rd_refcal(file, quackint=120., navg=3):
    ''' Reads a single UDB file representing a calibrator scan, and averages over the
        bands in the file
    '''
    from read_idb import read_idb, bl2ord
    from copy import deepcopy
    import chan_util_bc as cu
    import dbutil as db
    
    out = read_idb([file], navg=navg, quackint=quackint)

    bds = np.unique(out['band'])
    nt = len(out['time'])
    nbd = len(bds)
    vis = np.zeros((15, 4, 34, nt), dtype=complex)
    fghz = np.zeros(34)
    # average over channels within each band
    o = out['x'][bl2ord[13,:13]]
    for bd in bds:
        idx = np.where(out['band'] == bd)[0]
        fghz[bd-1] = np.nanmean(out['fghz'][idx])
        vis[:13,:,bd-1] = np.mean(o[:, :, idx], axis=2)
    # Need to apply unrot to correct for feed rotation, before returning
    xml, buf = ch.read_cal(11, Time(out['time'][0],format='jd'))
    dph = extract(buf,xml['XYphase'])
    xi_rot = extract(buf,xml['Xi_Rot'])
    freq = extract(buf,xml['FGHz'])
    freq = freq[np.where(freq != 0)]
    band = []
    for f in freq:
        band.append(cu.freq2bdname(f))
    bds, sidx = np.unique(band, return_index=True)
    nbd = len(bds)
    eidx = np.append(sidx[1:], len(band))
    dxy = np.zeros((14, 34), dtype=np.float)
    xi = np.zeros(34, dtype=np.float)
    fghz = np.zeros(34)
    # average dph and xi_rot frequencies within each band, to convert to 34-band representation
    for b, bd in enumerate(bds):
        fghz[bd - 1] = np.nanmean(freq[sidx[b]:eidx[b]])
        xi[bd - 1] = np.nanmean(xi_rot[sidx[b]:eidx[b]])
        for a in range(14):
            dxy[a, bd - 1] = np.angle(np.sum(np.exp(1j * dph[a, sidx[b]:eidx[b]])))
    # Read parallactic angles for this scan
    trange = Time(out['time'][[0,-1]],format='jd')
    times, chi = db.get_chi(trange)
    tchi = times.jd
    t = out['time']
    if len(t) > 0:
        vis2 = deepcopy(vis)
        idx = nearest_val_idx(t, tchi)
        pa = chi[idx]  # Parallactic angle for the times of this refcal.
        pa[:, [8, 9, 10, 12]] = 0.0
        nt = len(idx)  # Number of times in this refcal
        # Apply X-Y delay phase correction
        for a in range(13):
            a1 = lobe(dxy[a] - dxy[13])
            a2 = -dxy[13] - xi
            a3 = dxy[a] - xi + np.pi
            for j in range(nt):
                vis2[a, 1, :, j] *= np.exp(1j * a1)
                vis2[a, 2, :, j] *= np.exp(1j * a2)
                vis2[a, 3, :, j] *= np.exp(1j * a3)
        for j in range(nt):
            for a in range(13):
                vis[a, 0, :, j] = vis2[a, 0, :, j] * np.cos(pa[j, a]) + vis2[a, 3, :, j] * np.sin(pa[j, a])
                vis[a, 2, :, j] = vis2[a, 2, :, j] * np.cos(pa[j, a]) + vis2[a, 1, :, j] * np.sin(pa[j, a])
                vis[a, 3, :, j] = vis2[a, 3, :, j] * np.cos(pa[j, a]) - vis2[a, 0, :, j] * np.sin(pa[j, a])
                vis[a, 1, :, j] = vis2[a, 1, :, j] * np.cos(pa[j, a]) - vis2[a, 2, :, j] * np.sin(pa[j, a])
    # *******
    return {'file': file, 'source': out['source'], 'vis': vis, 'bands': bds, 'fghz': fghz, 'times': out['time'], 'ha': out['ha'], 'dec': out['dec'], 'flag': np.zeros_like(vis, dtype=np.int)}
コード例 #16
0
ファイル: gaincal2.py プロジェクト: donghaoliu/eovsa
def apply_fem_level(data, gctime=None):
    ''' Applys the FEM level corrections to the given data dictionary.
        
        Inputs:
          data     A dictionary such as that returned by read_idb().
          gctime   A Time() object whose date specifies which GAINCALTEST
                     measurements to use.  If omitted, the date of the data
                     is used.

        Output:
          cdata    A dictionary with the level-corrected data.  The keys
                     p, x, p2, and a are all updated.
    '''
    from util import common_val_idx, nearest_val_idx
    import attncal as ac
    import copy

    # Get timerange from data
    trange = Time([data['time'][0], data['time'][-1]], format='jd')
    if gctime is None:
        gctime = trange[0]
    # Get time cadence
    dt = np.int(
        np.round(np.median(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the FEM levels of the requested timerange
    src_lev = get_fem_level(trange,
                            dt)  # solar gain state for timerange of file
    nf = len(data['fghz'])
    nt = len(src_lev['times'])
    # First attempt to read from the SQL database.  If that fails, read from the IDB file itself
    try:
        attn = ac.read_attncal(gctime)[0]  # Attn from SQL
    except:
        attn = ac.get_attncal(
            gctime
        )[0]  # Attn measured by GAINCALTEST (returns a list, but use first, generally only, one)
    antgain = np.zeros((15, 2, nf, nt),
                       np.float32)  # Antenna-based gains [dB] vs. frequency
    # Find common frequencies of attn with data
    idx1, idx2 = common_val_idx(data['fghz'], attn['fghz'], precision=4)
    a = attn['attn']
    for i in range(13):
        for k, j in enumerate(idx1):
            antgain[i, 0, j] = a[src_lev['hlev'][i], i, 0, idx2[k]]
            antgain[i, 1, j] = a[src_lev['vlev'][i], i, 0, idx2[k]]
    cdata = copy.deepcopy(data)
    blgain = np.zeros((120, 4, nf, nt),
                      float)  # Baseline-based gains vs. frequency
    for i in range(14):
        for j in range(i + 1, 15):
            blgain[ri.bl2ord[i, j],
                   0] = 10**((antgain[i, 0] + antgain[j, 0]) / 20.)
            blgain[ri.bl2ord[i, j],
                   1] = 10**((antgain[i, 1] + antgain[j, 1]) / 20.)
            blgain[ri.bl2ord[i, j],
                   2] = 10**((antgain[i, 0] + antgain[j, 1]) / 20.)
            blgain[ri.bl2ord[i, j],
                   3] = 10**((antgain[i, 1] + antgain[j, 0]) / 20.)
    antgainf = 10**(antgain / 10.)

    #idx1, idx2 = common_val_idx(data['time'],src_gs['times'].jd)
    idx = nearest_val_idx(data['time'], src_lev['times'].jd)
    # Apply corrections (some times may be eliminated from the data)
    # Correct the cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Correct the power
    cdata['p'][:15] *= antgainf[:, :, :, idx]
    # Correct the autocorrelation
    cdata['a'][:15, :2] *= antgainf[:, :, :, idx]
    cross_fac = np.sqrt(antgainf[:, 0] * antgainf[:, 1])
    cdata['a'][:15, 2] *= cross_fac[:, :, idx]
    cdata['a'][:15, 3] *= cross_fac[:, :, idx]
    # Correct the power-squared -- this should preserve SK
    cdata['p2'][:15] *= antgainf[:, :, :, idx]**2
    # Remove any uncorrected times before returning
    #cdata['time'] = cdata['time'][idx1]
    #cdata['p'] = cdata['p'][:,:,:,idx1]
    #cdata['a'] = cdata['a'][:,:,:,idx1]
    #cdata['p2'] = cdata['p2'][:,:,:,idx1]
    #cdata['ha'] = cdata['ha'][idx1]
    #cdata['m'] = cdata['m'][:,:,:,idx1]
    return cdata
コード例 #17
0
ファイル: pipeline_cal.py プロジェクト: binchensolar/eovsa
def apply_attn_corr(data, tref=None):
    ''' Applys the attenuator state corrections to the given data dictionary,
        corrected to the gain-state at time given by Time() object tref.
        
        Inputs:
          data     A dictionary returned by udb_util.py's readXdata().
          tref     A Time() object with the reference time, or if None,
                     the gain state of the nearest earlier REFCAL is 
                     used.
        Output:
          cdata    A dictionary with the gain-corrected data.  The keys
                     px, py, and x, are updated.
                     
        NB: This is the same routine as in gaincal2.py, but modified
        to handle the different ordering/format of data from udb_util.py's
        readXdata() routine.
    '''
    from gaincal2 import get_gain_state
    from util import common_val_idx, nearest_val_idx
    import copy
    if tref is None:
        # No reference time specified, so get nearest earlier REFCAL
        trange = Time(data['time'][[0,-1]],format='jd')
        xml, buf = ch.read_cal(8,t=trange[0])
        tref = Time(stateframe.extract(buf,xml['Timestamp']),format='lv')
    # Get the gain state at the reference time (actually median over 1 minute)
    trefrange = Time([tref.iso,Time(tref.lv+60,format='lv').iso])
    ref_gs =  get_gain_state(trefrange)  # refcal gain state for 60 s
    # Get median of refcal gain state (which should be constant anyway)
    ref_gs['h1'] = np.median(ref_gs['h1'],1)
    ref_gs['h2'] = np.median(ref_gs['h2'],1)
    ref_gs['v1'] = np.median(ref_gs['v1'],1)
    ref_gs['v2'] = np.median(ref_gs['v2'],1)

    # Get timerange from data
    trange = Time([data['time'][0],data['time'][-1]],format='jd')
    # Get time cadence
    dt = np.int(np.round(np.median(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the gain state of the requested timerange
    src_gs = get_gain_state(trange,dt)   # solar gain state for timerange of file
    nt = len(src_gs['times'])
    antgain = np.zeros((15,2,34,nt),np.float32)   # Antenna-based gains vs. band
    for i in range(15):
        for j in range(34):
            antgain[i,0,j] = src_gs['h1'][i] + src_gs['h2'][i] - ref_gs['h1'][i] - ref_gs['h2'][i] + src_gs['dcmattn'][i,0,j] - ref_gs['dcmattn'][i,0,j]
            antgain[i,1,j] = src_gs['v1'][i] + src_gs['v2'][i] - ref_gs['v1'][i] - ref_gs['v2'][i] + src_gs['dcmattn'][i,1,j] - ref_gs['dcmattn'][i,1,j]

    cdata = copy.deepcopy(data)
    # Create giant array of baseline-based gains, translated to baselines and frequencies
    fghz = data['fghz']
    nf = len(fghz)
    blist = (fghz*2 - 1).astype(int) - 1       # Band list corresponding to frequencies in data
    blgain = np.zeros((nf,136,4,nt),float)     # Baseline-based gains vs. frequency
    for k,bl in enumerate(get_bl_order()):
        i, j = bl
        if i < 15 and j < 15:
            blgain[:,k,0] = 10**((antgain[i,0,blist] + antgain[j,0,blist])/20.)
            blgain[:,k,1] = 10**((antgain[i,1,blist] + antgain[j,1,blist])/20.)
            blgain[:,k,2] = 10**((antgain[i,0,blist] + antgain[j,1,blist])/20.)
            blgain[:,k,3] = 10**((antgain[i,1,blist] + antgain[j,0,blist])/20.)
    # Reorder antgain axes to put frequencies in first slot, to match data
    antgain = np.swapaxes(np.swapaxes(antgain,1,2),0,1)
    antgainf = 10**(antgain[blist]/10.)

    idx = nearest_val_idx(data['time'],src_gs['times'].jd)
    # Correct the auto- and cross-correlation data
    cdata['x'] *= blgain[:,:,:,idx]
    # Reshape px and py arrays
    cdata['px'].shape = (134,16,3,nt)
    cdata['py'].shape = (134,16,3,nt)
    # Correct the power
    cdata['px'][:,:15,0] *= antgainf[:,:,0,idx]
    cdata['py'][:,:15,0] *= antgainf[:,:,1,idx]
    # Correct the power-squared
    cdata['px'][:,:15,1] *= antgainf[:,:,0,idx]**2
    cdata['py'][:,:15,1] *= antgainf[:,:,1,idx]**2
    # Reshape px and py arrays back to original
    cdata['px'].shape = (134*16*3,nt)
    cdata['py'].shape = (134*16*3,nt)
    return cdata
コード例 #18
0
ファイル: gaincal2.py プロジェクト: donghaoliu/eovsa
def apply_gain_corr(data, tref=None):
    ''' Applys the gain_state() corrections to the given data dictionary,
        corrected to the gain-state at time given by Time() object tref.
        
        Inputs:
          data     A dictionary such as that returned by read_idb().
          tref     A Time() object with the reference time, or if None,
                     the gain state of the nearest earlier REFCAL is 
                     used.
        Output:
          cdata    A dictionary with the gain-corrected data.  The keys
                     p, x, p2, and a are all updated.
    '''
    from util import common_val_idx, nearest_val_idx
    import copy
    if tref is None:
        # No reference time specified, so get nearest earlier REFCAL
        trange = Time(data['time'][[0, -1]], format='jd')
        xml, buf = ch.read_cal(8, t=trange[0])
        if xml == {}:
            # No refcal for this date, so just use an early time as reference
            tref = Time(trange[0].iso[:10] + ' 13:30')
        else:
            tref = Time(stf.extract(buf, xml['Timestamp']), format='lv')
    # Get the gain state at the reference time (actually median over 1 minute)
    trefrange = Time([tref.iso, Time(tref.lv + 61, format='lv').iso])
    ref_gs = get_gain_state(trefrange)  # refcal gain state for 60 s
    # Get median of refcal gain state (which should be constant anyway)
    ref_gs['h1'] = np.median(ref_gs['h1'], 1)
    ref_gs['h2'] = np.median(ref_gs['h2'], 1)
    ref_gs['v1'] = np.median(ref_gs['v1'], 1)
    ref_gs['v2'] = np.median(ref_gs['v2'], 1)

    # Get timerange from data
    trange = Time([data['time'][0], data['time'][-1]], format='jd')
    # Get time cadence
    dt = np.int(
        np.round(np.median(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the gain state of the requested timerange
    src_gs = get_gain_state(trange,
                            dt)  # solar gain state for timerange of file
    nt = len(src_gs['times'])
    antgain = np.zeros((15, 2, 34, nt),
                       np.float32)  # Antenna-based gains vs. band
    for i in range(15):
        for j in range(34):
            antgain[i, 0, j] = src_gs['h1'][i] + src_gs['h2'][i] - ref_gs[
                'h1'][i] - ref_gs['h2'][i] + src_gs['dcmattn'][
                    i, 0, j] - ref_gs['dcmattn'][i, 0, j]
            antgain[i, 1, j] = src_gs['v1'][i] + src_gs['v2'][i] - ref_gs[
                'v1'][i] - ref_gs['v2'][i] + src_gs['dcmattn'][
                    i, 1, j] - ref_gs['dcmattn'][i, 1, j]

    cdata = copy.deepcopy(data)
    # Frequency list is provided, so produce baseline-based gain table as well
    # Create giant array of gains, translated to baselines and frequencies
    fghz = data['fghz']
    nf = len(fghz)
    blist = (fghz * 2 - 1).astype(int) - 1
    blgain = np.zeros((120, 4, nf, nt),
                      float)  # Baseline-based gains vs. frequency
    for i in range(14):
        for j in range(i + 1, 15):
            blgain[ri.bl2ord[i, j],
                   0] = 10**((antgain[i, 0, blist] + antgain[j, 0, blist]) /
                             20.)
            blgain[ri.bl2ord[i, j],
                   1] = 10**((antgain[i, 1, blist] + antgain[j, 1, blist]) /
                             20.)
            blgain[ri.bl2ord[i, j],
                   2] = 10**((antgain[i, 0, blist] + antgain[j, 1, blist]) /
                             20.)
            blgain[ri.bl2ord[i, j],
                   3] = 10**((antgain[i, 1, blist] + antgain[j, 0, blist]) /
                             20.)
    antgainf = 10**(antgain[:, :, blist] / 10.)

    #idx1, idx2 = common_val_idx(data['time'],src_gs['times'].jd)
    idx = nearest_val_idx(data['time'], src_gs['times'].jd)
    # Apply corrections (some times may be eliminated from the data)
    # Correct the cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Correct the power
    cdata['p'][:15] *= antgainf[:, :, :, idx]
    # Correct the autocorrelation
    cdata['a'][:15, :2] *= antgainf[:, :, :, idx]
    cross_fac = np.sqrt(antgainf[:, 0] * antgainf[:, 1])
    cdata['a'][:15, 2] *= cross_fac[:, :, idx]
    cdata['a'][:15, 3] *= cross_fac[:, :, idx]
    # Correct the power-squared -- this should preserve SK
    cdata['p2'][:15] *= antgainf[:, :, :, idx]**2
    # Remove any uncorrected times before returning
    #cdata['time'] = cdata['time'][idx1]
    #cdata['p'] = cdata['p'][:,:,:,idx1]
    #cdata['a'] = cdata['a'][:,:,:,idx1]
    #cdata['p2'] = cdata['p2'][:,:,:,idx1]
    #cdata['ha'] = cdata['ha'][idx1]
    #cdata['m'] = cdata['m'][:,:,:,idx1]
    return cdata
コード例 #19
0
def calpntanal(t,ant_str='ant1-13',do_plot=True,ax=None):
    ''' Does a complete analysis of CALPNTCAL, reading information from the SQL
        database, finding the corresponding Miriad IDB data, and doing the 
        gaussian fit to the beam, to return the beam and offset parameters.
        
        t   Time object with a time near the start of the desired scan (finds the scan
              that starts closest time to the given time)

        ax  If specified as a two-element array of axes, the plots will be placed
              in an already existing window, allowing reuse of the same window.
              Otherwise, a new figure is created (if do_plot is True).
        Returns a dictionary containing 
           Source name, Time, HA, Dec, RA offset and Dec offset
    '''
    import matplotlib.pyplot as plt
    from matplotlib.transforms import Bbox
    import read_idb
    import dbutil as db
    bl2ord = read_idb.bl2ord
    tdate = t.iso.replace('-','')[:8]
    fdir = '/data1/eovsa/fits/IDB/'+tdate+'/'
    fdb = dump_tsys.rd_fdb(t)
    scanidx, = np.where(fdb['PROJECTID'] == 'CALPNTCAL')
    # Set offset coordinates appropriate to the type of PROJECTID found
    if scanidx.size == 0:
        # No CALPNTCAL scans, so search for CALPNT2M
        scanidx, = np.where(fdb['PROJECTID'] == 'CALPNT2M')
        if scanidx.size == 0:
            print 'No CALPNTCAL or CALPNT2M project IDs found for date'+t.iso[:10]
            return {}
        else:
            # Found CALPNT2M, so set offset coordinates to match calpnt2m.trj
            rao = np.array([-5.00, -2.0, -1.0, -0.5, 0.00, 0.5, 1.0, 2.0])
            deco = np.array([-2.0, -1.0, -0.5, 0.00, 0.5, 1.0, 2.0, 5.00])
            pltfac = 10.
    else:
        # Found CALPNTCAL, so set offset coordinates to match calpnt.trj
        rao = np.array([-1.00, -0.20, -0.10, -0.05, 0.00, 0.05, 0.10, 0.20])
        deco = np.array([-0.20, -0.10, -0.05, 0.00, 0.05, 0.10, 0.20, 1.00])
        pltfac = 1.
    scans,sidx = np.unique(fdb['SCANID'][scanidx],return_index=True)
    tlist = Time(fdb['ST_TS'][scanidx[sidx]].astype(float).astype(int),format='lv')
    idx, = nearest_val_idx([t.jd],tlist.jd)
    filelist = [fdir+f for f in fdb['FILE'][np.where(fdb['SCANID'] == scans[idx])]]
    # Read pointing data (timerange t must be accurate)
    out = read_idb.read_idb(filelist, navg=30)
    # Determine wanted baselines with ant 14 from ant_str
    idx = read_idb.p.ant_str2list(ant_str)
    idx1 = idx[idx>7]  # Ants > 8
    idx2 = idx[idx<8]  # Ants <= 8
    # Determine parallactic angle for azel antennas (they are all the same, so find median).  
    #    If 0 < abs(chi) < 30, use channel XX
    #    If 30 < abs(chi) < 60, use sum of channel XX and XY
    #    If 60 < abs(chi) < 90, use channel XY
    midtime = Time((out['time'][0] + out['time'][-1])/2.,format='jd')
    times, chi = db.get_chi(Time([midtime.lv+1,midtime.lv + 10],format='lv'))
    abschi = abs(lobe(np.median(chi[0,0:8])))
    if pltfac == 1.:
        # Case of 27m antenna pointing
        # Do appropriate sums over frequency, polarization and baseline
        if abschi >= 0 and abschi < np.pi/6:
            pntdata = np.sum(np.abs(np.sum(out['x'][bl2ord[idx,13],0,:,:48],1)),0)  # Use only XX
        elif abschi >= np.pi/6 and abschi < np.pi/3:
            pntdata1 = np.sum(np.abs(np.sum(out['x'][bl2ord[idx1,13],0,:,:48],1)),0)  # Use XX only for ants > 8
            pntdata2 = np.sum(np.abs(np.sum(out['x'][bl2ord[idx2,13],:,:,:48],2)),0)  # Use sum of XX and XY for ants <= 8
            pntdata = pntdata1 + np.sum(pntdata2[np.array([0,2])],0)
        else:
            pntdata1 = np.sum(np.abs(np.sum(out['x'][bl2ord[idx1,13],0,:,:48],1)),0)  # Use XX only for ants > 8
            pntdata2 = np.sum(np.abs(np.sum(out['x'][bl2ord[idx2,13],2,:,:48],1)),0)  # Use sum of XY for ants <= 8
            pntdata = pntdata1 + pntdata2
        # Measurements are 90 s long, hence 3 consecutive 30 s points, so do final
        # sum over these
        pntdata.shape = (16,3)
        stdev = np.std(pntdata,1)
        pntdata = np.sum(pntdata,1)
        radat = pntdata[:8]
        decdat = pntdata[8:]
        plsqr, xr, yr = solpnt.gausfit(rao, radat)
        plsqd, xd, yd = solpnt.gausfit(deco, decdat)
        midtime = Time((out['time'][0] + out['time'][-1])/2.,format='jd')
        if (do_plot):
            if ax is None:
                f, ax = plt.subplots(1,2)
                f.set_size_inches(2.5,1.5,forward=True)
            ax[0].errorbar(rao,radat,yerr=stdev[:8],fmt='.')
            ax[0].plot(xr,yr)
            ax[0].axvline(x=0,color='k')
            ax[0].axvline(x=plsqr[1],linestyle='--')
            ax[1].errorbar(deco,decdat,yerr=stdev[8:],fmt='.')
            ax[1].plot(xd,yd)
            ax[1].axvline(x=0,color='k')
            ax[1].axvline(x=plsqd[1],linestyle='--')
            for j in range(2):
                ax[j].set_xlim(-0.3, 0.3)
                ax[j].grid()
            ax[0].text(0.05,0.9,'RAO :'+str(plsqr[1])[:5],transform=ax[0].transAxes)
            ax[0].text(0.55,0.9,'FWHM:'+str(plsqr[2])[:5],transform=ax[0].transAxes)
            ax[0].set_xlabel('RA Offset [deg]')
            ax[1].text(0.05,0.9,'DECO:'+str(plsqd[1])[:5],transform=ax[1].transAxes)
            ax[1].text(0.55,0.9,'FWHM:'+str(plsqd[2])[:5],transform=ax[1].transAxes)
            ax[1].set_xlabel('Dec Offset [deg]')
            if ax is None:
                f.suptitle('Pointing on '+out['source']+' at '+midtime.iso)
            else:
                ax[0].set_title(out['source']+' at')
                ax[1].set_title(midtime.iso[:16])
            plt.pause(0.5)
        return {'source':out['source'],'ha':out['ha'][24]*180./np.pi,'dec':out['dec']*180/np.pi,
                   'rao':plsqr[1],'deco':plsqd[1],'time':midtime,'antidx':13}
    else:
        # Case of 2m antenna pointing
        # Do appropriate sum over frequency and polarization but not baseline
        if abschi >= 0 and abschi < np.pi/6:
            pntdata = np.abs(np.sum(out['x'][bl2ord[idx,13],0,:,:48],1))  # Use only XX
        elif abschi >= np.pi/6 and abschi < np.pi/3:
            pntdata1 = np.abs(np.sum(out['x'][bl2ord[idx1,13],0,:,:48],1))  # Use XX only for ants > 8
            pntdata2 = np.abs(np.sum(out['x'][bl2ord[idx2,13],:,:,:48],2))  # Use sum of XX and XY for ants <= 8
            pntdata = np.concatenate((pntdata1,np.sum(pntdata2[:,np.array([0,2])],1)),0)
        else:
            pntdata1 = np.abs(np.sum(out['x'][bl2ord[idx1,13],0,:,:48],1))  # Use XX only for ants > 8
            pntdata2 = np.abs(np.sum(out['x'][bl2ord[idx2,13],2,:,:48],1))  # Use sum of XY for ants <= 8
            pntdata = np.concatenate((pntdata1,pntdata2),0)
        # Measurements are 90 s long, hence 3 consecutive 30 s points, so do final
        # sum over these
        pntdata.shape = (idx.size,16,3)
        stdev = np.std(pntdata,2)
        pntdata = np.sum(pntdata,2)
        rao_fit = np.zeros(idx.size,float)
        deco_fit = np.zeros(idx.size,float)
        if (do_plot):
            if ax is None:
                f, ax = plt.subplots(1,2*idx.size)
                f.set_size_inches(2.5*idx.size,1.5,forward=True)
                plt.subplots_adjust(left=0.03, right=0.97, top=0.89, bottom=0.3, wspace=0.1, hspace=0.1)
        for k in range(idx.size):
            radat = pntdata[k,:8]
            decdat = pntdata[k,8:]
            plsqr, xr, yr = solpnt.gausfit(rao, radat)
            plsqd, xd, yd = solpnt.gausfit(deco, decdat)
            midtime = Time((out['time'][0] + out['time'][-1])/2.,format='jd')
            if (do_plot):
                ax[k*2+0].errorbar(rao,radat,yerr=stdev[k,:8],fmt='.')
                ax[k*2+0].plot(xr,yr)
                ax[k*2+0].axvline(x=0,color='k')
                ax[k*2+0].axvline(x=plsqr[1],linestyle='--')
                ax[k*2+1].errorbar(deco,decdat,yerr=stdev[k,8:],fmt='.')
                ax[k*2+1].plot(xd,yd)
                ax[k*2+1].axvline(x=0,color='k')
                ax[k*2+1].axvline(x=plsqd[1],linestyle='--')
                for j in range(2):
                    ax[k*2+j].set_xlim(-3.0, 3.0)
                    ax[k*2+j].grid()
                ax[k*2+0].text(0.05,0.7,'RAO :'+str(plsqr[1])[:5],transform=ax[k*2+0].transAxes,fontsize=9)
                ax[k*2+0].text(0.05,0.5,'FWHM:'+str(plsqr[2])[:5],transform=ax[k*2+0].transAxes,fontsize=9)
                ax[k*2+0].set_xlabel('RAO [deg]',fontsize=9)
                ax[k*2+1].text(-0.2,0.85,'Ant :'+str(idx[k]+1),transform=ax[k*2+1].transAxes,fontsize=9)
                ax[k*2+1].text(0.05,0.7,'DECO:'+str(plsqd[1])[:5],transform=ax[k*2+1].transAxes,fontsize=9)
                ax[k*2+1].text(0.05,0.5,'FWHM:'+str(plsqd[2])[:5],transform=ax[k*2+1].transAxes,fontsize=9)
                ax[k*2+1].set_yticklabels([])
                ax[k*2+1].set_xlabel('DECO [deg]',fontsize=9)
                if k == idx.size-1:
                    ax[k+0].set_title(out['source']+' at',fontsize=9)
                    ax[k+1].set_title(midtime.iso[:16],fontsize=9)
                # Adjust the pairs of subplots to group RA/Dec for each antenna together 
                ax[k*2+0].set_position(Bbox(ax[k*2+0].get_position().get_points() + np.array([[0.0025,0],[0.0025,0]])))
                ax[k*2+1].set_position(Bbox(ax[k*2+1].get_position().get_points() + np.array([[-0.0025,0],[-0.0025,0]])))
                # Set to the same amplitude scale
                ymin = min(ax[k*2+0].get_ylim()[0],ax[k*2+1].get_ylim()[0])
                ymax = max(ax[k*2+0].get_ylim()[1],ax[k*2+1].get_ylim()[1])
                ax[k*2+0].set_ylim(ymin,ymax)
                ax[k*2+1].set_ylim(ymin,ymax)
                plt.pause(0.5)
            rao_fit[k] = plsqr[1]
            deco_fit[k] = plsqd[1]
        return {'source':out['source'],'ha':out['ha'][24]*180./np.pi,'dec':out['dec']*180/np.pi,
                   'rao':rao_fit,'deco':deco_fit,'time':midtime,'antidx':idx}
コード例 #20
0
ファイル: pipeline_cal.py プロジェクト: binchensolar/eovsa
def unrot(data, azeldict=None):
    ''' Apply the correction to differential feed rotation to data, and return
        the corrected data.

        Inputs:
          data     A dictionary returned by udb_util.py's readXdata().
          azeldict The dictionary returned from get_sql_info(), or if None, the appropriate
                     get_sql_info() call is done internally.

        Output:
          cdata    A dictionary with the phase-corrected data.  Only the key
                     x is updated.
    '''
    import copy
    from util import lobe
    trange = Time(data['time'][[0,-1]],format='jd')

    if azeldict is None:
        azeldict = get_sql_info(trange)
    chi = azeldict['ParallacticAngle']  # (nt, nant)
    # Correct parallactic angle for equatorial mounts, relative to Ant14
    for i in [8,9,10,12,13]:
        chi[:,i] -= chi[:,13]
        
    # Ensure that nearest valid parallactic angle is used for times in the data
    good, = np.where(azeldict['ActualAzimuth'][0] != 0)
    tidx = nearest_val_idx(data['time'],azeldict['Time'][good].jd)

    # Read X-Y Delay phase from SQL database and get common frequencies
    xml, buf = ch.read_cal(11,t=trange[0])
    fghz = stateframe.extract(buf,xml['FGHz'])
    good, = np.where(fghz != 0.)
    fghz = fghz[good]
    dph = stateframe.extract(buf,xml['XYphase'])
    dph = dph[:,good]
    fidx1, fidx2 = common_val_idx(data['fghz'],fghz,precision=4)
    missing = np.setdiff1d(np.arange(len(data['fghz'])),fidx1)
    
    nf, nbl, npol, nt = data['x'].shape
    nf = len(fidx1)
    # Correct data for X-Y delay phase
    for k,bl in enumerate(get_bl_order()):
        i, j = bl
        if i < 14 and j < 14 and i != j:
            a1 = lobe(dph[i,fidx2] - dph[j,fidx2])
            a2 = -dph[j,fidx2] + np.pi/2
            a3 = dph[i,fidx2] - np.pi/2
            data['x'][fidx1,k,1] *= np.repeat(np.exp(1j*a1),nt).reshape(nf,nt)
            data['x'][fidx1,k,2] *= np.repeat(np.exp(1j*a2),nt).reshape(nf,nt) 
            data['x'][fidx1,k,3] *= np.repeat(np.exp(1j*a3),nt).reshape(nf,nt)
    
    # Correct data for differential feed rotation
    cdata = copy.deepcopy(data)
    for n in range(nt):
        for k,bl in enumerate(get_bl_order()):
            i, j = bl
            if i < 14 and j < 14 and i != j:
                dchi = chi[n,i] - chi[n,j]
                cchi = np.cos(dchi)
                schi = np.sin(dchi)
                cdata['x'][:,k,0,n] = data['x'][:,k,0,n]*cchi + data['x'][:,k,3,n]*schi
                cdata['x'][:,k,2,n] = data['x'][:,k,2,n]*cchi + data['x'][:,k,1,n]*schi
                cdata['x'][:,k,3,n] = data['x'][:,k,3,n]*cchi - data['x'][:,k,0,n]*schi
                cdata['x'][:,k,1,n] = data['x'][:,k,1,n]*cchi - data['x'][:,k,2,n]*schi
    # Set flags for any missing frequencies (hopefully this also works when missing is np.array([]))
    cdata[missing] = np.ma.masked
    return cdata
コード例 #21
0
def get_gain_state(trange, dt=None, relax=False):
    ''' Get all gain-state information for a given timerange.  Returns a dictionary
        with keys as follows:
        
        times:     A Time object containing the array of times, size (nt)
        h1:        The first HPol attenuator value for 15 antennas, size (nt, 15) 
        v1:        The first VPol attenuator value for 15 antennas, size (nt, 15) 
        h2:        The second HPol attenuator value for 15 antennas, size (nt, 15) 
        v2:        The second VPol attenuator value for 15 antennas, size (nt, 15)
        dcmattn:   The base DCM attenuations for nbands x 15 antennas x 2 Poln, size (34 or 52,30)
                      The order is Ant1 H, Ant1 V, Ant2 H, Ant2 V, etc.
        dcmoff:    If DPPoffset-on is 0, this is None (meaning there are no changes to the
                      above base attenuations).  
                   If DPPoffset-on is 1, then dcmoff is a table of offsets to the 
                      base attenuation, size (nt, 50).  The offset applies to all 
                      antennas/polarizations.
                      
        Optional keywords:
           dt      Seconds between entries to read from SQL stateframe database. 
                     If omitted, 1 s is assumed.
           relax   Used for gain of reference time, in case there are no SQL data for the
                     requested time.  In that case it finds the data for the nearest later time.
    '''
    if dt is None:
        tstart, tend = [str(i) for i in trange.lv]
    else:
        # Expand time by 1/2 of dt before and after
        tstart = str(np.round(trange[0].lv - dt / 2))
        tend = str(np.round(trange[1].lv + dt / 2))
    cursor = db.get_cursor()
    ver = db.find_table_version(cursor, trange[0].lv)
    # Get front end attenuator states
    # Attempt to solve the problem if there are no data
    if relax:
        # Special case of reference gain, where we want the first nt records after tstart, in case there
        # are no data at time tstart
        nt = int(float(tend) - float(tstart) - 1) * 15
        query = 'select top '+str(nt)+' Timestamp,Ante_Fron_FEM_HPol_Atte_First,Ante_Fron_FEM_HPol_Atte_Second,' \
            +'Ante_Fron_FEM_VPol_Atte_First,Ante_Fron_FEM_VPol_Atte_Second,Ante_Fron_FEM_Clockms from fV' \
            +ver+'_vD15 where Timestamp >= '+tstart+' order by Timestamp'
    else:
        query = 'select Timestamp,Ante_Fron_FEM_HPol_Atte_First,Ante_Fron_FEM_HPol_Atte_Second,' \
            +'Ante_Fron_FEM_VPol_Atte_First,Ante_Fron_FEM_VPol_Atte_Second,Ante_Fron_FEM_Clockms from fV' \
            +ver+'_vD15 where Timestamp >= '+tstart+' and Timestamp < '+tend+' order by Timestamp'
    #if dt:
    #    # If dt (seconds between measurements) is set, add appropriate SQL statement to query
    #    query += ' and (cast(Timestamp as bigint) % '+str(dt)+') = 0 '
    data, msg = db.do_query(cursor, query)
    if msg == 'Success':
        if dt:
            # If we want other than full cadence, get new array shapes and times
            n = len(data['Timestamp'])  # Original number of times
            new_n = (
                n / 15 / dt
            ) * 15 * dt  # Truncated number of times equally divisible by dt
            new_shape = (n / 15 / dt, dt, 15)  # New shape of truncated arrays
            times = Time(data['Timestamp'][:new_n].astype('int')[::15 * dt],
                         format='lv')
        else:
            times = Time(data['Timestamp'].astype('int')[::15], format='lv')
        # Change tstart and tend to correspond to actual times from SQL
        tstart, tend = [str(i) for i in times[[0, -1]].lv]
        h1 = data['Ante_Fron_FEM_HPol_Atte_First']
        h2 = data['Ante_Fron_FEM_HPol_Atte_Second']
        v1 = data['Ante_Fron_FEM_VPol_Atte_First']
        v2 = data['Ante_Fron_FEM_VPol_Atte_Second']
        ms = data['Ante_Fron_FEM_Clockms']
        nt = len(h1) / 15
        h1.shape = (nt, 15)
        h2.shape = (nt, 15)
        v1.shape = (nt, 15)
        v2.shape = (nt, 15)
        ms.shape = (nt, 15)
        # Find any entries for which Clockms is zero, which indicates where no
        # gain-state measurement is available.
        for i in range(15):
            bad, = np.where(ms[:, i] == 0)
            if bad.size != 0 and bad.size != nt:
                # Find nearest adjacent good value
                good, = np.where(ms[:, i] != 0)
                idx = nearest_val_idx(bad, good)
                h1[bad, i] = h1[good[idx], i]
                h2[bad, i] = h2[good[idx], i]
                v1[bad, i] = v1[good[idx], i]
                v2[bad, i] = v2[good[idx], i]
        if dt:
            # If we want other than full cadence, find mean over dt measurements
            h1 = np.mean(h1[:new_n / 15].reshape(new_shape), 1)
            h2 = np.mean(h2[:new_n / 15].reshape(new_shape), 1)
            v1 = np.mean(v1[:new_n / 15].reshape(new_shape), 1)
            v2 = np.mean(v2[:new_n / 15].reshape(new_shape), 1)
        # Put results in canonical order [nant, nt]
        h1 = h1.T
        h2 = h2.T
        v1 = v1.T
        v2 = v2.T
    else:
        print 'Error reading FEM attenuations:', msg
        return {}
    # Get back end attenuator states
    xml, buf = ch.read_cal(2, t=trange[0])
    dcmattn = stf.extract(buf, xml['Attenuation'])
    nbands = dcmattn.shape[0]
    dcmattn.shape = (nbands, 15, 2)
    # Put into canonical order [nant, npol, nband]
    dcmattn = np.moveaxis(dcmattn, 0, 2)
    # See if DPP offset is enabled
    query = 'select Timestamp,DPPoffsetattn_on from fV' \
            +ver+'_vD1 where Timestamp >= '+tstart+' and Timestamp <= '+tend+'order by Timestamp'
    data, msg = db.do_query(cursor, query)
    if msg == 'Success':
        dppon = data['DPPoffsetattn_on']
        if np.where(dppon > 0)[0].size == 0:
            dcm_off = None
        else:
            query = 'select Timestamp,DCMoffset_attn from fV' \
                    +ver+'_vD50 where Timestamp >= '+tstart+' and Timestamp <= '+tend
            #if dt:
            #    # If dt (seconds between measurements) is set, add appropriate SQL statement to query
            #    query += ' and (cast(Timestamp as bigint) % '+str(dt)+') = 0 '
            query += ' order by Timestamp'
            data, msg = db.do_query(cursor, query)
            if msg == 'Success':
                otimes = Time(data['Timestamp'].astype('int')[::15],
                              format='lv')
                dcmoff = data['DCMoffset_attn']
                dcmoff.shape = (nt, 50)
                # We now have a time-history of offsets, at least some of which are non-zero.
                # Offsets by slot number do us no good, so we need to translate to band number.
                # Get fseqfile name at mean of timerange, from stateframe SQL database
                fseqfile = get_fseqfile(
                    Time(int(np.mean(trange.lv)), format='lv'))
                if fseqfile is None:
                    print 'Error: No active fseq file.'
                    dcm_off = None
                else:
                    # Get fseqfile from ACC and return bandlist
                    bandlist = fseqfile2bandlist(fseqfile)
                    nbands = len(bandlist)
                    # Use bandlist to covert nt x 50 array to nt x nbands array of DCM attn offsets
                    # Note that this assumes DCM offset is the same for any multiply-sampled bands
                    # in the sequence.
                    dcm_off = np.zeros((nt, nbands), float)
                    dcm_off[:, bandlist - 1] = dcmoff
                    # Put into canonical order [nband, nt]
                    dcm_off = dcm_off.T
                    if dt:
                        # If we want other than full cadence, find mean over dt measurements
                        new_nt = len(times)
                        dcm_off = dcm_off[:, :new_nt * dt]
                        dcm_off.shape = (nbands, dt, new_nt)
                        dcm_off = np.mean(dcm_off, 1)
            else:
                print 'Error reading DCM attenuations:', msg
                dcm_off = None
    else:
        print 'Error reading DPPon state:', msg
        dcm_off = None
    cursor.close()
    return {
        'times': times,
        'h1': h1,
        'v1': v1,
        'h2': h2,
        'v2': v2,
        'dcmattn': dcmattn,
        'dcmoff': dcm_off
    }
コード例 #22
0
def apply_fem_level(data, skycal=None, gctime=None):
    ''' Applys the FEM level corrections to the given data dictionary.
        
        Inputs:
          data     A dictionary such as that returned by read_idb().
          skycal   A dictionary returned by skycal_anal() in calibration.py.  This is
                     used to subtract a small "receiver background" before scaling for
                     fem level, and then adding it back.
          gctime   A Time() object whose date specifies which GAINCALTEST
                     measurements to use.  If omitted, the date of the data
                     is used.

        Output:
          cdata    A dictionary with the level-corrected data.  The keys
                     p, x, p2, and a are all updated.
    '''
    from util import common_val_idx, nearest_val_idx
    import attncal as ac
    import copy

    # Get timerange from data
    trange = Time([data['time'][0], data['time'][-1]], format='jd')
    if gctime is None:
        gctime = trange[0]
    # Get time cadence
    dt = np.int(
        np.round(np.median(data['time'][1:] - data['time'][:-1]) * 86400))
    if dt == 1: dt = None
    # Get the FEM levels of the requested timerange
    src_lev = get_fem_level(trange,
                            dt)  # solar gain state for timerange of file
    nf = len(data['fghz'])
    nt = len(src_lev['times'])
    # First attempt to read from the SQL database.  If that fails, read from the IDB file itself
    try:
        attn = ac.read_attncal(gctime)[0]  # Attn from SQL
        if (gctime.mjd - attn['time'].mjd) > 1:
            # SQL entry is too old, so analyze the GAINCALTEST
            attn = ac.get_attncal(
                gctime
            )[0]  # Attn measured by GAINCALTEST (returns a list, but use first, generally only, one)
            ch.fem_attn_val2sql([attn])  # Go ahead and write it to SQL
    except:
        attn = ac.get_attncal(
            gctime
        )[0]  # Attn measured by GAINCALTEST (returns a list, but use first, generally only, one)
    antgain = np.zeros((15, 2, nf, nt),
                       np.float32)  # Antenna-based gains [dB] vs. frequency
    # Find common frequencies of attn with data
    idx1, idx2 = common_val_idx(data['fghz'], attn['fghz'], precision=4)
    # Currently, GAINCALTEST measures 8 levels of attenuation (16 dB).  I assumed this would be enough,
    # but the flare of 2017-09-10 actually went to 10 levels (20 dB), so we have no choice but to extend
    # to higher levels using only the nominal, 2 dB steps above the 8th level.  This part of the code
    # extends to the maximum 16 levels.
    a = np.zeros((16, 13, 2, nf), float)  # Extend attenuation to 14 levels
    a[1:9, :, :, idx1] = attn[
        'attn'][:, :13, :,
                idx2]  # Use GAINCALTEST results in levels 1-9 (bottom level is 0dB)
    for i in range(8, 15):
        # Extend to levels 9-15 by adding 2 dB to each previous level
        a[i + 1] = a[i] + 2.
    a[15] = 62.  # Level 15 means 62 dB have been inserted.
    if dt:
        # For this case, src_lev is an array of dictionaries where keys are levels and
        # values are the proportion of that level for the given integration
        for i in range(13):
            for k, j in enumerate(idx1):
                for m in range(nt):
                    for lev, prop in src_lev['hlev'][i, m].items():
                        antgain[i, 0, j, m] += prop * a[lev, i, 0, idx2[k]]
                    for lev, prop in src_lev['vlev'][i, m].items():
                        antgain[i, 1, j, m] += prop * a[lev, i, 1, idx2[k]]
    else:
        # For this case, src_lev is just an array of levels
        for i in range(13):
            for k, j in enumerate(idx1):
                antgain[i, 0, j] = a[src_lev['hlev'][i], i, 0, idx2[k]]
                antgain[i, 1, j] = a[src_lev['vlev'][i], i, 1, idx2[k]]
    cdata = copy.deepcopy(data)
    blgain = np.zeros((120, 4, nf, nt),
                      float)  # Baseline-based gains vs. frequency
    for i in range(14):
        for j in range(i + 1, 15):
            blgain[ri.bl2ord[i, j],
                   0] = 10**((antgain[i, 0] + antgain[j, 0]) / 20.)
            blgain[ri.bl2ord[i, j],
                   1] = 10**((antgain[i, 1] + antgain[j, 1]) / 20.)
            blgain[ri.bl2ord[i, j],
                   2] = 10**((antgain[i, 0] + antgain[j, 1]) / 20.)
            blgain[ri.bl2ord[i, j],
                   3] = 10**((antgain[i, 1] + antgain[j, 0]) / 20.)
    antgainf = 10**(antgain / 10.)

    #idx1, idx2 = common_val_idx(data['time'],src_gs['times'].jd)
    idx = nearest_val_idx(data['time'], src_lev['times'].jd)
    # Apply corrections (some times may be eliminated from the data)
    # Correct the cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # If a skycal dictionary exists, subtract receiver noise before scaling
    # NB: This will break SK!
    if skycal:
        sna, snp, snf = skycal['rcvr_bgd'].shape
        bgd = skycal['rcvr_bgd'].repeat(nt).reshape((sna, snp, snf, nt))
        bgd_auto = skycal['rcvr_bgd_auto'].repeat(nt).reshape(
            (sna, snp, snf, nt))
        cdata['p'][:13] -= bgd[:, :, :, idx]
        cdata['a'][:13, :2] -= bgd_auto[:, :, :, idx]
    # Correct the power,
    cdata['p'][:15] *= antgainf[:, :, :, idx]
    # Correct the autocorrelation
    cdata['a'][:15, :2] *= antgainf[:, :, :, idx]
    # If a skycal dictionary exists, add back the receiver noise
    #if skycal:
    #    cdata['p'][:13] += bgd[:,:,:,idx]
    #    cdata['a'][:13,:2] += bgd_auto[:,:,:,idx]
    cross_fac = np.sqrt(antgainf[:, 0] * antgainf[:, 1])
    cdata['a'][:15, 2] *= cross_fac[:, :, idx]
    cdata['a'][:15, 3] *= cross_fac[:, :, idx]
    # Correct the power-squared -- this should preserve SK
    cdata['p2'][:15] *= antgainf[:, :, :, idx]**2
    # Remove any uncorrected times before returning
    #cdata['time'] = cdata['time'][idx1]
    #cdata['p'] = cdata['p'][:,:,:,idx1]
    #cdata['a'] = cdata['a'][:,:,:,idx1]
    #cdata['p2'] = cdata['p2'][:,:,:,idx1]
    #cdata['ha'] = cdata['ha'][idx1]
    #cdata['m'] = cdata['m'][:,:,:,idx1]
    return cdata
コード例 #23
0
ファイル: autocorrect_tp.py プロジェクト: sjyu1988/eovsa
def autocorrect(out, ant_str='ant1-13', brange=[0, 300]):
    nt = len(out['time'])
    nf = len(out['fghz'])
    pfac1 = (out['p'][:, :, :, :-1] -
             out['p'][:, :, :, 1:]) / out['p'][:, :, :, :-1]
    trange = Time(out['time'][[0, -1]], format='jd')
    src_lev = gc.get_fem_level(trange)  # Read FEM levels from SQL
    # Match times with data
    tidx = nearest_val_idx(out['time'], src_lev['times'].jd)
    # Find attenuation changes
    for ant in range(13):
        for pol in range(2):
            if pol == 0:
                lev = src_lev['hlev'][ant, tidx]
            else:
                lev = src_lev['vlev'][ant, tidx]
            jidx, = np.where(abs(lev[:-1] - lev[1:]) == 1)
            for freq in range(nf):
                idx, = np.where(
                    np.logical_and(
                        abs(pfac1[ant, pol, freq]) > 0.05,
                        abs(pfac1[ant, pol, freq]) < 0.95))
                for i in range(len(idx - 1)):
                    if idx[i] in jidx or idx[i] in jidx - 1:
                        out['p'][ant, pol, freq, idx[i] +
                                 1:] /= (1 - pfac1[ant, pol, freq, idx[i]])
    # Time of total power calibration is 20 UT on the date given
    tptime = Time(np.floor(trange[0].mjd) + 20. / 24., format='mjd')
    calfac = pc.get_calfac(tptime)
    tpcalfac = calfac['tpcalfac']
    tpoffsun = calfac['tpoffsun']
    hlev = src_lev['hlev'][:13, 0]
    vlev = src_lev['vlev'][:13, 0]
    attn_dict = ac.read_attncal(trange[0])[0]  # Read GCAL attn from SQL
    attn = np.zeros((13, 2, nf))
    for i in range(13):
        attn[i, 0] = attn_dict['attn'][hlev[i], 0, 0]
        attn[i, 1] = attn_dict['attn'][vlev[i], 0, 1]
        print 'Ant', i + 1, attn[i, 0, 20], attn[i, 1, 20]
    attnfac = 10**(attn / 10.)
    for i in range(13):
        print attnfac[i, 0, 20], attnfac[i, 1, 20]
    for i in range(nt):
        out['p'][:13, :, :,
                 i] = (out['p'][:13, :, :, i] * attnfac - tpoffsun) * tpcalfac
    antlist = ant_str2list(ant_str)
    bg = np.zeros_like(out['p'])
    # Subtract background for each antenna/polarization
    for ant in antlist:
        for pol in range(2):
            bg[ant,
               pol] = np.median(out['p'][ant, pol, :, brange[0]:brange[1]],
                                1).repeat(nt).reshape(nf, nt)
            #out['p'][ant,pol] -= bg
    # Form median over antennas/pols
    med = np.mean(np.median((out['p'] - bg)[antlist], 0), 0)
    # Do background subtraction once more for good measure
    bgd = np.median(med[:, brange[0]:brange[1]], 1).repeat(nt).reshape(nf, nt)
    med -= bgd
    pdata = np.log10(med)
    f, ax = plt.subplots(1, 1)
    vmax = np.median(np.nanmax(pdata, 1))
    im = ax.pcolormesh(Time(out['time'], format='jd').plot_date,
                       out['fghz'],
                       pdata,
                       vmin=1,
                       vmax=vmax)
    ax.axvspan(Time(out['time'][brange[0]], format='jd').plot_date,
               Time(out['time'][brange[1]], format='jd').plot_date,
               color='w',
               alpha=0.3)
    cbar = plt.colorbar(im, ax=ax)
    cbar.set_label('Log Flux Density [sfu]')
    ax.xaxis_date()
    ax.xaxis.set_major_formatter(DateFormatter("%H:%M"))
    ax.set_ylim(out['fghz'][0], out['fghz'][-1])
    ax.set_xlabel('Time [UT]')
    ax.set_ylabel('Frequency [GHz]')
    return {'caldata': out, 'med_sub': med, 'bgd': bg}