Beispiel #1
0
def get_xy_corr(out, doplot=True):
    ''' Analyze a pair of parallel and cross polarization calibration scans and
        return the X vs. Y delay phase corrections on all antennas 1-14.
        
        Required keyword:
           out   a 2-element array of dicts representing two scans, the first 
                       being the parallel-feed scan, and the second being the
                       crossed-feed scan.
        Optional keyword:
           doplot    True => plot the final result, False => no plot
    '''
    if doplot: import matplotlib.pylab as plt

    tstr = Time(out[0]['time'][0],format='jd').iso[:19].replace('-','').replace(' ','').replace(':','')
    ph0 = np.angle(np.sum(out[0]['x'][ri.bl2ord[:13,13]],3))
    ph1 = np.angle(np.sum(out[1]['x'][ri.bl2ord[:13,13]],3))
    ph0[:,2:] = ph1[:,2:]  # Insert crossed-feed phases from ph1 into ph0

    fghz = out[0]['fghz']
    nf = len(fghz)
    dph = np.zeros((14,nf),np.float)
    # Determine xi_rot
    xi2 = ph0[:,2] - ph0[:,0] + ph0[:,3] - ph0[:,1]  # This is 2 * xi, measured separately on each of 13 antennas
    xi_rot = np.unwrap(np.angle(np.sum(np.exp(1j*xi2),0)))/2.   # Very clever average does not suffer from wrapping issues
    # Form differential delay phase from channels, and average them
    # dph14 = XY - XX and YY - YX + pi
    #dph14 = np.concatenate((lobe(ph0[:,2] - ph0[:,0] + np.pi/2),lobe(ph0[:,1] - ph0[:,3] - np.pi/2)))  # 26 values for Ant 14
    #dph[13] = np.angle(np.sum(np.exp(1j*dph14),0))  # Very clever average does not suffer from wrapping issues
    # dphi = XX - YX and XY - YY + pi 
    #dphi = np.array((lobe(ph0[:,0] - ph0[:,3] - np.pi/2),lobe(ph0[:,2] - ph0[:,1] + np.pi/2)))  # 2 values for Ant 14
    #dph[:13] = np.angle(np.sum(np.exp(1j*dphi),0))
    # dph14 = XY - XX - xi_rot and YY - YX + xi_rot
    dph14 = np.concatenate((lobe(ph0[:,2] - ph0[:,0] - xi_rot),lobe(ph0[:,1] - ph0[:,3] + xi_rot)))  # 26 values for Ant 14
    dph[13] = np.angle(np.sum(np.exp(1j*dph14),0))  # Very clever average does not suffer from wrapping issues
    # dphi = XX - YX + xi_rot and XY - YY - xi_rot 
    dphi = np.array((lobe(ph0[:,0] - ph0[:,3] + xi_rot),lobe(ph0[:,2] - ph0[:,1] - xi_rot)))  # 2 values for Ant 14
    dph[:13] = np.angle(np.sum(np.exp(1j*dphi),0))
    
    if doplot:
        f, ax = plt.subplots(4, 4, num='XY_Phase')
        ax.shape = (16,)
        for i in range(13): 
            ax[i].plot(fghz,dphi[0,i],'.')
            ax[i].plot(fghz,dphi[1,i],'.')
            ax[i].plot(fghz,dph[i],'k.')
        for i in range(26):
            ax[13].plot(fghz,dph14[i],'.')
        ax[13].plot(fghz,dph[13],'k.')
        for i in range(14): ax[i].set_ylim(-4,4)
        f.suptitle('Multicolor: Measurements, Black: Final Results')
    np.savez('/common/tmp/Feed_rotation/'+tstr+'_delay_phase.npz',fghz=fghz,dph=dph,xi_rot=xi_rot)
    xy_phase = {'timestamp':Time(out[0]['time'][0],format='jd').lv,'fghz':fghz,'xyphase':dph,'xi_rot':xi_rot, 'dphi':dphi, 'dph14':dph14}
    return xy_phase
Beispiel #2
0
def get_xy_corr(npzlist=None, doplot=True):
    ''' Analyze a pair of parallel and cross polarization calibration scans and
        return the X vs. Y delay phase corrections on all antennas 1-14.
        
        Required keyword:
           npzlist   a list of 2 NPZ filenames, the first being the 
                       parallel-feed scan, and the second being the
                       crossed-feed scan.
        Optional keyword:
           doplot    True => plot the final result, False => no plot
    '''
    if npzlist is None:
        print 'Must provide a list of 2 NPZ files.'
        return None, None
    import read_idb as ri
    import numpy as np
    from util import lobe
        
    if doplot: import matplotlib.pylab as plt

    out0 = ri.read_npz([npzlist[0]])  # Parallel scan
    out1 = ri.read_npz([npzlist[1]])  # Perpendicular scan
    ph0 = np.angle(np.sum(out0['x'][ri.bl2ord[:13,13]],3))
    ph1 = np.angle(np.sum(out1['x'][ri.bl2ord[:13,13]],3))
    ph0[:,2:] = ph1[:,2:]  # Insert crossed-feed phases from ph1 into ph0

    fghz = out0['fghz']
    nf = len(fghz)
    dph = np.zeros((14,nf),np.float)
    # Form differential delay phase from channels, and average them
    # dph14 = XY - XX and YY - YX + pi
    dph14 = np.concatenate((lobe(ph0[:,2] - ph0[:,0] + np.pi/2),lobe(ph0[:,1] - ph0[:,3] - np.pi/2)))  # 26 values for Ant 14
    dph[13] = np.angle(np.sum(np.exp(1j*dph14),0))  # Very clever average does not suffer from wrapping issues
    # dphi = XX - YX and XY - YY + pi 
    dphi = np.array((lobe(ph0[:,0] - ph0[:,3] - np.pi/2),lobe(ph0[:,2] - ph0[:,1] + np.pi/2)))  # 2 values for Ant 14
    dph[:13] = np.angle(np.sum(np.exp(1j*dphi),0))
    
    if doplot:
        f, ax = plt.subplots(4,4)
        ax.shape = (16,)
        for i in range(13): 
            ax[i].plot(fghz,dphi[0,i],'.')
            ax[i].plot(fghz,dphi[1,i],'.')
            ax[i].plot(fghz,dph[i],'k.')
        for i in range(26):
            ax[13].plot(fghz,dph14[i],'.')
        ax[13].plot(fghz,dph[13],'k.')
        for i in range(14): ax[i].set_ylim(-4,4)
        f.suptitle('Multicolor: Measurements, Black: Final Results')
    np.savez('/common/tmp/Feed_rotation/'+npzlist[0].split('/')[-1][:14]+'_delay_phase.npz',fghz=fghz,dph=dph)
    return dph
Beispiel #3
0
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
Beispiel #4
0
 def coarse_delay(fghz,phz):
     # Do a coarse search of delays corresponding to phase errors ranging from -0.1 to 0.1
     # Returns the delay value with the minimum sigma
     tvals = np.arange(-0.1,0.1,0.01)
     sigma = []
     for t in tvals:
         sigma.append(np.std(lobe(phz - 2*np.pi*t*fghz)))
     return tvals[np.argmin(np.array(sigma))]
Beispiel #5
0
def apply_xy_corr(out,dph):
    ''' Does not actually change the data, only calculates and displays it
    '''
    import copy
    import matplotlib.pylab as plt
    ph0 = np.angle(np.sum(out['x'][ri.bl2ord[:13,13]],3))
    ph1 = copy.deepcopy(ph0)
    for i in range(13):
        ph1[i,1] += dph[i] - dph[13]
        ph1[i,2] += -dph[13] + np.pi/2
        ph1[i,3] += dph[i] + np.pi/2
    f, ax = plt.subplots(4,13)
    for i in range(13):
        for j in range(4):
            ax[j,i].cla()
            ax[j,i].plot(fghz,lobe(ph0[i,j]),'.',color='lightgreen')
            ax[j,i].plot(fghz,lobe(ph1[i,j]),'.',color='black')
            ax[j,i].set_ylim(-4,4)
Beispiel #6
0
def apply_xy_corr(out, dph):
    ''' Does not actually change the data, only calculates and displays it
    '''
    import copy
    import matplotlib.pylab as plt
    ph0 = np.angle(np.sum(out['x'][ri.bl2ord[:13, 13]], 3))
    ph1 = copy.deepcopy(ph0)
    for i in range(13):
        ph1[i, 1] += dph[i] - dph[13]
        ph1[i, 2] += -dph[13] + np.pi / 2
        ph1[i, 3] += dph[i] + np.pi / 2
    f, ax = plt.subplots(4, 13)
    for i in range(13):
        for j in range(4):
            ax[j, i].cla()
            ax[j, i].plot(fghz, lobe(ph0[i, j]), '.', color='lightgreen')
            ax[j, i].plot(fghz, lobe(ph1[i, j]), '.', color='black')
            ax[j, i].set_ylim(-4, 4)
