def main(args): # Setup the LWA station information if args.metadata is not None: try: station = stations.parse_ssmif(args.metadata) except ValueError: try: station = metabundle.get_station(args.metadata, apply_sdm=True) except: station = metabundleADP.get_station(args.metadata, apply_sdm=True) elif args.lwasv: station = stations.lwasv else: station = stations.lwa1 antennas = [] for ant in station.antennas[0::2]: if ant.combined_status == 33: antennas.append(ant) print("Displaying uv coverage for %i good stands" % len(antennas)) HA = 0.0 dec = station.lat * 180.0 / math.pi uvw = uvutils.compute_uvw(antennas, HA=HA, dec=dec, freq=args.frequency) uvw = numpy.squeeze(uvw[:, :, 0]) # Coursely grid the uv data to come up with a rough beam grid = numpy.zeros((1 * 240, 1 * 240)) for i in range(uvw.shape[0]): u = round((uvw[i, 0] + 120) * 1) v = round((uvw[i, 1] + 120) * 1) try: grid[u, v] += 1 except IndexError: pass # Plot # Part 1 - Setup fig = plt.figure(figsize=(8, 8)) ax1 = plt.axes([0.30, 0.30, 0.60, 0.60]) ax2 = plt.axes([0.30, 0.05, 0.60, 0.15]) ax3 = plt.axes([0.05, 0.30, 0.15, 0.60]) ax4 = plt.axes([0.08, 0.08, 0.15, 0.15]) ax5 = plt.axes([0.32, 0.32, 0.15, 0.15]) # Part 2 - Beam response (in dB) beam = numpy.fft.fft2(grid) beam = numpy.fft.fftshift(beam) beam = numpy.abs(beam)**2 beam = numpy.log10(beam) * 10.0 ax5.imshow(beam[40:200, 40:200], interpolation="nearest", vmin=numpy.median(beam), vmax=beam.max()) ax5.xaxis.set_major_formatter(NullFormatter()) ax5.yaxis.set_major_formatter(NullFormatter()) # Part 3 - uv plane plot c = ax1.scatter(uvw[:, 0], uvw[:, 1], c=uvw[:, 2], s=10.0, alpha=0.75) d = ax1.scatter(-uvw[:, 0], -uvw[:, 1], c=-uvw[:, 2], s=10.0, alpha=0.75) ax1.set_xlabel('u [$\\lambda$]') ax1.set_ylabel('v [$\\lambda$]') ax1.set_title( 'UV Coverage for HA=%+.3f$^h$, $\delta$=%+.3f$^\circ$ at %s' % (HA, dec, station.name)) # Part 4 - uw plane plot ax2.scatter(uvw[:, 0], uvw[:, 2], c=uvw[:, 2], s=10.0) ax2.scatter(-uvw[:, 0], -uvw[:, 2], c=-uvw[:, 2], s=10.0) ax2.xaxis.set_major_formatter(NullFormatter()) ax2.set_ylabel('w [$\\lambda$]') # Part 5 - wv plane plot ax3.scatter(uvw[:, 2], uvw[:, 1], c=uvw[:, 2], s=10.0) ax3.scatter(-uvw[:, 2], -uvw[:, 1], c=-uvw[:, 2], s=10.0) ax3.yaxis.set_major_formatter(NullFormatter()) ax3.set_xlabel('w [$\\lambda$]') # Part 6 - Histogram of uvw distances in lambda rad = numpy.zeros(uvw.shape[0]) for i in range(rad.shape[0]): rad[i] = math.sqrt(uvw[i, 0]**2.0 + uvw[i, 1]**2.0 + uvw[i, 2]**2.0) try: ax4.hist(rad, 20) except TypeError: ## I don't know why this happens pass ax4.set_xlabel('uvw Radius [$\lambda$]') ax4.set_ylabel('Baselines') # Plot adjustment xlim = ax1.get_xlim() ylim = ax1.get_ylim() ax1.set_xlim([ numpy.floor(xlim[0] / 25.0) * 25.0, numpy.ceil(xlim[1] / 25.0) * 25.0 ]) ax1.set_ylim([ numpy.floor(ylim[0] / 25.0) * 25.0, numpy.ceil(ylim[1] / 25.0) * 25.0 ]) ax2.set_xlim(ax1.get_xlim()) ax2.yaxis.set_major_locator(MaxNLocator(nbins=4)) ax3.set_ylim(ax1.get_ylim()) ax3.xaxis.set_major_locator(MaxNLocator(nbins=4)) xlim = ax4.get_xlim() ylim = ax4.get_ylim() ax4.set_xlim([ numpy.floor(xlim[0] / 25.0) * 25.0, numpy.ceil(xlim[1] / 25.0) * 25.0 ]) ax4.set_ylim([ numpy.floor(ylim[0] / 5.e3) * 5.e3, numpy.ceil(ylim[1] / 5.e3) * 5.e3 ]) ax4.xaxis.set_major_locator(MaxNLocator(nbins=4)) ax4.yaxis.set_major_locator(MaxNLocator(nbins=4)) # Show n' save plt.show() if args.output is not None: fig.savefig(args.output)
def main(args): # Parse command line options filename = args.filename # Setup the LWA station information if args.metadata is not None: try: station = stations.parse_ssmif(args.metadata) except ValueError: station = metabundleADP.get_station(args.metadata, apply_sdm=True) else: station = stations.lwasv antennas = station.antennas idf = LWASVDataFile(filename) if not isinstance(idf, TBFFile): raise RuntimeError("File '%s' does not appear to be a valid TBF file" % os.path.basename(filename)) jd = idf.get_info('start_time').jd date = idf.get_info('start_time').datetime nFpO = idf.get_info('nchan') // 12 sample_rate = idf.get_info('sample_rate') nInts = idf.get_info('nframe') // nFpO # Get valid stands for both polarizations goodX = [] goodY = [] for i in range(len(antennas)): ant = antennas[i] if ant.combined_status != 33 and not args.all: pass else: if ant.pol == 0: goodX.append(ant) else: goodY.append(ant) # Now combine both lists to come up with stands that # are in both so we can form the cross-polarization # products if we need to good = [] for antX in goodX: for antY in goodY: if antX.stand.id == antY.stand.id: good.append(antX.digitizer - 1) good.append(antY.digitizer - 1) # Report on the valid stands found. This is a little verbose, # but nice to see. print("Found %i good stands to use" % (len(good) // 2, )) for i in good: print("%3i, %i" % (antennas[i].stand.id, antennas[i].pol)) # Number of frames to read in at once and average nFrames = min([int(args.avg_time * sample_rate), nInts]) args.offset = idf.offset(args.offset) nSets = idf.get_info('nframe') // nFpO // nFrames nSets = nSets - int(args.offset * sample_rate) // nFrames central_freq = idf.get_info('freq1') central_freq = central_freq[len(central_freq) // 2] print("Data type: %s" % type(idf)) print("Samples per observations: %i" % nFpO) print("Sampling rate: %i Hz" % sample_rate) print("Tuning frequency: %.3f Hz" % central_freq) print("Captures in file: %i (%.3f s)" % (nInts, nInts / sample_rate)) print("==") print("Station: %s" % station.name) print("Date observed: %s" % date) print("Julian day: %.5f" % jd) print("Offset: %.3f s (%i frames)" % (args.offset, args.offset * sample_rate)) print("Integration Time: %.3f s" % (nFrames / sample_rate)) print("Number of integrations in file: %i" % nSets) # Make sure we don't try to do too many sets if args.samples > nSets: args.samples = nSets # Loop over junks of 100 integrations to make sure that we don't overflow # the FITS IDI memory buffer s = 0 leftToDo = args.samples basename = os.path.split(filename)[1] basename, ext = os.path.splitext(basename) while leftToDo > 0: fitsFilename = "%s.FITS_%i" % ( basename, (s + 1), ) if leftToDo > 100: chunk = 100 else: chunk = leftToDo process_chunk(idf, station, good, fitsFilename, int_time=args.avg_time, pols=args.products, chunk_size=chunk) s += 1 leftToDo = leftToDo - chunk idf.close()
def main(args): # Setup the LWA station information if args.metadata is not None: try: station = stations.parse_ssmif(args.metadata) except ValueError: try: station = metabundle.get_station(args.metadata, apply_sdm=True) except: station = metabundleADP.get_station(args.metadata, apply_sdm=True) elif args.lwasv: station = stations.lwasv else: station = stations.lwa1 antennas = station.antennas # Length of the FFT LFFT = args.fft_length idf = LWADataFile(args.filename) if not isinstance(idf, TBNFile): raise RuntimeError("File '%s' does not appear to be a valid TBN file" % os.path.basename(filename)) nFramesFile = idf.get_info('nframe') srate = idf.get_info('sample_rate') antpols = len(antennas) # Offset in frames for beampols beam/tuning/pol. sets args.skip = idf.offset(args.skip) # Make sure that the file chunk size contains is an integer multiple # of the FFT length so that no data gets dropped. This needs to # take into account the number of antpols in the data, the FFT length, # and the number of samples per frame. maxFrames = int( (2 * 260 * 750) / antpols * 512 / float(LFFT)) * LFFT / 512 * antpols # Number of frames to integrate over nFrames = int(args.average * srate / 512) * antpols nFrames = int( 1.0 * (nFrames // antpols) * 512 / float(LFFT)) * LFFT / 512 * antpols args.average = 1.0 * (nFrames // antpols) * 512 / srate # Number of remaining chunks nChunks = int(math.ceil(1.0 * (nFrames) / maxFrames)) # Read in the first frame and get the date/time of the first sample # of the frame. This is needed to get the list of stands. beginDate = idf.get_info('start_time').datetime central_freq = idf.get_info('freq1') # File summary print("Filename: %s" % args.filename) print("Date of First Frame: %s" % str(beginDate)) print("Ant/Pols: %i" % antpols) print("Sample Rate: %i Hz" % srate) print("Tuning Frequency: %.3f Hz" % central_freq) print("Frames: %i (%.3f s)" % (nFramesFile, 1.0 * nFramesFile / antpols * 512 / srate)) print("---") print("Offset: %.3f s (%i frames)" % (args.skip, args.skip * srate * antpols / 512)) print("Integration: %.3f s (%i frames; %i frames per stand/pol)" % (args.average, nFrames, nFrames / antpols)) print("Chunks: %i" % nChunks) # Sanity check if args.skip * srate * antpols / 512 > nFramesFile: raise RuntimeError("Requested offset is greater than file length") if nFrames > (nFramesFile - args.skip * srate * antpols / 512): raise RuntimeError( "Requested integration time+offset is greater than file length") # Setup the window function to use if args.bartlett: window = numpy.bartlett elif args.blackman: window = numpy.blackman elif args.hanning: window = numpy.hanning else: window = fxc.null_window # Master loop over all of the file chunks masterWeight = numpy.zeros((nChunks, antpols, LFFT)) masterSpectra = numpy.zeros((nChunks, antpols, LFFT)) for i in range(nChunks): print("Working on chunk #%i of %i" % (i + 1, nChunks)) try: readT, t, data = idf.read(args.average / nChunks) except Exception as e: print("Error: %s" % str(e)) continue # Calculate the spectra for this block of data and then weight the results by # the total number of frames read. This is needed to keep the averages correct. freq, tempSpec = fxc.SpecMaster(data, LFFT=LFFT, window=window, pfb=args.pfb, verbose=args.verbose, sample_rate=srate) for stand in range(tempSpec.shape[0]): masterSpectra[i, stand, :] = tempSpec[stand, :] masterWeight[i, stand, :] = int(readT * srate / LFFT) # Apply the cable loss corrections, if requested if args.gain_correct: for s in range(masterSpectra.shape[1]): currGain = antennas[s].cable.gain(freq) for c in range(masterSpectra.shape[0]): masterSpectra[c, s, :] /= currGain # Now that we have read through all of the chunks, perform the final averaging by # dividing by all of the chunks spec = numpy.squeeze( (masterWeight * masterSpectra).sum(axis=0) / masterWeight.sum(axis=0)) # Put the frequencies in the best units possible freq += central_freq freq, units = _best_freq_units(freq) # Deal with the `keep` options if args.keep == 'all': antpolsDisp = int(numpy.ceil(antpols / 20)) js = [i for i in range(antpols)] else: antpolsDisp = int(numpy.ceil(len(args.keep) * 2 / 20)) if antpolsDisp < 1: antpolsDisp = 1 js = [] for k in args.keep: for i, ant in enumerate(antennas): if ant.stand.id == k: js.append(i) nPlot = len(js) if nPlot < 20: if nPlot % 4 == 0 and nPlot != 4: figsY = 4 else: figsY = 2 figsX = int(numpy.ceil(1.0 * nPlot / figsY)) else: figsY = 4 figsX = 5 figsN = figsX * figsY for i in range(antpolsDisp): # Normal plotting fig = plt.figure() for k in range(i * figsN, i * figsN + figsN): try: j = js[k] currSpectra = numpy.squeeze(numpy.log10(spec[j, :]) * 10.0) except IndexError: break ax = fig.add_subplot(figsX, figsY, (k % figsN) + 1) ax.plot( freq, currSpectra, label='Stand: %i, Pol: %i (Dig: %i)' % (antennas[j].stand.id, antennas[j].pol, antennas[j].digitizer)) # If there is more than one chunk, plot the difference between the global # average and each chunk if nChunks > 1 and not args.disable_chunks: for l in range(nChunks): # Some files are padded by zeros at the end and, thus, carry no # weight in the average spectra. Skip over those. if masterWeight[l, j, :].sum() == 0: continue # Calculate the difference between the spectra and plot subspectra = numpy.squeeze( numpy.log10(masterSpectra[l, j, :]) * 10.0) diff = subspectra - currSpectra ax.plot(freq, diff) ax.set_title('Stand: %i (%i); Dig: %i [%i]' % (antennas[j].stand.id, antennas[j].pol, antennas[j].digitizer, antennas[j].combined_status)) ax.set_xlabel('Frequency [%s]' % units) ax.set_ylabel('P.S.D. [dB/RBW]') ax.set_ylim([-10, 30]) # Save spectra image if requested if args.output is not None: base, ext = os.path.splitext(args.output) outFigure = "%s-%02i%s" % (base, i + 1, ext) fig.savefig(outFigure) plt.draw() print("RBW: %.4f %s" % ((freq[1] - freq[0]), units)) plt.show()
def main(args): # Parse command line toMark = numpy.array(args.stand)-1 # Setup the LWA station information if args.metadata is not None: try: station = stations.parse_ssmif(args.metadata) except ValueError: try: station = metabundle.get_station(args.metadata, apply_sdm=True) except: station = metabundleADP.get_station(args.metadata, apply_sdm=True) elif args.lwasv: station = stations.lwasv else: station = stations.lwa1 stands = station.stands stands.sort() # Load in the stand position data data = numpy.zeros((len(stands)//2,3)) i = 0 for stand in stands[::2]: data[i,0] = stand.x data[i,1] = stand.y data[i,2] = stand.z i += 1 # Color-code the stands by their elevation color = data[:,2] # Plot the stands as colored circles fig = plt.figure(figsize=(8,8)) ax1 = plt.axes([0.30, 0.30, 0.60, 0.60]) ax2 = plt.axes([0.30, 0.05, 0.60, 0.15]) ax3 = plt.axes([0.05, 0.30, 0.15, 0.60]) ax4 = plt.axes([0.05, 0.05, 0.15, 0.15]) c = ax1.scatter(data[:,0], data[:,1], c=color, s=40.0, alpha=0.50) ax1.set_xlabel('$\Delta$X [E-W; m]') ax1.set_xlim([-80, 80]) ax1.set_ylabel('$\Delta$Y [N-S; m]') ax1.set_ylim([-80, 80]) ax1.set_title('%s Site: %.3f$^\circ$N, %.3f$^\circ$W' % (station.name, station.lat*180.0/numpy.pi, -station.long*180.0/numpy.pi)) ax2.scatter(data[:,0], data[:,2], c=color, s=40.0) ax2.xaxis.set_major_formatter( NullFormatter() ) ax2.set_ylabel('$\Delta$Z [m]') ax3.scatter(data[:,2], data[:,1], c=color, s=40.0) ax3.yaxis.set_major_formatter( NullFormatter() ) ax3.set_xlabel('$\Delta$Z [m]') # Explicitly mark those that need to be marked if toMark.size != 0: for i in range(toMark.size): ax1.plot(data[toMark[i],0], data[toMark[i],1], marker='x', linestyle=' ', color='black') ax2.plot(data[toMark[i],0], data[toMark[i],2], marker='x', linestyle=' ', color='black') ax3.plot(data[toMark[i],2], data[toMark[i],1], marker='x', linestyle=' ', color='black') if args.label: ax1.annotate('%i' % (toMark[i]+1), xy=(data[toMark[i],0], data[toMark[i],1]), xytext=(data[toMark[i],0]+1, data[toMark[i],1]+1)) # Add and elevation colorbar to the right-hand side of the figure plt.colorbar(c, cax=ax4, orientation='vertical', ticks=[-2, -1, 0, 1, 2]) # Set the axis limits ax1.set_xlim([-60, 60]) ax1.set_ylim([-60, 60]) ax2.set_xlim( ax1.get_xlim() ) ax3.set_ylim( ax1.get_ylim() ) # Show n' save plt.show() if args.output is not None: fig.savefig(args.output)
def main(args): # Setup the LWA station information if args.metadata is not None: try: station = stations.parse_ssmif(args.metadata) except ValueError: station = metabundleADP.get_station(args.metadata, apply_sdm=True) else: station = stations.lwasv antennas = station.antennas fh = open(args.filename, 'rb') nFrames = os.path.getsize(args.filename) / tbf.FRAME_SIZE antpols = len(antennas) # Read in the first frame and get the date/time of the first sample # of the frame. This is needed to get the list of stands. junkFrame = tbf.read_frame(fh) fh.seek(0) beginDate = junkFrame.time.datetime # Figure out how many frames there are per observation and the number of # channels that are in the file nFramesPerObs = tbf.get_frames_per_obs(fh) nchannels = tbf.get_channel_count(fh) nSamples = 7840 # Figure out how many chunks we need to work with nChunks = nFrames / nFramesPerObs # Pre-load the channel mapper mapper = [] for i in range(2*nFramesPerObs): cFrame = tbf.read_frame(fh) if cFrame.header.first_chan not in mapper: mapper.append( cFrame.header.first_chan ) fh.seek(-2*nFramesPerObs*tbf.FRAME_SIZE, 1) mapper.sort() # Calculate the frequencies freq = numpy.zeros(nchannels) for i,c in enumerate(mapper): freq[i*12:i*12+12] = c + numpy.arange(12) freq *= 25e3 # File summary print("Filename: %s" % args.filename) print("Date of First Frame: %s" % str(beginDate)) print("Frames per Observation: %i" % nFramesPerObs) print("Channel Count: %i" % nchannels) print("Frames: %i" % nFrames) print("===") print("Chunks: %i" % nChunks) spec = numpy.zeros((nchannels,256,2)) norm = numpy.zeros_like(spec) for i in range(nChunks): # Inner loop that actually reads the frames into the data array for j in range(nFramesPerObs): # Read in the next frame and anticipate any problems that could occur try: cFrame = tbf.read_frame(fh) except errors.EOFError: break except errors.SyncError: print("WARNING: Mark 5C sync error on frame #%i" % (int(fh.tell())/tbf.FRAME_SIZE-1)) continue if not cFrame.header.is_tbf: continue first_chan = cFrame.header.first_chan # Figure out where to map the channel sequence to try: aStand = mapper.index(first_chan) except ValueError: mapper.append(first_chan) aStand = mapper.index(first_chan) # Actually load the data. spec[aStand*12:aStand*12+12,:,:] += numpy.abs(cFrame.payload.data)**2 norm[aStand*12:aStand*12+12,:,:] += 1 spec /= norm fh.close() # Reshape and transpose to get it in to a "normal" order spec.shape = (spec.shape[0], spec.shape[1]*spec.shape[2]) spec = spec.T # Apply the cable loss corrections, if requested if False: for s in range(spec.shape[0]): currGain = antennas[s].cable.gain(freq) spec[s,:] /= currGain # Put the frequencies in the best units possible freq, units = _best_freq_units(freq) # Deal with the `keep` options if args.keep == 'all': antpolsDisp = int(numpy.ceil(antpols/20)) js = [i for i in range(antpols)] else: antpolsDisp = int(numpy.ceil(len(args.keep)*2/20)) if antpolsDisp < 1: antpolsDisp = 1 js = [] for k in args.keep: for i,ant in enumerate(antennas): if ant.stand.id == k: js.append(i) nPlot = len(js) if nPlot < 16: if nPlot % 4 == 0 and nPlot != 4: figsY = 4 else: figsY = 2 figsX = int(numpy.ceil(1.0*nPlot/figsY)) else: figsY = 4 figsX = 4 figsN = figsX*figsY for i in range(antpolsDisp): # Normal plotting fig = plt.figure() for k in range(i*figsN, i*figsN+figsN): try: j = js[k] currSpectra = numpy.squeeze( numpy.log10(spec[j,:])*10.0 ) except IndexError: break ax = fig.add_subplot(figsX, figsY, (k%figsN)+1) ax.plot(freq, currSpectra, label='Stand: %i, Pol: %i (Dig: %i)' % (antennas[j].stand.id, antennas[j].pol, antennas[j].digitizer)) ax.set_title('Stand: %i (%i); Dig: %i [%i]' % (antennas[j].stand.id, antennas[j].pol, antennas[j].digitizer, antennas[j].combined_status)) ax.set_xlabel('Frequency [%s]' % units) ax.set_ylabel('P.S.D. [dB/RBW]') ax.set_ylim([-10, 30]) # Save spectra image if requested if args.output is not None: base, ext = os.path.splitext(args.output) outFigure = "%s-%02i%s" % (base, i+1, ext) fig.savefig(outFigure) plt.draw() print("RBW: %.4f %s" % ((freq[1]-freq[0]), units)) plt.show()
def test_station(self): """Test building a station from a tarball.""" station = metabundleADP.get_station(mdbFileADP)