def simulate_gaintable(gt: GainTable, phase_error=0.1, amplitude_error=0.0, leakage=0.0) -> GainTable: """ Simulate a gain table :type gt: GainTable :param phase_error: std of normal distribution, zero mean :param amplitude_error: std of log normal distribution :param leakage: std of cross hand leakage """ log.info("simulate_gaintable: Simulating amplitude error = %.4f, phase error = %.4f" % (amplitude_error, phase_error)) amp = 1.0 phasor = 1.0 if phase_error: phasor = numpy.exp(1j * numpy.random.normal(0, phase_error, gt.data['gain'].shape)) if amplitude_error > 0.0: amp = numpy.random.lognormal(mean=0.0, sigma=amplitude_error, size=gt.data['gain'].shape) gt.data['gain'] = amp * phasor nrec = gt.data['gain'].shape[-1] if nrec > 1: if leakage > 0.0: leak = numpy.random.normal(0, leakage, gt.data['gain'][..., 0, 0].shape) + 1j * \ numpy.random.normal(0, leakage, gt.data['gain'][..., 0, 0].shape) gt.data['gain'][..., 0, 1] = gt.data['gain'][..., 0, 0] * leak leak = numpy.random.normal(0, leakage, gt.data['gain'][..., 1, 1].shape) + 1j * \ numpy.random.normal(0, leakage, gt.data['gain'][..., 1, 1].shape) gt.data['gain'][..., 1, 0] = gt.data['gain'][..., 1, 1] * leak else: gt.data['gain'][..., 0, 1] = 0.0 gt.data['gain'][..., 1, 0] = 0.0 return gt
def create_gaintable_from_rows(gt: GainTable, rows: numpy.ndarray, makecopy=True) -> GainTable: """ Create a GainTable from selected rows :param gt: GainTable :param rows: Boolean array of row selection :param makecopy: Make a deep copy (True) :return: GainTable """ if rows is None or numpy.sum(rows) == 0: return None assert len( rows ) == gt.ntimes, "Length of rows does not agree with length of GainTable" assert isinstance(gt, GainTable), gt if makecopy: newgt = copy_gaintable(gt) newgt.data = copy.deepcopy(gt.data[rows]) return newgt else: gt.data = copy.deepcopy(gt.data[rows]) return gt
def test_create_gaintable_from_other(self): for timeslice in [10.0, 'auto', 1e5]: for spf, dpf in [('stokesIQUV', 'linear')]: self.actualSetup(spf, dpf) gt = create_gaintable_from_blockvisibility(self.vis, timeslice=timeslice) log.info("Created gain table: %s" % (gaintable_summary(gt))) new_gt = GainTable(data=gt.data) assert new_gt.data.shape == gt.data.shape
def append_gaintable(gt: GainTable, othergt: GainTable) -> GainTable: """Append othergt to gt :param gt: :param othergt: :return: GainTable gt + othergt """ assert gt.receptor_frame == othergt.receptor_frame gt.data = numpy.hstack((gt.data, othergt.data)) return gt
def create_gaintable_from_blockvisibility(vis: BlockVisibility, time_width: float = None, frequency_width: float = None, **kwargs) -> GainTable: """ Create gain table from visibility. This makes an empty gain table consistent with the BlockVisibility. :param vis: BlockVisibilty :param time_width: Time interval between solutions (s) :param frequency_width: Frequency solution width (Hz) :return: GainTable """ assert isinstance( vis, BlockVisibility), "vis is not a BlockVisibility: %r" % vis nants = vis.nants utimes = numpy.unique(vis.time) ntimes = len(utimes) ufrequency = numpy.unique(vis.frequency) nfrequency = len(ufrequency) receptor_frame = ReceptorFrame(vis.polarisation_frame.type) nrec = receptor_frame.nrec gainshape = [ntimes, nants, nfrequency, nrec, nrec] gain = numpy.ones(gainshape, dtype='complex') if nrec > 1: gain[..., 0, 1] = 0.0 gain[..., 1, 0] = 0.0 gain_weight = numpy.ones(gainshape) gain_time = utimes gain_frequency = ufrequency gain_residual = numpy.zeros([ntimes, nfrequency, nrec, nrec]) gt = GainTable(gain=gain, time=gain_time, weight=gain_weight, residual=gain_residual, frequency=gain_frequency, receptor_frame=receptor_frame) assert isinstance(gt, GainTable), "gt is not a GainTable: %r" % gt assert_vis_gt_compatible(vis, gt) return gt
def create_gaintable_from_blockvisibility(vis: BlockVisibility, timeslice: float = None, frequencyslice: float = None, **kwargs) -> GainTable: """ Create gain table from visibility. This makes an empty gain table consistent with the BlockVisibility. :param vis: BlockVisibilty :param timeslice: Time interval between solutions (s) :param frequency_width: Frequency solution width (Hz) :return: GainTable """ assert isinstance( vis, BlockVisibility), "vis is not a BlockVisibility: %r" % vis nants = vis.nants if timeslice is None or timeslice == 'auto': utimes = numpy.unique(vis.time) ntimes = len(utimes) gain_interval = numpy.zeros([ntimes]) if ntimes > 1: gain_interval[:-1] = utimes[1:] - utimes[0:-1] gain_interval[-1] = utimes[-1] - utimes[-2] else: gain_interval[...] = 1.0 else: ntimes = numpy.ceil((numpy.max(vis.time) - numpy.min(vis.time)) / timeslice).astype('int') utimes = numpy.linspace(numpy.min(vis.time), numpy.max(vis.time), ntimes) gain_interval = timeslice * numpy.ones([ntimes]) log.debug('create_gaintable_from_blockvisibility: times are %s' % str(utimes)) log.debug('create_gaintable_from_blockvisibility: intervals are %s' % str(gain_interval)) ntimes = len(utimes) ufrequency = numpy.unique(vis.frequency) nfrequency = len(ufrequency) receptor_frame = ReceptorFrame(vis.polarisation_frame.type) nrec = receptor_frame.nrec gainshape = [ntimes, nants, nfrequency, nrec, nrec] gain = numpy.ones(gainshape, dtype='complex') if nrec > 1: gain[..., 0, 1] = 0.0 gain[..., 1, 0] = 0.0 gain_weight = numpy.ones(gainshape) gain_time = utimes gain_frequency = ufrequency gain_residual = numpy.zeros([ntimes, nfrequency, nrec, nrec]) gt = GainTable(gain=gain, time=gain_time, interval=gain_interval, weight=gain_weight, residual=gain_residual, frequency=gain_frequency, receptor_frame=receptor_frame) assert isinstance(gt, GainTable), "gt is not a GainTable: %r" % gt assert_vis_gt_compatible(vis, gt) return gt
def gaintable_summary(gt: GainTable): """Return string summarizing the Gaintable """ return "%s rows, %.3f GB" % (gt.data.shape, gt.size())
def simulate_gaintable(gt: GainTable, phase_error=0.1, amplitude_error=0.0, smooth_channels=1, leakage=0.0, seed=180555, **kwargs) -> GainTable: """ Simulate a gain table :type gt: GainTable :param phase_error: std of normal distribution, zero mean :param amplitude_error: std of log normal distribution :param leakage: std of cross hand leakage :param seed: Seed for random numbers def: 180555 :param smooth_channels: Use bspline over smooth_channels :param kwargs: :return: Gaintable """ def moving_average(a, n=3): return numpy.convolve(a, numpy.ones((n, )) / n, mode='valid') numpy.random.seed(seed) log.debug( "simulate_gaintable: Simulating amplitude error = %.4f, phase error = %.4f" % (amplitude_error, phase_error)) amps = 1.0 phases = 1.0 ntimes, nant, nchan, nrec, _ = gt.data['gain'].shape if phase_error > 0.0: phases = numpy.zeros(gt.data['gain'].shape) for time in range(ntimes): for ant in range(nant): phase = numpy.random.normal(0, phase_error, nchan + int(smooth_channels) - 1) if smooth_channels > 1: phase = moving_average(phase, smooth_channels) phases[time, ant, ...] = phase[..., numpy.newaxis, numpy.newaxis] if amplitude_error > 0.0: amps = numpy.ones(gt.data['gain'].shape, dtype='complex') for time in range(ntimes): for ant in range(nant): amp = numpy.random.lognormal(mean=0.0, sigma=amplitude_error, size=nchan + int(smooth_channels) - 1) if smooth_channels > 1: amp = moving_average(amp, smooth_channels) amp = amp / numpy.average(amp) amps[time, ant, ...] = amp[..., numpy.newaxis, numpy.newaxis] gt.data['gain'] = amps * numpy.exp(0 + 1j * phases) nrec = gt.data['gain'].shape[-1] if nrec > 1: if leakage > 0.0: leak = numpy.random.normal(0, leakage, gt.data['gain'][..., 0, 0].shape) + 1j * \ numpy.random.normal(0, leakage, gt.data['gain'][..., 0, 0].shape) gt.data['gain'][..., 0, 1] = gt.data['gain'][..., 0, 0] * leak leak = numpy.random.normal(0, leakage, gt.data['gain'][..., 1, 1].shape) + 1j * \ numpy.random.normal(0, leakage, gt.data['gain'][..., 1, 1].shape) gt.data['gain'][..., 1, 0] = gt.data['gain'][..., 1, 1] * leak else: gt.data['gain'][..., 0, 1] = 0.0 gt.data['gain'][..., 1, 0] = 0.0 return gt