Beispiel #7
0
def phase_diff(phacal, refcal):
    ''' Finds the delay slope (phase slope is 2*pi*fghz) of the difference
        between the input phase calibration and the input reference calibration.
        Adds some keywords to the phacal dict.  This does NOT fit for a phase
        offset, but still returns offsets of zero, in case this is needed in
        the future.  The sflags keyword is different from flags, because sflags
        can be set for either missing phase calibrations or missing reference
        calibrations.  The slope values are zero for entries flagged in sflags.
        
        2018-02-14  DG 
          Added brute-force coarse delay calculation
    '''
    def mbdfunc0(fghz, mbd):
        # fghz: frequency in GHz
        # ph0 = 0: phase offset identically set to zero (not fitted)
        # mbd: multi-band delay associated with the phase_phacal - phase_refcal in ns
        return 2. * np.pi * fghz * mbd
        
    def coarse_delay(fghz,phz):
        # Do a coarse search of delays corresponding to phase errors ranging from -0.1 to 0.1
        # Returns the delay value with the minimum sigma
        tvals = np.arange(-0.1,0.1,0.01)
        sigma = []
        for t in tvals:
            sigma.append(np.std(lobe(phz - 2*np.pi*t*fghz)))
        return tvals[np.argmin(np.array(sigma))]
        
    from scipy.optimize import curve_fit
    
    fghz = phacal['fghz']
    if len(fghz) != len(refcal['fghz']):
        self.status.config(text = 'Status: Phase and Reference calibrations have different frequencies.  No action taken.')
        return phacal
    dpha = np.angle(phacal['x'][:,:2]) - np.angle(refcal['x'][:,:2])
    flags = np.logical_or(phacal['flags'][:,:2],refcal['flags'][:,:2]).astype(np.int)
    amp_pc = np.abs(phacal['x'][:,:2])
    amp_rc = np.abs(refcal['x'][:,:2])
    sigma = ((phacal['sigma'][:,:2]/amp_pc)**2. + (refcal['sigma'][:,:2]/amp_rc)**2)**0.5
    slopes = np.zeros((15,2),np.float)
    offsets = np.zeros((15,2),np.float)
    flag = np.zeros((15,2),np.float)
    for ant in range(13):
        for pol in range(2):
            good, = np.where(flags[ant,pol] == 0)
            if len(good) > 3:
                x = fghz[good]
                t = coarse_delay(x,dpha[ant,pol,good])   # Get coarse delay 
                y = np.unwrap(lobe(dpha[ant,pol,good] - 2*np.pi*t*x))  # Correct for coarse delay
                p, pcov = curve_fit(mbdfunc0, x, y, p0=[0.], sigma=sigma[ant,pol,good], absolute_sigma=False)
                slopes[ant,pol] = p + t  # Add back coarse delay
                flag[ant,pol] = 0
            else:
                flag[ant,pol] = 1
    phacal.update({'mbd':slopes, 'mbd_flag':flag, 'flags': flags, 'offsets':offsets, 'pdiff':dpha})
    return phacal
Beispiel #8
0
def apply_unrot_new(filename):

    import read_idb as ri
    import dbutil as db
    import copy
    from util import lobe, Time
    import matplotlib.pylab as plt
    import numpy as np
    blah = np.load('/common/tmp/Feed_rotation/20171223001448_delay_phase.npz')
    dph = blah['dph']
    fghz = blah['fghz']
    xi_rot = blah['xi_rot']
    out = ri.read_npz([filename])
    nbl, npol, nfrq, nt = out['x'].shape
    # Correct data for phase
    #n = [0,0,0,1,1,0,1,0,1,1,0,0,0]
    for i in range(13):
        a1 = lobe(dph[i] - dph[13])
        a2 = -dph[13] - xi_rot
        a3 = dph[i] - xi_rot + np.pi
        for j in range(nt):
            out['x'][ri.bl2ord[i,13],1,:,j] *= np.exp(1j*a1)
            out['x'][ri.bl2ord[i,13],2,:,j] *= np.exp(1j*a2) 
            out['x'][ri.bl2ord[i,13],3,:,j] *= np.exp(1j*a3)
        
    trange = Time(out['time'][[0,-1]],format='jd')
    times, chi = db.get_chi(trange)
    nskip = len(times)/nt
    chi = np.transpose(chi[::nskip+1])
    chi[[8,9,10,12]] = 0.0
    outp = copy.deepcopy(out)
    for i in range(nt):
        for k in range(13):
            outp['x'][ri.bl2ord[k,13],0,:,i] = out['x'][ri.bl2ord[k,13],0,:,i]*np.cos(chi[k,i]) + out['x'][ri.bl2ord[k,13],3,:,i]*np.sin(chi[k,i])
            outp['x'][ri.bl2ord[k,13],2,:,i] = out['x'][ri.bl2ord[k,13],2,:,i]*np.cos(chi[k,i]) + out['x'][ri.bl2ord[k,13],1,:,i]*np.sin(chi[k,i])
            outp['x'][ri.bl2ord[k,13],3,:,i] = out['x'][ri.bl2ord[k,13],3,:,i]*np.cos(chi[k,i]) - out['x'][ri.bl2ord[k,13],0,:,i]*np.sin(chi[k,i])
            outp['x'][ri.bl2ord[k,13],1,:,i] = out['x'][ri.bl2ord[k,13],1,:,i]*np.cos(chi[k,i]) - out['x'][ri.bl2ord[k,13],2,:,i]*np.sin(chi[k,i])
    amp0 = np.abs(np.sum(out['x'][ri.bl2ord[:13,13]],3))
    amp2 = np.abs(np.sum(outp['x'][ri.bl2ord[:13,13]],3))
    f, ax = plt.subplots(4,13)
    for i in range(13):
        for j in range(4):
            ax[j,i].cla()
            ax[j,i].plot(fghz, amp0[i,j],'.',color='lightgreen')
            ax[j,i].plot(fghz, amp2[i,j],'k.')
            ax[j,i].set_ylim(0,10)
    ph0 = np.angle(np.sum(out['x'][ri.bl2ord[:13,13]],3))
    ph2 = np.angle(np.sum(outp['x'][ri.bl2ord[:13,13]],3))
    f, ax = plt.subplots(4,13)
    for i in range(13):
        for j in range(4):
            ax[j,i].cla()
            ax[j,i].plot(fghz, ph0[i,j],'.',color='lightgreen')
            ax[j,i].plot(fghz, ph2[i,j],'k.')
Beispiel #9
0
def apply_unrot(filename):

    import read_idb as ri
    import dbutil as db
    import copy
    from util import lobe, Time
    import matplotlib.pylab as plt
    import numpy as np
    blah = np.load('/common/tmp/Feed_rotation/20170702121949_delay_phase.npz')
    dph = blah['dph']
    fghz = blah['fghz']
    out = ri.read_npz([filename])
    nbl, npol, nfrq, nt = out['x'].shape
    # Correct data for phase
    #n = [0,0,0,1,1,0,1,0,1,1,0,0,0]
    for i in range(13):
        a1 = lobe(dph[i] - dph[13])
        a2 = -dph[13] + np.pi/2
        a3 = dph[i] - np.pi/2
        for j in range(nt):
            out['x'][ri.bl2ord[i,13],1,:,j] *= np.exp(1j*a1)
            out['x'][ri.bl2ord[i,13],2,:,j] *= np.exp(1j*a2) 
            out['x'][ri.bl2ord[i,13],3,:,j] *= np.exp(1j*a3)
        
    trange = Time(out['time'][[0,-1]],format='jd')
    times, chi = db.get_chi(trange)
    nskip = len(times)/nt
    chi = np.transpose(chi[::nskip+1])
    chi[[8,9,10,12]] = 0.0
    outp = copy.deepcopy(out)
    for i in range(nt):
        for k in range(13):
            outp['x'][ri.bl2ord[k,13],0] = out['x'][ri.bl2ord[k,13],0]*np.cos(chi[k,i]) + out['x'][ri.bl2ord[k,13],3]*np.sin(chi[k,i])
            outp['x'][ri.bl2ord[k,13],2] = out['x'][ri.bl2ord[k,13],2]*np.cos(chi[k,i]) + out['x'][ri.bl2ord[k,13],1]*np.sin(chi[k,i])
            outp['x'][ri.bl2ord[k,13],3] = out['x'][ri.bl2ord[k,13],3]*np.cos(chi[k,i]) - out['x'][ri.bl2ord[k,13],0]*np.sin(chi[k,i])
            outp['x'][ri.bl2ord[k,13],1] = out['x'][ri.bl2ord[k,13],1]*np.cos(chi[k,i]) - out['x'][ri.bl2ord[k,13],2]*np.sin(chi[k,i])
    amp0 = np.abs(np.sum(out['x'][ri.bl2ord[:,13]],3))
    amp2 = np.abs(np.sum(outp['x'][ri.bl2ord[:,13]],3))
    f, ax = plt.subplots(4,13)
    for i in range(13):
        for j in range(4):
            ax[j,i].cla()
            ax[j,i].plot(fghz, amp0[i,j],'.',color='lightgreen')
            ax[j,i].plot(fghz, amp2[i,j],'k.')
    ph0 = np.angle(np.sum(out['x'][ri.bl2ord[:,13]],3))
    ph2 = np.angle(np.sum(outp['x'][ri.bl2ord[:,13]],3))
    f, ax = plt.subplots(4,13)
    for i in range(13):
        for j in range(4):
            ax[j,i].cla()
            ax[j,i].plot(fghz, ph0[i,j],'.',color='lightgreen')
            ax[j,i].plot(fghz, ph2[i,j],'k.')
            
