Example #1
0
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")
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
	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])
Example #5
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])
Example #6
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")
Example #7
0
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])