From 0ae8fb557eb50b4e17b380609f65c1d07dc12834 Mon Sep 17 00:00:00 2001 From: Eric Kooistra <kooistra@astron.nl> Date: Mon, 1 Feb 2021 17:14:42 +0100 Subject: [PATCH] Derived from apertif_arts_firmware_model.py, but in a very intermediate state, so not working. --- .../model/lofar_station_firmware_model.py | 1035 +++++++++++++++++ 1 file changed, 1035 insertions(+) create mode 100644 applications/lofar2/model/lofar_station_firmware_model.py diff --git a/applications/lofar2/model/lofar_station_firmware_model.py b/applications/lofar2/model/lofar_station_firmware_model.py new file mode 100644 index 0000000000..11d1ecea59 --- /dev/null +++ b/applications/lofar2/model/lofar_station_firmware_model.py @@ -0,0 +1,1035 @@ +############################################################################### +# +# Copyright (C) 2018 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################### + +# Author: Eric Kooistra, 28 Oct 2018, + +"""Model the LOFAR2.0 Station Digital Processor (SDP) firmware data path signal levels + +[1] https://support.astron.nl/confluence/display/L2M/L4+SDP+Decision%3A+LOFAR2.0+SDP+Firmware+Quantization+Model + +The SDP FW processing is described in [1]. +The purpose of the lofar_station_firmware_model is to understand signal levels +in the data path processing and to prove that the internal requantization in +the firmware implementation is does not increase the system noise while +providing the maximum dynamic range, given data widths at the external +interfaces (i.e. W_adc = 14, W_subband = 18, W_beamlet = 8). + +This lofar_station_firmware_model.py model consists of the following sections: + +- User parameters +- Firmware parameters +- A static model to determine the expected internal signal levels as function + of the WG amplitude or the ADC noise sigma level. +- A dynamic model using FFT, BF and ()**2 to model the data path signal + processing for a WG input signal or a system noise input signal. The FIR + part of the F_sub and F_chan is not modelled. + . WG input for test purposes to verify the linearity and dynamic range + as function of the WG amplitude and the number of dishes. + . Noise input for operational purposes to verify that the system noise + maintains represented by suffcient LSbits throughout the data path + processing chain from ADC via subband to station beamlet output. +- Plot results of the static and the dynamic model. + +The model matches the drawings of the firmware parameters and signal levels in [1]. + + +Parameters: +* wgEnable + When True then a WG input is used for the dynamic model, else a noise input. +* wgSweep + The WG makes a sweep through wgSweep number of subbands if wgSweep != 0. The + wgSweep can be < 1 and negative. If wgSweep != 0 then an image plot is made + of the subbands spectrum and the channels spectrum. The expected signal + levels that are reported by the dynamic model are only relevant when wgSweep + = 0. +* quantize + The quantize parameter provides rounding of internal signal levels, weights + and gain factors. For the dynamic model clipping is not supported, because + the static model already shows when the signals clip. In the static model the + clipping can be controlled via the adjust parameter. + +Remark: +- power = rms**2 +- mean powers = (rms voltages)**2 +- rms**2 = std**2 + mean**2 = std**2 when mean = 0 +- rms = std = ampl / sqrt(2) when mean is 0 + --> pi_apr.wgScale = sqrt(2) + +- power complex = power real + power imag + = (rms real)**2 + (rms imag)**2 + = (ampl real/sqrt(2))**2 + (ampl imag/sqrt(2))**2 +- power real = power imag = power complex / 2, when signal is random or periodic +- rms real = rms imag = rms complex / sqrt(2), when signal is random or periodic + --> pi_apr.rcScale = sqrt(2) = sqrt(nof_complex) +- rms complex = sqrt(power complex) +- ampl real = ampl imag = sqrt(power complex / 2) * sqrt(2) + = sqrt(power complex) + = rms complex + = (rms real) * sqrt(2) + = (rms imag) * sqrt(2) + +A = 1.0 +N = 100000 +realSamples = A * np.random.randn(N) +realPowers = realSamples * realSamples +x = rms(realSamples)**2 +y = np.mean(realPowers) +z = np.std(realPowers) +x # = A * 1.0 +y # = A * 1.0 +z # = A * sqrt(2) +complexSamples = A * np.random.randn(N) + A * np.random.randn(N) * 1j +complexPowers = complexSamples * np.conjugate(complexSamples) +complexPowers = complexPowers.real +x = rms(complexSamples)**2 +xr = rms(complexSamples.real)**2 +xi = rms(complexSamples.imag)**2 +y = np.mean(complexPowers) +z = np.std(complexPowers) +x # = A * 2.0 +xr +xi +y # = A * 2.0 +z # = A * 2.0 + +Use prefix rmsComplexY for rms of complex signal Y +Use prefix rmsY for rms of real signal Y or of Y.real or of Y.imag, so + for complex signal Y then rmsY = rmsComplexY / pi_apr.rcScale, + for real signal Y then rmsY = rmsY. + +Usage: +# in iPython: +import os +filepath='E:\\svn_radiohdl\\trunk\\applications\\apertif\\matlab' +os.chdir(filepath) +run apertif_arts_firmware_model.py + +# on command line +python lofar_station_firmware_model.py + +""" + +import argparse +import math +import numpy as np +import common as cm +import test_plot +import pi_apertif_system as pi_apr + +################################################################################ +# SDP settings +################################################################################ + + +W_adc = 14 # Word width in number of bits of the ADC +W_adc_max = W_adc-1 # ADC full scale + +N_complex = 2 +N_fft = 1024 +N_sub = 512 # = N_fft / N_complex +W_fsub_proc = math.log(math.sqrt(N_sub), 2) # = 4.5, processing gain of F_sub in number of bits + +N_int_sub = 195312.5 +W_se_weight = 16 +W_se_magnitude = 1 +W_se_fraction = 14 +c_se_unit_weight = 2**W_se_fraction + +W_bf_weight = 16 +W_bf_magnitude = 1 +W_bf_fraction = 14 +c_bf_unit_weight = 2**W_sub_fraction + +W_beamlet_scale = 16 +W_beamlet_scale_magnitude = 1 +W_beamlet_scale_fraction = 14 +c_beamlet_scale_unit = 2**W_beamlet_scale_fraction + + +W_sst_fraction = 4 # Extra fraction bits for SST subband input compared to W_adc +W_sst_in = 18 # Word width in number of bits of SST subband data input, = W_adc + W_sst_fraction +W_sst_out = 54 # Word width in number of bits of SST subband statistics output, = 2*W_sst_in + log2(N_int_sub) + +W_bf_in = 18 # Word width in number of bits of BF subband data input +W_bf_weight = 16 # Word width in number of bits of the BF weights +W_cb_max_weight = W_cb_weight-1 # = 15 = 16 - 1 +W_cb_unit_scale = -2 # Unit weight scale factor in number of bits +W_cb_weight_fraction = W_cb_max_weight + W_cb_unit_scale +cbMaxWeight = 2.0**W_cb_max_weight - 1 # = 32767, maximum positive BF weight value in full scale range +cbUnitWeight = 2.0**W_cb_weight_fraction # = 8192, unit BF weight value mapped in full scale range + +W_bst_fraction = 8 # Extra fraction bits for BST beamlet input compared to W_adc, = W_fsub_gain - W_cb_unit_scale + 1 +W_bst_in = 16 # Word width in number of bits of BST beamlet data input, = W_adc + W_bst_fraction +W_bst_out = 56 # Word width in number of bits of BST beamlet statistics output +W_bst_out_sz = 2 # Number of 32b words per W_bst_out + +W_beamlet_sc1 = 8 # Word width in number of bits of a beamlet voltage sample at the BF to Arts SC1 interface +W_beamlet_max_sc1 = W_beamlet_sc1-1 # = 7 = 8 - 1 +W_beamlet = 8 # Word width in number of bits of a beamlet voltage sample at the BF to XC and Arts SC3 and SC4 interface +W_beamlet_max = W_beamlet-1 # = 7 = 8 - 1 or = 5 = 6 - 1 +W_beamlet_fraction = 6 # Extra fraction bits for beamlet output compared to W_adc, = W_fsub_gain - W_cb_unit_scale - 1, + # do -1 to have 1 bit extra for noise at ADC interface than at BF beamlet output interface + +W_channel_x = 9 # Word width in number of bits of XC input channel voltage sample +W_channel_x_max = W_channel_x-1 # = 8 = 9 - 1 +W_channel_x_fraction = 9 # Extra fraction bits for XC input channel compared to W_adc, = W_beamlet_fraction + W_fchan_x_gain + +W_tab_weight_sc1 = 16 # Word width in number of bits of the TAB weights for SC1 +W_tab_max_weight_sc1 = W_tab_weight_sc1-1 # = 15 = 16 - 1 +tabMaxWeightSc1 = 2.0**W_tab_max_weight_sc1 - 1 # = 32767 = 2**(16-1) - 1, do -1 to avoid wrap to -32768 + +W_int_ax = cm.ceil_log2(M_int_ax) # = 4, number of bits to fit integration of M_int_ax = 16 power samples + +W_tab_weight_sc4 = 9 # Word width in number of bits of the TAB weights for SC3 and SC4, required is >= 5 bits complex +W_tab_max_weight_sc4 = W_tab_weight_sc4-1 # = 8 = 9 - 1 +W_tab_unit_scale_sc4 = -1 # Unit weight scale factor in number of bits +W_tab_weight_fraction_sc4 = W_tab_max_weight_sc4 + W_tab_unit_scale_sc4 +tabMaxWeightSc4 = 2.0**W_tab_max_weight_sc4 - 1 # = 255, maximum positive TAB SC4 weight value in full scale range +tabUnitWeightSc4 = 2.0**W_tab_weight_fraction_sc4 # = 128, unit TAB SC4 weight value mapped in full scale range + +W_iab_gain = 16 # Word width in number of bits of the IAB outputgain for SC3 and SC4 +W_iab_unit_scale = -2 # = -2 +W_iab_gain_fraction = W_iab_gain-1 + W_iab_unit_scale # = 13 = 16-1 + -2 +iabMaxGain = 2.0**(W_iab_gain-1) - 1 # = 32767, maximum positive IAB gain value in full scale range +iabUnitGain = 2.0**W_iab_gain_fraction # = 8192 = 2**13 + + # Determine signal scale factors relative to ADC sigma level + # . apply factor 2**W_cb_unit_scale to account for unit level of the BF weights relative to full scale +wgSstScale = 1.0 / 2.0**W_sst_fraction +wgBstScale = 1.0 / 2.0**(W_bst_fraction + W_cb_unit_scale) +wgBeamletScale = 1.0 / 2.0**(W_beamlet_fraction + W_cb_unit_scale) +wgChannelXcorScale = 1.0 / 2.0**(W_channel_x_fraction + W_cb_unit_scale) + +noiseSstScale = 2.0**W_fsub_gain * wgSstScale +noiseBstScale = 2.0**W_fsub_gain * wgBstScale +noiseBeamletScale = 2.0**W_fsub_gain * wgBeamletScale +noiseChannelXcorScale = 2.0**W_fsub_gain * wgChannelXcorScale * 2**W_fchan_x_gain +noiseSubbandXcorScale = 2.0**W_fsub_gain * wgChannelXcorScale # for XC subband, is sum of all XC channels + +wgScale = math.sqrt(2) # Apply factor wgScale = sqrt(2) to account for WG ampl = sqrt(2) * WG sigma, because WG power = A**2 / 2 +rcScale = math.sqrt(2) # Apply factor rcScale = sqrt(2) to account for rms real = rms imag = rms complex / sqrt(2) + + +################################################################################ +# Model settings +################################################################################ + +def rms(arr): + """Root mean square of values in arr + Use this root-mean-square rms() instead of std() for CW signals that are at + center of bin and result in static phasor with std() = 0. For noise + signals with zero mean rms() is equal to std(). This rms() also works for + complex input thanks to using np.abs(). + """ + return np.sqrt(np.mean(np.abs(arr)**2.0)) + +nofSigma = 4 # Number of sigma to fit in full scale + +################################################################################ +# Parse arguments to derive user settings +################################################################################ + +_parser = argparse.ArgumentParser('lofar_station_firmware_model') +_parser.add_argument('--model', default='all', type=str, help='Model: static, dynamic or all') +_parser.add_argument('--sky_sigma', default=4.0, type=float, help='Signal sigma level at ADC input') +_parser.add_argument('--wg_enable', default=False, action='store_true', help='Model coherent ADC input using WG sinus or model incoherent ADC input using Gaussian white noise') +_parser.add_argument('--wg_ampl', default=4.0 * 2**0.5, type=float, help='WG amplitude at ADC input') +_parser.add_argument('--wg_sweep', default=0.0, type=float, help='Number of subbands fsub to sweep with WG in dynamic model') +_parser.add_argument('--nof_periods', default=250, type=int, help='Number of subband periods in dynamic model') +_parser.add_argument('--quantize', default=False, action='store_true', help='Use fixed point rounding or no rounding of weights, gains and internal signals') +_parser.add_argument('--useplot', default=False, action='store_true', help='Use plots or skip plotting') +_parser.add_argument('--sub_weight_adjust', default=1.0, type=float, help='Factor to adjust unit subband weight') +_parser.add_argument('--bf_weight_adjust', default=1.0, type=float, help='Factor to adjust unit BF weight') +args = _parser.parse_args() + +if args.model=='all': + models = ['static', 'dynamic'] +else: + models = [args.model] + +skySigma = args.sky_sigma +#skySigma = 16 # 16 for 4 bit noise +#skySigma = 5792 # 5792 * 2**0.5 = 8191 for full scale WG amplitude + +wgAmpl = args.wg_ampl +wgSigma = wgAmpl / np.sqrt(2) + +wgEnable = args.wg_enable +wgSweep = args.wg_sweep +if wgSweep != 0: + wgEnable = True # force WG + +quantize = args.quantize + +useplot = args.useplot + +subWeightAdjust = args.sub_weight_adjust +bfWeightAdjust = args.bf_weight_adjust +#subWeightAdjust = 1.0/8 # use <= 1/8 to have no beamlet (8 bit) clipping + +# Time series +if 'dynamic' in models: + # use args.nof_periods for number of subband periods to simulate: + if wgEnable: + nofTsub = args.nof_periods + #nofTsub = 10 # use >~10 for WG + #nofTsub = 100 + else: + nofTsub = args.nof_periods + #nofTsub = 100 # number of subband periods to simulate, use >~ 100 for noise + #nofTsub = 1000 # use >= 1000 for more accuracy + #nofTsub = 250 # use < 1000 to speed up simulation + + # also use args.nof_periods for number of Ts, Tsub periods to plot + # . to speed up plotting for Ts + # . to have same density of samples per plot + nof_periods = args.nof_periods + +# Frequency selection +if 'dynamic' in models: + # Select frequency for WG, SST, BST + selSub = 65 + +################################################################################ +# Derived gains + +# Aperif BF subband CB voltage weight +subWeight = c_sub_unit_weight * subWeightAdjust # = 16384 = 2**14 * 1.0 +bfWeight = c_bf_unit_weight * bfWeightAdjust # = 16384 = 2**14 * 1.0 +if quantize: + subWeight = np.round(subWeight) + bfWeight = np.round(bfWeight) + + +if 'static' in models: + ################################################################################ + # Static model of signal level as function of: + # . WG input amplitude level + # . Noise input sigma level + ################################################################################ + + # Input axis + inputResolution = 0.05 + + # Dish + A_wg = np.arange(inputResolution, 2**W_adc_max, inputResolution) + S_wg = A_wg / wgScale + S_wg_complex = S_wg + S_wg_complex_phase = S_wg_complex / rcScale + A_wg_complex_phase = S_wg_complex + S_noise = np.arange(inputResolution, 2**W_adc_max / nofSigma, inputResolution) + S_noise_complex = S_noise + S_noise_complex_phase = S_noise / rcScale + + SST_wg_inputs = S_wg_complex / pi_apr.wgSstScale + SST_wg_values = SST_wg_inputs**2 * N_int_sub + SST_wg_dBs = 10*np.log10(SST_wg_values) + SST_noise_inputs = S_noise_complex / pi_apr.noiseSstScale + SST_noise_values = SST_noise_inputs**2 * N_int_sub + SST_noise_dBs = 10*np.log10(SST_noise_values) + + BST_wg_inputs = S_wg_complex * cbWeightAdjust / pi_apr.wgBstScale + BST_wg_values = BST_wg_inputs**2 * N_int_sub + BST_wg_dBs = 10*np.log10(BST_wg_values) + BST_noise_inputs = S_noise_complex * cbWeightAdjust / pi_apr.noiseBstScale + BST_noise_values = BST_noise_inputs**2 * N_int_sub + BST_noise_dBs = 10*np.log10(BST_noise_values) + + clip = 2.0**pi_apr.W_beamlet_max - 1 + beamlet_wg_complex_phase_values = S_wg_complex_phase * cbWeightAdjust / pi_apr.wgBeamletScale + beamlet_wg_complex_phase_values = np.clip(beamlet_wg_complex_phase_values, -clip, clip) + beamlet_noise_complex_phase_values = S_noise_complex_phase * cbWeightAdjust / pi_apr.noiseBeamletScale + beamlet_noise_complex_phase_values = np.clip(beamlet_noise_complex_phase_values, -clip, clip) + + # Central + clip = 2.0**pi_apr.W_channel_x_max - 1 + channel_x_wg_complex_phase_values = S_wg_complex_phase * cbWeightAdjust / pi_apr.wgChannelXcorScale + channel_x_wg_complex_phase_values = np.clip(channel_x_wg_complex_phase_values, -clip, clip) + channel_x_wg_complex_values = channel_x_wg_complex_phase_values * pi_apr.rcScale + channel_x_noise_complex_phase_values = S_noise_complex_phase * cbWeightAdjust / pi_apr.noiseChannelXcorScale + channel_x_noise_complex_phase_values = np.clip(channel_x_noise_complex_phase_values, -clip, clip) + channel_x_noise_complex_values = channel_x_noise_complex_phase_values * pi_apr.rcScale + + +if 'dynamic' in models: + ################################################################################ + # Dynamic model parameters + ################################################################################ + + ################################################################################ + # Apertif / Arts settings + # . BF + fs = 800e6 + fsub = fs / N_fft + Ts = 1/fs + Tsub = 1/fsub + + # . XC, SC4 + fchan_x = fsub / N_chan_x + Tchanx = 1/fchan_x + + # . SC4 + Tstokesx = Tchanx + M_int_ax = pi_apr.M_int_ax # = 16 + W_int_ax = pi_apr.W_int_ax # = 4 = log2(16) + #M_int_ax = 1 + #W_int_ax = cm.ceil_log2(M_int_ax) + + ################################################################################ + # Dish CB + + # Number of bits for internal product + W_cb_product = pi_apr.W_cb_in + pi_apr.W_cb_weight - 1 # = 31 = 16 + 16 -1, do -1 to skip double sign bit of product + + # Number of bits for fraction < 1 + W_beamlet_fraction = pi_apr.W_beamlet_fraction # number of bits for fraction < 1 + + + ################################################################################ + # Dynamic model time series + ################################################################################ + + # Time, frequency axis + nofTs = nofTsub * N_fft + t = np.arange(nofTs) * Ts + + ################################################################################ + # Dish Compound Beamformer + + # ADC input + if wgEnable: + wgFreq = (selSub + (selChanx + selChanxFraction - N_chan_x/2.0) / N_chan_x) * fsub + chirpFreq = 0 + if wgSweep: + chirpFreq = wgSweep * fsub * np.arange(nofTs)/nofTs/2.0 + spSamples = wgAmpl * np.sin(2*np.pi*(wgFreq + chirpFreq) * t) + else: + spSamples = np.random.randn(nofTs) + spSamples *= skySigma / rms(spSamples) + + if quantize: + # The unit level is at 1 lsb of the ADC input, so the W_adc = 8 bit input + # has no fraction and can thus directly be rounded to model quantization. + spSamples = np.round(spSamples) + rmsSp = rms(spSamples) # real signal + amplSp = rmsSp * pi_apr.wgScale + + # Fsub subbands full bandwidth + spBlocks = spSamples.reshape((nofTsub, N_fft)) # [nofTsub][N_fft] + fftSamples = np.fft.fft(spBlocks) / N_fft # [nofTsub][N_fft] + fSubSamples = fftSamples[:, 0:N_sub] # [nofTsub][N_sub], real input, so only keep positive frequencies + + # SST for selSub + sstSamples = fSubSamples[:, selSub].copy() + if quantize: + sstSamples *= 2.0**pi_apr.W_sst_fraction # fixed point fraction + sstSamples = np.round(sstSamples) + sstSamples /= 2.0**pi_apr.W_sst_fraction # back to normalized fraction + rmsComplexSST = rms(sstSamples) # complex signal + rmsSST = rmsComplexSST / pi_apr.rcScale + amplSST = rmsSST * pi_apr.wgScale + SSTpower = N_int_sub * rmsComplexSST**2 + + # BF samples full bandwidth + bfSamples = fSubSamples * cbGain + + # BST for selSub + bstSamples = bfSamples[:, selSub].copy() + if quantize: + bstSamples *= 2.0**pi_apr.W_bst_fraction # fixed point fraction + bstSamples = np.round(bstSamples) + bstSamples /= 2.0**pi_apr.W_bst_fraction # back to normalized fraction + rmsComplexBST = rms(bstSamples) # complex signal + rmsBST = rmsComplexBST / pi_apr.rcScale + amplBST = rmsBST * pi_apr.wgScale + BSTpower = N_int_sub * rmsComplexBST**2 + + # CB beamlet for selSub + beamletSamples = bfSamples[:, selSub].copy() + if quantize: + beamletSamples *= 2.0**pi_apr.W_beamlet_fraction # fixed point fraction + beamletSamples = np.round(beamletSamples) + beamletSamples /= 2.0**pi_apr.W_beamlet_fraction # back to normalized fraction + rmsComplexBeamlet = rms(beamletSamples) # complex signal + rmsBeamlet = rmsComplexBeamlet / pi_apr.rcScale + amplBeamlet = rmsBeamlet * pi_apr.wgScale + + + ################################################################################ + # Dynamic model: Normalized floating point fraction to fixed point fraction + ################################################################################ + + # SST + rmsComplexSST *= 2.0**pi_apr.W_sst_fraction + rmsSST *= 2.0**pi_apr.W_sst_fraction + amplSST *= 2.0**pi_apr.W_sst_fraction + SSTpower *= 2.0**(2*pi_apr.W_sst_fraction) + + # BST + rmsComplexBST *= 2.0**pi_apr.W_bst_fraction + rmsBST *= 2.0**pi_apr.W_bst_fraction + amplBST *= 2.0**pi_apr.W_bst_fraction + BSTpower *= 2.0**(2*pi_apr.W_bst_fraction) + + # CB beamlet for selSub + beamletSamples *= 2.0**pi_apr.W_beamlet_fraction + rmsComplexBeamlet *= 2.0**pi_apr.W_beamlet_fraction + rmsBeamlet *= 2.0**pi_apr.W_beamlet_fraction + amplBeamlet *= 2.0**pi_apr.W_beamlet_fraction + + # CB fine channel for selSub, selChanx + fineChannelSamples *= 2.0**pi_apr.W_channel_x_fraction + rmsComplexFineChannel *= 2.0**pi_apr.W_channel_x_fraction + rmsFineChannel *= 2.0**pi_apr.W_channel_x_fraction + amplFineChannel *= 2.0**pi_apr.W_channel_x_fraction + + if 'apertif' in apps: + # Aperif XC channel auto-visibility + XCpower *= 2.0**(2*pi_apr.W_channel_x_fraction) + + if 'arts_sc1' in apps: + # Arts SC1 beamlet voltage TAB + beamletTabSamples *= 2.0**W_tab_fraction_sc1 + rmsComplexBeamletTab *= 2.0**W_tab_fraction_sc1 + rmsBeamletTab *= 2.0**W_tab_fraction_sc1 + amplBeamletTab *= 2.0**W_tab_fraction_sc1 + + if 'arts_sc4' in apps: + # Arts SC4 Power TAB for single polarization Stokes I = XX* + 0 + # . Fine channel voltage TAB + fineChannelTabSamples *= 2.0**W_tab_voltage_fraction_sc4 + rmsComplexFineChannelTab *= 2.0**W_tab_voltage_fraction_sc4 + rmsFineChannelTab *= 2.0**W_tab_voltage_fraction_sc4 + amplFineChannelTab *= 2.0**W_tab_voltage_fraction_sc4 + + # . Fine channel power TAB + fineChannelTabPowers *= 2.0**W_tab_power_fraction_sc4 + meanFineChannelTabPower *= 2.0**W_tab_power_fraction_sc4 + stdFineChannelTabPower *= 2.0**W_tab_power_fraction_sc4 + + # . Integrated channels power TAB + integratedTabPowers *= 2.0**W_tab_power_int_fraction_sc4 + meanIntegratedTabPower *= 2.0**W_tab_power_int_fraction_sc4 + stdIntegratedTabPower *= 2.0**W_tab_power_int_fraction_sc4 + + # Arts SC4 IAB for single polarization Stokes I = XX* + 0 + # . Fine channel powers + fineChannelPowers *= 2.0**W_iab_power_fraction + meanFineChannelPower *= 2.0**W_iab_power_fraction + + # . Integrated channel powers + integratedChannelPowers *= 2.0**W_iab_power_fraction + meanIntegratedChannelPower *= 2.0**W_iab_power_fraction + + # . Sum of powers is coherent sum + integratedIabPowers *= 2.0**W_iab_power_fraction + meanIntegratedIabPower *= 2.0**W_iab_power_fraction + + # . Output gain + outputIabPowers *= 2.0**W_iab_gain_fraction + meanOutputIabPower *= 2.0**W_iab_gain_fraction + stdOutputIabPower *= 2.0**W_iab_gain_fraction + +################################################################################ +# Logging +################################################################################ +print '--------------------------------------------------------------------' +print '-- User settings' +print '--------------------------------------------------------------------' +if wgEnable: + print 'WG sinus input:' + print '. wgSigma = %f' % wgSigma + print '. wgAmpl = %f [fsub]' % wgAmpl + print '. wgSweep = %f [fsub]' % wgSweep +else: + print 'ADC noise input:' + print '. skySigma = %f' % skySigma +print '. quantize = %s' % quantize +print '. nofDishes = %d (= %.1f bit)' % (nofDishes, math.log(nofDishes, 2)) +print '' + +if 'dynamic' in models: + print 'Dynamic model:' + print '. selSub = %d' % selSub + print '. selChanx = %d' % selChanx + print '. selChanxFraction = %d' % selChanxFraction + print '. nofTchanx = %d' % nofTchanx + print '. nofTsub = %d' % nofTsub + print '. nofTs = %d' % nofTs + print '' + +print '--------------------------------------------------------------------' +print '-- Design settings' +print '--------------------------------------------------------------------' +print 'Apertif BF:' +print '. N_fft = %d' % N_fft +print '. N_sub = %d' % N_sub +print '. N_int_sub = %d' % N_int_sub +print '' +if 'apertif' in apps: + print 'Apertif XC:' + print '. N_chan_x = %d' % N_chan_x + print '. N_chan_bf = %d' % N_chan_bf + print '. N_int_chan_x = %d' % N_int_chan_x + print '. cbWeightAdjust = %f' % cbWeightAdjust + print '. cbMaxWeight = %d' % pi_apr.cbMaxWeight + print '. cbUnitWeight = %d' % pi_apr.cbUnitWeight + print '. cbWeight = %d' % cbWeight + print '. cbGain = %f' % cbGain + print '' +if 'arts_sc1' in apps: + print 'Arts SC1:' + print '. sc1_use_qua = %s' % sc1_use_qua + print '. tabWeightAdjustSc1 = %f' % tabWeightAdjustSc1 + print '. tabUnitWeightSc1 = %d' % tabUnitWeightSc1 + print '. tabWeightSc1 = %d' % tabWeightSc1 + print '. tabGainSc1 = %.8f' % tabGainSc1 + print '' +if 'arts_sc4' in apps: + print 'Arts SC4:' + print '. tabWeightAdjustSc4 = %f' % tabWeightAdjustSc4 + print '. iabGainAdjust = %f' % iabGainAdjust + print '. iabMaxGain = %d' % pi_apr.iabMaxGain + print '. iabUnitGain = %d' % pi_apr.iabUnitGain + print '. iabGainReg = %d' % iabGainReg + print '. iabGain = %.8f' % iabGain + print '' + +if 'dynamic' in models: + print '--------------------------------------------------------------------' + print '-- Dynamic model settings' + print '--------------------------------------------------------------------' + print 'Design:' + print '. fs = %f [Hz]' % fs + print '. Ts = %.2f [ns]' % (Ts * 1e9) + print '. fsub = %f [Hz]' % fsub + print '. Tsub = %.2f [us]' % (Tsub * 1e6) + print '. W_fsub_gain = %d [bit]' % pi_apr.W_fsub_gain + if 'apertif' in apps: + print '. fchan_x = %f [Hz]' % fchan_x + print '. Tchanx = %.2f [us]' % (Tchanx * 1e6) + print '. W_fchan_x_gain = %d [bit]' % pi_apr.W_fchan_x_gain + if 'arts_sc4' in apps: + print '. Tstokesx = %.2f [us]' % (Tstokesx * 1e6) + print '' + + print 'Dish:' + print '. W_adc = %d [bit]' % pi_apr.W_adc + print '. W_adc_max = %d [bit], adc max = %d' % (pi_apr.W_adc_max, 2**pi_apr.W_adc_max-1) + print '. W_sst_in = %d [bit]' % pi_apr.W_sst_in + print '. W_sst_fraction = %d [bit]' % pi_apr.W_sst_fraction + print '. W_cb_weight = %d [bit]' % pi_apr.W_cb_weight + print '. W_cb_unit_scale = %d [bit]' % pi_apr.W_cb_unit_scale + print '. W_cb_weight_fraction = %d [bit]' % pi_apr.W_cb_weight_fraction + print '. W_cb_in = %d [bit]' % pi_apr.W_cb_in + print '. W_cb_product = %d [bit]' % W_cb_product + print '. W_bst_in = %d [bit]' % pi_apr.W_bst_in + print '. W_bst_fraction = %d [bit]' % pi_apr.W_bst_fraction + print '. W_beamlet_sc1 = %d [bit]' % pi_apr.W_beamlet_sc1 + print '. W_beamlet = %d [bit]' % pi_apr.W_beamlet + print '. W_beamlet_fraction = %d [bit]' % pi_apr.W_beamlet_fraction + print '' + + if 'apertif' in apps: + print 'Apertif XC:' + print '. W_channel_x = %d [bit]' % pi_apr.W_channel_x + print '. W_channel_x_fraction = %d [bit]' % pi_apr.W_channel_x_fraction + print '' + + if 'arts_sc1' in apps: + print 'Arts SC1 beamlet TAB:' + print '. W_tab_weight_sc1 = %d [bit]' % pi_apr.W_tab_weight_sc1 + print '. W_tab_unit_scale_sc1 = %d [bit]' % W_tab_unit_scale_sc1 + print '. W_tab_weight_fraction_sc1 = %d [bit]' % W_tab_weight_fraction_sc1 + print '. W_beamlet_sc1 = %d [bit]' % pi_apr.W_beamlet_sc1 + print '. W_tab_product_sc1 = %d [bit]' % W_tab_product_sc1 + print '. W_tab_fraction_sc1 = %d [bit]' % W_tab_fraction_sc1 + print '' + + if 'arts_sc4' in apps: + print 'Arts SC4 TAB:' + print '. W_channel_x = %d [bit]' % pi_apr.W_channel_x + print '. W_channel_x_fraction = %d [bit]' % pi_apr.W_channel_x_fraction + print '. W_tab_weight_sc4 = %d [bit]' % pi_apr.W_tab_weight_sc4 + print '. W_tab_unit_scale_sc4 = %d [bit]' % pi_apr.W_tab_unit_scale_sc4 + print '. W_tab_weight_fraction_sc4 = %d [bit]' % pi_apr.W_tab_weight_fraction_sc4 + print '. tabUnitWeightSc4 = %d' % pi_apr.tabUnitWeightSc4 + print '. tabWeightSc4 = %d' % tabWeightSc4 + print '. tabGainSc4 = %.8f' % tabGainSc4 + print '. W_beamlet = %d [bit]' % pi_apr.W_beamlet + print '. W_tab_voltage_product_sc4 = %d [bit]' % W_tab_voltage_product_sc4 + print '. W_tab_voltage_fraction_sc4 = %d [bit]' % W_tab_voltage_fraction_sc4 + print '. W_tab_power_product_sc4 = %d [bit]' % W_tab_power_product_sc4 + print '. W_tab_power_fraction_sc4 = %d [bit]' % W_tab_power_fraction_sc4 + print '. W_tab_power_int_fraction_sc4 = %d [bit]' % W_tab_power_int_fraction_sc4 + print '. W_int_ax = %d [bit]' % W_int_ax + print '. M_int_ax = %d' % M_int_ax + print '' + + print 'Arts SC4 IAB:' + print '. W_channel_x = %d [bit]' % pi_apr.W_channel_x + print '. W_channel_x_fraction = %d [bit]' % pi_apr.W_channel_x_fraction + print '. W_int_ax = %d [bit]' % W_int_ax + print '. M_int_ax = %d' % M_int_ax + print '. W_iab_gain = %d [bit]' % pi_apr.W_iab_gain + print '. W_iab_unit_scale = %d [bit]' % pi_apr.W_iab_unit_scale + print '. W_iab_gain_fraction = %d [bit]' % pi_apr.W_iab_gain_fraction + print '. W_iab_power_product = %d [bit]' % W_iab_power_product + print '. W_iab_power_fraction = %d [bit]' % W_iab_power_fraction + print '. W_iab_gain_product = %d [bit]' % W_iab_gain_product + print '. W_iab_gain_fraction = %d [bit]' % W_iab_gain_fraction + print '' + +if 'dynamic' in models and wgSweep == 0: + print '--------------------------------------------------------------------' + print '-- Dynamic model results' + print '--------------------------------------------------------------------' + if wgEnable: + print 'Apertif BF internal levels (excluding sign bit) for coherent WG sinus input:' + print '. ADC input rms = %20.2f (= %4.1f [bit])' % (rmsSp, math.log(rmsSp, 2)) + print '. ADC input ampl = %20.2f (= %4.1f [bit])' % (amplSp, math.log(amplSp, 2)) + print '. SST input rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexSST, math.log(rmsComplexSST, 2)) + print '. SST input ampl = %20.2f (= %4.1f [bit])' % (amplSST, math.log(amplSST, 2)) + print '. BST input rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexBST, math.log(rmsComplexBST, 2)) + print '. BST input ampl = %20.2f (= %4.1f [bit])' % (amplBST, math.log(amplBST, 2)) + print '. CB beamlet rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexBeamlet, math.log(rmsComplexBeamlet, 2)) + print '. CB beamlet ampl = %20.2f (= %4.1f [bit])' % (amplBeamlet, math.log(amplBeamlet, 2)) + else: + print 'Apertif BF internal levels (excluding sign bit) for incoherent ADC noise input:' + print '. ADC input rms = %20.2f (= %4.1f [bit])' % (rmsSp, math.log(rmsSp, 2)) + print '. SST input rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexSST, math.log(rmsComplexSST, 2)) + print '. SST input rms = %20.2f (= %4.1f [bit])' % (rmsSST, math.log(rmsSST, 2)) + print '. BST input rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexBST, math.log(rmsComplexBST, 2)) + print '. BST input rms = %20.2f (= %4.1f [bit])' % (rmsBST, math.log(rmsBST, 2)) + print '. CB beamlet rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexBeamlet, math.log(rmsComplexBeamlet, 2)) + print '. CB beamlet rms = %20.2f (= %4.1f [bit])' % (rmsBeamlet, math.log(rmsBeamlet, 2)) + print '. SST power = %20.2f = %7.2f dB (= %4.1f [bit])' % (SSTpower, 10*math.log(SSTpower, 10), math.log(SSTpower, 2)) + print '. BST power = %20.2f = %7.2f dB (= %4.1f [bit])' % (BSTpower, 10*math.log(BSTpower, 10), math.log(BSTpower, 2)) + print '' + + if 'apertif' in apps: + if wgEnable: + print 'Apertif XC output for coherent WG sinus input:' + print '. Fine channel rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannel, math.log(rmsComplexFineChannel, 2)) + print '. Fine channel ampl = %20.2f (= %4.1f [bit])' % (amplFineChannel, math.log(amplFineChannel, 2)) + else: + print 'Apertif XC output for incoherent ADC noise input:' + print '. Fine channel rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannel, math.log(rmsComplexFineChannel, 2)) + print '. Fine channel rms = %20.2f (= %4.1f [bit])' % (rmsFineChannel, math.log(rmsFineChannel, 2)) + print '. XC auto power = %20.2f = %7.2f dB (= %4.1f [bit])' % (XCpower, 10*math.log(XCpower, 10), math.log(XCpower, 2)) + print '' + + if 'arts_sc1' in apps: + if wgEnable: + print 'Arts SC1 beamlet TAB internal levels (excluding sign bit) for coherent WG sinus input:' + print '. Output TAB rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexBeamletTab, math.log(rmsComplexBeamletTab, 2)) + print '. Output TAB ampl = %20.2f (= %4.1f [bit])' % (amplBeamletTab, math.log(amplBeamletTab, 2)) + else: + print 'Arts SC1 beamlet TAB internal levels (excluding sign bit) for incoherent ADC noise input:' + print '. Output TAB rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexBeamletTab, math.log(rmsComplexBeamletTab, 2)) + print '. Output TAB rms = %20.2f (= %4.1f [bit])' % (rmsBeamletTab, math.log(rmsBeamletTab, 2)) + print '' + + if 'arts_sc4' in apps: + if wgEnable: + print 'Arts SC4 TAB internal levels (excluding sign bit) for coherent WG sinus input:' + print '. Fine channel rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannel, math.log(rmsComplexFineChannel, 2)) + print '. Fine channel ampl = %20.2f (= %4.1f [bit])' % (amplFineChannel, math.log(amplFineChannel, 2)) + print '. Fine channel TAB rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannelTab, math.log(rmsComplexFineChannelTab, 2)) + print '. Fine channel TAB ampl = %20.2f (= %4.1f [bit])' % (amplFineChannelTab, math.log(amplFineChannelTab, 2)) + print '. Fine channel TAB power = %20.2f (= %4.1f [bit])' % (meanFineChannelTabPower, math.log(meanFineChannelTabPower, 2)) + print '. Output TAB power = %20.2f (= %4.1f [bit])' % (meanIntegratedTabPower, math.log(meanIntegratedTabPower, 2)) + else: + print 'Arts SC4 TAB internal levels (excluding sign bit) for incoherent ADC noise input:' + print '. Fine channel rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannel, math.log(rmsComplexFineChannel, 2)) + print '. Fine channel rms = %20.2f (= %4.1f [bit])' % (rmsFineChannel, math.log(rmsFineChannel, 2)) + print '. Fine channel TAB rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannelTab, math.log(rmsComplexFineChannelTab, 2)) + print '. Fine channel TAB rms = %20.2f (= %4.1f [bit])' % (rmsFineChannelTab, math.log(rmsFineChannelTab, 2)) + print '. Fine channel TAB power = %20.2f (= %4.1f [bit])' % (meanFineChannelTabPower, math.log(meanFineChannelTabPower, 2)) + print '. Fine channel TAB power std = %20.2f (= %4.1f [bit])' % (stdFineChannelTabPower, math.log(stdFineChannelTabPower, 2)) + print '. Output TAB power = %20.2f (= %4.1f [bit])' % (meanIntegratedTabPower, math.log(meanIntegratedTabPower, 2)) + print '. Output TAB power std = %20.2f (= %4.1f [bit])' % (stdIntegratedTabPower, math.log(stdIntegratedTabPower, 2)) + print '' + + if wgEnable: + print 'Arts SC4 IAB internal levels (excluding sign bit) for coherent WG sinus input:' + print '. Fine channel rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannel, math.log(rmsComplexFineChannel, 2)) + print '. Fine channel ampl = %20.2f (= %4.1f [bit])' % (amplFineChannel, math.log(amplFineChannel, 2)) + print '. Fine channel power = %20.2f (= %4.1f [bit])' % (meanFineChannelPower, math.log(meanFineChannelPower, 2)) + print '. Integrated channel power = %20.2f (= %4.1f [bit])' % (meanIntegratedChannelPower, math.log(meanIntegratedChannelPower, 2)) + print '. Integrated IAB power = %20.2f (= %4.1f [bit])' % (meanIntegratedIabPower, math.log(meanIntegratedIabPower, 2)) + print '. Output IAB power = %20.2f (= %4.1f [bit])' % (meanOutputIabPower, math.log(meanOutputIabPower, 2)) + else: + print 'Arts SC4 IAB internal levels (excluding sign bit) for incoherent ADC noise input:' + print '. Fine channel rms complex = %20.2f (= %4.1f [bit])' % (rmsComplexFineChannel, math.log(rmsComplexFineChannel, 2)) + print '. Fine channel rms = %20.2f (= %4.1f [bit])' % (rmsFineChannel, math.log(rmsFineChannel, 2)) + print '. Fine channel power = %20.2f (= %4.1f [bit])' % (meanFineChannelPower, math.log(meanFineChannelPower, 2)) + print '. Integrated channel power = %20.2f (= %4.1f [bit])' % (meanIntegratedChannelPower, math.log(meanIntegratedChannelPower, 2)) + print '. Integrated IAB power = %20.2f (= %4.1f [bit])' % (meanIntegratedIabPower, math.log(meanIntegratedIabPower, 2)) + print '. Output IAB power = %20.2f (= %4.1f [bit])' % (meanOutputIabPower, math.log(meanOutputIabPower, 2)) + print '. Output IAB power std = %20.2f (= %4.1f [bit])' % (stdOutputIabPower, math.log(stdOutputIabPower, 2)) + print '' + +################################################################################ +# Plotting +################################################################################ +if useplot: + tplot = test_plot.Testplot() + tplot.close_plots() + + if 'static' in models: + ################################################################################ + # Static model: + # . WG, coherent input + # . Noise, incoherent input + ################################################################################ + + if wgEnable: + # WG, coherent input + # Plot internal levels as function of WG amplitude + Lx = A_wg + if 'apertif' in apps or 'arts_sc4' in apps: + A = [] + A.append(A_wg) + A.append(beamlet_wg_complex_phase_values * pi_apr.wgScale) + A.append(channel_x_wg_complex_phase_values * pi_apr.wgScale) + Alegend = ['adc', 'beamlet', 'channel_x'] + lineFormats = ['-', '-', '-'] + Title = 'Amplitudes for cbWeight=%d' % cbWeight + Ylim = None + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='WG amplitude', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=lineFormats) + tplot.save_figure('plots/apertif_arts_firmware_model_static_wg_amplitudes.png') # Save current figure + + if 'arts_sc1' in apps: + A = [] + A.append(A_wg) + A.append(beamlet_wg_complex_phase_values * pi_apr.wgScale) + A.append(beamlet_tab_wg_complex_phase_values_sc1 * pi_apr.wgScale) + Alegend = ['adc', 'beamlet', 'tab sc1'] + lineFormats = ['-', '-', '*'] + Title = 'Amplitudes for cbWeight=%d, tabWeightSc1=%d, nofDishes=%d' % (cbWeight, tabWeightSc1, nofDishes) + Ylim = None + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='WG amplitude', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=lineFormats) + tplot.save_figure('plots/apertif_arts_firmware_model_static_wg_amplitudes_sc1.png') # Save current figure + + if 'arts_sc4' in apps: + A = [] + A.append(power_tab_xx_wg_complex_values_sc4) + A.append(iab_xx_wg_complex_values_sc4) + Alegend = ['TAB XX* power', 'IAB XX* power'] + lineFormats = ['-', '*'] + Title = 'Powers for cbWeight=%d, tabWeightSc4=%d, iabGainReg=%d, nofDishes=%d' % (cbWeight, tabWeightSc4, iabGainReg, nofDishes) + Ylim = [0, 1.1 * 2.0**pi_apr.W_pow] + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='WG amplitude', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=lineFormats) + tplot.save_figure('plots/apertif_arts_firmware_model_static_wg_powers_sc4.png') # Save current figure + + # Plot power statistics as function of WG amplitude + A = [] + A.append(SST_wg_dBs) + A.append(BST_wg_dBs) + if 'apertif' in apps: + A.append(XC_wg_auto_visibilities_dB) + Alegend = ['SST', 'BST', 'XC'] + else: + Alegend = ['SST', 'BST'] + Title = 'Auto correlation power statistics for CB weight = %d' % cbWeight + Ylim = None + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='WG amplitude', Ylabel='Level [dB]', Xlim=None, Ylim=Ylim, lineFormats=None) + tplot.save_figure('plots/apertif_arts_firmware_model_static_wg_auto_powers.png') # Save current figure + + else: + # Noise, incoherent input + # Plot internal levels as function of WG amplitude + Lx = S_noise + if 'apertif' in apps or 'arts_sc4' in apps: + A = [] + A.append(S_noise) + A.append(beamlet_noise_complex_phase_values) + A.append(channel_x_noise_complex_phase_values) + Alegend = ['adc', 'beamlet', 'channel_x'] + lineFormats = ['-', '*', '-'] + Title = 'Sigmas for cbWeight=%d' % cbWeight + Ylim = None + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='ADC noise', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=lineFormats) + tplot.save_figure('plots/apertif_arts_firmware_model_static_noise_sigmas.png') # Save current figure + + if 'arts_sc1' in apps: + A = [] + A.append(S_noise) + A.append(beamlet_noise_complex_phase_values) + A.append(beamlet_tab_noise_complex_phase_values_sc1) + Alegend = ['adc', 'beamlet', 'tab sc1'] + lineFormats = ['-', '-', '*'] + Title = 'Sigmas for cbWeight=%d, tabWeightSc1=%d, nofDishes=%d' % (cbWeight, tabWeightSc1, nofDishes) + Ylim = None + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='ADC noise', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=lineFormats) + tplot.save_figure('plots/apertif_arts_firmware_model_static_noise_sigmas_sc1.png') # Save current figure + + if 'arts_sc4' in apps: + A = [] + A.append(power_tab_xx_noise_values_sc4) + A.append(iab_xx_noise_values_sc4) + Alegend = ['TAB XX* power', 'IAB XX* power'] + lineFormats = ['-', '*'] + Title = 'Powers for cbWeight=%d, tabWeightSc4=%d, iabGainReg=%d, nofDishes=%d' % (cbWeight, tabWeightSc4, iabGainReg, nofDishes) + Ylim = [0, 1.1 * 2.0**pi_apr.W_pow] + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='ADC noise', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=lineFormats) + tplot.save_figure('plots/apertif_arts_firmware_model_static_noise_powers_sc4.png') # Save current figure + + # Plot power statistics as function of WG amplitude + A = [] + A.append(SST_noise_dBs) + A.append(BST_noise_dBs) + A.append(XC_noise_auto_visibilities_dB) + Alegend = ['SST', 'BST', 'XC'] + Title = 'Auto correlation power statistics for CB weight = %d' % cbWeight + Ylim = None + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=Lx, representation='', offset=0, Title=Title, Xlabel='ADC noise', Ylabel='Level [dB]', Xlim=None, Ylim=Ylim, lineFormats=None) + tplot.save_figure('plots/apertif_arts_firmware_model_static_noise_auto_powers.png') # Save current figure + + + if 'dynamic' in models and wgSweep == 0: + ############################################################################### + # Dynamic model: Processing + ############################################################################### + + # Plot dish ADC + L = spSamples[0:nof_periods] # do not plot all to save time + if wgEnable: + Title = 'Dish ADC input (sigma = %.2f, ampl = %.2f)' % (rmsSp, wgAmpl) + ylim = 5 * math.ceil(0.2 * 1.1 * amplSp) + else: + Title = 'ADC input (sigma = %.2f)' % rmsSp + ylim = 5 * math.ceil(0.2 * 1.1 * rmsSp * nofSigma) + Ylim = [-ylim, ylim] + tplot.plot_one_dimensional_list(3, L, Lx=None, representation='', offset=0, Title=Title, Xlabel='Time [Tsub]', Ylabel='Voltage', Xlim=None, Ylim=Ylim) + tplot.save_figure('plots/apertif_arts_firmware_model_dynamic_adc.png') # Save current figure + + # Plot dish output beamlets for selSub + A = [] + A.append(beamletSamples.real[0:nof_periods]) + A.append(beamletSamples.imag[0:nof_periods]) + Alegend = ['real', 'imag'] + if wgEnable: + Title = 'Dish CB output samples (ampl = %.2f)' % amplBeamlet + ylim = 5 * math.ceil(0.2 * 1.1 * amplBeamlet) + else: + Title = 'Dish CB output samples (sigma = %.2f)' % rmsBeamlet + ylim = 5 * math.ceil(0.2 * 1.1 * rmsBeamlet * nofSigma) + Ylim = [-ylim, ylim] + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=None, representation='', offset=0, Title=Title, Xlabel='time [Tsub]', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=None) + tplot.save_figure('plots/apertif_arts_firmware_model_dynamic_beamlet.png') # Save current figure + + if 'apertif' in apps or 'arts_sc4' in apps: + # Plot correlator fine channels for selSub, selChanx + A = [] + A.append(fineChannelSamples.real[0:nof_periods]) + A.append(fineChannelSamples.imag[0:nof_periods]) + Alegend = ['real', 'imag'] + if wgEnable: + Title = 'Central fine channel samples (ampl = %.2f)' % amplFineChannel + ylim = 5 * math.ceil(0.2 * 1.1 * amplFineChannel) + else: + Title = 'Central fine channel samples (sigma = %.2f)' % rmsFineChannel + ylim = 5 * math.ceil(0.2 * 1.1 * rmsFineChannel * nofSigma) + Ylim = [-ylim, ylim] + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=None, representation='', offset=0, Title=Title, Xlabel='time [Tsub]', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=None) + tplot.save_figure('plots/apertif_arts_firmware_model_dynamic_fine_channel.png') # Save current figure + + if 'arts_sc1' in apps: + # Plot Arts SC1 output TAB samples for selSub and nofDishes + # . Independent of nofDishes when tabWeightSc1 is scaled by nofDishes or sqrt(nofDishes) + A = [] + A.append(beamletTabSamples.real[0:nof_periods]) + A.append(beamletTabSamples.imag[0:nof_periods]) + Alegend = ['real', 'imag'] + if wgEnable: + Title = 'Arts SC1 output TAB samples (ampl = %.2f, nofDishes = %d)' % (amplBeamletTab, nofDishes) + ylim = 5 * math.ceil(0.2 * 1.1 * amplBeamletTab) + else: + Title = 'Arts SC1 output TAB samples (sigma = %.2f, nofDishes = %d)' % (rmsBeamletTab, nofDishes) + ylim = 5 * math.ceil(0.2 * 1.1 * rmsBeamletTab * nofSigma) + Ylim = [-ylim, ylim] + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=None, representation='', offset=0, Title=Title, Xlabel='time [Tsub]', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=None) + tplot.save_figure('plots/apertif_arts_firmware_model_dynamic_beamlet_tab.png') # Save current figure + + if 'arts_sc4' in apps: + # Plot Arts SC4 output TAB powers for selSub, selChanx and nofDishes + # . Independent of nofDishes, because tabWeightSc4 is scaled by nofDishes or sqrt(nofDishes) + A = [] + A.append(integratedTabPowers[0:nof_periods]) + Alegend = None + Title = 'Arts SC4 output TAB powers (mean = %.2f = %.1f [bit], nofDishes = %d)' % (meanIntegratedTabPower, math.log(meanIntegratedTabPower, 2), nofDishes) + if wgEnable: + ylim = 5 * math.ceil(0.2 * 1.1 * meanIntegratedTabPower) + else: + ylim = 5 * math.ceil(0.2 * 1.1 * meanIntegratedTabPower * nofSigma) + Ylim = [0, ylim] + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=None, representation='', offset=0, Title=Title, Xlabel='time [Tchanx]', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=None) + tplot.save_figure('plots/apertif_arts_firmware_model_dynamic_power_tab.png') # Save current figure + + # Plot Arts SC4 output IAB powers for selSub, selChanx and nofDishes + # . Independent of nofDishes, because tabWeightSc4 is scaled by nofDishes or sqrt(nofDishes) + A = [] + A.append(outputIabPowers) + Alegend = None + Title = 'Arts SC4 output IAB powers (mean = %.2f = %.1f [bit], nofDishes = %d)' % (meanOutputIabPower, math.log(meanOutputIabPower, 2), nofDishes) + if wgEnable: + ylim = 5 * math.ceil(0.2 * 1.1 * meanOutputIabPower) + else: + ylim = 5 * math.ceil(0.2 * 1.1 * meanOutputIabPower * nofSigma) + Ylim = [0, ylim] + tplot.plot_two_dimensional_list(3, A, Alegend=Alegend, Lx=None, representation='', offset=0, Title=Title, Xlabel='time [Tchanx]', Ylabel='Level', Xlim=None, Ylim=Ylim, lineFormats=None) + tplot.save_figure('plots/apertif_arts_firmware_model_dynamic_power_iab.png') # Save current figure + + + if 'dynamic' in models and wgSweep != 0: + ############################################################################### + # Dynamic model: WG frequency sweep + ############################################################################### + + # Plot subband spectrum abs(fSubSamples[nofTsub][N_sub]) + A = np.abs(fSubSamples) + tplot.image_two_dimensional_list(3, A, transpose=True, grid=True, Title='Subband magnitudes', Xlabel='time [Tsub]', Ylabel='freq [fsub]') + tplot.save_figure('plots/apertif_arts_firmware_model_wg_sweep_subband_spectrum.png') # Save current figure + + # Plot fine channels spectrum abs(fSubChanSamples[N_sub][nofTchanx][N_chan_x]) + A = np.abs(fSubChanSamples.reshape(nofTchanx, N_sub*N_chan_x)) # [nofTchanx][N_sub*N_chan_x] + chanLo = 0 + chanHi = N_sub*N_chan_x - 1 + nofSubBorder = 0 + nofSubBorder = 1 + int(abs(wgSweep)) + if nofSubBorder>0: + if wgSweep>0: + chanLo = N_chan_x * (selSub - nofSubBorder) + chanHi = N_chan_x * (selSub + nofSubBorder + wgSweep + 1) - 1 + else: + chanLo = N_chan_x * (selSub - nofSubBorder + wgSweep) + chanHi = N_chan_x * (selSub + nofSubBorder + 1) - 1 + A = A[:, chanLo:chanHi+1] + extent = [0, nofTchanx-1, 1.0 * chanLo / N_chan_x - 0.5, 1.0 * chanHi / N_chan_x - 0.5] + #print chanLo, chanHi, extent + #extent = None + tplot.image_two_dimensional_list(3, A, transpose=True, grid=True, Title='Channel magnitudes', Xlabel='time [Tchanx]', Ylabel='freq [fsub]', extent=extent) + tplot.save_figure('plots/apertif_arts_firmware_model_wg_sweep_fine_channel_spectrum.png') # Save current figure + + tplot.show_plots() + -- GitLab