Beispiel #10
0
def xydla(filename, ant_str='ant1-14', apply=False):
    ''' Determine X vs. Y delay based on packet capture with Noise Diode on
    
        filename    Name and path of a PRT (packet capture) file taken with ND-ON,
                      using a fixed band, e.g. band15.fsq.
                      
        Returns xy  14-element list of delays to apply, for use in second argument
                      of cal_header.dla_update2sql()
                      
        Optional argument:
        ant_str     If supplied, is the standard specification of antennas to include.
                       Antennas not included are updated with 0 (i.e. no change)
        apply       If True, calls cal_header.dla_update2sql() and 
                                   cal_header.dla_censql2table()
                      to update X vs. Y delays
    '''
    import matplotlib.pylab as plt
    from util import lobe
    f, ax = plt.subplots(4, 4)
    ants = p.ant_str2list(ant_str)
    ax.shape = (16)
    if type(filename) is dict:
        # Interpret input as an already read dictionary, rather than a filename, and skip
        # the slow process of reading it again.
        out = filename
    else:
        out = p.rd_jspec(filename)
    xy = []
    chrange = np.arange(
        2100, 3900)  # Portion of 4096 sub-channel range to use for the fit
    npts = len(chrange)
    x = np.linspace(
        0, np.pi * npts / 4096.,
        1800)  # This makes phase slope come out in units of delay steps
    for i in range(14):
        if i in ants:
            ax[i].plot(np.angle(out['a'][i, 2, :, 30]),
                       'y.',
                       label='Ant ' + str(i + 1))
            res = np.polyfit(x, np.unwrap(np.angle(out['a'][i, 2, chrange,
                                                            30])), 1)
            ax[i].plot(chrange, lobe(np.polyval(res, x)), 'r.')
            ax[i].set_ylim(-4, 4)
            ax[i].legend(fontsize=9, loc='best', fancybox=True, framealpha=0.5)
        else:
            res = [0., 0.]
        xy.append(res[0])
    if apply:
        import cal_header as ch
        ch.dla_update2sql(np.zeros(14, np.float), np.array(xy))
        ch.dla_censql2table()
    return np.array(xy)
Beispiel #11
0
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                
Beispiel #12
0
 def doplot(self, ant=1):
     dla = self.delays[ant - 1]
     ydla = self.xydelays[ant - 1]
     # Also need delay settings for ant 1
     dla1 = self.delays[0]
     ydla1 = self.xydelays[0]
     ydla14 = np.float(self.dla14.get())
     for i, ax in enumerate(self.ax):
         if self.pol[i] == 0:
             # XX => use only the ant X delay
             tau = dla
             tau1 = dla1
         elif self.pol[i] == 1:
             # YY => use the ant (X delay + Y-X delay) + Ant 14 Y-X delay
             tau = dla + ydla + ydla14
             tau1 = dla1 + ydla1 + ydla14
         elif self.pol[i] == 2:
             # XY => use the ant X delay + Ant 14 Y-X delay
             tau = dla + ydla14
             tau1 = dla1 + ydla14
         else:
             #YX => use the ant (X delay + Y-X delay)
             tau = dla + ydla
             tau1 = dla1 + ydla1
         ax.cla()
         if ant == 1:
             ax.plot(
                 self.fghz,
                 lobe(self.ph[ant - 1, self.pol[i]] -
                      2 * np.pi * self.fghz * tau), '.')
         else:
             ax.plot(
                 self.fghz,
                 lobe(self.ph[ant - 1, self.pol[i]] -
                      self.ph[0, self.pol[i]] - 2 * np.pi * self.fghz *
                      (tau - tau1)), '.')
         ax.set_ylim(-4, 4)
     self.canvas.draw()
Beispiel #13
0
def apply_xy_corr(out,dph,dphnew=None):
    ''' Does not actually change the data, only calculates and displays it
    '''
    import copy
    import matplotlib.pylab as plt
    from util import lobe
    fghz = out['fghz']
    ph0 = np.angle(np.sum(out['x'][ri.bl2ord[:13,13]],3))
    ph1 = copy.deepcopy(ph0)
    for i in range(13):
        ph1[i,1] += dph[i] - dph[13]
        ph1[i,2] += -dph[13] + np.pi/2
        ph1[i,3] += dph[i] - np.pi/2
    if not dphnew is None:
        ph2 = copy.deepcopy(ph0)
        dph, xi_rot = dphnew
        for i in range(13):
            ph2[i,1] += dph[i] - dph[13]
            ph2[i,2] += -dph[13] - xi_rot[i]
            ph2[i,3] += dph[i] - xi_rot[i] + np.pi
    f, ax = plt.subplots(4,13)
    f.suptitle('Old Correction Applied')
    for i in range(13):
        for j in range(4):
            ax[j,i].cla()
            ax[j,i].plot(fghz,lobe(ph0[i,j]),'.',color='lightgreen')
            ax[j,i].plot(fghz,lobe(ph1[i,j]),'.',color='black')
            ax[j,i].set_ylim(-4,4)
    f, ax = plt.subplots(4,13)
    f.suptitle('New Correction Applied')
    for i in range(13):
        for j in range(4):
            ax[j,i].cla()
            ax[j,i].plot(fghz,lobe(ph0[i,j]),'.',color='lightgreen')
            ax[j,i].plot(fghz,lobe(ph2[i,j]),'.',color='black')
            ax[j,i].set_ylim(-4,4)
Beispiel #14
0
def shift_time(told, target):
    ''' This is for calculating a time shift for a given schedule, to 
        bring it to the current date.  When editing a .scd file with
        calibrators, enter the first time as a Time() object told,
        and enter the current date/time as a Time() object target.
        
        Returns a new Time() object with the date/time that the schedule
        should be adjusted to.  There is a potential for the time to 
        be off by four minutes (one day's sidereal lag).
    '''
    from astropy.time import TimeDelta
    dt = TimeDelta((util.lobe(eovsa_lst(target) - eovsa_lst(told)) * 0.158720),
                   format='jd')
    print dt
    return target - dt
Beispiel #15
0
def sat_unrot(data,xyphase,band=0):
    from util import bl2ord
    xi_rot = xyphase['xi_rot']
    dph = xyphase['xyphase']
    nf = 4096
    fidx2 = np.arange(nf)
    for i in range(13):
        for j in range(i + 1, 14):
            k = bl2ord[i, j]
            if j == 13:                  # xi_rot was applied for all antennas, but this
                xi = xi_rot[fidx2]       # is wrong.  Now it is only done for ant14.
            else:
                xi = 0.0                 # xi_rot for other antennas is just zero.
            a1 = lobe(dph[i, fidx2] - dph[j, fidx2])
            a2 = -dph[j, fidx2] - xi
            a3 = dph[i, fidx2] - xi + np.pi
            data['x'][k, 1, fidx2, 10*band:10*(band+1)] *= np.repeat(np.exp(1j * a1), 10).reshape(nf, 10)
            data['x'][k, 2, fidx2, 10*band:10*(band+1)] *= np.repeat(np.exp(1j * a2), 10).reshape(nf, 10)
            data['x'][k, 3, fidx2, 10*band:10*(band+1)] *= np.repeat(np.exp(1j * a3), 10).reshape(nf, 10)
    return data
Beispiel #16
0
 def doplot(self,ant=1):
     dla = self.delays[ant-1]
     ydla = self.xydelays[ant-1]
     ydla14 = np.float(self.dla14.get())
     for i,ax in enumerate(self.ax):
         if self.pol[i] == 0:
             # XX => use only the ant X delay 
             tau = dla
         elif self.pol[i] == 1:
             # YY => use the ant (X delay + Y-X delay) + Ant 14 Y-X delay
             tau = dla + ydla + ydla14
         elif self.pol[i] == 2:
             # XY => use the ant X delay + Ant 14 Y-X delay
             tau = dla + ydla14
         else:
             #YX => use the ant (X delay + Y-X delay)
             tau = dla + ydla
         ax.cla()
         ax.plot(self.fghz,lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau),'.')
         ax.set_ylim(-4,4)
     self.canvas.draw()
Beispiel #17
0
 def doplot(self, ant=1):
     dla = self.delays[ant - 1]
     ydla = self.xydelays[ant - 1]
     ydla14 = np.float(self.dla14.get())
     for i, ax in enumerate(self.ax):
         if self.pol[i] == 0:
             # XX => use only the ant X delay
             tau = dla
         elif self.pol[i] == 1:
             # YY => use the ant (X delay + Y-X delay) + Ant 14 Y-X delay
             tau = dla + ydla + ydla14
         elif self.pol[i] == 2:
             # XY => use the ant X delay + Ant 14 Y-X delay
             tau = dla + ydla14
         else:
             #YX => use the ant (X delay + Y-X delay)
             tau = dla + ydla
         ax.cla()
         ax.plot(
             self.fghz,
             lobe(self.ph[ant - 1, self.pol[i]] -
                  2 * np.pi * self.fghz * tau), '.')
         ax.set_ylim(-4, 4)
     self.canvas.draw()
