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 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]
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)
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)
def setUp(self) -> None: self.frame = WaveformGeneratorOfdm(oversampling_factor=4) self.pilot = SchmidlCoxPilotSection(frame=self.frame)
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)