def test_pilot_subsymbols_validation(self) -> None: """Pilot subsymbol setter should raise ValueErrors on invalid arguments""" with self.assertRaises(ValueError): self.pilot_section.pilot_elements = Symbols(np.array([[1], [1]])) with self.assertRaises(ValueError): self.pilot_section.pilot_elements = Symbols()
def test_synchronize(self) -> None: """Test the proper estimation of delays during Schmidl-Cox 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 test_synchronization(self) -> None: """Synchronization should properly partition signal samples into frame sections.""" # Generate frame signal models num_samples = 2 * self.max_offset + self.num_frames * self.waveform.samples_in_frame csi = ChannelStateInformation.Ideal(num_samples) samples = np.zeros((1, num_samples), dtype=complex) expected_frames = [] pilot_indices = self.rng.integers( 0, self.max_offset, self.num_frames) + np.arange( self.num_frames) * self.waveform.samples_in_frame for p in pilot_indices: data_symbols = Symbols( self.rng.integers(0, self.waveform.modulation_order, self.waveform.symbols_per_frame)) signal_samples = self.waveform.modulate(data_symbols).samples samples[:, p:p + self.waveform.samples_in_frame] += signal_samples expected_frames.append(samples[:, p:p + self.waveform.samples_in_frame]) synchronized_frames = self.synchronization.synchronize(samples, csi) if len(synchronized_frames) != len(expected_frames): self.fail() for expected_frame, (synchronized_frame, _) in zip(expected_frames, synchronized_frames): assert_array_equal(expected_frame, synchronized_frame)
def test_samples_in_frame(self) -> None: """Samples in frame property should compute the correct sample count.""" symbols = Symbols( np.exp(2j * self.rng.uniform(0, pi, self.generator.symbols_per_frame))) signal = self.generator.modulate(symbols) self.assertEqual(signal.num_samples, self.generator.samples_in_frame)
def test_pilot_subsymbols_setget(self) -> None: """Pilot subsymbol getter should return setter argument""" self.pilot_section.pilot_elements = None self.assertIs(None, self.pilot_section.pilot_elements) expected_subsymbols = Symbols(np.array([-1., 1.])) self.pilot_section.pilot_elements = expected_subsymbols self.assertIs(expected_subsymbols, self.pilot_section.pilot_elements)
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)
def test_pilot(self) -> None: """Pilot samples should be the inverse Fourier transform of subsymbols""" expected_pilot_symbols = np.exp( 2j * pi * self.rng.uniform(0, 1, self.frame.num_subcarriers)) self.pilot_section.pilot_elements = Symbols(expected_pilot_symbols) pilot = self.pilot_section._pilot() pilot_symbols = fft(pilot, norm='ortho')[:self.frame.num_subcarriers] assert_array_almost_equal(expected_pilot_symbols, pilot_symbols)
def test_symbol_samples_in_frame(self) -> None: """Symbol samples in frame property should compute the correct sample count.""" self.generator.tx_filter = ShapingFilter(ShapingFilter.FilterType.NONE, self.oversampling_factor) symbols = Symbols( np.exp(2j * self.rng.uniform(0, pi, self.generator.symbols_per_frame))) signal = self.generator.modulate(symbols) self.assertEqual(signal.num_samples, self.generator.symbol_samples_in_frame)
def test_configured_pilot_sequence(self) -> None: """Specified subsymbols should result in the generation of a valid pilot sequence""" self.pilot_section.pilot_elements = Symbols( np.array([1., -1., 1.j, -1.j], dtype=complex)) pilot_sequence = self.pilot_section._pilot_sequence() self.assertEqual(1, pilot_sequence.num_streams) self.assertEqual(self.frame.num_subcarriers, pilot_sequence.num_symbols) assert_array_equal(self.pilot_section.pilot_elements.raw, pilot_sequence.raw[:, :4])
def test_modulate(self) -> None: """Modulation should return a valid pilot section""" expected_pilot_symbols = np.exp( 2j * pi * self.rng.uniform(0, 1, self.frame.num_subcarriers)) self.pilot_section.pilot_elements = Symbols(expected_pilot_symbols) pilot = self.pilot_section.modulate() pilot_symbols = fft(pilot, norm='ortho')[:self.frame.num_subcarriers] assert_array_almost_equal(expected_pilot_symbols, pilot_symbols) cached_pilot = self.pilot_section.modulate() assert_array_equal(pilot, cached_pilot)
def test_modulate_demodulate(self) -> None: """Modulating and subsequently de-modulating a symbol stream 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.rng.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, decimal=1)
def test_modulate_demodulate_no_filter(self) -> None: """Modulating and subsequently de-modulating a symbol stream should yield identical symbols.""" self.generator.rx_filter = ShapingFilter(ShapingFilter.FilterType.NONE, self.oversampling_factor) self.generator.tx_filter = ShapingFilter(ShapingFilter.FilterType.NONE, self.oversampling_factor) 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)