Пример #1
0
    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')
Пример #2
0
    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)
Пример #3
0
    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)
Пример #4
0
    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')
Пример #5
0
    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)
Пример #6
0
    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')
Пример #7
0
 def do(self, nb_tx, nb_rx):
     chan = MIMOFlatChannel(nb_tx, nb_rx, 0)
     with assert_raises(TypeError):
         chan.propagate(array((1, 1j)))
Пример #8
0
    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')
Пример #9
0
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])
Пример #10
0
 def do(self, nb_tx, nb_rx):
     chan = MIMOFlatChannel(nb_tx, nb_rx, 0)
     with assert_raises(TypeError):
         chan.propagate(array((1, 1j)))
Пример #11
0
    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')