mirror of
https://github.com/jhshi/openofdm.git
synced 2025-06-17 06:38:18 +00:00
scripts init
This commit is contained in:
237
scripts/commpy/channelcoding/ldpc.py
Normal file
237
scripts/commpy/channelcoding/ldpc.py
Normal file
@ -0,0 +1,237 @@
|
||||
|
||||
|
||||
# Authors: Veeresh Taranalli <veeresht@gmail.com>
|
||||
# License: BSD 3-Clause
|
||||
|
||||
""" LDPC Codes """
|
||||
import numpy as np
|
||||
|
||||
__all__ = ['get_ldpc_code_params, ldpc_bp_decode']
|
||||
|
||||
MAX_POS_LLR = 38.0
|
||||
MIN_NEG_LLR = -38.0
|
||||
|
||||
def get_ldpc_code_params(ldpc_design_filename):
|
||||
"""
|
||||
Extract parameters from LDPC code design file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ldpc_design_filename : string
|
||||
Filename of the LDPC code design file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ldpc_code_params : dictionary
|
||||
Parameters of the LDPC code.
|
||||
"""
|
||||
|
||||
ldpc_design_file = open(ldpc_design_filename)
|
||||
|
||||
ldpc_code_params = {}
|
||||
|
||||
[n_vnodes, n_cnodes] = [int(x) for x in ldpc_design_file.readline().split(' ')]
|
||||
[max_vnode_deg, max_cnode_deg] = [int(x) for x in ldpc_design_file.readline().split(' ')]
|
||||
vnode_deg_list = np.array([int(x) for x in ldpc_design_file.readline().split(' ')[:-1]], np.int32)
|
||||
cnode_deg_list = np.array([int(x) for x in ldpc_design_file.readline().split(' ')[:-1]], np.int32)
|
||||
|
||||
cnode_adj_list = -np.ones([n_cnodes, max_cnode_deg], int)
|
||||
vnode_adj_list = -np.ones([n_vnodes, max_vnode_deg], int)
|
||||
|
||||
for vnode_idx in range(n_vnodes):
|
||||
vnode_adj_list[vnode_idx, 0:vnode_deg_list[vnode_idx]] = \
|
||||
np.array([int(x)-1 for x in ldpc_design_file.readline().split('\t')])
|
||||
|
||||
for cnode_idx in range(n_cnodes):
|
||||
cnode_adj_list[cnode_idx, 0:cnode_deg_list[cnode_idx]] = \
|
||||
np.array([int(x)-1 for x in ldpc_design_file.readline().split('\t')])
|
||||
|
||||
cnode_vnode_map = -np.ones([n_cnodes, max_cnode_deg], int)
|
||||
vnode_cnode_map = -np.ones([n_vnodes, max_vnode_deg], int)
|
||||
cnode_list = np.arange(n_cnodes)
|
||||
vnode_list = np.arange(n_vnodes)
|
||||
|
||||
for cnode in range(n_cnodes):
|
||||
for i, vnode in enumerate(cnode_adj_list[cnode, 0:cnode_deg_list[cnode]]):
|
||||
cnode_vnode_map[cnode, i] = cnode_list[np.where(vnode_adj_list[vnode, :] == cnode)]
|
||||
|
||||
for vnode in range(n_vnodes):
|
||||
for i, cnode in enumerate(vnode_adj_list[vnode, 0:vnode_deg_list[vnode]]):
|
||||
vnode_cnode_map[vnode, i] = vnode_list[np.where(cnode_adj_list[cnode, :] == vnode)]
|
||||
|
||||
|
||||
cnode_adj_list_1d = cnode_adj_list.flatten().astype(np.int32)
|
||||
vnode_adj_list_1d = vnode_adj_list.flatten().astype(np.int32)
|
||||
cnode_vnode_map_1d = cnode_vnode_map.flatten().astype(np.int32)
|
||||
vnode_cnode_map_1d = vnode_cnode_map.flatten().astype(np.int32)
|
||||
|
||||
pmat = np.zeros([n_cnodes, n_vnodes], int)
|
||||
for cnode_idx in range(n_cnodes):
|
||||
pmat[cnode_idx, cnode_adj_list[cnode_idx, :]] = 1
|
||||
|
||||
ldpc_code_params['n_vnodes'] = n_vnodes
|
||||
ldpc_code_params['n_cnodes'] = n_cnodes
|
||||
ldpc_code_params['max_cnode_deg'] = max_cnode_deg
|
||||
ldpc_code_params['max_vnode_deg'] = max_vnode_deg
|
||||
ldpc_code_params['cnode_adj_list'] = cnode_adj_list_1d
|
||||
ldpc_code_params['cnode_vnode_map'] = cnode_vnode_map_1d
|
||||
ldpc_code_params['vnode_adj_list'] = vnode_adj_list_1d
|
||||
ldpc_code_params['vnode_cnode_map'] = vnode_cnode_map_1d
|
||||
ldpc_code_params['cnode_deg_list'] = cnode_deg_list
|
||||
ldpc_code_params['vnode_deg_list'] = vnode_deg_list
|
||||
|
||||
ldpc_design_file.close()
|
||||
|
||||
return ldpc_code_params
|
||||
|
||||
def _limit_llr(in_llr):
|
||||
|
||||
out_llr = in_llr
|
||||
|
||||
if in_llr > MAX_POS_LLR:
|
||||
out_llr = MAX_POS_LLR
|
||||
|
||||
if in_llr < MIN_NEG_LLR:
|
||||
out_llr = MIN_NEG_LLR
|
||||
|
||||
return out_llr
|
||||
|
||||
def sum_product_update(cnode_idx, cnode_adj_list, cnode_deg_list, cnode_msgs,
|
||||
vnode_msgs, cnode_vnode_map, max_cnode_deg, max_vnode_deg):
|
||||
|
||||
start_idx = cnode_idx*max_cnode_deg
|
||||
offset = cnode_deg_list[cnode_idx]
|
||||
vnode_list = cnode_adj_list[start_idx:start_idx+offset]
|
||||
vnode_list_msgs_tanh = np.tanh(vnode_msgs[vnode_list*max_vnode_deg +
|
||||
cnode_vnode_map[start_idx:start_idx+offset]]/2.0)
|
||||
msg_prod = np.prod(vnode_list_msgs_tanh)
|
||||
|
||||
# Compute messages on outgoing edges using the incoming message product
|
||||
cnode_msgs[start_idx:start_idx+offset]= 2.0*np.arctanh(msg_prod/vnode_list_msgs_tanh)
|
||||
|
||||
|
||||
def min_sum_update(cnode_idx, cnode_adj_list, cnode_deg_list, cnode_msgs,
|
||||
vnode_msgs, cnode_vnode_map, max_cnode_deg, max_vnode_deg):
|
||||
|
||||
start_idx = cnode_idx*max_cnode_deg
|
||||
offset = cnode_deg_list[cnode_idx]
|
||||
vnode_list = cnode_adj_list[start_idx:start_idx+offset]
|
||||
vnode_list_msgs = vnode_msgs[vnode_list*max_vnode_deg +
|
||||
cnode_vnode_map[start_idx:start_idx+offset]]
|
||||
vnode_list_msgs = np.ma.array(vnode_list_msgs, mask=False)
|
||||
|
||||
# Compute messages on outgoing edges using the incoming messages
|
||||
for i in range(start_idx, start_idx+offset):
|
||||
vnode_list_msgs.mask[i-start_idx] = True
|
||||
cnode_msgs[i] = np.prod(np.sign(vnode_list_msgs))*np.min(np.abs(vnode_list_msgs))
|
||||
vnode_list_msgs.mask[i-start_idx] = False
|
||||
#print cnode_msgs[i]
|
||||
|
||||
def ldpc_bp_decode(llr_vec, ldpc_code_params, decoder_algorithm, n_iters):
|
||||
"""
|
||||
LDPC Decoder using Belief Propagation (BP).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
llr_vec : 1D array of float
|
||||
Received codeword LLR values from the channel.
|
||||
|
||||
ldpc_code_params : dictionary
|
||||
Parameters of the LDPC code.
|
||||
|
||||
decoder_algorithm: string
|
||||
Specify the decoder algorithm type.
|
||||
SPA for Sum-Product Algorithm
|
||||
MSA for Min-Sum Algorithm
|
||||
|
||||
n_iters : int
|
||||
Max. number of iterations of decoding to be done.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dec_word : 1D array of 0's and 1's
|
||||
The codeword after decoding.
|
||||
|
||||
out_llrs : 1D array of float
|
||||
LLR values corresponding to the decoded output.
|
||||
"""
|
||||
|
||||
n_cnodes = ldpc_code_params['n_cnodes']
|
||||
n_vnodes = ldpc_code_params['n_vnodes']
|
||||
max_cnode_deg = ldpc_code_params['max_cnode_deg']
|
||||
max_vnode_deg = ldpc_code_params['max_vnode_deg']
|
||||
cnode_adj_list = ldpc_code_params['cnode_adj_list']
|
||||
cnode_vnode_map = ldpc_code_params['cnode_vnode_map']
|
||||
vnode_adj_list = ldpc_code_params['vnode_adj_list']
|
||||
vnode_cnode_map = ldpc_code_params['vnode_cnode_map']
|
||||
cnode_deg_list = ldpc_code_params['cnode_deg_list']
|
||||
vnode_deg_list = ldpc_code_params['vnode_deg_list']
|
||||
|
||||
dec_word = np.zeros(n_vnodes, int)
|
||||
out_llrs = np.zeros(n_vnodes, int)
|
||||
|
||||
cnode_msgs = np.zeros(n_cnodes*max_cnode_deg)
|
||||
vnode_msgs = np.zeros(n_vnodes*max_vnode_deg)
|
||||
|
||||
_limit_llr_v = np.vectorize(_limit_llr)
|
||||
|
||||
if decoder_algorithm == 'SPA':
|
||||
check_node_update = sum_product_update
|
||||
elif decoder_algorithm == 'MSA':
|
||||
check_node_update = min_sum_update
|
||||
else:
|
||||
raise NameError('Please input a valid decoder_algorithm string.')
|
||||
|
||||
# Initialize vnode messages with the LLR values received
|
||||
for vnode_idx in range(n_vnodes):
|
||||
start_idx = vnode_idx*max_vnode_deg
|
||||
offset = vnode_deg_list[vnode_idx]
|
||||
vnode_msgs[start_idx : start_idx+offset] = llr_vec[vnode_idx]
|
||||
|
||||
# Main loop of Belief Propagation (BP) decoding iterations
|
||||
for iter_cnt in range(n_iters):
|
||||
|
||||
continue_flag = 0
|
||||
|
||||
# Check Node Update
|
||||
for cnode_idx in range(n_cnodes):
|
||||
|
||||
check_node_update(cnode_idx, cnode_adj_list, cnode_deg_list, cnode_msgs,
|
||||
vnode_msgs, cnode_vnode_map, max_cnode_deg, max_vnode_deg)
|
||||
|
||||
# Variable Node Update
|
||||
for vnode_idx in range(n_vnodes):
|
||||
|
||||
# Compute sum of all incoming messages at the variable node
|
||||
start_idx = vnode_idx*max_vnode_deg
|
||||
offset = vnode_deg_list[vnode_idx]
|
||||
cnode_list = vnode_adj_list[start_idx:start_idx+offset]
|
||||
cnode_list_msgs = cnode_msgs[cnode_list*max_cnode_deg + vnode_cnode_map[start_idx:start_idx+offset]]
|
||||
msg_sum = np.sum(cnode_list_msgs)
|
||||
|
||||
# Compute messages on outgoing edges using the incoming message sum
|
||||
vnode_msgs[start_idx:start_idx+offset] = _limit_llr_v(llr_vec[vnode_idx] + msg_sum -
|
||||
cnode_list_msgs)
|
||||
|
||||
# Update output LLRs and decoded word
|
||||
out_llrs[vnode_idx] = llr_vec[vnode_idx] + msg_sum
|
||||
if out_llrs[vnode_idx] > 0:
|
||||
dec_word[vnode_idx] = 0
|
||||
else:
|
||||
dec_word[vnode_idx] = 1
|
||||
|
||||
# Compute if early termination using parity check matrix
|
||||
for cnode_idx in range(n_cnodes):
|
||||
p_sum = 0
|
||||
for i in range(cnode_deg_list[cnode_idx]):
|
||||
p_sum ^= dec_word[cnode_adj_list[cnode_idx*max_cnode_deg + i]]
|
||||
|
||||
if p_sum != 0:
|
||||
continue_flag = 1
|
||||
break
|
||||
|
||||
# Stop iterations
|
||||
if continue_flag == 0:
|
||||
break
|
||||
|
||||
return dec_word, out_llrs
|
Reference in New Issue
Block a user