Esempio n. 1
0
 def SaveLoRX(self):
     # Send saved Ant 14 delays as Ant 15 to the SQL database and the ACC (if the data source is not 'Simulation')
     # Note, ONLY Ant 14 delay is changed, and it is ascribed to Ant 15.  No other delay changes are made.
     if self.data_source == 'Data':
         if (Time.now().mjd - self.time.mjd) > 1.0:
             question = "Warning: Data more than a day old. Are you sure you want to save delays to SQL and ACC?"
         else:
             question = "Save delays to SQL and ACC?"
         import cal_header as ch
         
         delays = self.delays[0] - self.delays
         delays = np.append(delays,self.delays[0])
         # Have to change the sign of Ant 14 Y-X delay, hence the minus sign
         xydelays = np.append(self.xydelays,-float(self.dla14.get()))
         # Do not change delays where both delays and xydelays are zero
         # which is taken as a missing antenna
         bad, = np.where(self.delays == 0)
         bad2, = np.where(self.xydelays == 0)
         idx1,idx2 = common_val_idx(bad,bad2)
         delays[bad[idx1]] = 0.0
         # Check that the delays to all antennas except Ant 14 are zero, or give warning if not
         for i in range(13):
             if delays[i] != 0.0:
                 question = "Some Ant1-13 delays are not 0, but will NOT be updated.  Save anyway?"
                 break
             if xydelays[i] != 0.0:
                 question = "Some Ant1-13 delays are not 0, but will NOT be updated.  Save anyway?"
                 break
         
         if askyesno("Write Delays",question):
             # All Y-X delays need a sign flip, hence the minus sign
             ch.dla_update2sql(delays,-xydelays,lorx=True)
             #ch.dla_update2sql(-delays,xydelays)  # 300 MHz design uses flipped signs!
             ch.dla_censql2table()
Esempio n. 2
0
 def show(self):
     delays_str = '   '
     xydelays_str = '   '
     delays = np.append(self.delays[0] - self.delays,self.delays[0])
     # Do not change delays where both delays and xydelays are zero
     # which is taken as a missing antenna
     bad, = np.where(self.delays == 0)
     bad2, = np.where(self.xydelays == 0)
     idx1,idx2 = common_val_idx(bad,bad2)
     delays[bad[idx1]] = 0.0
     self.label1.configure(text='Ant    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14')
     fmt = '{:5.1f},'*14
     delays_str = fmt.format(*delays)
     self.label2.configure(text='   '+delays_str[:-1])
     xydelays = np.append(self.xydelays,-float(self.dla14.get()))
     xydelays_str = fmt.format(*xydelays)
     self.label3.configure(text='   '+xydelays_str[:-1])
Esempio n. 3
0
 def __init__(self,trange):
     ''' Create the object for the specified timerange specified by the 
         2-element Time() trange.  The timerange is used to create a list 
         of Miriad database files to read, and the data are read.
     '''
     # Read data, assuming 16-element correlator if after 2016 May 1
     if trange[0].lv > 3544905600.0:
         out = dump_tsys.rd_miriad_tsys_16(trange)
     else:
         out = dump_tsys.rd_miriad_tsys(trange)
     nant, npol, nf, nt = out['tsys'].shape
     self.xdata = out['tsys'][:,0,:,:]
     self.ydata = out['tsys'][:,1,:,:]
     self.fghz = out['fghz']
     self.time = Time(out['ut_mjd'],format='mjd')
     self.tidx = [0,len(self.time)]
     # Read calibration
     fghz, self.calfac, self.offsun = offline.read_dbcalfac(trange[0])
     # Make sure frequencies in data and calibration agree
     calidx, dataidx = common_val_idx((fghz*1000).astype('int'),(self.fghz*1000).astype('int'))
     self.bidx = [0,100]
     self.fghz = self.fghz[dataidx]
     self.xdata = self.xdata[:,dataidx,:]
     self.ydata = self.ydata[:,dataidx,:]
     if self.calfac is not None:
         # Select frequencies and swap axes to put into standard form
         self.calfac = np.rollaxis(self.calfac[:,calidx,:],2)
         self.offsun = np.rollaxis(self.offsun[:,calidx,:],2)
         fghz = fghz[calidx]
     # Set frequency index range (fidx) to default to show only frequencies > 2.5 GHz
     lowf, = np.where(self.fghz > 2.5)
     self.fidx = [lowf[0],len(self.fghz)]
     self.drange = [None,None]
     self.antlist = range(nant)
     self.cbar = True
     self.showants = range(nant)
     self.domedian = True
     self.docal = True
     self.dolog = False
     self.dosub = True
     self.ax = None
     self.version = __version__
