async def rrc(dut): """ Test a Root Raised Cosine filter. Load the filter coefficients with a RRC filter kernel then send a unit pulse to find the impulse response of the filter """ # setup the DUT dut_control_obj = dut_control_polyphase_filter.dut_control_polyphase_filter( dut) await dut_control_obj.init() # create the coefficients coeffs = comms_filters.rrcosfilter(N=dut_control_obj.NUMBER_TAPS, alpha=0.5, Ts=1, Fs=dut_control_obj.RATE_CHANGE)[1] # scale the coefficients coeff_max = sum(coeffs) coeffs = [ int(coeff * ((2**(dut_control_obj.COEFFS_WIDTH - 1) - 1) / coeff_max)) for coeff in coeffs ] # write in the coefficients await dut_control_obj.coefficients_write(coeffs) # send in a first pulse await dut_control_obj.data_out_read_enable() await dut_control_obj.impulse_response(coeffs) # if we have reached this point the test is a success dut._log.info("Test has completed with no failures detected")
def __init__(self, filter_type, samples_per_symbol, pulse_factor, pulse_length): """ Create the generic modulator object and specify the modulation parameters """ fir_filter.__init__(self, coeffs=[0 + 1j * 0], complex=True) # save the input parameters internally self.filter_type = filter_type self.samples_per_symbol = samples_per_symbol self.pulse_factor = pulse_factor self.pulse_length = pulse_length # create the pulse coefficients if (self.filter_type == "Gaussian"): # print("TODO: need to implement Laurent AMP decomposition for Gaussian pulse in Python!") self.pulse_coefficients = gauss_pulse.gauss_laurent_amp( sps=self.samples_per_symbol, BT=self.pulse_factor) else: self.pulse_coefficients = comms_filters.rrcosfilter( N=self.pulse_length * self.samples_per_symbol, alpha=self.pulse_factor, Ts=1, Fs=self.samples_per_symbol)[1] self.pulse_coefficients = np.append(self.pulse_coefficients, self.pulse_coefficients[0]) # normalise the pulse energy pulse_energy = np.sum(np.square(abs(self.pulse_coefficients))) / 2.0 self.pulse_coefficients = [ _ / pulse_energy for _ in self.pulse_coefficients ] # initialse the underlying FIR filter now that the parameters are set self.update_coeffs(coeffs=self.pulse_coefficients, complex=True)
def coefficients_write(self): """ Write coefficients into the DUT. """ # create the coefficients if self.pulse_filter_type == "RRC": coefficients = comms_filters.rrcosfilter( N=self.NUMBER_TAPS, alpha=self.pulse_factor, Ts=1, Fs=self.SAMPLES_PER_SYMBOL)[1] else: assert False, "Unsupported filter type (%s) specified" % self.pulse_filter_type # scale the coefficients coefficients_max = sum(coefficients) coefficients = [ int(coefficient * ((2**(self.COEFFS_WIDTH - 1) - 1) / coefficients_max)) for coefficient in coefficients ] # if requested plot the filter coefficients if self.PLOT: plt.plot(coefficients) plt.title("Filter Coefficients") plt.xlabel("Samples") plt.ylabel("Amplitude") plt.show() # convert negative numbers to twos complement and arrange for the polyphase structure coefficients = self.signed_to_fixedpoint(coefficients, self.COEFFS_WIDTH, multiplier=1.0) # reset the coefficients self.dut.coefficients_in_aresetn = 0 yield self.wait(2) self.dut.coefficients_in_aresetn = 1 yield self.wait(2) # write the coefficients through the bus yield self.axism_coeffs_in.write(coefficients) yield self.wait(1)
def __init__(self, modulation_type, samples_per_symbol, pulse_factor, pulse_length, config, filename): """ Create the generic modulator object and specify the modulation parameters. """ # save the input parameters internally self.modulation_type = modulation_type self.samples_per_symbol = samples_per_symbol self.pulse_factor = pulse_factor self.pulse_length = pulse_length self.config = config self.filename = filename # read in the modulation constellation definition with open(self.filename) as json_file: constellations = json.load(json_file) # select the modulation scheme self.bits_per_symbol = constellations[self.config[0]][self.config[1]]["bits_per_symbol"] self.offset = constellations[self.config[0]][self.config[1]]["offset"] self.filter = constellations[self.config[0]][self.config[1]]["filter"] self.relative_rate = constellations[self.config[0]][self.config[1]]["relative_rate"] self.bit_map = constellations[self.config[0]][self.config[1]]["bit_map"] # create the pulse coefficients if(self.filter == "Gaussian"): self.pulse_coefficients = gauss_pulse.gauss_pulse( sps = 2*self.samples_per_symbol, BT = self.pulse_factor) else: self.pulse_coefficients = comms_filters.rrcosfilter(N = self.pulse_length*self.samples_per_symbol, alpha = self.pulse_factor, Ts = 1, Fs = self.samples_per_symbol)[1] # normalise the pulse energy pulse_energy = np.sum(np.square(abs(self.pulse_coefficients)))/self.samples_per_symbol self.pulse_coefficients = [_/pulse_energy for _ in self.pulse_coefficients] self.pulse_coefficients = np.append(self.pulse_coefficients, self.pulse_coefficients[0])
def __init__(self, modulation_type, samples_per_symbol, pulse_factor, pulse_length, config): """ Create the generic modulator object and specify the modulation parameters. Supported modulation types are: BPSK GMSK QPSK OQPSK 8PSK 8APSK 16APSK 32APSK 64APSK 128APSK 256APSK """ # save the input parameters internally self.modulation_type = modulation_type self.samples_per_symbol = samples_per_symbol self.pulse_factor = pulse_factor self.pulse_length = pulse_length self.config = config # set the spectral density and offset characteristics if self.modulation_type == "BPSK": self.spectral_density = 2 self.period_offset = 0 elif self.modulation_type == "GMSK": self.spectral_density = 2 self.period_offset = 1 elif self.modulation_type == "QPSK": self.spectral_density = 4 self.period_offset = 0 elif self.modulation_type == "OQPSK": self.spectral_density = 4 self.period_offset = 1 elif self.modulation_type == "8PSK": self.spectral_density = 8 self.period_offset = 0 elif self.modulation_type == "8APSK": self.spectral_density = 8 self.period_offset = 0 elif self.modulation_type == "16APSK": self.spectral_density = 16 self.period_offset = 0 elif self.modulation_type == "32APSK": self.spectral_density = 32 self.period_offset = 0 elif self.modulation_type == "64APSK": self.spectral_density = 64 self.period_offset = 0 elif self.modulation_type == "128APSK": self.spectral_density = 128 self.period_offset = 0 elif self.modulation_type == "256APSK": self.spectral_density = 256 self.period_offset = 0 else: assert False, "Unsupported modulation type supplied." # create the pulse coefficients if(self.modulation_type == "GMSK"): self.pulse_coefficients = gauss_pulse.gauss_pulse( sps = 2*self.samples_per_symbol, BT = self.pulse_factor) else: self.pulse_coefficients = comms_filters.rrcosfilter(N = self.pulse_length*self.samples_per_symbol, alpha = self.pulse_factor, Ts = 1, Fs = self.samples_per_symbol)[1] # normalise the pulse energy pulse_energy = np.sum(np.square(abs(self.pulse_coefficients)))/self.samples_per_symbol self.pulse_coefficients = [_/pulse_energy for _ in self.pulse_coefficients] self.pulse_coefficients = np.append(self.pulse_coefficients, self.pulse_coefficients[0])
async def gnuradio_impulse(dut): """ Test a Root Raised Cosine filter. Load the filter coefficients with a RRC filter kernel then send a unit pulse to find the impulse response of the filter """ # setup the DUT dut_control_obj = dut_control_polyphase_filter.dut_control_polyphase_filter( dut) await dut_control_obj.init() # # create the coefficients # coeffs = comms_filters.rrcosfilter( N = dut_control_obj.NUMBER_TAPS, # alpha = 0.5, # Ts = 1, # Fs = dut_control_obj.RATE_CHANGE)[1] # create the coefficients coeffs = comms_filters.rrcosfilter(N=101, alpha=0.2, Ts=1, Fs=2)[1] print('len(coeffs)', len(coeffs)) # scale the coefficients coeff_max = sum(coeffs) coeffs = [ int(coeff * ((2**(dut_control_obj.COEFFS_WIDTH - 1) - 1) / coeff_max)) for coeff in coeffs ] for coeff in coeffs: if coeff < 0: print("%04X" % (coeff + 2**16)) else: print("%04X" % coeff) # write in the coefficients await dut_control_obj.coefficients_write(coeffs) # read the GNURadio data # gnuradio_data = np.fromfile(open("gnuradio_filterout.bin"), dtype=np.complex64) gnuradio_data = np.fromfile(open("gnuradio_filterout_short.bin"), dtype=np.int16) gnuradio_data = gnuradio_data[256:256 + 404] gnr_impulse = [] for i in range(0, int(len(gnuradio_data) / 2), 2): gnr_impulse.append( int(gnuradio_data[i] / 1) + 1j * int(gnuradio_data[i + 1] / 1)) print(gnr_impulse) # plt.plot(gnr_impulse) # plt.show() # send in a first pulse await dut_control_obj.data_out_read_enable() await dut_control_obj.axism_data_in.write( [int(2**(dut_control_obj.DATA_WIDTH - 2))]) # read the output await dut_control_obj.axiss_read_handle.join() received_data = helper_functions.fixedpoint_to_signed( dut_control_obj.axiss_data_out.data, dut_control_obj.COEFFS_WIDTH) plt.plot(gnr_impulse) plt.plot(coeffs) plt.plot(received_data) plt.show() # received_data = helper_functions.fixedpoint_to_signed(self.axiss_data_out.data, self.COEFFS_WIDTH) # # if we have reached this point the test is a success # dut._log.info("Test has completed with no failures detected")
async def gnuradio_input(dut): """ Test a Root Raised Cosine filter. Load the filter coefficients with a RRC filter kernel then send a unit pulse to find the impulse response of the filter """ # setup the DUT dut_control_obj = dut_control_polyphase_filter.dut_control_polyphase_filter( dut) await dut_control_obj.init() # create the coefficients # coeffs = comms_filters.rrcosfilter( N = dut_control_obj.NUMBER_TAPS, # alpha = 0.5, # Ts = 1, # Fs = dut_control_obj.RATE_CHANGE)[1] # create the coefficients coeffs = comms_filters.rrcosfilter( N=32, alpha=0.5, # Ts = 1, Ts=2, # Fs = 1)[1] Fs=2)[1] # scale the coefficients coeff_max = sum(coeffs) coeffs = [ int(coeff * ((2**(dut_control_obj.COEFFS_WIDTH - 1) - 1) / coeff_max)) for coeff in coeffs ] for coeff in coeffs: if coeff < 0: print("%04X" % (coeff + 2**16)) else: print("%04X" % coeff) # write in the coefficients await dut_control_obj.coefficients_write(coeffs) # read the GNURadio data gnuradio_data = np.fromfile(open( "/home/tom/repositories/dvb_fpga/gnuradio_data/FECFRAME_NORMAL_MOD_QPSK_C1_2/plframe_pilots_on_fixed_point.bin" ), dtype=np.int16) gnuradio_data = gnuradio_data[:256] input_data = [] for i in range(0, int(len(gnuradio_data) / 2), 2): input_data.append(int(gnuradio_data[i] / 1)) # send in a first pulse await dut_control_obj.data_out_read_enable() await dut_control_obj.axism_data_in.write(input_data) # read the output await dut_control_obj.axiss_read_handle.join() received_data = helper_functions.fixedpoint_to_signed( dut_control_obj.axiss_data_out.data, dut_control_obj.COEFFS_WIDTH) # plt.plot([_*8 for _ in range(len(input_data)+2)], [0]*2 + input_data) plt.plot([_ * 2 for _ in range(len(input_data) + 8)], [0] * 8 + input_data) plt.plot(received_data) plt.show() # received_data = helper_functions.fixedpoint_to_signed(self.axiss_data_out.data, self.COEFFS_WIDTH) # if we have reached this point the test is a success dut._log.info("Test has completed with no failures detected")
def __init__(self, modulation_type, samples_per_symbol, pulse_factor, pulse_length, filename, config=""): """ Create the generic MODEM (modulator / demodulator) object and specify the modulation parameters. Parameters ---------- modulation_type : list Definition of the modulation type samples_per_symbol : int The number of samples to create per information symbol pulse_factor : float The pulse factor for either the RRC or Gaussian filters pulse_length : int The length of the pulse shaping filter in number of symbol periods filename : str The location of JSON file containing the modulation definition config : optional Extra configuration setting """ # save the input parameters internally self.modulation_type = modulation_type self.samples_per_symbol = samples_per_symbol self.pulse_factor = pulse_factor self.pulse_length = pulse_length self.config = config self.filename = filename # read in the modulation constellation definition with open(self.filename) as json_file: constellations = json.load(json_file) # pull out the modulation settings temp_dict = constellations for i in range(constellations["modulation_type_depth"]): temp_dict = temp_dict[self.modulation_type[i]] self.bits_per_symbol = temp_dict["bits_per_symbol"] self.offset = temp_dict["offset"] self.filter = temp_dict["filter"] self.relative_rate = temp_dict["relative_rate"] self.bit_map = temp_dict["bit_map"] # create the pulse coefficients if (self.filter == "Gaussian"): self.pulse_coefficients = gauss_pulse.gauss_pulse( sps=2 * self.samples_per_symbol, BT=self.pulse_factor) else: self.pulse_coefficients = comms_filters.rrcosfilter( N=self.pulse_length * self.samples_per_symbol, alpha=self.pulse_factor, Ts=1, Fs=self.samples_per_symbol)[1] # normalise the pulse energy pulse_energy = np.sum(np.square(abs( self.pulse_coefficients))) / self.samples_per_symbol self.pulse_coefficients = [ _ / pulse_energy for _ in self.pulse_coefficients ] self.pulse_coefficients = np.append(self.pulse_coefficients, self.pulse_coefficients[0])