Beispiel #18
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
Beispiel #19
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
Beispiel #20
0
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
Beispiel #21
0
def fit_diskmodel(out, bidx, rstn_flux, uvfitrange=[1, 150], angle_tolerance=np.pi / 2, doplot=True):
    ''' Given the result returned by read_ms(), plots the amplitude vs. uvdistance
        separately for polar and equatorial directions rotated for P-angle, then overplots
        a disk model for a disk enlarged by eqfac in the equatorial direction, and polfac
        in the polar direction.  Also requires the RSTN flux spectrum for the date of the ms,
        determined from (example for 2019-09-01):
           import rstn
           frq, flux = rstn.rd_rstnflux(t=Time('2019-09-01'))
           rstn_flux = rstn.rstn2ant(frq, flux, out['fghz']*1000, t=Time('2019-09-01'))
    '''
    from util import bl2ord, lobe
    import matplotlib.pylab as plt
    import sun_pos
    from scipy.special import j1
    import scipy.constants
    mperns = scipy.constants.c / 1e9  # speed of light in m/ns
    # Rotate uv angle for P-angle
    pa, b0, r = sun_pos.get_pb0r(out['mjd'][0], arcsec=True)
    uvangle = lobe(out['uvangle'] - pa * np.pi / 180.)
    a = 2 * r * np.pi ** 2 / (180. * 3600.)  # Initial scale for z, uses photospheric radius of the Sun
    if doplot: f, ax = plt.subplots(3, 1)
    uvmin, uvmax = uvfitrange
    uvdeq = []
    uvdpol = []
    ampeq = []
    amppol = []
    zeq = []
    zpol = []
    # Loop over antennas 1-4
    antmax = 7
    at = angle_tolerance
    for i in range(4):
        fidx, = np.where(out['band'] == bidx)  # Array of frequency indexes for channels in this band
        for j, fi in enumerate(fidx):
            amp = out['amp'][0, fi, bl2ord[i, i + 1:antmax]].flatten() / 10000.  # Convert to sfu
            # Use only non-zero amplitudes
            good, = np.where(amp != 0)
            amp = amp[good]
            uva = uvangle[bl2ord[i, i + 1:antmax]].flatten()[good]
            # Equatorial points are within +/- pi/8 of solar equator
            eq, = np.where(np.logical_or(np.abs(uva) < at / 2, np.abs(uva) >= np.pi - at / 2))
            # Polar points are within +/- pi/8 of solar pole
            pol, = np.where(np.logical_and(np.abs(uva) >= np.pi / 2 - at / 2, np.abs(uva) < np.pi / 2 + at / 2))
            uvd = out['uvdist'][bl2ord[i, i + 1:antmax]].flatten()[good] * out['fghz'][fi] / mperns  # Wavelengths
            # Add data for this set of baselines to global arrays
            uvdeq.append(uvd[eq])
            uvdpol.append(uvd[pol])
            ampeq.append(amp[eq])
            amppol.append(amp[pol])
            zeq.append(uvd[eq])
            zpol.append(uvd[pol])
    uvdeq = np.concatenate(uvdeq)
    uvdpol = np.concatenate(uvdpol)
    uvdall = np.concatenate((uvdeq, uvdpol))
    ampeq = np.concatenate(ampeq)
    amppol = np.concatenate(amppol)
    ampall = np.concatenate((ampeq, amppol))
    zeq = np.concatenate(zeq)
    zpol = np.concatenate(zpol)
    zall = np.concatenate((zeq, zpol))
    # These indexes are for a restricted uv-range to be fitted
    ieq, = np.where(np.logical_and(uvdeq > uvmin, uvdeq <= uvmax))
    ipol, = np.where(np.logical_and(uvdpol > uvmin, uvdpol <= uvmax))
    iall, = np.where(np.logical_and(uvdall > uvmin, uvdall <= uvmax))
    if doplot:
        # Plot all of the data points
        ax[0].plot(uvdeq, ampeq, 'k+')
        ax[1].plot(uvdpol, amppol, 'k+')
        ax[2].plot(uvdall, ampall, 'k+')
        # Overplot the fitted data points in a different color
        ax[0].plot(uvdeq[ieq], ampeq[ieq], 'b+')
        ax[1].plot(uvdpol[ipol], amppol[ipol], 'b+')
        ax[2].plot(uvdall[iall], ampall[iall], 'b+')
    # Minimize ratio of points to model
    ntries = 300
    solfac = np.linspace(1.0, 1.3, ntries)
    d2m_eq = np.zeros(ntries, np.float)
    d2m_pol = np.zeros(ntries, np.float)
    d2m_all = np.zeros(ntries, np.float)
    sfac = np.zeros(ntries, np.float)
    sfacall = np.zeros(ntries, np.float)
    # Loop over ntries (300) models of solar disk size factor ranging from 1.0 to 1.3 r_Sun
    for k, sizfac in enumerate(solfac):
        eqpts = rstn_flux[fidx][0] * 2 * np.abs(j1(a * sizfac * zeq[ieq]) / (a * sizfac * zeq[ieq]))
        polpts = rstn_flux[fidx[0]] * 2 * np.abs(j1(a * sizfac * zpol[ipol]) / (a * sizfac * zpol[ipol]))
        sfac[k] = (np.nanmedian(ampeq[ieq] / eqpts) + np.nanmedian(amppol[ipol] / polpts)) / 2
        eqpts = rstn_flux[fidx[0]] * (2 * sfac[k]) * np.abs(j1(a * sizfac * zeq[ieq]) / (a * sizfac * zeq[ieq]))
        polpts = rstn_flux[fidx[0]] * (2 * sfac[k]) * np.abs(j1(a * sizfac * zpol[ipol]) / (a * sizfac * zpol[ipol]))
        allpts = rstn_flux[fidx[0]] * (2 * sfac[k]) * np.abs(j1(a * sizfac * zall[iall]) / (a * sizfac * zall[iall]))
        sfacall[k] = np.nanmedian(ampall[iall] / allpts)
        d2m_eq[k] = np.nanmedian(abs(ampeq[ieq] / eqpts - 1))
        d2m_pol[k] = np.nanmedian(abs(amppol[ipol] / polpts - 1))
        d2m_all[k] = np.nanmedian(abs(ampall[iall] / allpts - 1))
    keq = np.argmin(d2m_eq)
    kpol = np.argmin(d2m_pol)
    kall = np.argmin(d2m_all)
    eqradius = solfac[keq] * r
    polradius = solfac[kpol] * r
    allradius = solfac[kall] * r
    sfactor = sfac[keq]
    sfall = sfacall[kall]
    sflux = sfall * rstn_flux[fidx[0]]
    if doplot:
        z = np.linspace(1.0, 1000.0, 10000)
        # Overplot the best fit
        ax[0].plot(z, rstn_flux[fidx[0]] * (2 * sfactor) * np.abs(j1(a * solfac[keq] * z) / (a * solfac[keq] * z)))
        ax[1].plot(z, rstn_flux[fidx[0]] * (2 * sfactor) * np.abs(j1(a * solfac[kpol] * z) / (a * solfac[kpol] * z)))
        ax[2].plot(z, rstn_flux[fidx[0]] * (2 * sfall) * np.abs(j1(a * solfac[kall] * z) / (a * solfac[kall] * z)))
        # ax[1].plot(zpol,polpts,'y.')
        ax[0].set_title(
            str(out['fghz'][fidx][0])[:4] + 'GHz. R_eq:' + str(eqradius)[:6] + '". R_pol' + str(polradius)[:6]
            + '". R_all' + str(allradius)[:6] + '". Flux scl fac:' + str(sfall)[:4])
        # ax[0].plot(uvdeq,ampeq/eqpts,'k+')
        # ax[0].plot([0,1000],np.array([1,1])*np.nanmedian(ampeq/eqpts))
        # ax[1].plot(uvdpol,amppol/polpts,'k+')
        # ax[1].plot([0,1000],np.array([1,1])*np.nanmedian(amppol/polpts))
        for i in range(3):
            ax[i].set_xlim(0, 1000)
            ax[i].set_ylim(0.01, rstn_flux[fidx[0]] * 2 * sfactor)
            ax[i].set_yscale('log')
            ax[2].set_xlabel('UV Distance (wavelengths)')
            ax[i].set_ylabel('Amplitude (sfu)')
            ax[i].text(850, 125, ['Equator', 'Pole', 'All'][i])
    return bidx, out['fghz'][fidx[0]], eqradius, polradius, allradius, sfall, sflux