Esempio n. 4
0
 def Save(self):
     # Send saved delays to the SQL database and the ACC (if the data source is not 'Simulation')
     if self.data_source == 'Data':
         if (Time.now().mjd - self.time.mjd) > 1.0:
             question = "Warning: Data more than a day old. Are you sure you want to save delays to SQL and ACC?"
         else:
             question = "Save delays to SQL and ACC?"
         import cal_header as ch
         # Calculate delays relative to Ant 1 and tack Ant1-14 delay at end
         delays = self.delays[0] - self.delays
         delays = np.append(delays,self.delays[0])
         # Have to change the sign of Ant 14 Y-X delay, hence the minus sign
         xydelays = np.append(self.xydelays,-float(self.dla14.get()))
         # Do not change delays where both delays and xydelays are zero
         # which is taken as a missing antenna
         bad, = np.where(self.delays == 0)
         bad2, = np.where(self.xydelays == 0)
         idx1,idx2 = common_val_idx(bad,bad2)
         delays[bad[idx1]] = 0.0
         if askyesno("Write Delays",question):
             # All Y-X delays need a sign flip, hence the minus sign
             ch.dla_update2sql(delays,-xydelays)
             #ch.dla_update2sql(-delays,xydelays)  # 300 MHz design uses flipped signs!
             ch.dla_censql2table()
