|
8 | 8 | from numpy.testing import run_module_suite, assert_allclose, dec |
9 | 9 | from scipy.special import erfc |
10 | 10 |
|
| 11 | +from commpy.channelcoding.ldpc import get_ldpc_code_params, triang_ldpc_systematic_encode, ldpc_bp_decode |
11 | 12 | from commpy.channels import MIMOFlatChannel, SISOFlatChannel |
12 | 13 | from commpy.links import link_performance, LinkModel |
13 | | -from commpy.modulation import QAMModem, kbest |
| 14 | +from commpy.modulation import QAMModem, kbest, best_first_detector |
14 | 15 |
|
15 | 16 |
|
16 | 17 | @dec.slow |
17 | 18 | def test_link_performance(): |
18 | 19 | # Set seed |
19 | | - seed(17121996) |
| 20 | + seed(8071996) |
| 21 | + ###################################### |
| 22 | + # Build models & desired solutions |
| 23 | + ###################################### |
| 24 | + models = [] |
| 25 | + desired_bers = [] |
| 26 | + snr_range = [] |
| 27 | + labels = [] |
| 28 | + rtols = [] |
| 29 | + code_rates = [] |
20 | 30 |
|
21 | | - # Apply link_performance to SISO QPSK and AWGN channel |
| 31 | + # SISO QPSK and AWGN channel |
22 | 32 | QPSK = QAMModem(4) |
23 | 33 |
|
24 | 34 | def receiver(y, h, constellation, noise_var): |
25 | 35 | return QPSK.demodulate(y, 'hard') |
26 | 36 |
|
27 | | - model = LinkModel(QPSK.modulate, SISOFlatChannel(fading_param=(1 + 0j, 0)), receiver, |
28 | | - QPSK.num_bits_symbol, QPSK.constellation, QPSK.Es) |
| 37 | + models.append(LinkModel(QPSK.modulate, SISOFlatChannel(fading_param=(1 + 0j, 0)), receiver, |
| 38 | + QPSK.num_bits_symbol, QPSK.constellation, QPSK.Es)) |
| 39 | + snr_range.append(arange(0, 9, 2)) |
| 40 | + desired_bers.append(erfc(sqrt(10 ** (snr_range[-1] / 10) / 2)) / 2) |
| 41 | + labels.append('SISO QPSK and AWGN channel') |
| 42 | + rtols.append(.25) |
| 43 | + code_rates.append(1) |
29 | 44 |
|
30 | | - BERs = link_performance(model, range(0, 9, 2), 600e4, 600) |
31 | | - desired = erfc(sqrt(10 ** (arange(0, 9, 2) / 10) / 2)) / 2 |
32 | | - assert_allclose(BERs, desired, rtol=0.25, |
33 | | - err_msg='Wrong performance for SISO QPSK and AWGN channel') |
34 | | - full_metrics = model.link_performance_full_metrics(range(0, 9, 2), 1000, 600) |
35 | | - assert_allclose(full_metrics[0], desired, rtol=0.25, |
36 | | - err_msg='Wrong performance for SISO QPSK and AWGN channel') |
37 | | - |
38 | | - # Apply link_performance to MIMO 16QAM and 4x4 Rayleigh channel |
| 45 | + # MIMO 16QAM, 4x4 Rayleigh channel and hard-output K-Best |
39 | 46 | QAM16 = QAMModem(16) |
40 | 47 | RayleighChannel = MIMOFlatChannel(4, 4) |
41 | 48 | RayleighChannel.uncorr_rayleigh_fading(complex) |
42 | 49 |
|
43 | 50 | def receiver(y, h, constellation, noise_var): |
44 | 51 | return QAM16.demodulate(kbest(y, h, constellation, 16), 'hard') |
45 | 52 |
|
46 | | - model = LinkModel(QAM16.modulate, RayleighChannel, receiver, |
47 | | - QAM16.num_bits_symbol, QAM16.constellation, QAM16.Es) |
48 | | - SNRs = arange(0, 21, 5) + 10 * log10(QAM16.num_bits_symbol) |
49 | | - |
50 | | - BERs = link_performance(model, SNRs, 600e4, 600) |
51 | | - desired = (2e-1, 1e-1, 3e-2, 2e-3, 4e-5) # From reference |
52 | | - assert_allclose(BERs, desired, rtol=1.25, |
53 | | - err_msg='Wrong performance for MIMO 16QAM and 4x4 Rayleigh channel') |
54 | | - full_metrics = model.link_performance_full_metrics(SNRs, 1000, 600) |
55 | | - assert_allclose(full_metrics[0], desired, rtol=1.25, |
56 | | - err_msg='Wrong performance for MIMO 16QAM and 4x4 Rayleigh channel') |
| 53 | + models.append(LinkModel(QAM16.modulate, RayleighChannel, receiver, |
| 54 | + QAM16.num_bits_symbol, QAM16.constellation, QAM16.Es)) |
| 55 | + snr_range.append(arange(0, 21, 5) + 10 * log10(QAM16.num_bits_symbol)) |
| 56 | + desired_bers.append((2e-1, 1e-1, 3e-2, 2e-3, 4e-5)) # From reference |
| 57 | + labels.append('MIMO 16QAM, 4x4 Rayleigh channel and hard-output K-Best') |
| 58 | + rtols.append(1.25) |
| 59 | + code_rates.append(1) |
| 60 | + |
| 61 | + # MIMO 16QAM, 4x4 Rayleigh channel and soft-output best-first |
| 62 | + QAM16 = QAMModem(16) |
| 63 | + RayleighChannel = MIMOFlatChannel(4, 4) |
| 64 | + RayleighChannel.uncorr_rayleigh_fading(complex) |
| 65 | + ldpc_params = get_ldpc_code_params('commpy/channelcoding/designs/ldpc/wimax/1440.720.txt', True) |
| 66 | + |
| 67 | + def modulate(bits): |
| 68 | + return QAM16.modulate(triang_ldpc_systematic_encode(bits, ldpc_params, False).reshape(-1, order='F')) |
| 69 | + |
| 70 | + def decoder(llrs): |
| 71 | + return ldpc_bp_decode(llrs, ldpc_params, 'MSA', 15)[0][:720].reshape(-1, order='F') |
| 72 | + |
| 73 | + def demode(symbs): |
| 74 | + return QAM16.demodulate(symbs, 'hard') |
| 75 | + |
| 76 | + def receiver(y, h, constellation, noise_var): |
| 77 | + return best_first_detector(y, h, constellation, (1, 3, 5), noise_var, demode, 500) |
| 78 | + |
| 79 | + models.append(LinkModel(modulate, RayleighChannel, receiver, |
| 80 | + QAM16.num_bits_symbol, QAM16.constellation, QAM16.Es, |
| 81 | + decoder, 0.5)) |
| 82 | + snr_range.append(arange(17, 20, 1)) |
| 83 | + desired_bers.append((1.7e-1, 1e-1, 2.5e-3)) # From reference |
| 84 | + labels.append('MIMO 16QAM, 4x4 Rayleigh channel and soft-output best-first') |
| 85 | + rtols.append(2) |
| 86 | + code_rates.append(.5) |
| 87 | + |
| 88 | + ###################################### |
| 89 | + # Make tests |
| 90 | + ###################################### |
| 91 | + |
| 92 | + for test in range(len(models)): |
| 93 | + BERs = link_performance(models[test], snr_range[test], 5e5, 200, 720, models[test].rate) |
| 94 | + assert_allclose(BERs, desired_bers[test], rtol=rtols[test], |
| 95 | + err_msg='Wrong performance for ' + labels[test]) |
| 96 | + full_metrics = models[test].link_performance_full_metrics(snr_range[test], 2500, 200, 720, models[test].rate) |
| 97 | + assert_allclose(full_metrics[0], desired_bers[test], rtol=rtols[test], |
| 98 | + err_msg='Wrong performance for ' + labels[test]) |
57 | 99 |
|
58 | 100 |
|
59 | 101 | if __name__ == "__main__": |
|
0 commit comments