def do(self, nb_tx, nb_rx): prod_nb = nb_tx * nb_rx # Real channel chan = MIMOFlatChannel(nb_tx, nb_rx) assert_allclose(chan.k_factor, 0, err_msg='k-factor should be 0 with Rayleigh fading in SISO channels') mean = randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rs = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = mean, Rs, Rr assert_allclose(chan.k_factor, 3, err_msg='Wrong k-factor with rician fading in SISO channels') # Complex channel chan.fading_param = (zeros((nb_rx, nb_tx), complex), identity(nb_tx), identity(nb_rx)) assert_allclose(chan.k_factor, 0, err_msg='k-factor should be 0 with Rayleigh fading in SISO channels') mean = randn(nb_rx, nb_tx) + 1j * randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rs = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = (mean, Rs, Rr) assert_allclose(chan.k_factor, 3, err_msg='Wrong k-factor with rician fading in SISO channels')
def do(self, nb_tx, nb_rx): 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(abs(chan.noises.mean()), 0., atol=0.5, 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(chan.nb_tx * P_msg / P_noise, corrected_SNR_lin, atol=0.2, err_msg='Wrong SNR') fading_param = zeros((nb_rx, nb_tx), complex), identity(nb_tx), identity(nb_rx) chan = MIMOFlatChannel(nb_tx, nb_rx, fading_param=fading_param) 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 do(self, nb_tx, nb_rx): 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 = MIMOFlatChannel(nb_tx, nb_rx) # 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)
def do(self, nb_tx, nb_rx): # Without padding chan = MIMOFlatChannel(nb_tx, nb_rx, 0) out = chan.propagate(ones(nb_tx * 2)) assert_array_equal(chan.channel_gains.shape, (2, nb_rx, nb_tx), err_msg='Wrong channel shape without padding') assert_array_equal(chan.noises.shape, (2, nb_rx), err_msg='Wrong channel shape without padding') assert_array_equal(chan.unnoisy_output.shape, (2, nb_rx), err_msg='Wrong channel shape without padding') assert_array_equal(out.shape, (2, nb_rx), err_msg='Wrong channel shape without padding') # With padding chan = MIMOFlatChannel(nb_tx, nb_rx, 0) out = chan.propagate(ones(nb_tx * 2 + 1)) assert_array_equal(chan.channel_gains.shape, (3, nb_rx, nb_tx), err_msg='Wrong channel shape with padding') assert_array_equal(chan.noises.shape, (3, nb_rx), err_msg='Wrong channel shape with padding') assert_array_equal(chan.unnoisy_output.shape, (3, nb_rx), err_msg='Wrong channel shape with padding') assert_array_equal(out.shape, (3, nb_rx), err_msg='Wrong channel shape with padding')
def do(self, nb_tx, nb_rx): 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(abs(chan.noises.mean()), 0., atol=0.5, 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(chan.nb_tx * P_msg / P_noise, corrected_SNR_lin, atol=0.2, err_msg='Wrong SNR') fading_param = zeros((nb_rx, nb_tx), complex), identity(nb_tx), identity(nb_rx) chan = MIMOFlatChannel(nb_tx, nb_rx, fading_param=fading_param) 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 do(self, nb_tx, nb_rx): 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 * chan.nb_tx, rtol=0.2, err_msg='Channel add or remove energy') # Test value checking in constructor construction with assert_raises(ValueError): MIMOFlatChannel(nb_tx, nb_tx, 0, (ones( (nb_tx, nb_tx)), ones((nb_tx, nb_tx)), ones((nb_rx, nb_rx)))) chan = MIMOFlatChannel(nb_tx, nb_rx, 0) prod_nb = nb_tx * nb_rx # Test on real channel for mod in self.real_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (ones((nb_tx, nb_tx)), ones( (nb_tx, nb_tx)), ones((nb_rx, nb_rx))) # Test with Rayleigh fading chan.fading_param = (zeros( (nb_rx, nb_tx)), identity(nb_tx), identity(nb_rx)) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(), 0, atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1, atol=5e-2, err_msg='Wrong channel variance with real channel') # Test with rician fading mean = randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rs = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = (mean, Rs, Rr) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(0), mean, atol=0.2, err_msg='Wrong channel mean 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 = (ones((nb_tx, nb_tx)), ones( (nb_tx, nb_tx)), ones((nb_rx, nb_rx))) # Test with Rayleigh fading chan.fading_param = (zeros( (nb_rx, nb_tx), complex), identity(nb_tx), identity(nb_rx)) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(), 0, atol=1e-2, err_msg='Wrong channel mean with complex channel') assert_allclose( chan.channel_gains.var(), 1, atol=5e-2, err_msg='Wrong channel variance with complex channel') # Test with rician fading mean = randn(nb_rx, nb_tx) + 1j * randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rs = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = (mean, Rs, Rr) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(0).real, mean.real, atol=0.1, err_msg='Wrong channel mean with complex channel') assert_allclose(chan.channel_gains.mean(0).imag, mean.imag, atol=0.1, err_msg='Wrong channel mean with complex channel')
def do(self, nb_tx, nb_rx): chan = MIMOFlatChannel(nb_tx, nb_rx, 0) with assert_raises(TypeError): chan.propagate(array((1, 1j)))
def do(self, nb_tx, nb_rx): # Set seed seed(17121996) 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 * chan.nb_tx, rtol=0.2, err_msg='Channel add or remove energy') def expo_correlation(t, r): # Construct the exponent matrix expo_tx = fromiter((j - i for i in range(chan.nb_tx) for j in range(chan.nb_tx)), int, chan.nb_tx ** 2) expo_rx = fromiter((j - i for i in range(chan.nb_rx) for j in range(chan.nb_rx)), int, chan.nb_rx ** 2) # Reshape expo_tx = expo_tx.reshape(chan.nb_tx, chan.nb_tx) expo_rx = expo_rx.reshape(chan.nb_rx, chan.nb_rx) return t ** expo_tx, r ** expo_rx def check_correlation(chan, Rt, Rr): nb_ant = chan.nb_tx * chan.nb_rx Rdes = kron(Rt, Rr) H = chan.channel_gains Ract = zeros_like(Rdes) for i in range(len(H)): Ract += H[i].T.reshape(nb_ant, 1).dot(H[i].T.reshape(1, nb_ant).conj()) Ract /= len(H) assert_allclose(Rdes, Ract, atol=0.05, err_msg='Wrong correlation matrix') # Test value checking in constructor construction with assert_raises(ValueError): MIMOFlatChannel(nb_tx, nb_tx, 0, (ones((nb_tx, nb_tx)), ones((nb_tx, nb_tx)), ones((nb_rx, nb_rx)))) chan = MIMOFlatChannel(nb_tx, nb_rx, 0) prod_nb = nb_tx * nb_rx # Test on real channel for mod in self.real_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (ones((nb_tx, nb_tx)), ones((nb_tx, nb_tx)), ones((nb_rx, nb_rx))) # Test with Rayleigh fading chan.fading_param = (zeros((nb_rx, nb_tx)), identity(nb_tx), identity(nb_rx)) check_chan_gain(mod, chan) # Test with rician fading mean = randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rt = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = (mean, Rt, Rr) check_chan_gain(mod, chan) # Test helper functions chan.uncorr_rayleigh_fading(float) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 0, err_msg='Wrong k-factor with uncorrelated Rayleigh fading') mean = randn(nb_rx, nb_tx) chan.uncorr_rician_fading(mean, 10) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 10, err_msg='Wrong k-factor with uncorrelated rician fading') # Test on complex channel for mod in self.all_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (ones((nb_tx, nb_tx)), ones((nb_tx, nb_tx)), ones((nb_rx, nb_rx))) # Test with Rayleigh fading chan.fading_param = (zeros((nb_rx, nb_tx), complex), identity(nb_tx), identity(nb_rx)) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(), 0, atol=1e-2, err_msg='Wrong channel mean with complex channel') assert_allclose(chan.channel_gains.var(), 1, atol=5e-2, err_msg='Wrong channel variance with complex channel') # Test with rician fading mean = randn(nb_rx, nb_tx) + 1j * randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rt = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = (mean, Rt, Rr) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(0).real, mean.real, atol=0.1, err_msg='Wrong channel mean with complex channel') assert_allclose(chan.channel_gains.mean(0).imag, mean.imag, atol=0.1, err_msg='Wrong channel mean with complex channel') # Test helper functions chan.uncorr_rayleigh_fading(complex) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 0, err_msg='Wrong k-factor with uncorrelated Rayleigh fading') mean = randn(nb_rx, nb_tx) + randn(nb_rx, nb_tx) * 1j chan.uncorr_rician_fading(mean, 10) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 10, err_msg='Wrong k-factor with uncorrelated rician fading') chan.expo_corr_rayleigh_fading(exp(-0.2j * pi), exp(-0.1j * pi)) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 0, err_msg='Wrong k-factor with correlated Rayleigh fading') Rt, Rr = expo_correlation(exp(-0.2j * pi), exp(-0.1j * pi)) check_correlation(chan, Rt, Rr) mean = randn(nb_rx, nb_tx) + randn(nb_rx, nb_tx) * 1j chan.expo_corr_rician_fading(mean, 10, exp(-0.1j * pi), exp(-0.2j * pi)) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 10, err_msg='Wrong k-factor with correlated rician fading') # Test with beta > 0 chan.expo_corr_rayleigh_fading(exp(-0.2j * pi), exp(-0.1j * pi), 1, 0.5) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 0, err_msg='Wrong k-factor with correlated Rayleigh fading') mean = randn(nb_rx, nb_tx) + randn(nb_rx, nb_tx) * 1j chan.expo_corr_rician_fading(mean, 5, exp(-0.1j * pi), exp(-0.2j * pi), 3, 2) check_chan_gain(mod, chan) assert_allclose(chan.k_factor, 5, err_msg='Wrong k-factor with correlated rician fading')
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 do(self, nb_tx, nb_rx): 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 * chan.nb_tx, rtol=0.2, err_msg='Channel add or remove energy') # Test value checking in constructor construction with assert_raises(ValueError): MIMOFlatChannel(nb_tx, nb_tx, 0, (ones((nb_tx, nb_tx)), ones((nb_tx, nb_tx)), ones((nb_rx, nb_rx)))) chan = MIMOFlatChannel(nb_tx, nb_rx, 0) prod_nb = nb_tx * nb_rx # Test on real channel for mod in self.real_mods: # Test value checking after construction with assert_raises(ValueError): chan.fading_param = (ones((nb_tx, nb_tx)), ones((nb_tx, nb_tx)), ones((nb_rx, nb_rx))) # Test with Rayleigh fading chan.fading_param = (zeros((nb_rx, nb_tx)), identity(nb_tx), identity(nb_rx)) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(), 0, atol=1e-2, err_msg='Wrong channel mean with real channel') assert_allclose(chan.channel_gains.var(), 1, atol=5e-2, err_msg='Wrong channel variance with real channel') # Test with rician fading mean = randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rs = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = (mean, Rs, Rr) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(0), mean, atol=0.2, err_msg='Wrong channel mean 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 = (ones((nb_tx, nb_tx)), ones((nb_tx, nb_tx)), ones((nb_rx, nb_rx))) # Test with Rayleigh fading chan.fading_param = (zeros((nb_rx, nb_tx), complex), identity(nb_tx), identity(nb_rx)) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(), 0, atol=1e-2, err_msg='Wrong channel mean with complex channel') assert_allclose(chan.channel_gains.var(), 1, atol=5e-2, err_msg='Wrong channel variance with complex channel') # Test with rician fading mean = randn(nb_rx, nb_tx) + 1j * randn(nb_rx, nb_tx) mean *= sqrt(prod_nb * 0.75 / einsum('ij,ij->', absolute(mean), absolute(mean))) Rs = self.random_SDP_matrix(nb_tx) * sqrt(prod_nb) * 0.5 Rr = self.random_SDP_matrix(nb_rx) * sqrt(prod_nb) * 0.5 chan.fading_param = (mean, Rs, Rr) check_chan_gain(mod, chan) assert_allclose(chan.channel_gains.mean(0).real, mean.real, atol=0.1, err_msg='Wrong channel mean with complex channel') assert_allclose(chan.channel_gains.mean(0).imag, mean.imag, atol=0.1, err_msg='Wrong channel mean with complex channel')