Esempio n. 5
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
Esempio n. 6
0
def get_reverseattn(trange_gaincal, trange_other=None, first_attn_base=5, second_attn_base=3, corrected_attns=False):
        # This function finds and return the tsys, the noise corrected tsys, and the noise and attenuation
        #  tsys. The first parameter it takes should be a GAINCALTEST trange, which may be located with find_gaincal, 
        #  The second parameter it takes should be a FEATTNTEST trange, which may be located with find_gaincal as
        #  well. It may or may not take a third parameter. Any form of file that was recorded by the system from 
        #  from the antennas may be inserted here, whether a flare or just quiet sun data.
        #
        #  PLEASE NOTE: ANY trange with data may be used as "trange_gaincal", use a trange from a GAINCALTEST and the other 
        #  file as "trange_other" if you want the noise to be calibrated from the GAINCALTEST file, which will most likely
        #  be more recent than the FEATTNTEST file it would otherwise take the noise from. 
        tsys1, res1, noise_level, idx1a, idx3a, marker1, trange_feattncal, trange_feattncal2  = attn_noises(trange_gaincal)
        if corrected_attns == True:
            all_attns_avg = get_all_attns(trange_feattncal, test='FEATTNTEST', from_corrected_attns=True)
            all_attns_avg1 = get_all_attns(trange_feattncal2, test='FEATTNTEST2', from_corrected_attns=True)
        else:
            if corrected_attns == False:
                all_attns_avg = get_all_avg_attns(trange_feattncal, test='FEATTNTEST')
                all_attns_avg1 = get_all_avg_attns(trange_feattncal2, test='FEATTNTEST2')
        
        if trange_other == None:
            tsys = tsys1
            res = res1
            idx1 = idx1a
            idx3 = idx3a
            marker = marker1
        else:
            s = sp.Spectrogram(trange_other)
      	    s.docal = False
	    s.dosub = False
	    s.domedian = False        
	    tsys, std = s.get_data()
            cursor = dbutil.get_cursor()
	    res, msg = dbutil.do_query(cursor,'select Timestamp,Ante_Fron_FEM_HPol_Atte_First,Ante_Fron_FEM_HPol_Atte_Second from fV54_vD15 where Timestamp between '+str(trange_other[0].lv)+' and '+str(trange_other[1].lv))
	    cursor.close()
            idx1, idx2 = util.common_val_idx(res['Timestamp'][0::15].astype('int'), (s.time.lv+0.5).astype('int'))
            marker = -1
            while idx1[-1] > idx2[-1]:
                idx1 = np.delete(idx1, -1)
                marker += 1
            tsys = tsys[:, :, :, idx1]
            idx3, idx4 = util.common_val_idx(res['Timestamp'].astype('int'), (s.time.lv+0.5).astype('int'))
            res['Timestamp'] = res['Timestamp'][idx3]

        if noise_level.shape[2] < tsys.shape[2]:
            freqs_for_range = noise_level.shape[2]
        else:
            freqs_for_range = tsys.shape[2]
                            
	tsys_noise_corrected = []
	for ant in range(tsys.shape[0]):
	    pol_corrected = []
	    for pol in range(tsys.shape[1]):
		freq_corrected = []
		for freq in range(freqs_for_range):
		    index_corrected = []
		    for index in range(tsys.shape[3]):
		        index_corrected.append(tsys[ant, pol, freq, index] - noise_level[ant, pol, freq])
		    freq_corrected.append(index_corrected)
		pol_corrected.append(freq_corrected)
	    tsys_noise_corrected.append(pol_corrected)
	tsys_noise_corrected= np.array(tsys_noise_corrected)
        
        freqloopslist = [tsys_noise_corrected.shape[2], all_attns_avg.shape[3], all_attns_avg1.shape[3]]
        freqloops = min(freqloopslist)

        if tsys.shape[3] < len(res['Ante_Fron_FEM_HPol_Atte_Second'][0::15]):
            indexloops = tsys.shape[3]
        else:
            if tsys.shape[3] >= len(res['Ante_Fron_FEM_HPol_Atte_Second'][0::15]):
                indexloops = len(res['Ante_Fron_FEM_HPol_Atte_Second'][0::15])-1  
        if tsys.shape[3] < len(res['Ante_Fron_FEM_HPol_Atte_First'][0::15]):
            indexloops1 = tsys.shape[3]
        else:
            if tsys.shape[3] >= len(res['Ante_Fron_FEM_HPol_Atte_First'][0::15]):
                indexloops1 = len(res['Ante_Fron_FEM_HPol_Atte_First'][0::15])-1   
        idxstart = marker + (15-8)
        xory = ['x' , 'y']
	ant_postcorrected = []
	for ant in range(tsys.shape[0]):
	    pol_postcorrected = []
	    for pol in range(tsys.shape[1]):
		freq_postcorrected = []
		for freq in range(freqloops):
                     
                    indices_postcorrected = []
                    for indx in range(indexloops): 
                        testlevel = res['Ante_Fron_FEM_HPol_Atte_Second'][ant::15][indx+idxstart] 
                        
                        if 0 <= testlevel <= 31:
                            pass
                        else:
                            print 'Problem with the attenuation of antenna ' + str(ant) + xory[pol] + ' at frequency channel ' + str(freq) + ' and time index '  + str(indx) + '. The attenuation is showing: ' + str(testlevel)       
                            testlevel = 0       
		        indices_postcorrected.append(10**((all_attns_avg[testlevel, ant, pol, freq]-all_attns_avg[second_attn_base, ant, pol, freq])/10)*tsys_noise_corrected[ant, pol, freq, indx])
                    indices_postcorrected1 = []
                    for indx in range(indexloops1): 
                        testlevel = res['Ante_Fron_FEM_HPol_Atte_First'][ant::15][indx+idxstart]                        
                        if 0 <= testlevel <= 31:
                            pass
                        else:
                            print 'Problem with the attenuation of antenna ' + str(ant) + xory[pol] + ' at frequency channel ' + str(freq) + ' and time index '  + str(indx) + '. The attenuation is showing: ' + str(testlevel)       
                            testlevel = 0      
		        indices_postcorrected1.append(10**((all_attns_avg1[testlevel, ant, pol, freq]-all_attns_avg1[first_attn_base, ant, pol, freq])/10)*indices_postcorrected[indx])                            
		    freq_postcorrected.append(indices_postcorrected1)
		pol_postcorrected.append(freq_postcorrected)
	    ant_postcorrected.append(pol_postcorrected)
	tsys_attn_noise_corrected = np.array(ant_postcorrected)
        
        return tsys_attn_noise_corrected, tsys_noise_corrected, tsys
