From 39437f8373f428200756490cda60765ef2d5e77c Mon Sep 17 00:00:00 2001 From: Daniel van der Schuur <schuur@astron.nl> Date: Tue, 10 Feb 2015 08:31:10 +0000 Subject: [PATCH] -Moved functions from verify_correlator to new file_io.py and common_dsp.py. --- .../correlator/tb/python/verify_correlator.py | 377 ++++-------------- 1 file changed, 86 insertions(+), 291 deletions(-) diff --git a/libraries/dsp/correlator/tb/python/verify_correlator.py b/libraries/dsp/correlator/tb/python/verify_correlator.py index 57db5c0e74..051a3d3b38 100644 --- a/libraries/dsp/correlator/tb/python/verify_correlator.py +++ b/libraries/dsp/correlator/tb/python/verify_correlator.py @@ -23,6 +23,7 @@ import os import time from common import * from common_dsp import * +from file_io import * from mem_init_file import list_to_hex # Purpose: @@ -38,21 +39,26 @@ from mem_init_file import list_to_hex # . .. # . Input 23 - 23 degrees -NOF_INPUTS = 6 -NOF_CHANNELS = 4 +NOF_INPUTS = 7 +NOF_CHANNELS = 8 COMPLEX_WIDTH = 8 -NOF_FOLDS = 0 +NOF_PRE_MULT_FOLDS = 2 +NOF_INPUT_FOLDS = 0 # =< NOF_PRE_MULT_FOLDS -USE_NEW_REC_FILE = False # True = don't use outdated .rec file; wait for new one. -PLOT_CORR_OUT_PHASES = False # Plot the correlator output phases of channel 0 of both the VHDL and the Model + +USE_NEW_REC_FILE = False #True = don't use outdated .rec file; wait for new one. +PLOT_CORR_OUT_PHASES = True # Plot the correlator output phases of channel 0 of both the VHDL and the Model NOF_VISIBILITIES = (NOF_INPUTS*(NOF_INPUTS+1))/2 NOF_LINES_IN_REC_FILE_TO_VERIFY = NOF_CHANNELS*NOF_VISIBILITIES -NOF_INPUT_STREAMS = NOF_INPUTS/pow(2, NOF_FOLDS) -INTEGRATION_PERIOD = NOF_VISIBILITIES +NOF_INPUT_STREAMS = NOF_INPUTS/pow(2, NOF_INPUT_FOLDS) + +NOF_MULTS = ceil_div(NOF_VISIBILITIES, pow(2, NOF_PRE_MULT_FOLDS)) + +INTEGRATION_PERIOD = NOF_MULTS # We always use the minimum integration period needed to be able to interleave the accumulator outputs onto one stream CORRELATOR_MULT_OUTPUT_COMPLEX_WIDTH = 2* COMPLEX_WIDTH CORRELATOR_OUTPUT_COMPLEX_WIDTH = CORRELATOR_MULT_OUTPUT_COMPLEX_WIDTH + ceil_log2(INTEGRATION_PERIOD) -NOF_WORDS_PER_BLOCK = NOF_CHANNELS*pow(2, NOF_FOLDS) +NOF_WORDS_PER_BLOCK = NOF_CHANNELS*pow(2, NOF_INPUT_FOLDS) MEM_WIDTH = COMPLEX_WIDTH*2 MEM_DEPTH = NOF_WORDS_PER_BLOCK PATH = "../../src/hex" @@ -60,262 +66,29 @@ FILENAME = "complex_subbands" REC_FILE = os.environ['RADIOHDL']+'/libraries/dsp/correlator/tb/rec/correlator_src_out_arr0.rec' -NOF_DP_RECORD_FIELDS = 11 - -DP_RECORD_INDEX_SYNC = 0 -DP_RECORD_INDEX_BSN = 1 -DP_RECORD_INDEX_DATA = 2 -DP_RECORD_INDEX_RE = 3 -DP_RECORD_INDEX_IM = 4 -DP_RECORD_INDEX_VALID = 5 -DP_RECORD_INDEX_SOP = 6 -DP_RECORD_INDEX_EOP = 7 -DP_RECORD_INDEX_EMPTY = 8 -DP_RECORD_INDEX_CHANNEL = 9 -DP_RECORD_INDEX_ERR = 10 - -def gen_complex_inputs(nof_inputs, nof_channels, complex_width): - """ - Returns a 2d list of NOF_INPUTS*NOF_CHANNELS, in complex format. - . 1 deg. phase shift between the inputs - . Amplitude increases with increasing channel index - """ - phase_incr = 1 - ampl_incr = 1 - - # != amplitude maar Y-val. Mag dus ook negatief zijn. - max_amplitude = pow(2, complex_width)/2-1 - - ampl_lo = max_amplitude-nof_channels*ampl_incr - - input_lists = [] - phase_deg = 0 - for input_nr in range(nof_inputs): - channel_block = [] # one channel block carries NOF_CHANNELS channel samples - ampl = ampl_lo - phase_deg = phase_deg + phase_incr - for channel_nr in range(nof_channels): - ampl = ampl + ampl_incr - print 'input_nr',input_nr, 'channel_nr', channel_nr, 'ampl',ampl,'phase_deg', phase_deg - sample = complex_phasor_to_binomial(ampl, phase_deg) - channel_block.append(sample) - input_lists.append(channel_block) - - return input_lists - -def complex_to_int(input_lists): - """ - complex to int - """ - output_lists = [] - for input_nr in range(NOF_INPUTS): - output_list = [] - for word in range(NOF_CHANNELS): - re = int(round(input_lists[input_nr][word].real)) - im = int(round(input_lists[input_nr][word].imag)) - print 'Input', input_nr, 'Channel', word, 're,im', re, im - output_list.append(complex(re,im)) - - output_lists.append(output_list) - - return output_lists #correlator_snk_in_arr - - -def concat_complex(input_lists): - """ - Concatenate im&re into one integer - """ - output_lists = [] - for input_nr in range(NOF_INPUTS): - output_list = [] - for word in range(NOF_CHANNELS): - re_bits = CommonBits(int(input_lists[input_nr][word].real), COMPLEX_WIDTH) - im_bits = CommonBits(int(input_lists[input_nr][word].imag), COMPLEX_WIDTH) - concat_bits = im_bits & re_bits - output_list.append(concat_bits.data) - output_lists.append(output_list) - - return output_lists - def gen_correlator_snk_in_arr_hex(input_lists): """ bla """ - concat_input_lists = concat_complex(input_lists) + concat_input_lists = concat_complex_2arr(input_lists, NOF_INPUTS, NOF_CHANNELS, COMPLEX_WIDTH) # ========================================================== # Interleave the lists if user wants folded correlator input # . Note: no support for more than 1 fold yet. # ========================================================== - if NOF_FOLDS==1: + if NOF_INPUT_FOLDS==1: input_stream_lists = [] for input_stream_nr in range(NOF_INPUT_STREAMS): input_stream_lists.append( interleave([concat_input_lists[2*input_stream_nr], concat_input_lists[2*input_stream_nr+1]] ) ) - elif NOF_FOLDS==0: + elif NOF_INPUT_FOLDS==0: input_stream_lists = concat_input_lists # ==================== # Write the HEX files # ==================== for input_stream_nr in range(NOF_INPUT_STREAMS): - list_to_hex( input_stream_lists[input_stream_nr], PATH+"/"+FILENAME+"_"+str(COMPLEX_WIDTH)+'b_fold_'+str(NOF_FOLDS)+'_'+str(input_stream_nr)+".hex", MEM_WIDTH, MEM_DEPTH) - -def complex_float_to_int(complex_list_float): - """ - Convert a list of float complex to a list of integer complex. - """ - complex_list_int = [] - for word in complex_list_float: - re_int = int(round(word.real)) - im_int = int(round(word.imag)) - complex_list_int.append( complex(re_int, im_int) ) - return complex_list_int - -def correlate(input_lists, accumulation_factor): - """ - Input_lists: nof_inputs*nof_channels - Output: nof_channels*nof_visibilities - """ - # First transpose the lists into nof_channels*nof_inputs - inputs_per_channel = transpose(input_lists) - - # Feed each channel to the correlation function - vis_per_channel = [] - for inputs in inputs_per_channel: - - vis = complex_matrix_corr(inputs, inputs, 'complex', conjugate=True) - - # complex_matrix_corr() returns a full matrix of nof_inputs*nof_inputs. - # Convert it to only the triangle incl.auto correlations - so don't - # include duplicates. - unique_vis_per_channel = full_matrix_to_unique_vis(vis) - - # Convert the compelx floats to complex integers - unique_vis_per_channel_int = complex_float_to_int(unique_vis_per_channel) - - # Fake accumulation by multiplying by accumulation_factor - # . this is OK because the inputs do not change in time. - unique_vis_per_channel_int_acc = [] - for v in unique_vis_per_channel_int: - unique_vis_per_channel_int_acc.append(accumulation_factor*v) - - vis_per_channel.append( unique_vis_per_channel_int_acc ) - - return vis_per_channel - -def rec_file_to_list(filename, field_indices=range(11)): - """ - Read a .rec file written by dp_stream_recorder.vhd and return the contents - as strings in a Python list. - - Every line in the file has 11 space-seperated fields: - - 0 1 2 3 4 5 6 7 8 9 10 - [sync] [bsn] [data] [re] [im] [valid] [sop] [eop] [empty] [channel] [err] - - A list of length 0..nof_lines-1 is returned for each field passed in - field_indices. - - """ - fields_sync = [] - fields_bsn = [] - fields_data = [] - fields_re = [] - fields_im = [] - fields_valid = [] - fields_sop = [] - fields_eop = [] - fields_empty = [] - fields_channel = [] - fields_err = [] - - ################################################################################ - # Read the lines from the file and turn them into a list of lines - ################################################################################ - with open (filename, "r") as recfile: - lines = recfile.read().splitlines() - - # Split each line into the 11 DP fields - for line in lines: - split_line = line.split(' ') - # Only process complete lines - if len(split_line)==NOF_DP_RECORD_FIELDS: - fields_sync.append ( split_line[DP_RECORD_INDEX_SYNC] ) - fields_bsn.append ( split_line[DP_RECORD_INDEX_BSN] ) - fields_data.append ( split_line[DP_RECORD_INDEX_DATA] ) - fields_re.append ( split_line[DP_RECORD_INDEX_RE] ) - fields_im.append ( split_line[DP_RECORD_INDEX_IM] ) - fields_valid.append ( split_line[DP_RECORD_INDEX_VALID] ) - fields_sop.append ( split_line[DP_RECORD_INDEX_SOP] ) - fields_eop.append ( split_line[DP_RECORD_INDEX_EOP] ) - fields_empty.append ( split_line[DP_RECORD_INDEX_EMPTY] ) - fields_channel.append( split_line[DP_RECORD_INDEX_CHANNEL]) - fields_err.append ( split_line[DP_RECORD_INDEX_ERR] ) - - fields = [fields_sync,fields_bsn,fields_data,fields_re,fields_im,fields_valid,fields_sop,fields_eop,fields_empty,fields_channel,fields_err] - - return [fields[i] for i in field_indices] - -def wait_for_rec_file(filename, nof_lines): - """ - Wait for .rec file with filename to contain nof_lines. - """ - cur_time = datetime.datetime.now() - print cur_time - -def file_a_newer_than_b(filename_a, filename_b): - """ - Returns True if file_a is newer than file_b, else False. - """ - file_a_mtime = os.path.getmtime(filename_a) - file_a_mtime = os.path.getmtime(filename_b) - - if file_a_mtime > file_b_mtime: - return True - else: - return False - -def file_mod_time(filename): - """ - Returns the time a file was last modified. - """ - return os.path.getmtime(filename) - -def file_linecount(filename): - """ - Returns the number of lines in file with fname. - """ - with open(filename) as f: - return sum(1 for _ in f) - -def rec_file_to_complex(filename, complex_width): - """ - Read from a .rec file and extract the complex fields. - Returns complex format. - The complex_list is re-shaped into packet-sized (as tagged by SOP and EOP) - sublists. - """ - # Read REC file and extract re,im,EOP fields. - re_im_eop_strings = rec_file_to_list(filename, [DP_RECORD_INDEX_RE,DP_RECORD_INDEX_IM,DP_RECORD_INDEX_EOP]) - complex_list = [] - - # Convert re,im strings to complex format - for re_str,im_str in zip(re_im_eop_strings[0], re_im_eop_strings[1]): - re = to_signed(int(re_str, 16), complex_width) - im = to_signed(int(im_str, 16), complex_width) - # Convert integers to complex - complex_list.append( complex(re,im) ) - - # Figure out the packet size based on EOP - for word_nr,eop in enumerate(re_im_eop_strings[2]): - if eop == '1': - packet_size=word_nr+1 - break - - # Split the complex_list into packet_size chunks and return the result. - return split_list(complex_list, packet_size) - + list_to_hex( input_stream_lists[input_stream_nr], PATH+"/"+FILENAME+"_"+str(COMPLEX_WIDTH)+'b_fold_'+str(NOF_INPUT_FOLDS)+'_'+str(input_stream_nr)+".hex", MEM_WIDTH, MEM_DEPTH) def compare_correlator_src_out_arr(vhdl_out, model_out): """ @@ -335,65 +108,87 @@ def compare_correlator_src_out_arr(vhdl_out, model_out): channel_nr+=1 print 'Checked %d channels, %d visibilities each: PASSED' %(channel_nr, vis_nr) -def plot_phase_shifts(correlator_output): + + + +def run_tb(): """ """ - ################################################################################ - # Extract the phases and amplitudes - ################################################################################ - phases = [] - amplitudes = [] - for word in correlator_output: - phasor = complex_binomial_to_phasor(word) - ampl = phasor[0] - amplitudes.append(ampl) - phase = phasor[1] - phases.append(phase) - - ################################################################################ - # Split the list into chunks of nof_visibilities, plot them channel after channel - ################################################################################ - phases_per_channel = split_list(phases, NOF_VISIBILITIES) - for channel_phases in phases_per_channel: - phases_mat = numpy.array(channel_phases) - mat = unique_vis_to_full_matrix(phases_mat) - plot_matrix_color([[mat]]) + import subprocess + import node_io + import test_case + # Create a .do file for ModelSim + c_do_file_name = os.environ['HOME']+"/.ms_do.do" + library_name = 'correlator' + tb_name = 'tb_correlator' + vhdl_generics = {} + vhdl_generics['g_nof_inputs'] = 8 + other=None + tc = test_case.Testcase(tb_name.upper()+' - ', '') + io = node_io.NodeIO(tc.nodeImages, 'sim') + io.simIO.make_do_file(os.environ['RADIOHDL'], c_do_file_name, library_name, tb_name, vhdl_generics, other) -# Generate input data -correlator_snk_in_arr_complex = gen_complex_inputs(NOF_INPUTS, NOF_CHANNELS, COMPLEX_WIDTH) -# Convert to int and generate HEX files from input data -correlator_snk_in_arr_int = complex_to_int(correlator_snk_in_arr_complex) -gen_correlator_snk_in_arr_hex(correlator_snk_in_arr_int) + # First setup the ModelSim environment for unb1 +# cmd = '/home/schuur/SVN/RadioHDL/trunk/tools/modelsim/set_modelsim' +# args = 'unb1' +# subprocess.call([cmd, args]) -# Calculate correlator output from input lists -correlator_src_out_arr_ref = correlate(correlator_snk_in_arr_int, INTEGRATION_PERIOD) + # Start modelsim in a separate terminal +# ms_cmd = ["konsole", "-e", "/home/software/Mentor/6.6c/modeltech/linux_x86_64/vsim", "-c", "-do", c_do_file_name] +# ms = subprocess.Popen(ms_cmd, shell=False, close_fds=True, preexec_fn=os.setsid) + + ms_cmd = ["konsole", "-e", "run_modelsim", "unb1", "-do", c_do_file_name] -# (run TB) -if USE_NEW_REC_FILE==True: - # Wait for the correlator output - print 'Waiting for %s to be modified...' %REC_FILE - now = time.time() - do_until_gt(file_mod_time, now, s_timeout=900, filename=REC_FILE) - - print '%s modified. Waiting for %d lines to be written...' %(REC_FILE, NOF_LINES_IN_REC_FILE_TO_VERIFY) - do_until_gt(file_linecount, NOF_LINES_IN_REC_FILE_TO_VERIFY, s_timeout=900, filename=REC_FILE) -else: - print 'Using old .rec file' -# Read test bench output file written by dp_stream_rec_play.vhd -correlator_src_out_arr = rec_file_to_complex(REC_FILE, complex_width=CORRELATOR_OUTPUT_COMPLEX_WIDTH) -# Compare modeloutput to VHDL output -compare_correlator_src_out_arr(correlator_src_out_arr, correlator_src_out_arr_ref) -if PLOT_CORR_OUT_PHASES==True: - plot_phase_shifts(correlator_src_out_arr[0]) - plot_phase_shifts(correlator_src_out_arr_ref[0]) + + +if __name__ == '__main__': + + # Generate input data + correlator_snk_in_arr_complex = gen_complex_inputs(NOF_INPUTS, NOF_CHANNELS, COMPLEX_WIDTH) + + # Convert to int and generate HEX files from input data + correlator_snk_in_arr_int = complex_to_int(correlator_snk_in_arr_complex, NOF_INPUTS, NOF_CHANNELS) + + gen_correlator_snk_in_arr_hex(correlator_snk_in_arr_int) + + # Calculate correlator output from input lists + correlator_src_out_arr_ref = correlate(correlator_snk_in_arr_int, INTEGRATION_PERIOD) + + + # (run TB) + #run_tb() + + if USE_NEW_REC_FILE==True: + # Wait for the correlator output + print 'Waiting for %s to be modified...' %REC_FILE + now = time.time() + do_until_gt(file_mod_time, now, s_timeout=900, filename=REC_FILE) + + print '%s modified. Waiting for %d lines to be written...' %(REC_FILE, NOF_LINES_IN_REC_FILE_TO_VERIFY) + do_until_gt(file_linecount, NOF_LINES_IN_REC_FILE_TO_VERIFY, s_timeout=900, filename=REC_FILE) + else: + print 'Using old .rec file' + + + + + # Read test bench output file written by dp_stream_rec_play.vhd + correlator_src_out_arr = rec_file_to_complex(REC_FILE, complex_width=CORRELATOR_OUTPUT_COMPLEX_WIDTH) + + # Compare modeloutput to VHDL output + compare_correlator_src_out_arr(correlator_src_out_arr, correlator_src_out_arr_ref) + + if PLOT_CORR_OUT_PHASES==True: + plot_phase_shifts(correlator_src_out_arr[0], NOF_VISIBILITIES) + plot_phase_shifts(correlator_src_out_arr_ref[0], NOF_VISIBILITIES) -- GitLab