Beispiel #22
0
def get_xy_corr(npzlist=None, doplot=True, npzlist2=None):
    ''' Analyze a pair of parallel and cross polarization calibration scans and
        return the X vs. Y delay phase corrections on all antennas 1-14.
        
        Required keyword:
           npzlist   a list of 2 NPZ filenames, the first being the 
                       parallel-feed scan, and the second being the
                       crossed-feed scan.
        Optional keyword:
           doplot    True => plot the final result, False => no plot
    '''
    if npzlist is None:
        print 'Must provide a list of 2 NPZ files.'
        return None, None
    import read_idb as ri
    from util import lobe, Time
        
    if doplot: import matplotlib.pylab as plt

    out0 = ri.read_npz([npzlist[0]])  # Parallel scan
    out1 = ri.read_npz([npzlist[1]])  # Perpendicular scan
    if npzlist2 is None:
        pass
    else:
        # Interpret second list as a set of additional files to be concatenated to the first
        for file in npzlist2:
            outx = ri.read_npz([file])
            out0['x'] = np.concatenate((out0['x'],outx['x']),3)
            out1['x'] = np.concatenate((out1['x'],outx['x']),3)
    ph0 = np.angle(np.sum(out0['x'][ri.bl2ord[:13,13]],3))
    ph1 = np.angle(np.sum(out1['x'][ri.bl2ord[:13,13]],3))
    ph0[:,2:] = ph1[:,2:]  # Insert crossed-feed phases from ph1 into ph0

    fghz = out0['fghz']
    nf = len(fghz)
    dph = np.zeros((14,nf),np.float)
    # Determine xi_rot
    xi2 = ph0[:,2] - ph0[:,0] + ph0[:,3] - ph0[:,1]  # This is 2 * xi, measured separately on each of 13 antennas
    xi_rot = np.unwrap(np.angle(np.sum(np.exp(1j*xi2),0)))/2.   # Very clever average does not suffer from wrapping issues
    # Form differential delay phase from channels, and average them
    # dph14 = XY - XX and YY - YX + pi
    #dph14 = np.concatenate((lobe(ph0[:,2] - ph0[:,0] + np.pi/2),lobe(ph0[:,1] - ph0[:,3] - np.pi/2)))  # 26 values for Ant 14
    #dph[13] = np.angle(np.sum(np.exp(1j*dph14),0))  # Very clever average does not suffer from wrapping issues
    # dphi = XX - YX and XY - YY + pi 
    #dphi = np.array((lobe(ph0[:,0] - ph0[:,3] - np.pi/2),lobe(ph0[:,2] - ph0[:,1] + np.pi/2)))  # 2 values for Ant 14
    #dph[:13] = np.angle(np.sum(np.exp(1j*dphi),0))
    # dph14 = XY - XX - xi_rot and YY - YX + xi_rot
    dph14 = np.concatenate((lobe(ph0[:,2] - ph0[:,0] - xi_rot),lobe(ph0[:,1] - ph0[:,3] + xi_rot)))  # 26 values for Ant 14
    dph[13] = np.angle(np.sum(np.exp(1j*dph14),0))  # Very clever average does not suffer from wrapping issues
    # dphi = XX - YX + xi_rot and XY - YY - xi_rot 
    dphi = np.array((lobe(ph0[:,0] - ph0[:,3] + xi_rot),lobe(ph0[:,2] - ph0[:,1] - xi_rot)))  # 2 values for Ant 14
    dph[:13] = np.angle(np.sum(np.exp(1j*dphi),0))
    
    if doplot:
        f, ax = plt.subplots(4, 4, num='XY_Phase')
        ax.shape = (16,)
        for i in range(13): 
            ax[i].plot(fghz,dphi[0,i],'.')
            ax[i].plot(fghz,dphi[1,i],'.')
            ax[i].plot(fghz,dph[i],'k.')
        for i in range(26):
            ax[13].plot(fghz,dph14[i],'.')
        ax[13].plot(fghz,dph[13],'k.')
        for i in range(14): ax[i].set_ylim(-4,4)
        f.suptitle('Multicolor: Measurements, Black: Final Results')
    np.savez('/common/tmp/Feed_rotation/'+npzlist[0].split('/')[-1][:14]+'_delay_phase.npz',fghz=fghz,dph=dph,xi_rot=xi_rot)
    xy_phase = {'timestamp':Time(out0['time'][0],format='jd').lv,'fghz':fghz,'xyphase':dph,'xi_rot':xi_rot}
    return xy_phase
Beispiel #23
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}
Beispiel #24
0
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)}
Beispiel #25
0
 def doplot(self,ant=1):
     polstr = ['XX','XY','YX','YY']
     dla = self.delays[ant-1]
     ydla = self.xydelays[ant-1]
     # Also need delay settings for ant 1
     dla1 = self.delays[0]
     ydla1 = self.xydelays[0]
     ydla14 = np.float(self.dla14.get())
     for i,ax in enumerate(self.ax[:4]):
         if self.pol[i] == 0:
             # XX => use only the ant X delay 
             tau = dla
             tau1 = dla1
         elif self.pol[i] == 1:
             # YY => use the ant (X delay + Y-X delay) + Ant 14 Y-X delay
             tau = dla + ydla + ydla14
             tau1 = dla1 + ydla1 + ydla14
         elif self.pol[i] == 2:
             # XY => use the ant X delay + Ant 14 Y-X delay
             tau = dla + ydla14
             tau1 = dla1 + ydla14
         else:
             #YX => use the ant (X delay + Y-X delay)
             tau = dla + ydla
             tau1 = dla1 + ydla1
         ax.cla()
         if ant == 1:
             ax.plot(self.fghz,lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau),'.',label=polstr[i])
             if self.pol[i] == 0:
                 pxx = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
             if self.pol[i] == 1:
                 pyy = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
             if self.pol[i] == 2:
                 pxy = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
             if self.pol[i] == 3:
                 pyx = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
         else:
             ax.plot(self.fghz,lobe(self.ph[ant-1,self.pol[i]] - self.ph[0,self.pol[i]] - 2*np.pi*self.fghz*(tau-tau1)),'.',label=polstr[i])
             if self.pol[i] == 0:
                 pxx = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
             if self.pol[i] == 1:
                 pyy = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
             if self.pol[i] == 2:
                 pxy = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
             if self.pol[i] == 3:
                 pyx = lobe(self.ph[ant-1,self.pol[i]] - 2*np.pi*self.fghz*tau)
         ax.set_ylim(-4,4)
         ax.legend(fontsize=9,loc='lower right')
     self.ax[4].cla()
     self.ax[4].plot(self.fghz,lobe(pyy - pxx),'.')
     self.ax[4].set_title('YY - XX Phase')
     #self.ax[4].plot(self.fghz,lobe(pxy - pyx),'.')
     self.ax[4].set_ylim(-4,4)
     self.canvas.draw()