Esempio n. 7
0
def get_state_idx(trange, cycles=4, attenuator=1):
    #This program creates an array of shape (6, 4) which contains the 
    #  times in which each attenuator is in each state. 6 attenuators,
    #  4 cycles. 
    firstorsecond = ['First', 'Second']
    s = sp.Spectrogram(trange)
    s.docal = False
    s.dosub = False
    s.domedian = False
    cursor = dbutil.get_cursor()
    res, msg = dbutil.do_query(cursor,'select Timestamp,Ante_Fron_FEM_HPol_Atte_First,Ante_Fron_FEM_HPol_Atte_Second from fV54_vD15 where Timestamp between '+str(trange[0].lv)+' and '+str(trange[1].lv))
    cursor.close()
    if msg == 'Success':
        antlist = []
        for i in [0, 1, 2, 4, 8, 16]:
            statelist = []
            for j in range(15):
                state, = np.where(np.logical_and(res['Ante_Fron_FEM_HPol_Atte_' + firstorsecond[attenuator]][j::15].astype('int') == i,res['Ante_Fron_FEM_HPol_Atte_' + firstorsecond[attenuator-1]][j::15].astype('int') != 0))
                statelist.append(state)
            statelist = np.array(statelist)
            antlist.append(statelist)
        states = np.array(antlist)
        states = np.rollaxis(states, 1)
        for i in range(15):
            for j in range(6):
                states[i, j] = res['Timestamp'][i::15][states[i, j]]
    else:
        print 'failure'
        return None
    time_array = (s.time.lv+0.001).astype('int')
    time_list = list(time_array)
    attns = ['0', '1', '2', '4', '8', '16']
    common_list = []
    for j in range(6):
        # Antenna 1 is used as the reference antenna here. 
        #  Earlier versions had only indices which were shared 
        #  for attenuations AND antennas, but because of a
        #  small timing error that occur between antennas
        #  during the scan itself, this older version would
        #  fail sometimes. 
        i1, i2 = util.common_val_idx(time_array,states[0,j])
        if i1.shape == i2.shape:
            common_ant_list = i2
        else: 
            print 'There is a problem with antenna '+str(i)+' at attenuation '+attns[j]
        common_list.append(common_ant_list)
    
    final_indices = []
    final_indices1 = []
    for i in range(6):
        index_list = []
        for indxs in common_list[i]:
            try:
                index_list.append(time_list.index(states[0,i][indxs]))
            except:
                pass
        final_indices1.append(index_list)
    for i in range(6):
        indices_array = np.array(final_indices1[i])
        final_indices.append(indices_array)
    final_indices = np.array(final_indices) 

    rolled_indices = []
    for i in range(6):
        rolled = np.roll(final_indices[i], -1)
        rolled_indices.append(rolled)
    subtracted_list = []
    for j in range(6):
        subtracted_list.append(rolled_indices[j] - final_indices[j])
    break_lists = []
    for k in range(6):
        break_list = []
        for indx in range(subtracted_list[k].shape[0]):
            if np.absolute(subtracted_list[k][indx]) <= 2:
                break_list.append(indx)
            else: 
                break_list.append(-1)
        break_lists.append(break_list)
    for i in range(6):
        for indx in range(int(len(break_lists[i]))-1):
            try:
                if break_lists[i][indx] == break_lists[i][indx-1]:
                    break_lists[i].pop(indx)
            except:
                pass
    break_list = []
    for j in range(6):
        breaklist = np.array(break_lists[j])
        break_list.append(breaklist)
    break_spots = []
    for i in range(6):
        try:
            break_spot = []
            for indx in range(len(break_list[i])):
                if break_list[i][indx] == -1:
                    break_spot.append(indx)
            break_spots.append(break_spot)
        except:
            pass
    split_lists = []
    for k in range(6):
        steps_list = [break_list[k][0:break_spots[k][0]]]
        for j in range(cycles-1):
            try:
                steps_list.append(break_list[k][1 + break_spots[k][j]:break_spots[k][j+1]])
            except:
                pass            
        split_lists.append(steps_list)
    split_lists = np.array(split_lists)  
    final_grouped_indices = []
    for i in range(6):
        grouped_indices = []
        for j in range(cycles):
            try:
                indices_ = []
                for indxs in split_lists[i][j]:
                    indices_.append(rolled_indices[i][indxs])
                grouped_indices.append(indices_)
            except:
                pass
        final_grouped_indices.append(grouped_indices)
    final_grouped_indices = np.array(final_grouped_indices)
    for i in range(6):
        for j in range(cycles):
            try:
                for k in range(1,int(len(final_grouped_indices[i][j]))-1):
                    try:
                        for m in range(len(final_ped_indices[i][j])):
                            if (final_grouped_indices[i][j][k-1] + 3) <= final_grouped_indices[i][j][k]:
                                final_grouped_indices[i][j].pop(k-1) 
                            if (final_grouped_indices[i][j][k+1]-3) >= final_grouped_indices[i][j][k]:
                                final_grouped_indices[i][j].pop(k+1)       
                    except:
                        pass
            except:
                pass
    return final_grouped_indices, res
