Esempio n. 1
0
    def setUp(self) -> None:

        self.subcarrier_spacing = 1e3
        self.num_subcarriers = 100
        self.oversampling_factor = 2

        self.rng = default_rng(42)

        self.modem = Mock()
        self.modem.random_generator = self.rng
        self.modem.carrier_frequency = 100e6

        self.repetitions_a = 2
        self.cp_ratio_a = 0.1
        self.elements_a = [
            FrameElement(ElementType.DATA, 2),
            FrameElement(ElementType.REFERENCE, 1),
            FrameElement(ElementType.NULL, 3)
        ]
        self.resource_a = FrameResource(self.repetitions_a, self.cp_ratio_a,
                                        self.elements_a)

        self.repetitions_b = 3
        self.cp_ratio_b = 0.0
        self.elements_b = [
            FrameElement(ElementType.REFERENCE, 2),
            FrameElement(ElementType.DATA, 1),
            FrameElement(ElementType.NULL, 3)
        ]
        self.resource_b = FrameResource(self.repetitions_b, self.cp_ratio_b,
                                        self.elements_b)

        self.section_a = FrameSymbolSection(2, [1, 0, 1])
        self.section_b = FrameGuardSection(1e-3)
        self.section_c = FrameSymbolSection(2, [0, 1, 0])

        self.resources = [self.resource_a, self.resource_b]
        self.sections = [self.section_a, self.section_b, self.section_c]

        self.generator = WaveformGeneratorOfdm(
            subcarrier_spacing=self.subcarrier_spacing,
            modem=self.modem,
            resources=self.resources,
            structure=self.sections,
            num_subcarriers=self.num_subcarriers,
            oversampling_factor=self.oversampling_factor)
Esempio n. 2
0
    def setUp(self) -> None:

        self.rng = default_rng(42)

        test_resource = FrameResource(
            repetitions=1,
            elements=[FrameElement(ElementType.DATA, repetitions=1200)])
        test_payload = FrameSymbolSection(num_repetitions=3, pattern=[0])
        self.frame = WaveformGeneratorOfdm(oversampling_factor=4,
                                           resources=[test_resource],
                                           structure=[test_payload])
        self.frame.pilot_section = SchmidlCoxPilotSection()

        self.synchronization = SchmidlCoxSynchronization(self.frame)

        self.num_streams = 3
        self.delays_in_samples = [0, 9, 80]
        self.num_frames = [1, 2, 3]
Esempio n. 3
0
    def setUp(self) -> None:

        self.rng = default_rng(42)
        self.subsymbols = Symbols(np.array([1., -1., 1.j, -1.j],
                                           dtype=complex))
        self.frame = WaveformGeneratorOfdm(oversampling_factor=4)

        self.pilot_section = PilotSection(pilot_elements=self.subsymbols,
                                          frame=self.frame)
Esempio n. 4
0
class TestCorrelationSynchronization(TestCase):
    """Test OFDM Synchronization via pilot section correlation"""
    def setUp(self) -> None:

        self.rng = default_rng(42)

        test_resource = FrameResource(
            repetitions=1,
            elements=[FrameElement(ElementType.DATA, repetitions=1200)])
        test_payload = FrameSymbolSection(num_repetitions=3, pattern=[0])
        self.frame = WaveformGeneratorOfdm(oversampling_factor=4,
                                           resources=[test_resource],
                                           structure=[test_payload])
        self.frame.pilot_section = PilotSection()

        self.synchronization = OFDMCorrelationSynchronization()
        self.frame.synchronization = self.synchronization

        self.num_streams = 3
        self.delays_in_samples = [0, 9, 80]
        self.num_frames = [1, 2, 3]

    def test_synchronize(self) -> None:
        """Test the proper estimation of delays during correlation synchronization"""

        for d, n in product(self.delays_in_samples, self.num_frames):

            symbols = np.exp(
                2j * pi * self.rng.uniform(0, 1,
                                           (n, self.frame.symbols_per_frame)))
            frames = [
                np.exp(2j * pi * self.rng.uniform(0, 1, (self.num_streams, 1)))
                @ self.frame.modulate(Symbols(symbols[f, :])).samples
                for f in range(n)
            ]

            signal = np.empty((self.num_streams, 0), dtype=complex)
            for frame in frames:

                signal = np.concatenate(
                    (signal, np.zeros(
                        (self.num_streams, d), dtype=complex), frame),
                    axis=1)

            channel_state = ChannelStateInformation.Ideal(
                len(signal), self.num_streams)

            synchronization = self.synchronization.synchronize(
                signal, channel_state)

            self.assertEqual(n, len(synchronization))
            for frame, (synchronized_frame, _) in zip(frames, synchronization):
                assert_array_equal(frame, synchronized_frame)
Esempio n. 5
0
    def setUp(self) -> None:

        self.frame = WaveformGeneratorOfdm(oversampling_factor=4)
        self.pilot = SchmidlCoxPilotSection(frame=self.frame)
