def test_default_args(self): def check(chan): assert_equal(chan.noises, None, err_msg='Default noises is not None') assert_equal(chan.channel_gains, None, err_msg='Default channel gains is not None') assert_equal(chan.unnoisy_output, None, err_msg='Default unnoisy output is not None') chan = SISOFlatChannel() # Test output state before any propagation check(chan) # Test that noise standard deviation must be set before propagation with assert_raises(AssertionError): chan.propagate(array((1, 1))) # Test output state before any propagation check(chan) assert_equal(chan.nb_rx, 1, err_msg='SISO channel as more than 1 Rx') assert_equal(chan.nb_tx, 1, err_msg='SISO channel as more than 1 Tx')
def test_noise_generation(self): def check_noise(mod, chan, corrected_SNR_lin): msg = choice(mod, self.msg_length) chan.propagate(msg) P_msg = signal_power(msg) # previous test asserted that channel neither add nor remove energy P_noise = signal_power(chan.noises) assert_allclose(absolute(chan.noises.mean()), 0., atol=5e-2, err_msg='Noise mean is not 0') if corrected_SNR_lin == inf: assert_allclose(P_noise, 0, atol=1e-2, err_msg='There is noise that should not be here') else: assert_allclose(P_msg / P_noise, corrected_SNR_lin, atol=0.2, err_msg='Wrong SNR') chan = SISOFlatChannel(fading_param=(1 + 0j, 0)) for mod in self.all_mods: chan.noise_std = 0 check_noise(mod, chan, inf) chan.set_SNR_lin(6, Es=signal_power(mod)) check_noise(mod, chan, 6) chan.set_SNR_lin(6, .5, signal_power(mod)) check_noise(mod, chan, 3) chan.set_SNR_dB(0, Es=signal_power(mod)) check_noise(mod, chan, 1) chan.set_SNR_dB(0, .5, signal_power(mod)) check_noise(mod, chan, .5)
def test_link_performance(): # Apply link_performance to SISO QPSK and AWGN channel QPSK = QAMModem(4) def receiver(y, h, constellation): return QPSK.demodulate(y, 'hard') model = LinkModel(QPSK.modulate, SISOFlatChannel(fading_param=(1 + 0j, 0)), receiver, QPSK.num_bits_symbol, QPSK.constellation, QPSK.Es) BERs = link_performance(model, range(0, 9, 2), 600e4, 600) desired = erfc(sqrt(10**(arange(0, 9, 2) / 10) / 2)) / 2 assert_allclose(BERs, desired, rtol=0.25, err_msg='Wrong performance for SISO QPSK and AWGN channel') # Apply link_performance to MIMO 16QAM and 4x4 Rayleigh channel QAM16 = QAMModem(16) RayleighChannel = MIMOFlatChannel(4, 4) RayleighChannel.uncorr_rayleigh_fading(complex) def receiver(y, h, constellation): return QAM16.demodulate(kbest(y, h, constellation, 16), 'hard') model = LinkModel(QAM16.modulate, RayleighChannel, receiver, QAM16.num_bits_symbol, QAM16.constellation, QAM16.Es) SNRs = arange(0, 21, 5) + 10 * log10(QAM16.num_bits_symbol) BERs = link_performance(model, SNRs, 600e4, 600) desired = (2e-1, 1e-1, 3e-2, 2e-3, 4e-5) # From reference assert_allclose(BERs, desired, rtol=1.25, err_msg='Wrong performance for MIMO 16QAM and 4x4 Rayleigh channel')
def test_wifi80211_siso_channel(): seed(17121996) wifi80211 = Wifi80211(1) BERs = wifi80211.link_performance( SISOFlatChannel(fading_param=(1 + 0j, 0)), range(0, 9, 2), 10**4, 600)[0] desired = (0.548, 0.508, 0.59, 0.81, 0.18) # From previous tests # for i, val in enumerate(desired): # print((BERs[i] - val) / val) assert_allclose(BERs, desired, rtol=0.3, err_msg='Wrong performance for SISO QPSK and AWGN channel')
def check_BER(modem, EbN0dB, BERs_expected): seed(8071996) model = LinkModel(modem.modulate, SISOFlatChannel(fading_param=(1 + 0j, 0)), lambda y, _, __, ___: modem.demodulate(y, 'hard'), modem.num_bits_symbol, modem.constellation, modem.Es) BERs = model.link_performance(EbN0dB + 10 * log10(log2(modem.m)), 5e5, 400, 720) assert_allclose( BERs, BERs_expected, atol=1e-4, rtol=.1, err_msg='Wrong BER for a standard modulation with {} symbols'. format(modem.m))
def test_k_factor(self): # Real channel chan = SISOFlatChannel() assert_allclose(chan.k_factor, inf, err_msg='k-factor should be infinite without fading in SISO channels') chan.fading_param = 0, 1 assert_allclose(chan.k_factor, 0, err_msg='k-factor should be 0 with Rayleigh fading in SISO channels') chan.fading_param = sqrt(0.5), 0.5 assert_allclose(chan.k_factor, 1, err_msg='Wrong k-factor with rician fading in SISO channels') # Complex channel chan.fading_param = 1j, 0 assert_allclose(chan.k_factor, inf, err_msg='k-factor should be infinite without fading in SISO channels') chan.fading_param = 0j, 1 assert_allclose(chan.k_factor, 0, err_msg='k-factor should be 0 with Rayleigh fading in SISO channels') chan.fading_param = 0.5 + 0.5j, 0.5 assert_allclose(chan.k_factor, 1, err_msg='Wrong k-factor with rician fading in SISO channels')
def test_fading(self): def check_chan_gain(mod, chan): msg = choice(mod, self.msg_length) chan.propagate(msg) P_msg = signal_power(msg) P_unnoisy = signal_power(chan.unnoisy_output) assert_allclose(P_unnoisy, P_msg, rtol=0.2, err_msg='Channel add or remove energy') # Test value checking in constructor construction with assert_raises(ValueError): SISOFlatChannel(0, (1, 1)) chan = SISOFlatChannel(0) # Test on real channel for mod in self.real_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (1, 1) # Test without fading chan.fading_param = (1, 0) check_chan_gain(mod, chan) assert_array_equal( chan.channel_gains, ones(self.msg_length), err_msg='Channel fading while fading is disabled') # Test with Rayleigh fading chan.fading_param = (0, 1) check_chan_gain(mod, chan) assert_allclose(absolute(chan.channel_gains.mean()), 0, atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1, atol=0.2, err_msg='Wrong channel variance with real channel') # Test with rician fading chan.fading_param = (sqrt(2 / 3), 1 / 3) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(), sqrt(2 / 3), atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1 / 3, atol=0.2, err_msg='Wrong channel variance with real channel') # Test on all channel for mod in self.all_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (1, 1) # Test without fading chan.fading_param = (1 + 0j, 0) check_chan_gain(mod, chan) assert_array_equal( chan.channel_gains, ones(self.msg_length), err_msg='Channel fading while fading is disabled') # Test with Rayleigh fading chan.fading_param = (0j, 1) check_chan_gain(mod, chan) assert_allclose(absolute(chan.channel_gains.mean()), 0, atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1, atol=0.2, err_msg='Wrong channel variance with real channel') # Test with rician fading chan.fading_param = (0.5 + 0.5j, 0.5) check_chan_gain(mod, chan) assert_allclose(absolute(chan.channel_gains.mean()), sqrt(0.5), atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 0.5, atol=0.2, err_msg='Wrong channel variance with real channel')
def test_type_check(self): chan = SISOFlatChannel(0) with assert_raises(TypeError): chan.propagate(array((1, 1j)))
def test_noise_generation(self): def check_noise(mod, chan, corrected_SNR_lin): msg = choice(mod, self.msg_length) chan.propagate(msg) P_msg = signal_power( msg ) # previous test asserted that channel neither add nor remove energy P_noise = signal_power(chan.noises) assert_allclose(absolute(chan.noises.mean()), 0., atol=5e-2, err_msg='Noise mean is not 0') if corrected_SNR_lin == inf: assert_allclose( P_noise, 0, atol=1e-2, err_msg='There is noise that should not be here') else: assert_allclose(P_msg / P_noise, corrected_SNR_lin, atol=0.2, err_msg='Wrong SNR') chan = SISOFlatChannel(fading_param=(1 + 0j, 0)) for mod in self.all_mods: chan.noise_std = 0 check_noise(mod, chan, inf) chan.set_SNR_lin(6, Es=signal_power(mod)) check_noise(mod, chan, 6) chan.set_SNR_lin(6, .5, signal_power(mod)) check_noise(mod, chan, 3) chan.set_SNR_dB(0, Es=signal_power(mod)) check_noise(mod, chan, 1) chan.set_SNR_dB(0, .5, signal_power(mod)) check_noise(mod, chan, .5)
def test_link_performance(): # Set seed seed(8071996) ###################################### # Build models & desired solutions ###################################### models = [] desired_bers = [] snr_range = [] labels = [] rtols = [] code_rates = [] # SISO QPSK and AWGN channel QPSK = QAMModem(4) def receiver(y, h, constellation, noise_var): return QPSK.demodulate(y, 'hard') models.append( LinkModel(QPSK.modulate, SISOFlatChannel(fading_param=(1 + 0j, 0)), receiver, QPSK.num_bits_symbol, QPSK.constellation, QPSK.Es)) snr_range.append(arange(0, 9, 2)) desired_bers.append(erfc(sqrt(10**(snr_range[-1] / 10) / 2)) / 2) labels.append('SISO QPSK and AWGN channel') rtols.append(.25) code_rates.append(1) # MIMO 16QAM, 4x4 Rayleigh channel and hard-output K-Best QAM16 = QAMModem(16) RayleighChannel = MIMOFlatChannel(4, 4) RayleighChannel.uncorr_rayleigh_fading(complex) def receiver(y, h, constellation, noise_var): return QAM16.demodulate(kbest(y, h, constellation, 16), 'hard') models.append( LinkModel(QAM16.modulate, RayleighChannel, receiver, QAM16.num_bits_symbol, QAM16.constellation, QAM16.Es)) snr_range.append(arange(0, 21, 5) + 10 * log10(QAM16.num_bits_symbol)) desired_bers.append((2e-1, 1e-1, 3e-2, 2e-3, 4e-5)) # From reference labels.append('MIMO 16QAM, 4x4 Rayleigh channel and hard-output K-Best') rtols.append(1.25) code_rates.append(1) # MIMO 16QAM, 4x4 Rayleigh channel and soft-output best-first QAM16 = QAMModem(16) RayleighChannel = MIMOFlatChannel(4, 4) RayleighChannel.uncorr_rayleigh_fading(complex) ldpc_params = get_ldpc_code_params( 'commpy/channelcoding/designs/ldpc/wimax/1440.720.txt', True) def modulate(bits): return QAM16.modulate( triang_ldpc_systematic_encode(bits, ldpc_params, False).reshape(-1, order='F')) def decoder(llrs): return ldpc_bp_decode(llrs, ldpc_params, 'MSA', 15)[0][:720].reshape(-1, order='F') def demode(symbs): return QAM16.demodulate(symbs, 'hard') def receiver(y, h, constellation, noise_var): return best_first_detector(y, h, constellation, (1, 3, 5), noise_var, demode, 500) models.append( LinkModel(modulate, RayleighChannel, receiver, QAM16.num_bits_symbol, QAM16.constellation, QAM16.Es, decoder, 0.5)) snr_range.append(arange(17, 20, 1)) desired_bers.append((1.7e-1, 1e-1, 2.5e-3)) # From reference labels.append( 'MIMO 16QAM, 4x4 Rayleigh channel and soft-output best-first') rtols.append(2) code_rates.append(.5) ###################################### # Make tests ###################################### for test in range(len(models)): BERs = link_performance(models[test], snr_range[test], 5e5, 200, 720, models[test].rate) assert_allclose(BERs, desired_bers[test], rtol=rtols[test], err_msg='Wrong performance for ' + labels[test]) full_metrics = models[test].link_performance_full_metrics( snr_range[test], 2500, 200, 720, models[test].rate) assert_allclose(full_metrics[0], desired_bers[test], rtol=rtols[test], err_msg='Wrong performance for ' + labels[test])
def test_fading(self): def check_chan_gain(mod, chan): msg = choice(mod, self.msg_length) chan.propagate(msg) P_msg = signal_power(msg) P_unnoisy = signal_power(chan.unnoisy_output) assert_allclose(P_unnoisy, P_msg, rtol=0.2, err_msg='Channel add or remove energy') # Test value checking in constructor construction with assert_raises(ValueError): SISOFlatChannel(0, (1, 1)) chan = SISOFlatChannel(0) # Test on real channel for mod in self.real_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (1, 1) # Test without fading chan.fading_param = (1, 0) check_chan_gain(mod, chan) assert_array_equal(chan.channel_gains, ones(self.msg_length), err_msg='Channel fading while fading is disabled') # Test with Rayleigh fading chan.fading_param = (0, 1) check_chan_gain(mod, chan) assert_allclose(absolute(chan.channel_gains.mean()), 0, atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1, atol=0.2, err_msg='Wrong channel variance with real channel') # Test with rician fading chan.fading_param = (sqrt(2 / 3), 1 / 3) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(), sqrt(2 / 3), atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1 / 3, atol=0.2, err_msg='Wrong channel variance with real channel') # Test on all channel for mod in self.all_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (1, 1) # Test without fading chan.fading_param = (1 + 0j, 0) check_chan_gain(mod, chan) assert_array_equal(chan.channel_gains, ones(self.msg_length), err_msg='Channel fading while fading is disabled') # Test with Rayleigh fading chan.fading_param = (0j, 1) check_chan_gain(mod, chan) assert_allclose(absolute(chan.channel_gains.mean()), 0, atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1, atol=0.2, err_msg='Wrong channel variance with real channel') # Test with rician fading chan.fading_param = (0.5 + 0.5j, 0.5) check_chan_gain(mod, chan) assert_allclose(absolute(chan.channel_gains.mean()), sqrt(0.5), atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 0.5, atol=0.2, err_msg='Wrong channel variance with real channel')