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 @@ ...@@ -32,16 +32,20 @@
The test verifies the read data and runs independently per PN on the correlator. The test does not access 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 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 telescope paths (TP) which will result in non-zero visibility data. The assumption is that the selected
are receiving (any noise) and outputting beamlets. --tel telescopes are receiving (sky) noise and are outputting beamlets.
Usage: Usage:
# -v 5 or 6 for debugging # use verbosity level -v 5 or 6 for debugging, or -v 0, 1, 2 or 3 for regression test
# -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/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 ...@@ -53,39 +57,11 @@ import test_case
import node_io import node_io
import pi_diag_data_buffer import pi_diag_data_buffer
import unb_apertif as apr import unb_apertif as apr
import pi_apertif_system as pi_apr
N_dish = 12 N_vis = pi_apr.N_vis # = 300
N_pol = 2 M_blk = pi_apr.M_blk # = 88 or 120
N_tp = N_pol * N_dish # = 24 N_chan_x = pi_apr.N_chan_x # = 64
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
############################################################################### ###############################################################################
# Instantiations # Instantiations
...@@ -97,219 +73,81 @@ activeDishes = apr.get_active_dishes(tc.telStrList) ...@@ -97,219 +73,81 @@ activeDishes = apr.get_active_dishes(tc.telStrList)
activePolarizations = tc.polNrs activePolarizations = tc.polNrs
activeTp = apr.get_active_telescope_paths(activeDishes, activePolarizations) activeTp = apr.get_active_telescope_paths(activeDishes, activePolarizations)
activeVis = apr.get_active_visibilities(activeTp) 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. # Declaring an object of this class is equivalent to func_apertif_unb1_correlator_packet_info() in VHDL.
corrPacketInfo = apr.CorrelatorPacketInfo(N_vis) corrPacketInfo = apr.CorrelatorPacketInfo(N_vis)
# One or more beamlet and channel indices to select the visibility packets # One or more beamlet indices to select the channel visibility packets
beamlets = tc.beamlets beamletIndices = tc.beamlets
if not cm.exist_all_elements_from_a_in_b(beamlets, range(M_blk)): 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)' % (tc.beamlets, M_blk)) tc.append_log(tc.V_ERRORS, 'Specified --beamlets %s must fit in range(%d)' % (beamletIndices, M_blk))
tc.set_result('FAILED') tc.set_result('FAILED')
sys.exit() sys.exit()
channels = tc.channels channelIndices = tc.channels
if not cm.exist_all_elements_from_a_in_b(channels, range(N_chan_x)): 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)' % (tc.channels, 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') tc.set_result('FAILED')
sys.exit() sys.exit()
tc.append_log(3, '>>>') 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(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, '>>> . beamlet(s) : %s (from index range(M_blk) = [0:%d])' % (beamletIndices, 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, '>>> . 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, '>>>')
tc.append_log(3, '') tc.append_log(3, '')
io = node_io.NodeIO(tc.nodeImages, tc.base_ip) io = node_io.NodeIO(tc.nodeImages, tc.base_ip)
# Create one DB object for all PN # Create correlator output object
db_output = pi_diag_data_buffer.PiDiagDataBuffer(tc, io, instanceName='OUTPUT', nofStreams=1, ramSizePerStream=c_dbSize, version=0) 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: # Setup and read DB output to capture the visibility packets
for ch in channels: for bui in beamletIndices:
############################################################################### for chi in channelIndices:
# Stimuli corDb.read_correlator_db_output(bui, chi)
# Overwrite DB data to be able to recognize new data # Verify visibility packet headers
db_output.overwrite_all_data_buffers(data=c_dbPattern, vLevel=9) corDb.verify_correlator_db_output_headers(beamletIndices, channelIndices)
# 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)
# 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 # Verify visibility payload data
rdIdMarker = cm.to_unsigned(rdData[11], 32) >> 24 #
if rdIdMarker == c_expIdMarker: # A visibility packet contains all N_vis = 300 complex visibilities for one (beamlet, channel):
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'ID marker = %d is OK' % rdIdMarker) # - The visibilities for which at least one TP is inactive must be zero, because for those TP the
else: # firmware forces the data to zero.
tc.append_log(tc.V_ERRORS, reportStr + 'read ID marker is wrong (read %d != %d expected)' % (rdIdMarker, c_expIdMarker)) # - If both TP in a visibility are active, then the visibility can be non-zero. The visibility
tc.set_result('FAILED') # can still be zero if the BF weights for the corresponding beamlet are zero.
#
# . ID version # Visibility (col, row) indices for
rdIdVersion = cm.to_unsigned(rdData[11], 24) >> 16 # 0 vis (0,0)
if rdIdVersion == c_expIdVersion: # 1 vis (0,1) 24 vis (1,1)
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'ID version = %d is OK' % rdIdVersion) # 2 vis (0,2) 25 vis (1,2) 47 vis (2,2)
else: # 3 vis (0,3) 26 vis (1,3) 48 vis (2,3)
tc.append_log(tc.V_ERRORS, reportStr + 'read ID version is wrong (read %d != %d expected)' % (rdIdVersion, c_expIdVersion)) # ... ... ...
tc.set_result('FAILED') # 23 vis (0,23) 46 vis (1,23) 68 vis (2,23) ... 299 vis (23,23)
#
# . beamlet # 24 + 23 + 22 ... + 1 = 300 visibilities
rdBeamlet = cm.to_unsigned(rdData[11], 16) #
if rdBeamlet == expBeamlet: for gn in tc.nodeNrs: # loop active PN
tc.append_log(tc.V_INFO_DETAILS, reportStr + 'beamlet = %d is OK' % rdBeamlet) unb, pn = apr.correlator_gn_to_unb_pn(gn)
else: for bui in beamletIndices: # loop serial beamlets
tc.append_log(tc.V_ERRORS, reportStr + 'read beamlet is wrong (read %d != %d expected)' % (rdBeamlet, expBeamlet)) for chi in channelIndices: # loop serial channels
tc.set_result('FAILED') reportStr = 'unb = %2d, pn = %d, bui = %3d, chi = %2d : ' % (unb, pn, bui, chi)
# . 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)
################################################################### rdVisibilities = corDb.dbOutputVisibilities[gn][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
# Find the TP for all read visibilities that are non-zero # Find the TP for all read visibilities that are non-zero
nonZeroVisibilities = cm.find_indices_where_ne(rdVisibilities, 0) nonZeroVisibilities = cm.find_indices_where_ne(rdVisibilities, 0)
...@@ -319,9 +157,12 @@ for bui in beamlets: ...@@ -319,9 +157,12 @@ for bui in beamlets:
nonZeroPolarizations = apr.tp_to_pol_indices(nonZeroTp) nonZeroPolarizations = apr.tp_to_pol_indices(nonZeroTp)
nonZeroAutoVisibilities = apr.get_auto_visibilities(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 # . 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. # 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: 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)) tc.append_log(tc.V_INFO_DETAILS, reportStr + 'Non zero TP = %s : polarizations = %s and dishes = %s are OK' % (nonZeroTp, nonZeroPolarizations, nonZeroDishes))
else: else:
...@@ -333,7 +174,10 @@ for bui in beamlets: ...@@ -333,7 +174,10 @@ for bui in beamlets:
for ai in nonZeroAutoVisibilities: for ai in nonZeroAutoVisibilities:
atp2 = apr.visibilities_to_tp_pairs(ai) 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 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) atpFail.append(atp)
#print ai, atp2, atp, rdVisibilities[ai] #print ai, atp2, atp, rdVisibilities[ai]
if len(atpFail)==0: if len(atpFail)==0:
...@@ -348,3 +192,4 @@ for bui in beamlets: ...@@ -348,3 +192,4 @@ for bui in beamlets:
tc.set_section_id('') tc.set_section_id('')
tc.append_log(tc.V_RESULT, '>>> Test result: %s' % tc.get_result()) 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.
Finish editing this message first!
Please register or to comment