Beispiel #26
0
def refcal_anal(out, timerange=None, scanidx=None, minsnr=0.7, bandplt=[5, 11, 17, 23], doplot=True, lohi=False):
    '''Analyze the visibility data from rd_refcal and return time averaged visibility values and flags.
       ***Optional Keywords***
       timerange: time range to obtain the average. E.g., timerange=Time(['2017-04-08T05:00','2017-04-08T07:00'])
       scanidx: index numbers of scans to select. Useful when other (undesired) types of observations exist. 
               !!!! The selected scans should have exactly the same frequency/band setup !!!!
       minsnr: minimum signal to noise to consider. Data with smaller SNRs will be flagged (as 1 in the flag array)
       bandplt: bands to show in the figure
       doplot: if True, display plots of results (default)
       ***Outputs***
       refcal: complex array of shape (15, 2, 34) (nant, npol, nband) as the result of the reference calibration
       flag: int array of shape (15, 2, 34). 0 is unflagged and 1 is flagged.
       timestamp: midpoint of the time range used for averaging to obtain the refcal values 
    '''
    if scanidx:
        scanlist = [out['scanlist'][i] for i in scanidx]
        srclist = [out['srclist'][i] for i in scanidx]
        tstlist = [out['tstlist'][i] for i in scanidx]
        tedlist = [out['tedlist'][i] for i in scanidx]
        bandnames = [out['bandnames'][i] for i in scanidx]
        vis = [out['vis'][i] for i in scanidx]
        times_ = [out['times'][i] for i in scanidx]
        fghzs = [out['fghzs'][i] for i in scanidx]
    else:
        scanlist = out['scanlist']
        srclist = out['srclist']
        tstlist = out['tstlist']
        tedlist = out['tedlist']
        bandnames = out['bandnames']
        vis = out['vis']
        times_ = out['times']
        fghzs = out['fghzs']

    scanidx = range(len(scanlist))
    if len(set(np.array(srclist)[scanidx])) > 1:
        prompt = ''
        while not (prompt.lower() in ['y', 'n']):
            prompt = raw_input('Multiple sources are selected. Are you sure to continue? [y/n]')
        if prompt.lower() == 'n':
            print 'Abort...'
            return None

    fghz = fghzs[0]
    times = np.concatenate(times_)
    vis = np.concatenate(vis, axis=3)
    # only keep the first 2 polarizations
    vis = vis[:, :2]
    if timerange:
        tidx, = np.where((times > timerange[0].jd) & (times < timerange[1].jd))
        if len(tidx) == 0:
            print 'no records within the selected timerange. Abort...'
        for i in range(len(scanlist)):
            sidx, = np.where((times_[i] > timerange[0].jd) & (times_[i] < timerange[1].jd))
            if len(sidx) > 0:
                src = srclist[i]
                break
        vis = vis[:, :, :, tidx]
        timeavg = times[tidx]
    else:
        timeavg = times
        src = srclist[0]
    # vismean = np.nanmean(np.angle(vis),axis=3)
    vis_ = np.zeros(vis.shape[:3], dtype=complex)
    flag = np.zeros(vis.shape[:3], dtype=int)
    sigma = np.zeros(vis.shape[:3]) + 1e10
    # compute standard deviation of the visibilities
    sigma_ = np.nanstd(vis, axis=3)
    # sigma = np.nanstd(np.abs(vis),axis=3)
    # mask out records with phases > 3 sigma
    for bd in range(34):
        # print 'band: ',bd
        for ant in range(13):
            # print 'ant: ',ant
            for pol in range(2):
                # print 'pol: ',pol
                amp = np.abs(vis[ant, pol, bd])
                amp_median = np.median(np.abs(vis[ant, pol, bd]))
                ind, = np.where(np.abs(amp - amp_median) < sigma_[ant, pol, bd])
                snr = amp_median / sigma_[ant, pol, bd]
                # pdb.set_trace()
                if snr < minsnr or np.isnan(snr):
                    flag[ant, pol, bd] = 1
                else:
                    if len(ind) > len(timeavg) / 2:
                        vis_[ant, pol, bd] = np.nanmean(vis[ant, pol, bd, ind])
                        sigma[ant, pol, bd] = np.nanstd(vis[ant, pol, bd, ind])
                    else:
                        vis_[ant, pol, bd] = np.nanmean(vis[ant, pol, bd])
                        flag[ant, pol, bd] = 1
                        # print '# of valid datapoints: ',len(ind)
        # count how many datapoints are flagged in a given band
        nflag = np.count_nonzero(flag[:13, :, bd])
        print '{0:d} of 26 measurements are flagged due to SNR < {1:.1f} in Band {2:d}'.format(nflag, minsnr, bd + 1)
    # flag zero values (e.g., antennas or bands not observed)
    zeroind = np.where(np.abs(vis_ == 0))
    flag[zeroind] = 1
    # timestamps
    timestamp = Time(np.mean(timeavg), format='jd')
    timestamp_gcal = Time((tstlist[0].jd + tedlist[0].jd) / 2., format='jd')
    
    #Calculate band 4 phases
    refcal_lohi = sql2refcal(timestamp, lohi=True)  #obtain from SQL database
    dph = np.zeros((15,2,30))
    for i in range(13):
         for j in range(2):
             dph[i,j,:] = np.unwrap(lobe(np.angle(vis_)[i,j,4:] - refcal_lohi['pha'][i,j,4:]))
                 
    dphfitxxyy = np.zeros((13,2,2))
    w = np.ones(31)
    w[0] += 99
    for i in range(13):
         for j in range(2):
             dphfitxxyy[i,j,:] = np.polyfit(np.append([0.],fghz[4:]),np.append([0.],[dph[i,j]]),1,w=w)
    
    fghz[3] = refcal_lohi['fghz'][3]
    dph4 = np.zeros((13,2))
    for i in range(13):
         for j in range(2):
             dph4[i,j] = np.polyval(dphfitxxyy[i,j,:],fghz[3])        
    dph4 = dph4
    for i in range(13):  #Insert band 4 phase in high frequency receiver
        for j in range(2):
            vis_[i,j,3] = np.complex(np.cos(refcal_lohi['pha'][i,j,3] + dph4[i,j]), np.sin(refcal_lohi['pha'][i,j,3] + dph4[i,j]))  #Amp = 1.0
    
    if doplot:
        visavg = {'pha': np.angle(vis_), 'amp': np.abs(vis_), 'timestamp': timestamp, 't_bg': timeavg[0], 't_ed': timeavg[-1], 'flag': flag}
        graph(out, visavg, scanidx=scanidx, bandplt=bandplt)
        graph(out, visavg, scanidx=scanidx, bandplt=bandplt, pol=1)
        f2, ax2 = plt.subplots(2, 13, figsize=(12, 5))
        if lohi == 0:
            f2.suptitle('Orange = Estimated band 4 phases based on lohi scans on ' + str(refcal_lohi['timestamp'].iso))
        plt.title('source: {}'.format(srclist[scanidx[0]]))
        f3, ax3 = plt.subplots(2, 13, figsize=(12, 5))
        plt.title('source: {}'.format(srclist[scanidx[0]]))
        allbands = np.arange(34) + 1
        for ant in range(13):
            for pol in range(2):
                ind, = np.where(flag[ant, pol, :] == 0)
                ax2[pol, ant].plot(allbands[ind], np.unwrap(visavg['pha'][ant, pol, ind]), '.', markersize=5)
                if lohi == 0:
                    ax2[pol, ant].plot(4., np.unwrap(visavg['pha'])[ant, pol, 3], '.', markersize=5)  #Add band 4
                ax2[pol, ant].set_ylim([-20, 20])
                ax2[pol, ant].set_xlim([1, 34])
                ax3[pol, ant].plot(allbands[ind], visavg['amp'][ant, pol, ind], '.', markersize=5)
                ax3[pol, ant].set_xlim([1, 34])
                ax3[pol, ant].set_ylim([0, 1.])
                if ant == 0:
                    ax2[pol, ant].set_ylabel('Phase (radian)')
                    ax3[pol, ant].set_ylabel('Amplitude')
                else:
                    ax2[pol, ant].set_yticks([])
                    ax3[pol, ant].set_yticks([])
                if pol == 1 and ant == 0:
                    ax2[pol, ant].set_xlabel('Band #')
                    ax3[pol, ant].set_xlabel('Band #')
                if pol == 0:
                    ax2[pol, ant].set_title('Ant ' + str(ant + 1))
                    ax2[pol, ant].set_xticks([])
                    ax3[pol, ant].set_title('Ant ' + str(ant + 1))
                    ax3[pol, ant].set_xticks([])
                    
        if lohi == 0:
            f, ax = plt.subplots(2,13,figsize=(12,5))  #Plot delay curve used for band 4 phase estimation
            f.suptitle('Phase differences with respect to ' + str(refcal_lohi['timestamp'].iso))
            for i in range(13):
                 ax[0,i].set_title('Ant ' + str(i+1))
                 for j in range(2):
                     ax[j,i].plot(fghz[4:],dph[i,j,:],'.')
                     ax[j,i].plot(np.append([0.],fghz[4:]),np.polyval(dphfitxxyy[i,j,:],np.append([0.],fghz[4:])))
                     ax[j,i].plot(fghz[3],np.polyval(dphfitxxyy[i,j,:],fghz[3]),'.')
                     ax[j,i].set_xlim([0.,18.])
                     ax[j,i].set_ylim([-np.pi,np.pi])
                     ax[0,0].set_ylabel('XX')
                     ax[1,0].set_ylabel('YY')
                     ax[1,0].set_xlabel('fghz')

    if lohi:
        fghz = out['fghzs'][0]
        fghz[3] = out['fghzs'][1][3]
        bandnames = np.append(4,out['bandnames'][0])
        com_idx = [4,5,6,7,8,9,10,11]  #because common_val_idx somehow failed
        phlo = np.angle(np.sum(out['vis'][1],3))[:,:2,:]
        phhi = np.angle(vis_)
        
        #Caliculate band 4 phase
        dphlohi = np.unwrap(lobe(phlo[:,:,com_idx] - phhi[:,:,com_idx]))  #dph over bands 5-12
        dphfitlohi = np.zeros((13,2,3))
        for i in range(13):  #Poly-fit dph curve
             for j in range(2):
                 dphfitlohi[i,j,:] = np.polyfit(out['fghzs'][0][com_idx],dphlohi[i,j,:],2)
        dph4 = np.zeros((13,2))  #Extrapolate the fit to band 4
        for i in range(13):
             for j in range(2):
                 dph4[i,j] = np.polyval(dphfitlohi[i,j,:],out['fghzs'][1][3])
        for i in range(13):  #Insert band 4 phase in high frequency receiver
            for j in range(2):
                vis_[i,j,3] = np.complex(np.cos(phlo[i,j,3] - dph4[i,j]), np.sin(phlo[i,j,3] - dph4[i,j]))  #Amp = 1.0
        phhi_new = np.angle(vis_)
        
        #Plot band 4 phase
        f, ax = plt.subplots(2,13,figsize=(12,5))
        f.suptitle('Calculated band 4 phases (orange)')
        plt.title('source: {}'.format(srclist[scanidx[0]]))
        for ant in range(13):
             ax[0,ant].set_title('Ant ' + str(ant+1))
             for pol in range(2):
                 ax[pol,ant].plot(bandnames[1:], np.unwrap(phhi_new)[ant,pol,4:],'.')
                 ax[pol,ant].plot(bandnames[0], np.unwrap(phhi_new)[ant,pol,3],'.')                                  
                 ax[pol,ant].set_ylim([-20,20])
                 ax[pol,ant].set_xlim([1,34])
                 if pol == 0: ax[pol,ant].set_xticks([])
                 if ant >= 1: ax[pol,ant].set_yticks([])
        ax[1,0].set_xlabel('Band #')
        ax[0,0].set_ylabel('XX Phase (radian)')
        ax[1,0].set_ylabel('YY Phase (radian)')
        
        return {'src': src, 'vis': vis_, 'pha': np.angle(vis_), 'amp': np.abs(vis_), 'fghz': fghz, 'flag': flag,
                'sigma': sigma, 'timestamp': timestamp, 't_gcal': timestamp_gcal, 't_bg': Time(timeavg[0], format='jd'),
                't_ed': Time(timeavg[-1], format='jd')}

    return {'src': src, 'vis': vis_, 'pha': np.angle(vis_), 'amp': np.abs(vis_), 'fghz': fghz, 'flag': flag, 'sigma': sigma, 'timestamp': timestamp,
            't_gcal': timestamp_gcal, 't_bg': Time(timeavg[0], format='jd'), 't_ed': Time(timeavg[-1], format='jd')}
Beispiel #27
0
def sat_xy_corr(out0, out1, band=0, ant_str='ant1-13', doplot=True):
    ''' Analyze a pair of parallel and cross polarization calibration packet captures
        on a Geosat in K-band (bands 33, 34, 35, 36, 37) and
        return the X vs. Y delay phase corrections on all antennas 1-14.
        
        Required keyword:
           prtlist   a list of 2 PRT filenames, the first being the 
                       parallel-feed scan, and the second being the
                       crossed-feed scan.
           band      the band index (0-4) corresponding to the above 5 bands
        Optional keyword:
           doplot    True => plot the final result, False => no plot
    '''
    import pcapture2 as p
    from util import bl2ord, ant_str2list
        
    if doplot: import matplotlib.pylab as plt

    antlist = ant_str2list(ant_str)
    nant = len(antlist)