Esempio n. 8
0
def attn_noises(trange_gaincal):
        # This function is used with "get_reverseattn." It find and returns background noise, and returns the "res"
        #  from dbutil.do_query and returns the "tsys" from spectrogram_fit and get_data().
        #  The first parameter it takes should be a GAINCALTEST trange, which may be located with find_gaincal, 
        #  The second parameter it takes should be a FEATTNTEST trange, which may be located with find_gaincal as
        #  well. 
        #
        #  PLEASE NOTE: ANY trange with data may be used as "trange_gaincal", use a trange from a GAINCALTEST and the other 
        #  file as "trange_other" if you want the noise to be calibrated from the GAINCALTEST file, which will most likely
        #  be more recent than the FEATTNTEST file it would otherwise take the noise from. 
        s = sp.Spectrogram(trange_gaincal)
	s.docal = False
	s.dosub = False
	s.domedian = False        
	tsys, std = s.get_data()
        trange_feattncal = find_gaincal()
        if type(trange_feattncal) == list:
            trange_feattncal = trange_feattncal[-1]
        else:
            pass
        trange_feattncal2 = find_gaincal(t = Time('2015-07-21 00:00'), scan_length=5, findwhat='FEATTNTEST2')
        if type(trange_feattncal2) == list:
            trange_feattncal2 = trange_feattncal2[-1]
        else:
            pass
        ratios, calfilenoise = show_dB_ratio(trange_feattncal)
        ratios1, calfilenoise1 = show_dB_ratio(trange_feattncal2, test='FEATTNTEST2')

	cursor = dbutil.get_cursor()
	res, msg = dbutil.do_query(cursor,'select Timestamp,Ante_Fron_FEM_HPol_Atte_First,Ante_Fron_FEM_HPol_Atte_Second from fV54_vD15 where Timestamp between '+str(trange_gaincal[0].lv)+' and '+str(trange_gaincal[1].lv))
	cursor.close()

        idx1, idx2 = util.common_val_idx(res['Timestamp'][0::15].astype('int'), (s.time.lv+0.5).astype('int'))       
        idx3, idx4 = util.common_val_idx(res['Timestamp'].astype('int'), (s.time.lv+0.5).astype('int'))
        marker = -1
        while idx1[-1] > idx2[-1]:
            idx1 = np.delete(idx1, -1)
            marker += 1
        tsys = tsys[:, :, :, idx1]

        calfilenoise_ = []
        for ant in range(calfilenoise.shape[0]):
            calfilenoisepol = []
            for pol in range(calfilenoise.shape[1]):
                calfilenoisefreq = []
                for freq in range(calfilenoise.shape[2]):
                    calfilenoisefreq.append(np.average(calfilenoise[ant, pol, freq, :]))
                calfilenoisepol.append(calfilenoisefreq)
            calfilenoise_.append(calfilenoisepol)
        calfilenoise = np.array(calfilenoise_)

	noise_level = []
	for ant in range(tsys.shape[0]):
	    pol_noise = []
	    for pol in range(tsys.shape[1]):
		freq_noise = []
		state, = np.where(np.logical_and(res['Ante_Fron_FEM_HPol_Atte_Second'][ant::15].astype('int') == 31,res['Ante_Fron_FEM_HPol_Atte_First'][ant::15].astype('int') == 31))
		for freq in range(tsys.shape[2]):
		    avg_noise = []
		    for index in state:
                        try:
		            if np.logical_and(tsys[ant, pol, freq, index] <= 0.005, index < tsys.shape[3]):
		                avg_noise.append(tsys[ant, pol, freq, index])
                        except:
                            pass
		    freq_noise.append(np.average(avg_noise))
		pol_noise.append(freq_noise)
	    noise_level.append(pol_noise)
	noise_level = np.array(noise_level)

        for ant in range(tsys.shape[0]):
	    for pol in range(tsys.shape[1]):
		for freq in range(tsys.shape[2]):                      
		    if np.isnan(noise_level[ant, pol, freq]) == False:
                        pass
                    else:
                        if np.isnan(noise_level[ant, pol, freq]) == True:                           
                            try:
                                noise_level[ant, pol, freq] = calfilenoise[ant, pol, freq]
                            except:
                                pass

        return tsys, res, noise_level, idx1, idx3, marker, trange_feattncal, trange_feattncal2
