Skip to content

Commit 87648d7

Browse files
author
Alexandre Marquet
committed
Update example to include log_bcjr decoding.
1 parent 0836148 commit 87648d7

File tree

1 file changed

+92
-36
lines changed

1 file changed

+92
-36
lines changed

examples/75_cc.py

Lines changed: 92 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
from PyTurbo import PyLogBCJR as bcjr
12
from PyTurbo import PyViterbi as viterbi
3+
from matplotlib import pyplot as plt
24

35
import numpy
46

@@ -18,18 +20,42 @@ def encode75(msg):
1820

1921
return out_msg
2022

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
2529

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)
2833

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()
3135

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
3359

3460
#Define trellis
3561
I=2
@@ -43,36 +69,66 @@ def branch_metrics(bits_rcvd):
4369
3, 0, \
4470
1, 2, \
4571
2, 1]
46-
47-
#Create decoder instance
48-
dec = viterbi(I, S, O, NS, OS)
72+
R = 1/2 # Code efficiency
4973

5074
#Length of the message
51-
K_m = 100;
75+
K_m = 200000;
5276
#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
6078

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)
6381

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
6885

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

Comments
 (0)