Esempio n. 6
0
class TestWaveformGeneratorOFDM(TestCase):
    """Test Orthogonal Frequency Division Multiplexing Waveform Generator."""
    def setUp(self) -> None:

        self.subcarrier_spacing = 1e3
        self.num_subcarriers = 100
        self.oversampling_factor = 2

        self.rng = default_rng(42)

        self.modem = Mock()
        self.modem.random_generator = self.rng
        self.modem.carrier_frequency = 100e6

        self.repetitions_a = 2
        self.cp_ratio_a = 0.1
        self.elements_a = [
            FrameElement(ElementType.DATA, 2),
            FrameElement(ElementType.REFERENCE, 1),
            FrameElement(ElementType.NULL, 3)
        ]
        self.resource_a = FrameResource(self.repetitions_a, self.cp_ratio_a,
                                        self.elements_a)

        self.repetitions_b = 3
        self.cp_ratio_b = 0.0
        self.elements_b = [
            FrameElement(ElementType.REFERENCE, 2),
            FrameElement(ElementType.DATA, 1),
            FrameElement(ElementType.NULL, 3)
        ]
        self.resource_b = FrameResource(self.repetitions_b, self.cp_ratio_b,
                                        self.elements_b)

        self.section_a = FrameSymbolSection(2, [1, 0, 1])
        self.section_b = FrameGuardSection(1e-3)
        self.section_c = FrameSymbolSection(2, [0, 1, 0])

        self.resources = [self.resource_a, self.resource_b]
        self.sections = [self.section_a, self.section_b, self.section_c]

        self.generator = WaveformGeneratorOfdm(
            subcarrier_spacing=self.subcarrier_spacing,
            modem=self.modem,
            resources=self.resources,
            structure=self.sections,
            num_subcarriers=self.num_subcarriers,
            oversampling_factor=self.oversampling_factor)

    def test_init(self) -> None:
        """Object initialization arguments should be properly stored as class attributes."""

        self.assertIs(self.modem, self.generator.modem)
        self.assertEqual(self.subcarrier_spacing,
                         self.generator.subcarrier_spacing)

    def test_add_resource(self) -> None:
        """Added resources should be properly appended to the resource list."""

        resource = Mock()
        self.generator.add_resource(resource)

        self.assertIn(resource, self.generator.resources)

    def test_add_section(self) -> None:
        """Added sections should be properly appended to the section list."""

        section = Mock()
        self.generator.add_section(section)

        self.assertIn(section, self.generator.structure)
        self.assertIs(self.generator, section.frame)

    def test_pilot_setget(self) -> None:
        """Pilot property getter should return setter argument"""

        pilot = Mock()
        self.generator.pilot_section = pilot

        self.assertIs(pilot, self.generator.pilot_section)

    def test_pilot_registration(self) -> None:
        """Setting a pilot should register the respective frame as a reference"""

        pilot = Mock()
        self.generator.pilot_section = pilot

        self.assertIs(self.generator, pilot.frame)

    def test_pilot_signal(self) -> None:
        """The pilot signal property should generate the correct pilot samples"""

        self.generator.pilot_section = None
        empty_pilot_signal = self.generator.pilot_signal

        self.assertEqual(0, empty_pilot_signal.num_samples)
        self.assertEqual(self.generator.sampling_rate,
                         empty_pilot_signal.sampling_rate)

        expected_samples = np.arange(100, dtype=complex)
        pilot_mock = Mock()
        pilot_mock.modulate.return_value = expected_samples
        self.generator.pilot_section = pilot_mock
        pilot_signal = self.generator.pilot_signal

        assert_array_equal(expected_samples[None, :], pilot_signal.samples)
        self.assertEqual(self.generator.sampling_rate,
                         pilot_signal.sampling_rate)

    def test_subcarrier_spacing_setget(self) -> None:
        """Subcarrier spacing property getter should return setter argument."""

        spacing = 123
        self.generator.subcarrier_spacing = spacing

        self.assertEqual(spacing, self.generator.subcarrier_spacing)

    def test_subcarrier_spacing_assert(self) -> None:
        """Subcarrier spacing property setter should raise ValueError on arguments zero or smaller."""

        with self.assertRaises(ValueError):
            self.generator.subcarrier_spacing = -1.

        with self.assertRaises(ValueError):
            self.generator.subcarrier_spacing = 0.

    def test_reference_based_channel_estimation(self) -> None:
        """Reference-based channel estimation should properly estimate channel at reference points."""

        self.generator.channel_estimation_algorithm = ChannelEstimation.REFERENCE

        expected_bits = self.rng.integers(0, 2, self.generator.bits_per_frame)
        expected_symbols = self.generator.map(expected_bits)
        signal = self.generator.modulate(expected_symbols)
        expected_csi = ChannelStateInformation.Ideal(signal.num_samples)

        symbols, csi, _ = self.generator.demodulate(signal.samples[0, :],
                                                    expected_csi)

        assert_array_almost_equal(np.ones(csi.state.shape, dtype=complex),
                                  csi.state)

    def test_modulate_demodulate(self) -> None:
        """Modulating and subsequently de-modulating a data frame should yield identical symbols."""

        expected_symbols = Symbols(
            np.exp(2j *
                   self.rng.uniform(0, pi, self.generator.symbols_per_frame)) *
            np.arange(1, 1 + self.generator.symbols_per_frame))

        baseband_signal = self.generator.modulate(expected_symbols)
        channel_state = ChannelStateInformation.Ideal(
            num_samples=baseband_signal.num_samples)
        symbols, _, _ = self.generator.demodulate(
            baseband_signal.samples[0, :], channel_state)

        assert_array_almost_equal(expected_symbols.raw, symbols.raw)