#    out0 = p.rd_jspec(prtlist[0])  # Parallel scan
#    out1 = p.rd_jspec(prtlist[1])  # Perpendicular scan
    # Integrate over (10) repeated records for the desired band
    ph0 = np.angle(np.sum(out0['x'][:,:,:,10*band:10*(band+1)],3))
    ph1 = np.angle(np.sum(out1['x'][:,:,:,10*band:10*(band+1)],3))
    # Determine secular change in phase at the two times, relative to ant 1
    for i in antlist:
        if i == antlist[0]:
            dp = np.zeros_like(ph0[0,0])
        else:
            dp = lobe(ph1[bl2ord[antlist[0],i],0] - ph0[bl2ord[antlist[0],i],0])
        ph0[bl2ord[i,13],2:] = lobe(ph1[bl2ord[i,13],2:]-dp)     # Insert crossed-feed phases from ph1 into ph0, corrected for secular change

    ph0 = ph0[bl2ord[antlist,13]]          # Now restrict to only baselines with ant 14
    fstart = (band+32)*0.325 + 1.1 - 0.025
    fghz = np.linspace(fstart,fstart+0.400,4096)
    nf = len(fghz)
    dph = np.zeros((nant+1,nf),np.float)
    # Determine xi_rot
    xi2 = ph0[:,2] - ph0[:,0] + ph0[:,3] - ph0[:,1]  # This is 2 * xi, measured separately on each of 13 antennas
    xi_rot = lobe(np.unwrap(np.angle(np.sum(np.exp(1j*xi2),0)))/2.)   # Very clever average does not suffer from wrapping issues
    #xi_rot = np.zeros_like(xi_rot) + np.pi/2.    # *********** Zero out xi_rot for now ****************
    # Form differential delay phase from channels, and average them
    # dph14 = XY - XX - xi_rot and YY - YX + xi_rot
    dph14 = np.concatenate((lobe(ph0[:,2] - ph0[:,0] - xi_rot),lobe(ph0[:,1] - ph0[:,3] + xi_rot)))  # 26 values for Ant 14
    dph[nant] = np.angle(np.sum(np.exp(1j*dph14),0))  # Very clever average does not suffer from wrapping issues
    # dphi = XX - YX + xi_rot and XY - YY - xi_rot 
    dphi = np.array((lobe(ph0[:,0] - ph0[:,3] + xi_rot),lobe(ph0[:,2] - ph0[:,1] - xi_rot)))  # 2 values for Ant 14
    dph[:nant] = np.angle(np.sum(np.exp(1j*dphi),0))
    
    if doplot:
        figlabel = 'XY_Phase_'+str(band+33)
        if figlabel in plt.get_figlabels():
            f = plt.figure(figlabel)
            ax = f.get_axes()
        else:
            f, ax = plt.subplots(4, 4, num=figlabel)
            ax.shape = (16,)
        for i in range(nant): 
            ax[antlist[i]].plot(fghz,dphi[0,i],',')
            ax[antlist[i]].plot(fghz,dphi[1,i],',')
            ax[antlist[i]].plot(fghz,dph[i],'k,')
            ax[antlist[i]].set_title('Ant '+str(antlist[i]+1),fontsize=9)
        for i in range(2*nant):
            ax[13].plot(fghz,dph14[i],',')
            ax[13].set_title('Ant 14',fontsize=9)
        ax[13].plot(fghz,dph[nant],'k,')
        for i in range(14): ax[i].set_ylim(-4,4)
        f.suptitle('Multicolor: Measurements, Black: Final Results')
        ax[14].plot(fghz,xi_rot)
        for i in range(nant):
            ax[15].plot(fghz,xi2[i],',')
#    np.savez('/common/tmp/Feed_rotation/' + npzlist[0].split('/')[-1][:14] + '_delay_phase.npz', fghz=fghz, dph=dph, xi_rot=xi_rot)
    time = Time.now().lv
    xy_phase = {'antlist':antlist, 'timestamp':time, 'fghz':fghz, 'xyphase':dph, 'xi_rot':xi_rot, 'dphi':dphi, 'dph14':dph14}
    return xy_phase
Beispiel #28
0
import read_idb as ri
from util import lobe
files = glob.glob('/data1/eovsa/fits/UDB/2018/UDB20180826*')
files.sort()
files = files[:20]
out1o = ri.read_idb(files, navg=20)
out2o = ri.read_idb(files[1:], navg=20)
ph1 = np.angle(out1o['x'][ri.bl2ord[13, :13]])
ph2 = np.angle(out2o['x'][ri.bl2ord[13, :13]])
ph_1 = np.zeros((13, 2, 12, 13), np.float)
ph_2 = np.zeros((13, 2, 12, 10), np.float)
for i in range(13):
    for j in range(2):
        for k in range(12):
            if i == 0:
                ph_1[i, 0, k] = lobe(ph1[i, j, k] - ph1[i, j, k, 0]
                                     ) * out1o['fghz'][0] / out1o['fghz'][k]
                ph_2[i, 1, k] = lobe(ph2[i, j, k] - ph2[i, j, k, 0]
                                     ) * out2o['fghz'][0] / out2o['fghz'][k]
            else:
                ph_1[i, 0,
                     k] = -lobe(ph1[i, j, k] - ph1[0, j, k] - ph1[i, j, k, 0] +
                                ph1[0, j, k,
                                    0]) * out1o['fghz'][0] / out1o['fghz'][k]
                ph_2[i, 1,
                     k] = -lobe(ph2[i, j, k] - ph2[0, j, k] - ph2[i, j, k, 0] +
                                ph2[0, j, k,
                                    0]) * out2o['fghz'][0] / out2o['fghz'][k]
# Mean over frequencies and polarizations, scaled by cos(dec)
ph_1t = np.mean(np.mean(ph_1, 1), 1) / cos(out1o['dec'])
ph_2t = np.mean(np.mean(ph_2, 1), 1) / cos(out2o['dec'])
f, ax = plt.subplots(4, 4)
Beispiel #29
0
def graph(f, navg=None, path=None):

    import matplotlib.pyplot as plt
    from matplotlib.ticker import FormatStrFormatter
    import struct, time, glob, sys, socket
    import read_idb as ri
    import dbutil as db

    if navg is None:
        navg = 60

    if path is None:
        path = ''

    out = ri.read_idb(f, navg=navg)
    if len(out['fghz']) == 0:
        # This file is no good, so skip it
        return
    fig, ax = plt.subplots(4, 13, sharex=True, sharey=True)
    trange = Time(
        [fname2mjd(f[0]), fname2mjd(f[-1]) + ten_minutes], format='mjd')
    # ************ This block commented out due to loss of SQL **************
    # times, wscram, avgwind = db.a14_wscram(trange)
    # nwind = len(wscram)
    # nbad = np.sum(wscram)
    nbad = 0  # Skip Windscram check
    if nbad != 0:
        warn = ' --> Windscram! (' + str(nbad) + ' of ' + str(nwind) + ')'
        color = '#d62728'  # Plot points with "warning" Red color
    else:
        warn = ''
        color = '#1f77b4'  # Plot points with "normal" Blue color
    fig.set_size_inches(18, 6)
    nf = len(out['fghz'])
    fstr = str(out['fghz'][nf / 2] * 1000)[:5] + ' MHz '
    for k in range(13):
        for j in range(4):
            ax[j, k].cla()
            ax[j, k].plot(out['ha'],
                          np.angle(out['x'][ri.bl2ord[k, 13], j, nf / 2]),
                          '.',
                          color=color)
            ax[j, k].set_ylim(-4, 4)
            ax[j, k].xaxis.set_major_formatter(FormatStrFormatter('%.2f'))
            if k in range(1, 13): ax[j, k].yaxis.set_visible(False)
            if j in range(3): ax[j, k].xaxis.set_visible(False)
            if j == 0: ax[0, k].title.set_text('antenna %d' % (k + 1))
    fig.suptitle(out['source'] + '  ' +
                 Time(out['time'][0], format='jd').iso[:19] + ' UT  ' + fstr +
                 warn)
    ax[0, 0].set_ylabel('XX Phase')
    ax[1, 0].set_ylabel('YY Phase')
    ax[2, 0].set_ylabel('XY Phase')
    ax[3, 0].set_ylabel('YX Phase')
    fig.text(0.5, 0.04, 'Hour Angle', ha='center')
    t = Time(out['time'][0],
             format='jd').iso[:19].replace('-',
                                           '').replace(':',
                                                       '').replace(' ', '')
    s = out['source']
    ofile = path + t[:14] + '_' + s + '.npz'
    np.savez(open(ofile, 'wb'), out=out)
    plt.savefig(path + 'pcT' + t + '_' + s + '.png', bbox_inches='tight')
    plt.close(fig)

    ph = np.angle(np.sum(out['x'], 3))
    fig, ax = plt.subplots(4, 13)
    fig.set_size_inches(18, 6)
    for k in range(13):
        for j in range(4):
            ax[j, k].cla()
            if k == 0:
                ax[j, k].plot(out['fghz'],
                              ph[ri.bl2ord[k, 13], j],
                              '.',
                              color=color)
            else:
                ax[j, k].plot(out['fghz'],
                              lobe(ph[ri.bl2ord[k, 13], j] -
                                   ph[ri.bl2ord[0, 13], j]),
                              '.',
                              color=color)
            ax[j, k].set_ylim(-4, 4)
            ax[j, k].xaxis.set_major_formatter(FormatStrFormatter('%.2f'))
            if k in range(1, 13): ax[j, k].yaxis.set_visible(False)
            if j in range(3): ax[j, k].xaxis.set_visible(False)
            if j == 0: ax[0, k].title.set_text('antenna %d' % (k + 1))
    fig.suptitle(out['source'] + ' ' +
                 Time(out['time'][0], format='jd').iso[:19] + ' UT' + warn)
    ax[0, 0].set_ylabel('XX Phase')
    ax[1, 0].set_ylabel('YY Phase')
    ax[2, 0].set_ylabel('XY Phase')
    ax[3, 0].set_ylabel('YX Phase')
    fig.text(0.5, 0.04, 'Frequency[GHz]', ha='center')
    t = Time(out['time'][0],
             format='jd').iso[:19].replace('-',
                                           '').replace(':',
                                                       '').replace(' ', '')
    plt.savefig(path + 'pcF' + t + '_' + s + '.png', bbox_inches='tight')
    plt.close(fig)
