1
+ from PyTurbo import PyLogBCJR as bcjr
1
2
from PyTurbo import PyViterbi as viterbi
3
+ from matplotlib import pyplot as plt
2
4
3
5
import numpy
4
6
@@ -18,18 +20,42 @@ def encode75(msg):
18
20
19
21
return out_msg
20
22
21
- #Compute branch metrics for a pair of received bits
22
- def branch_metrics (bits_rcvd ):
23
- ret_val = numpy .zeros (4 , dtype = numpy .float32 );
24
- cw = [[0.0 ,0.0 ], [0.0 ,1.0 ], [1.0 ,0.0 ], [1.0 ,1.0 ]] #The 4 different codewords
23
+ #Compute viterbi branch metrics for a sequence of received bits
24
+ def viterbi_branch_metrics (bits_rcvd , nbits_cw ):
25
+ N_cw = (2 ** nbits_cw )
26
+ K = int (len (bits_rcvd )/ nbits_cw )
27
+ ret_val = numpy .zeros ((K , N_cw ), dtype = numpy .float32 );
28
+ cw = numpy .array ([[0.0 ,0.0 ], [0.0 ,1.0 ], [1.0 ,0.0 ], [1.0 ,1.0 ]]) #The 4 different codewords
25
29
26
- bits_rcvd = numpy .array (bits_rcvd )
27
- cw = numpy .array (cw )
30
+ bits_rcvd = numpy .array (bits_rcvd ).reshape ((K , nbits_cw ))
31
+ for k in range (0 , K ):
32
+ ret_val [k ][:] = numpy .sum (numpy .abs (bits_rcvd [k ][:]- cw )** 2 , axis = 1 )
28
33
29
- for i in range (0 , len (cw )):
30
- ret_val [i ] = numpy .sum (numpy .abs (bits_rcvd - cw [i ])** 2 )
34
+ return ret_val .flatten ()
31
35
32
- return ret_val
36
+ #Compute log-BCJR branch metrics for a sequence of received bits
37
+ def log_bcjr_branch_metrics (bits_rcvd , nbits_cw , sigma_b2 ):
38
+ N_cw = (2 ** nbits_cw )
39
+ K = int (len (bits_rcvd )/ nbits_cw )
40
+ ret_val = numpy .zeros ((K , N_cw ), dtype = numpy .float32 );
41
+ cw = numpy .array ([[0.0 ,0.0 ], [0.0 ,1.0 ], [1.0 ,0.0 ], [1.0 ,1.0 ]]) #The 4 different codewords
42
+
43
+ bits_rcvd = numpy .array (bits_rcvd ).reshape ((K , nbits_cw ))
44
+ for k in range (0 , K ):
45
+ ret_val [k ][:] = - 1.0 / sigma_b2 * numpy .sum (numpy .abs (bits_rcvd [k ][:]- cw )** 2 , axis = 1 )
46
+
47
+ return ret_val .flatten ()
48
+
49
+ #Compute bit LLR from a posteriori-probabilities
50
+ def compute_llr (app , K , S ):
51
+ llr = numpy .zeros (K , dtype = numpy .float32 )
52
+
53
+ app = app .reshape ((K , S , 2 ))
54
+ for k in range (0 , K ):
55
+ #We need copy() to make the vectors C-contiguous
56
+ llr [k ] = bcjr .max_star (app [k ,:,0 ].copy ()) - bcjr .max_star (app [k ,:,1 ].copy ())
57
+
58
+ return llr
33
59
34
60
#Define trellis
35
61
I = 2
@@ -43,36 +69,66 @@ def branch_metrics(bits_rcvd):
43
69
3 , 0 , \
44
70
1 , 2 , \
45
71
2 , 1 ]
46
-
47
- #Create decoder instance
48
- dec = viterbi (I , S , O , NS , OS )
72
+ R = 1 / 2 # Code efficiency
49
73
50
74
#Length of the message
51
- K_m = 100 ;
75
+ K_m = 200000 ;
52
76
#Length of the coded message
53
- K_c = 200 #Code efficiency is 1/2
54
-
55
- #Generate message
56
- m = numpy .random .randint (0 , 2 , K_m , dtype = numpy .bool )
57
-
58
- #Encode message
59
- c = encode75 (m )
77
+ K_c = int (K_m / R ) #Code efficiency is 1/2
60
78
61
- #Add noise
62
- r = c + numpy .random . normal ( 0.0 , 0.01 , K_c )
79
+ # Per-bit SNR (in dB)
80
+ EbN0dB = numpy .arange ( 0 , 10 )
63
81
64
- #Compute branch metrics
65
- bm = numpy .zeros (K_m * O , dtype = numpy .float32 )
66
- for i in range (0 , K_m ):
67
- bm [O * i :O * (i + 1 )] = branch_metrics ([r [2 * i ], r [2 * i + 1 ]])
82
+ # Compute noise variance from EB/N0
83
+ sigma_b2 = numpy .power (10 , - EbN0dB / 10 )
84
+ sigma_b2 *= 1 / 2 # 0.5*Ps/R
68
85
69
- #decode message
70
- m_hat = dec .viterbi_algorithm (- 1 , - 1 , bm );
71
-
72
- print (numpy .array (m , dtype = numpy .int ))
73
- print ('...' )
74
- print (m_hat )
75
-
76
- ##Compute BER
77
- BER = numpy .sum (numpy .abs (m - m_hat ))/ K_m
78
- print (BER )
86
+ #Create decoder instance
87
+ dec_vit = viterbi (I , S , O , NS , OS )
88
+ dec_log_bcjr = bcjr (I , S , O , NS , OS )
89
+
90
+ BER_viterbi = numpy .zeros (len (EbN0dB ))
91
+ BER_log_bcjr = numpy .zeros (len (EbN0dB ))
92
+ for i in range (0 , len (EbN0dB )):
93
+ #Generate message
94
+ m = numpy .random .randint (0 , 2 , K_m , dtype = numpy .bool )
95
+
96
+ #Encode message
97
+ c = encode75 (m )
98
+
99
+ #Add noise
100
+ noise = numpy .random .normal (0.0 , numpy .sqrt (sigma_b2 [i ]), K_c ) \
101
+ + 1j * numpy .random .normal (0.0 , numpy .sqrt (sigma_b2 [i ]), K_c )
102
+ noise /= numpy .sqrt (2 )
103
+ r = c + noise
104
+
105
+ ## Viterbi
106
+ #Compute branch metrics
107
+ bm_viterbi = viterbi_branch_metrics (r , int (1 / R ))
108
+
109
+ #decode message
110
+ m_hat_viterbi = dec_vit .viterbi_algorithm (- 1 , - 1 , bm_viterbi );
111
+
112
+ ## Log BCJR
113
+ #Compute branch metrics
114
+ bm_log_bcjr = log_bcjr_branch_metrics (r , int (1 / R ), sigma_b2 [i ])
115
+
116
+ #Compute posterior probabilities of codewords
117
+ #A0 = numpy.log([1.0, 1e-20, 1e-20, 1e-20], dtype=numpy.float32) #Trellis begin in first state (all-0)
118
+ A0 = numpy .log ([1.0 / 4 ]* 4 , dtype = numpy .float32 ) #Do not know in which state we end
119
+ BK = numpy .log ([1.0 / 4 ]* 4 , dtype = numpy .float32 ) #Do not know in which state we end
120
+ post_log_bcjr = dec_log_bcjr .log_bcjr_algorithm (A0 , BK , bm_log_bcjr );
121
+
122
+ #Compute bit LLR and take decisions
123
+ llr = compute_llr (post_log_bcjr , K_m , S )
124
+ m_hat_log_bcjr = (llr < 0 )
125
+
126
+ ##Compute BER
127
+ BER_viterbi [i ] = numpy .mean (numpy .abs (m != m_hat_viterbi ))
128
+ print ('BER For viterbi at Eb/N0 = ' + str (EbN0dB [i ]) + 'dB: ' + str (BER_viterbi [i ]))
129
+ BER_log_bcjr [i ] = numpy .mean (numpy .abs (m != m_hat_log_bcjr ))
130
+ print ('BER For log_bcjr at Eb/N0 = ' + str (EbN0dB [i ]) + 'dB: ' + str (BER_log_bcjr [i ]))
131
+
132
+ plt .semilogy (EbN0dB , BER_viterbi );
133
+ plt .semilogy (EbN0dB , BER_log_bcjr );
134
+ plt .show ()
0 commit comments