Esempio n. 9
0
def apply_fem_level(data, gctime=None):
    ''' Applys the FEM level corrections to the given data dictionary.
        
        Inputs:
          data     A dictionary such as that returned by read_idb().
          gctime   A Time() object whose date specifies which GAINCALTEST
                     measurements to use.  If omitted, the date of the data
                     is used.

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

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

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

    idx = nearest_val_idx(data['time'], src_lev['times'].jd)
    nt = len(idx)  # New number of times
    # Correct the auto- and cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Reshape px and py arrays
    cdata['px'].shape = (nf, 16, 3, nt)
    cdata['py'].shape = (nf, 16, 3, nt)
    # Correct the power
    cdata['px'][:, :15, 0] *= antgainf[:, :, 0, idx]
    cdata['py'][:, :15, 0] *= antgainf[:, :, 1, idx]
    # Correct the power-squared
    cdata['px'][:, :15, 1] *= antgainf[:, :, 0, idx]**2
    cdata['py'][:, :15, 1] *= antgainf[:, :, 1, idx]**2
    # Reshape px and py arrays back to original
    cdata['px'].shape = (nf * 16 * 3, nt)
    cdata['py'].shape = (nf * 16 * 3, nt)
    return cdata
Esempio n. 10
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
Esempio n. 11
0
def apply_calfac(data, calfac):
    ''' Applies calibration factors in calfac dictionary returned by get_calfac(),
        to the data and returns the calibrated data in the same form.  No calibration
        can be applied for antennas/frequencies in data that are not included in
        calfac, so for those the data are returned unchanged, except the correlated
        data for missing frequencies are flagged.
        
        Inputs:
            data    The data to be calibrated
            calfac  The calfac dictionary returned by a call to get_calfac().
            
        Output:
            cdata   The calibrated data
            
        N.B.:  The offsun level needs to be subtracted to calibrate power and 
               auto-correlation, but this is not done here.  Instead, one must
               later read the calfac dictionary using get_calfac(), and then
               subtract tpoffsun*tpcalfac from power, and acoffsun*accalfac from 
               auto-correlation.
    '''
    import copy
    from util import common_val_idx, bl2ord
    fghz = data['fghz']
    nfin = len(fghz)
    # Find common frequencies
    idx1, idx2 = common_val_idx(fghz, calfac['fghz'], precision=4)
    nf = len(idx1)
    missing = np.setdiff1d(np.arange(len(fghz)), idx1)
    nant = 16
    nblant = nant * (nant - 1) / 2 + nant
    blfac = np.ones(
        (nf, nblant, 4),
        float)  # Factors for missing antennas/frequencies are set to unity
    fac = calfac['accalfac'][:, :, idx2]  # Extract only common frequencies
    for i in range(13):
        for j in range(i, 13):
            blfac[idx1, bl2ord[i, j], 0] = np.sqrt(fac[i, 0] * fac[j, 0])
            blfac[idx1, bl2ord[i, j], 1] = np.sqrt(fac[i, 1] * fac[j, 1])
            blfac[idx1, bl2ord[i, j], 2] = np.sqrt(fac[i, 0] * fac[j, 1])
            blfac[idx1, bl2ord[i, j], 3] = np.sqrt(fac[i, 1] * fac[j, 0])
    antfac = np.ones(
        (nf, nant, 2),
        float)  # Factors for missing antennas/frequencies are set to unity
    for i in range(13):
        for j in range(2):
            antfac[idx1, i, j] = calfac['tpcalfac'][i, j, idx2]
    cdata = copy.deepcopy(data)
    nt = len(data['time'])
    # Calibrate the auto- and cross-correlation data
    for i in range(nt):
        cdata['x'][idx1, :, :, i] *= blfac
    # Reshape px and py arrays
    cdata['px'].shape = (nfin, 16, 3, nt)
    cdata['py'].shape = (nfin, 16, 3, nt)
    for i in range(nt):
        # Correct the power
        cdata['px'][idx1, :, 0, i] *= antfac[:, :, 0]
        cdata['py'][idx1, :, 0, i] *= antfac[:, :, 1]
        # Correct the power-squared
        cdata['px'][idx1, :, 1, i] *= antfac[:, :, 0]**2
        cdata['py'][idx1, :, 1, i] *= antfac[:, :, 1]**2
    # Reshape px and py arrays back to original
    cdata['px'].shape = (nfin * 16 * 3, nt)
    cdata['py'].shape = (nfin * 16 * 3, nt)
    # Set flags for any missing frequencies (hopefully this also works when "missing" is np.array([]))
    cdata['x'][missing] = np.ma.masked
    return cdata
Esempio n. 12
0
def apply_calfac(data, calfac):
    ''' Applies calibration factors in calfac dictionary returned by get_calfac(),
        to the data and returns the calibrated data in the same form.  No calibration
        can be applied for antennas/frequencies in data that are not included in
        calfac, so for those the data are returned unchanged, except the correlated
        data for missing frequencies are flagged.
        
        Inputs:
            data    The data to be calibrated
            calfac  The calfac dictionary returned by a call to get_calfac().
            
        Output:
            cdata   The calibrated data
            
        N.B.:  Spectral Kurtosis is no longer valid after applying calibration
    '''
    import copy
    fghz = data['fghz']
    nfin = len(fghz)
    # Find common frequencies
    idx1, idx2 = common_val_idx(fghz, calfac['fghz'], precision=4)
    nf = len(idx1)
    missing = np.setdiff1d(np.arange(len(fghz)), idx1)
    nant = 16
    nblant = nant * (nant - 1) / 2 + nant
    blfac = np.ones(
        (nf, nblant, 4),
        float)  # Factors for missing antennas/frequencies are set to unity
    bloff = np.zeros(
        (nf, nblant, 4),
        float)  # Offsun values (will be zero except for auto-correlations)
    fac = calfac['accalfac'][:, :, idx2]  # Extract only common frequencies
    acoffsun = calfac['acoffsun'][:, :,
                                  idx2]  # Extract only common frequencies
    nsolant = 13  # Number of solar antennas
    for i in range(nsolant):
        for j in range(i, nsolant):
            blfac[idx1, bl2ord[i, j], 0] = np.sqrt(fac[i, 0] * fac[j, 0])
            blfac[idx1, bl2ord[i, j], 1] = np.sqrt(fac[i, 1] * fac[j, 1])
            blfac[idx1, bl2ord[i, j], 2] = np.sqrt(fac[i, 0] * fac[j, 1])
            blfac[idx1, bl2ord[i, j], 3] = np.sqrt(fac[i, 1] * fac[j, 0])
            if i == j:
                bloff[idx1, bl2ord[i, j], 0] = acoffsun[j, 0]
                bloff[idx1, bl2ord[i, j], 1] = acoffsun[j, 1]
    antfac = np.ones(
        (nf, nant, 2),
        float)  # Factors for missing antennas/frequencies are set to unity
    offsun = np.zeros(
        (nf, nant, 2),
        float)  # Offsun for missing antennas/frequencies are set to zero
    for i in range(nsolant):
        for j in range(2):
            antfac[idx1, i, j] = calfac['tpcalfac'][i, j, idx2]
            offsun[idx1, i, j] = calfac['tpoffsun'][i, j, idx2]
    cdata = copy.deepcopy(data)
    nt = len(data['time'])
    # Calibrate the auto- and cross-correlation data
    # Note that bloff is non-zero only for the real part of auto-correlations
    for i in range(nt):
        cdata['x'][idx1, :, :, i] = (cdata['x'][idx1, :, :, i] - bloff) * blfac
    # Reshape px and py arrays
    cdata['px'].shape = (nfin, 16, 3, nt)
    cdata['py'].shape = (nfin, 16, 3, nt)
    for i in range(nt):
        # Correct the power
        cdata['px'][idx1, :, 0, i] = (cdata['px'][idx1, :, 0, i] -
                                      offsun[:, :, 0]) * antfac[:, :, 0]
        cdata['py'][idx1, :, 0, i] = (cdata['py'][idx1, :, 0, i] -
                                      offsun[:, :, 1]) * antfac[:, :, 1]
        # Zero-out the power-squared, since SK is no longer valid after applying calibration
        cdata['px'][idx1, :, 1, i] = 0.0
        cdata['py'][idx1, :, 1, i] = 0.0
    # Reshape px and py arrays back to original
    cdata['px'].shape = (nfin * 16 * 3, nt)
    cdata['py'].shape = (nfin * 16 * 3, nt)
    # Set flags for any missing frequencies (hopefully this also works when "missing" is np.array([]))
    cdata['x'][missing] = np.ma.masked
    return cdata
Esempio n. 13
0
def apply_fem_level(data, gctime=None, skycal=None):
    ''' Applys the FEM level corrections to the given data dictionary.
        
        Inputs:
          data     A dictionary such as that returned by readXdata().
          gctime   A Time() object whose date specifies which GAINCALTEST
                     measurements to use.  If omitted, the date of the data
                     is used.
          skycal   Optional array of receiver noise from SKYCAL or GAINCAL
                     calibration.  Only the receiver noise is applied (subtracted)

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

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

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

    idx = nearest_val_idx(data['time'], src_lev['times'].jd)
    nt = len(idx)  # New number of times
    # If a skycal dictionary exists, subtract auto-correlation receiver noise before scaling (clip to 0)
    if skycal:
        sna, snp, snf = skycal['rcvr_bgd_auto'].shape
        bgd = skycal['rcvr_bgd_auto'].repeat(nt).reshape((sna, snp, snf, nt))
        bgd = bgd[:, :, idx2]  # Extract only frequencies matching the data
        # Reorder axes
        bgd = np.swapaxes(bgd, 0, 2)
        #        bslice = bgd[:,:,:,idx]
        for i in range(13):
            cdata['x'][:, bl2ord[i, i], 0] = np.clip(
                cdata['x'][:, bl2ord[i, i], 0] - bgd[:, 0, i], 0,
                None)  #bslice[:,0,i],0,None)
            cdata['x'][:, bl2ord[i, i], 1] = np.clip(
                cdata['x'][:, bl2ord[i, i], 1] - bgd[:, 1, i], 0,
                None)  #bslice[:,1,i],0,None)
    # Correct the auto- and cross-correlation data
    cdata['x'] *= blgain[:, :, :, idx]
    # Reshape px and py arrays
    cdata['px'].shape = (nf, 16, 3, nt)
    cdata['py'].shape = (nf, 16, 3, nt)
    # If a skycal dictionary exists, subtract total power receiver noise before scaling (clip to 0)
    # NB: This will break SK!
    if skycal:
        sna, snp, snf = skycal['rcvr_bgd'].shape
        bgd = skycal['rcvr_bgd'].repeat(nt).reshape((sna, snp, snf, nt))
        bgd = bgd[:, :, idx2]  # Extract only frequencies matching the data
        # Reorder axes
        bgd = np.swapaxes(bgd, 0, 2)
        #bslice = bgd[:,:,:,idx]
        #bgnd = np.rollaxis(bslice,3)
        cdata['px'][:, :13, 0] = np.clip(cdata['px'][:, :13, 0] - bgd[:, 0], 0,
                                         None)  #bslice[:,0],0,None)
        cdata['py'][:, :13, 0] = np.clip(cdata['py'][:, :13, 0] - bgd[:, 1], 0,
                                         None)  #bslice[:,1],0,None)
    # Correct the power
    cdata['px'][:, :15, 0] *= antgainf[:, :, 0, idx]
    cdata['py'][:, :15, 0] *= antgainf[:, :, 1, idx]
    # Correct the power-squared
    cdata['px'][:, :15, 1] *= antgainf[:, :, 0, idx]**2
    cdata['py'][:, :15, 1] *= antgainf[:, :, 1, idx]**2
    # Reshape px and py arrays back to original
    cdata['px'].shape = (nf * 16 * 3, nt)
    cdata['py'].shape = (nf * 16 * 3, nt)
    return cdata