Beispiel #30
0
def get_xy_corr(npzlist=None, doplot=True):
    ''' Analyze a pair of parallel and cross polarization calibration scans and
        return the X vs. Y delay phase corrections on all antennas 1-14.
        
        Required keyword:
           npzlist   a list of 2 NPZ filenames, the first being the 
                       parallel-feed scan, and the second being the
                       crossed-feed scan.
        Optional keyword:
           doplot    True => plot the final result, False => no plot
    '''
    if npzlist is None:
        print 'Must provide a list of 2 NPZ files.'
        return None, None
    import read_idb as ri
    import numpy as np
    from util import lobe

    if doplot: import matplotlib.pylab as plt

    out0 = ri.read_npz([npzlist[0]])  # Parallel scan
    out1 = ri.read_npz([npzlist[1]])  # Perpendicular scan
    ph0 = np.angle(np.sum(out0['x'][ri.bl2ord[:13, 13]], 3))
    ph1 = np.angle(np.sum(out1['x'][ri.bl2ord[:13, 13]], 3))
    ph0[:, 2:] = ph1[:, 2:]  # Insert crossed-feed phases from ph1 into ph0

    fghz = out0['fghz']
    nf = len(fghz)
    dph = np.zeros((14, nf), np.float)
    # Form differential delay phase from channels, and average them
    # dph14 = XY - XX and YY - YX + pi
    dph14 = np.concatenate(
        (lobe(ph0[:, 2] - ph0[:, 0] + np.pi / 2),
         lobe(ph0[:, 1] - ph0[:, 3] - np.pi / 2)))  # 26 values for Ant 14
    dph[13] = np.angle(
        np.sum(np.exp(1j * dph14),
               0))  # Very clever average does not suffer from wrapping issues
    # dphi = XX - YX and XY - YY + pi
    dphi = np.array(
        (lobe(ph0[:, 0] - ph0[:, 3] - np.pi / 2),
         lobe(ph0[:, 2] - ph0[:, 1] + np.pi / 2)))  # 2 values for Ant 14
    dph[:13] = np.angle(np.sum(np.exp(1j * dphi), 0))

    if doplot:
        f, ax = plt.subplots(4, 4)
        ax.shape = (16, )
        for i in range(13):
            ax[i].plot(fghz, dphi[0, i], '.')
            ax[i].plot(fghz, dphi[1, i], '.')
            ax[i].plot(fghz, dph[i], 'k.')
        for i in range(26):
            ax[13].plot(fghz, dph14[i], '.')
        ax[13].plot(fghz, dph[13], 'k.')
        for i in range(14):
            ax[i].set_ylim(-4, 4)
        f.suptitle('Multicolor: Measurements, Black: Final Results')
    np.savez('/common/tmp/Feed_rotation/' + npzlist[0].split('/')[-1][:14] +
             '_delay_phase.npz',
             fghz=fghz,
             dph=dph)
    return dph
Beispiel #31
0
def xydelay_anal(npzfiles, fix_tau_lo=None):
    ''' Analyze a "standard" X vs. Y delay calibration, consisting of four observations
        on a strong calibrator near 0 HA, in the order:
           90-degree  Low-frequency  receiver,
           90-degree  High-frequency receiver,
            0-degree  High-frequency receiver,
            0-degree  Low-frequency  receiver
            
        It has happened that the low-frequency receiver delays were not set for one
        of the observation sets.  This can be fixed by reading the delay-center table
        for the relevant date and applying a phase correction according to the delay
        difference.  Setting fix_tau_lo to "first" means correct first scan, and to
        "last" means correct last scan.
    '''
    import matplotlib.pylab as plt
    from util import common_val_idx

    npzfiles = np.array(npzfiles)
    out = []
    for file in npzfiles:
        out.append(ri.read_npz([file]))
    out = np.array(out)
    if fix_tau_lo != None:
        # Correct for low-frequency delay error, if requested
        import cal_header as ch
        from stateframe import extract
        if fix_tau_lo == 'first':
            icorr=0
        elif fix_tau_lo == 'last':
            icorr=3
        else:
            print 'Invalid value for fix_tau_lo.  Must be "first" or "last"'
            return
        xml, buf = ch.read_cal(4,t=Time(out[icorr]['time'][0],format='jd'))
        dlatbl = extract(buf,xml['Delaycen_ns'])
        dtau_x, dtau_y = dlatbl[14] - dlatbl[13]
        dp_x = out[icorr]['fghz']*2*np.pi*dtau_x
        dp_y = out[icorr]['fghz']*2*np.pi*dtau_y
        nt, = out[icorr]['time'].shape
        for i in range(nt):
            for iant in range(13):
                out[icorr]['x'][ri.bl2ord[iant,13],0,:,i] *= np.exp(1j*dp_x)
                out[icorr]['x'][ri.bl2ord[iant,13],1,:,i] *= np.exp(1j*dp_y)
                out[icorr]['x'][ri.bl2ord[iant,13],2,:,i] *= np.exp(1j*dp_y)
                out[icorr]['x'][ri.bl2ord[iant,13],3,:,i] *= np.exp(1j*dp_x)
    dph_lo = get_xy_corr(out[[3,0]], doplot=False)
    dph_hi = get_xy_corr(out[[2,1]])
    fghz = np.union1d(dph_lo['fghz'],dph_hi['fghz'])
    # Check for LO and HI being off by pi due to pi-ambiguity in xi_rot
    lo_com, hi_com = common_val_idx(dph_lo['fghz'],dph_hi['fghz'])
    # Average xi_rot angle difference over common frequencies
    a = lobe(dph_hi['xi_rot'][hi_com]-dph_lo['xi_rot'][lo_com]) # angle difference
    xi_rot_diff = np.angle(np.sum(np.exp(1j*a)))  # Average angle difference
    if np.abs(xi_rot_diff) > np.pi/2:
        # Looks like shifting by pi will get us closer, so shift both xyphase and xi_rot
        # This does not actually change any phase relationships, it only makes the plots
        # and HI/LO data comparison more consistent.
        dph_lo['xyphase'] += np.pi
        dph_lo['xi_rot'] += np.pi
        dph_lo['dphi'] += np.pi
        dph_lo['dph14'] += np.pi
    ax = plt.figure('XY_Phase').get_axes()
    for i in range(13):
        ax[i].plot(dph_lo['fghz'], lobe(dph_lo['dphi'][0,i]), '.',color='C0')    
        ax[i].plot(dph_lo['fghz'], lobe(dph_lo['dphi'][1,i]), '.',color='C1')    
        ax[i].plot(dph_lo['fghz'],lobe(dph_lo['xyphase'][i]),'r.')
        ax[i].set_xlim(0,20)
    for i in range(26):
        ax[13].plot(dph_lo['fghz'],lobe(dph_lo['dph14'][i]),'.')
    ax[13].plot(dph_lo['fghz'],lobe(dph_lo['xyphase'][13]),'r.')
    nf, = fghz.shape
    flo_uniq = np.setdiff1d(dph_lo['fghz'],dph_hi['fghz'])  # List of frequencies in LO not in HI
    idx_lo_not_hi, idx2 = common_val_idx(fghz, flo_uniq)    # List of indexes of unique LO frequencies
    # Make empty arrays with enough frequencies
    xyphase = np.zeros((14,nf),dtype=float)
    xi_rot = np.zeros((nf),dtype=float)
    idx_hi, idx2 = common_val_idx(fghz,dph_hi['fghz'])  # List of indexes of HI receiver frequencies
    xyphase[:14,idx_hi] = dph_hi['xyphase']       # Insert all high-receiver xyphases
    xyphase[:14,idx_lo_not_hi] = dph_lo['xyphase'][:14,idx_lo_not_hi]  # For unique low-receiver frequencies, insert LO xyphases
    
    xi_rot[idx_hi] = dph_hi['xi_rot']   # Insert all high-receiver xi_rot
    xi_rot[idx_lo_not_hi] = lobe(dph_lo['xi_rot'][idx_lo_not_hi])   # For unique low-receiver frequencies, insert LO xi_rot
    ax[14].plot(fghz,xi_rot)
    dph_hi.update({'xi_rot':xi_rot, 'xyphase':xyphase, 'fghz':fghz})
    print 'Referring to the output of this routine as "xyphase,"'
    print 'run cal_header.xy_phasecal2sql(xyphase) to write the SQL record.' 
    return dph_hi