Skip to content
Snippets Groups Projects
Commit 7ccb07c6 authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Use methods from pi-apertif_system.py to access DB output.

parent 138005d0
No related branches found
No related tags found
No related merge requests found
......@@ -32,16 +32,20 @@
The test verifies the read data and runs independently per PN on the correlator. The test does not access
the telescopes, but some --tel must be specified because --tel and --pol are used to derive the active
telescope paths (TP) which will result in non-zero visibility data. The assumption is that the telescopes
are receiving (any noise) and outputting beamlets.
telescope paths (TP) which will result in non-zero visibility data. The assumption is that the selected
--tel telescopes are receiving (sky) noise and are outputting beamlets.
Usage:
# -v 5 or 6 for debugging
# -v 0, 1, 2 or 3 for regression test
# use verbosity level -v 5 or 6 for debugging, or -v 0, 1, 2 or 3 for regression test
# At central correlator verify expected result via DB
# First start the dishes and central boards
> python $RADIOHDL/applications/apertif/commissioning/main.py --app apertif-dev --tel a --pol 0,1 --unb 0,1
> python $RADIOHDL/applications/apertif/commissioning/tests/verify_correlator_db_output.py -v 3 --tel a --unb 0 --fn 0:3 --bn 0:3 --beamlets 0 --channels 0
# Set dish BF weights to have one SP per CB for all beamlets and rely on the measured sky noise to provide ADC input
> ssh lcu-rta "python $UPE/peripherals/pi_apertif_system.py -v 3 --unb 0:7 --fn 0:3 --cmd 62 --cbeams 0:36 --pol 0,1 --subbands 0:511 --globalsp 56 --weight 32767,0"
# At central correlator verify expected visibility packet result via DB output
> python $RADIOHDL/applications/apertif/commissioning/tests/verify_correlator_db_output.py -v 3 --tel a --unb 0,1 --fn 0:3 --bn 0:3 --beamlets 0 --channels 0
"""
###############################################################################
......@@ -53,39 +57,11 @@ import test_case
import node_io
import pi_diag_data_buffer
import unb_apertif as apr
import pi_apertif_system as pi_apr
N_dish = 12
N_pol = 2
N_tp = N_pol * N_dish # = 24
N_vis = N_tp * (N_tp + 1) / 2
N_band = 16
N_slot = 1024
N_clk = 256
N_blk = 176 # 8b mode
Q_interleave = 2
M_blk = N_blk / Q_interleave # = 88
N_int_x = 800000
N_chan_x = 64
N_chan_x_w = cm.ceil_log2(N_chan_x)
nof_bn = 4 # Number of back node FPGAs (BN) per UniBoard
nof_fn = 4 # Number of front node FPGAs (FN) per UniBoard
nof_pn = 8 # Number of processing node FPGAs per UniBoard, = nof_fn + nof_bn
nof_10g = 3 # Number of external 10G links per PN on UniBoard
c_dbSize = 1024
c_dbPattern = [13]*c_dbSize
c_baseSrcMac = 0x002286080000
c_wcudata = 1 # is 1 if Data Write is 'wcudata1', else is 2 if DataWriter is 'wcudata2', as defined in central_commands.sh
if c_wcudata==1:
c_baseDstMacEth01 = 0xe41d2de42690
c_baseDstMacEth23 = 0xe41d2dbc3cd0
else:
c_baseDstMacEth01 = 0xe41d2dbc3dc0
c_baseDstMacEth23 = 0xe41d2de40d30
c_expIdMarker = 65
c_expIdVersion = 2
N_vis = pi_apr.N_vis # = 300
M_blk = pi_apr.M_blk # = 88 or 120
N_chan_x = pi_apr.N_chan_x # = 64
###############################################################################
# Instantiations
......@@ -97,219 +73,81 @@ activeDishes = apr.get_active_dishes(tc.telStrList)
activePolarizations = tc.polNrs
activeTp = apr.get_active_telescope_paths(activeDishes, activePolarizations)
activeVis = apr.get_active_visibilities(activeTp)
activeAutoVis = apr.get_auto_visibilities(activeTp)
# Declaring an object of this class is equivalent to func_apertif_unb1_correlator_packet_info() in VHDL.
corrPacketInfo = apr.CorrelatorPacketInfo(N_vis)
# One or more beamlet and channel indices to select the visibility packets
beamlets = tc.beamlets
if not cm.exist_all_elements_from_a_in_b(beamlets, range(M_blk)):
tc.append_log(tc.V_ERRORS, 'Specified --beamlets %s must fit in range(%d)' % (tc.beamlets, M_blk))
# One or more beamlet indices to select the channel visibility packets
beamletIndices = tc.beamlets
if not cm.exist_all_elements_from_a_in_b(beamletIndices, range(M_blk)):
tc.append_log(tc.V_ERRORS, 'Specified --beamlets %s must fit in range(%d)' % (beamletIndices, M_blk))
tc.set_result('FAILED')
sys.exit()
channels = tc.channels
if not cm.exist_all_elements_from_a_in_b(channels, range(N_chan_x)):
tc.append_log(tc.V_ERRORS, 'Specified --channels %s must fit in range(%d)' % (tc.channels, N_chan_x))
channelIndices = tc.channels
if not cm.exist_all_elements_from_a_in_b(channelIndices, range(N_chan_x)):
tc.append_log(tc.V_ERRORS, 'Specified --channels %s must fit in range(%d)' % (channelIndices, N_chan_x))
tc.set_result('FAILED')
sys.exit()
tc.append_log(3, '>>>')
tc.append_log(1, '>>> Title : Test case to verify visibility packet header and zero/non-zero payload of correlator DB OUTPUT for %s' % tc.unb_nodes_string())
tc.append_log(3, '>>> . beamlet(s) : %s (from range(M_blk) = [0:%d])' % (beamlets, M_blk-1))
tc.append_log(3, '>>> . channel(s) : %s (from range(N_chan_x) = [0:%d])' % (channels, N_chan_x-1))
tc.append_log(3, '>>> . beamlet(s) : %s (from index range(M_blk) = [0:%d])' % (beamletIndices, M_blk-1))
tc.append_log(3, '>>> . channel(s) : %s (from index range(N_chan_x) = [0:%d])' % (channelIndices, N_chan_x-1))
tc.append_log(3, '')
tc.append_log(3, '>>> . activeDishes : %s is %s from %s' % (activeDishes, tc.telStrList, apr.wsrtTelescopes))
tc.append_log(3, '>>> . activePolarizations : %s is %s' % (activePolarizations, tc.to_pol_xy(tc.polNrs)))
tc.append_log(3, '>>> . activeTp : %s' % activeTp)
tc.append_log(3, '>>> . activeVis : %s' % activeVis)
tc.append_log(3, '>>> . activeAutoVis : %s' % activeAutoVis)
tc.append_log(3, '>>>')
tc.append_log(3, '')
io = node_io.NodeIO(tc.nodeImages, tc.base_ip)
# Create one DB object for all PN
db_output = pi_diag_data_buffer.PiDiagDataBuffer(tc, io, instanceName='OUTPUT', nofStreams=1, ramSizePerStream=c_dbSize, version=0)
# Create correlator output object
rsub = pi_apr.declare_reorder_subbands(tc, io)
rbeam = pi_apr.declare_reorder_beamlets(tc, io)
corDb = pi_apr.CorrelatorOutputDataBuffer(tc, io, rsub, rbeam, dbSize=1024) # assume minimum DB size that can fit 1 visibility packet
###############################################################################
# Stimuli
for bui in beamlets:
for ch in channels:
###############################################################################
# Stimuli
# Setup and read DB output to capture the visibility packets
for bui in beamletIndices:
for chi in channelIndices:
corDb.read_correlator_db_output(bui, chi)
# Overwrite DB data to be able to recognize new data
db_output.overwrite_all_data_buffers(data=c_dbPattern, vLevel=9)
# Use start of packet address for DB sync delay
sopAddr = ((bui * N_chan_x) + ch) * corrPacketInfo.vis_packet_size
dbSyncDelay = sopAddr
db_output.write_sync_delay(data=dbSyncDelay)
db_output.read_sync_delay()
# when dbSyncDelay=0 then the DB is written every sync
# else need to arm the DB using write access strobe to capture once at next sync + dbSyncDelay + latency(14)
if dbSyncDelay>0:
# Wait unit DB is ready to arm
tc.sleep(2)
db_output.write_arm_reg(data=1)
# Wait unit DB have been filled
tc.sleep(2)
# Verify visibility packet headers
corDb.verify_correlator_db_output_headers(beamletIndices, channelIndices)
# Read DB on all PN
dbOutputReadData = db_output.read_data_buffer(nofColumns=tc.nofCol)
###############################################################################
# Verification per PN
for ni,nr in enumerate(tc.nodeNrs): # loop PN
# Get read packet data
rdData = dbOutputReadData[ni]
# Get packet info
unb = nr / nof_pn # = range(N_band) = 0:15 = [0:127] / 8
pn = nr % nof_pn # = range(nof_pn) = 0:7 = [0:127] % 8
reportStr = 'unb = %2d, pn = %d, bui = %3d, ch = %2d : ' % (unb, pn, bui, ch)
###################################################################
# Verify header fields
# Beamlet mapping as specified in SP-062 table 6 (SC1), 9 (SC4):
#
# u bi dest bui
# 0 0 0 FN0 0 2 ...
# 1 0 1 FN1 256 258 ...
# 2 0 2 FN2 512 514 ...
# 3 0 3 FN3 768 770 ...
# 0 1 4 BN0 1 3 ...
# 1 1 5 BN1 257 259 ...
# 2 1 6 BN2 513 515 ...
# 3 1 7 BN3 769 771 ...
#
# Beamlet mapping as implemented in Apertif X due to reordered_sosi_arr wiring in node_apertif_unb1_correlator_mesh.vhd:
#
# u bi dest bui
# 0 0 0 FN0 0 2 ...
# 1 0 1 FN1 1 3 ...
# 2 0 2 FN2 256 258 ...
# 3 0 3 FN3 257 259 ...
# 0 1 4 BN0 512 514 ...
# 1 1 5 BN1 513 515 ...
# 2 1 6 BN2 768 770 ...
# 3 1 7 BN3 769 771 ...
expBeamlet = N_slot * unb # offset for UniBoard band
expBeamlet = expBeamlet + N_clk * (pn / Q_interleave) + (pn % Q_interleave) # offset for Local PN
expBeamlet = expBeamlet + bui * Q_interleave # offset serial beamlets
expChannel = cm.reverse_bits(ch, N_chan_x_w)
expChannel = cm.invert_msbit(expChannel, N_chan_x_w)
# Header fields
# 0 gap(16) + ETH dst mac hi(16)
# 1 ETH dst mac lo
# 2 ETH src mac hi
# 3 ETH src mac lo(16) + type(16)
# 4 IP
# 5 IP
# 6 IP
# 7 IP src addr
# 8 IP dst addr
# 9 UDP src port(16) + dst port(16)
# 10 UDP total len(16) + checksum(16)
# 11 ID marker(8) + version(8) + beamlet(16)
# 12 ID channel(16) + rsvd(16)
# 13 ID timestamp hi
# 14 ID timestamp lo
# 15 FLAG
# 16 FLAG
# 17 FLAG
# 18 FLAG
# 19 FLAG
# 20 FLAG
# . dst mac as defined in central_commands.sh
if unb< 4: expDstMac = c_baseDstMacEth01
elif unb< 8: expDstMac = c_baseDstMacEth01 + 1
elif unb<12: expDstMac = c_baseDstMacEth23
elif unb<16: expDstMac = c_baseDstMacEth23 + 1
rdDstMac = cm.to_unsigned(rdData[0], 16) << 32
rdDstMac += cm.to_unsigned(rdData[1], 32)
if rdDstMac == expDstMac:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'destination MAC = 0x%012X is OK' % rdDstMac)
else:
tc.append_log(tc.V_ERRORS, reportStr + 'read destination MAC is wrong (read 0x%012X != 0x%012X expected)' % (rdDstMac, expDstMac))
tc.set_result('FAILED')
# . src mac
expSrcMac = c_baseSrcMac + unb * 256 + pn
rdSrcMac = cm.to_unsigned(rdData[2], 32) << 16
rdSrcMac += cm.to_unsigned(rdData[3], 32) >> 16
if rdSrcMac == expSrcMac:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'source MAC = 0x%012X is OK' % rdSrcMac)
else:
tc.append_log(tc.V_ERRORS, reportStr + 'read source MAC is wrong (read 0x%012X != 0x%012X expected)' % (rdSrcMac, expSrcMac))
tc.set_result('FAILED')
# . ID marker
rdIdMarker = cm.to_unsigned(rdData[11], 32) >> 24
if rdIdMarker == c_expIdMarker:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'ID marker = %d is OK' % rdIdMarker)
else:
tc.append_log(tc.V_ERRORS, reportStr + 'read ID marker is wrong (read %d != %d expected)' % (rdIdMarker, c_expIdMarker))
tc.set_result('FAILED')
# . ID version
rdIdVersion = cm.to_unsigned(rdData[11], 24) >> 16
if rdIdVersion == c_expIdVersion:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'ID version = %d is OK' % rdIdVersion)
else:
tc.append_log(tc.V_ERRORS, reportStr + 'read ID version is wrong (read %d != %d expected)' % (rdIdVersion, c_expIdVersion))
tc.set_result('FAILED')
# . beamlet
rdBeamlet = cm.to_unsigned(rdData[11], 16)
if rdBeamlet == expBeamlet:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'beamlet = %d is OK' % rdBeamlet)
else:
tc.append_log(tc.V_ERRORS, reportStr + 'read beamlet is wrong (read %d != %d expected)' % (rdBeamlet, expBeamlet))
tc.set_result('FAILED')
# . channel
rdChannel = cm.to_unsigned(rdData[12], 32) >> 16
if rdChannel == expChannel:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'channel = %d is OK' % rdChannel)
else:
tc.append_log(tc.V_ERRORS, reportStr + 'read channel is wrong (read %d != %d expected)' % (rdChannel, expChannel))
tc.set_result('FAILED')
# . timestamp (= bsn)
rdBsn = cm.to_unsigned(rdData[13], 32) << 32
rdBsn += cm.to_unsigned(rdData[14], 32)
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'read BSN = %d' % rdBsn)
# Verify visibility payload data
#
# A visibility packet contains all N_vis = 300 complex visibilities for one (beamlet, channel):
# - The visibilities for which at least one TP is inactive must be zero, because for those TP the
# firmware forces the data to zero.
# - If both TP in a visibility are active, then the visibility can be non-zero. The visibility
# can still be zero if the BF weights for the corresponding beamlet are zero.
#
# Visibility (col, row) indices for
# 0 vis (0,0)
# 1 vis (0,1) 24 vis (1,1)
# 2 vis (0,2) 25 vis (1,2) 47 vis (2,2)
# 3 vis (0,3) 26 vis (1,3) 48 vis (2,3)
# ... ... ...
# 23 vis (0,23) 46 vis (1,23) 68 vis (2,23) ... 299 vis (23,23)
#
# 24 + 23 + 22 ... + 1 = 300 visibilities
#
for gn in tc.nodeNrs: # loop active PN
unb, pn = apr.correlator_gn_to_unb_pn(gn)
for bui in beamletIndices: # loop serial beamlets
for chi in channelIndices: # loop serial channels
reportStr = 'unb = %2d, pn = %d, bui = %3d, chi = %2d : ' % (unb, pn, bui, chi)
###################################################################
# Verify payload data
#
# A visibility packet contains all N_vis = 300 visibilities for one (beamlet, channel):
# - The visibilities for which at least one TP is inactive must be zero, because for those TP the
# firmware forces the data to zero.
# - If both TP in a visibility are active, then the visibility can be non-zero. The visibility
# can still be zero if the BF weights for the corresponding beamlet are zero.
#
# Visibility (col, row) indices for
# 0 vis (0,0)
# 1 vis (0,1) 24 vis (1,1)
# 2 vis (0,2) 25 vis (1,2) 47 vis (2,2)
# 3 vis (0,3) 26 vis (1,3) 48 vis (2,3)
# ... ... ...
# 23 vis (0,23) 46 vis (1,23) 68 vis (2,23) ... 299 vis (23,23)
#
# 24 + 23 + 22 ... + 1 = 300 visibilities
#
# The visibilities are stored in two 32b words: real, imag, so in total 600 words payload.
rdPayload = rdData[corrPacketInfo.vis_header_size:corrPacketInfo.vis_header_size+N_vis*cm.c_nof_complex]
rdVisibilities = []
even = True
for data in rdPayload:
dataNtoh = cm.reverse_word(data) # change endianess
if even:
visReal = cm.to_signed(dataNtoh, 32)
else:
visImag = cm.to_signed(dataNtoh, 32)
rdVisibilities.append(complex(visReal, visImag))
even = not even
rdVisibilities = corDb.dbOutputVisibilities[gn][bui][chi]
# Find the TP for all read visibilities that are non-zero
nonZeroVisibilities = cm.find_indices_where_ne(rdVisibilities, 0)
......@@ -319,9 +157,12 @@ for bui in beamlets:
nonZeroPolarizations = apr.tp_to_pol_indices(nonZeroTp)
nonZeroAutoVisibilities = apr.get_auto_visibilities(nonZeroTp)
# Verify that the active TP yield non-zero visibilities
# Verify that only the active TP yield non-zero visibilities
# . Assume the BF weights have been set to select at least one ADC input per CB then the input (sky) noise at the ADC
# will contribute to all channels, so the visibilities for the TP pairs of active TP will then be none zero.
for vi in nonZeroVisibilities:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'Non zero correlation[%d] = %s' % (vi, rdVisibilities[vi]))
if activeTp == nonZeroTp:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'Non zero TP = %s : polarizations = %s and dishes = %s are OK' % (nonZeroTp, nonZeroPolarizations, nonZeroDishes))
else:
......@@ -333,7 +174,10 @@ for bui in beamlets:
for ai in nonZeroAutoVisibilities:
atp2 = apr.visibilities_to_tp_pairs(ai)
atp = atp2[0][0] # get tp from list with one tuple(tp, tp), both tp in tuple are the same index for auto correlation visibility
if not (rdVisibilities[ai].real>0 and rdVisibilities[ai].imag==0):
if rdVisibilities[ai].real>0 and rdVisibilities[ai].imag==0:
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'Auto correlation[%d] = %s' % (ai, rdVisibilities[ai]))
else:
tc.append_log(tc.V_ERRORS, reportStr + 'Auto correlation[%d] = %s is wrong' % (ai, rdVisibilities[ai]))
atpFail.append(atp)
#print ai, atp2, atp, rdVisibilities[ai]
if len(atpFail)==0:
......@@ -348,3 +192,4 @@ for bui in beamlets:
tc.set_section_id('')
tc.append_log(tc.V_RESULT, '>>> Test result: %s' % tc.get_result())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment