Skip to content

Commit

Permalink
Merge pull request #86 from eSoares/fix-coding-rate-send-chunk-roundi…
Browse files Browse the repository at this point in the history
…ng-error

Fix coding rate send chunk rounding error
  • Loading branch information
BastienTr committed Oct 6, 2020
2 parents 7ae3bb8 + 3bc2faf commit 292b4e5
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 19 deletions.
7 changes: 4 additions & 3 deletions commpy/channelcoding/convcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,12 +695,13 @@ def viterbi_decode(coded_bits, trellis, tb_depth=None, decoding_type='hard'):
rate = k/n
total_memory = trellis.total_memory

if tb_depth is None:
tb_depth = 5*total_memory

# Number of message bits after decoding
L = int(len(coded_bits)*rate)

if tb_depth is None:
tb_depth = min(5 * total_memory, L)


path_metrics = np.full((trellis.number_states, 2), np.inf)
path_metrics[0][0] = 0
paths = np.empty((trellis.number_states, tb_depth), 'int')
Expand Down
2 changes: 1 addition & 1 deletion commpy/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def generate_noises(self, dims):
else:
self.noises = standard_normal(dims) * self.noise_std

def set_SNR_dB(self, SNR_dB, code_rate=1, Es=1):
def set_SNR_dB(self, SNR_dB, code_rate: float = 1., Es=1):

"""
Sets the the noise standard deviation based on SNR expressed in dB.
Expand Down
39 changes: 24 additions & 15 deletions commpy/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import math
from inspect import getfullargspec
from fractions import Fraction

import numpy as np

Expand Down Expand Up @@ -49,7 +50,7 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
so it should be large enough regarding the code type.
*Default*: send_chunck = err_min
code_rate : float in (0,1]
code_rate : float or Fraction in (0,1]
Rate of the used code.
*Default*: 1 i.e. no code.
Expand Down Expand Up @@ -97,9 +98,9 @@ class LinkModel:
binary array.
*Default* is no process.
rate : float
Code rate.
*Default* is 1.
rate : float or Fraction in (0,1]
Rate of the used code.
*Default*: 1 i.e. no code.
Attributes
----------
Expand Down Expand Up @@ -134,13 +135,15 @@ class LinkModel:
*Default* is 1.
"""

def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, Es=1, decoder=None, rate=1.):
def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, Es=1, decoder=None, rate=Fraction(1, 1)):
self.modulate = modulate
self.channel = channel
self.receive = receive
self.num_bits_symbol = num_bits_symbol
self.constellation = constellation
self.Es = Es
if type(rate) is float:
rate = Fraction(rate).limit_denominator(100)
self.rate = rate

if decoder is None:
Expand All @@ -149,7 +152,7 @@ def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, E
self.decoder = decoder
self.full_simulation_results = None

def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None, code_rate: float = 1.,
def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None, code_rate: Fraction = Fraction(1, 1),
number_chunks_per_send=1, stop_on_surpass_error=True):
"""
Estimate the BER performance of a link model with Monte Carlo simulation.
Expand All @@ -171,7 +174,7 @@ def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None,
so it should be large enough regarding the code type.
*Default*: send_chunck = err_min
code_rate : float in (0,1]
code_rate : Fraction in (0,1]
Rate of the used code.
*Default*: 1 i.e. no code.
Expand Down Expand Up @@ -200,18 +203,21 @@ def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None,
BEs = np.zeros((len(SNRs), tx_max), dtype=int) # Bit errors per tx
CEs = np.zeros((len(SNRs), tx_max), dtype=int) # Chunk Errors per tx
NCs = np.zeros((len(SNRs), tx_max), dtype=int) # Number of Chunks per tx
# Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
# Set chunk size and round it to be a multiple of num_bits_symbol* nb_tx to avoid padding taking in to account the coding rate
if send_chunk is None:
send_chunk = err_min
divider = self.num_bits_symbol * self.channel.nb_tx
if type(code_rate) is float:
code_rate = Fraction(code_rate).limit_denominator(100)
self.rate = code_rate
divider = (Fraction(1, self.num_bits_symbol * self.channel.nb_tx) * 1 / code_rate).denominator
send_chunk = max(divider, send_chunk // divider * divider)

receive_size = self.channel.nb_tx * self.num_bits_symbol
full_args_decoder = len(getfullargspec(self.decoder).args) > 1

# Computations
for id_SNR in range(len(SNRs)):
self.channel.set_SNR_dB(SNRs[id_SNR], code_rate, self.Es)
self.channel.set_SNR_dB(SNRs[id_SNR], float(code_rate), self.Es)
total_tx_send = 0
bit_err = np.zeros(tx_max, dtype=int)
chunk_loss = np.zeros(tx_max, dtype=int)
Expand All @@ -227,7 +233,7 @@ def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None,
# Deals with MIMO channel
if isinstance(self.channel, MIMOFlatChannel):
nb_symb_vector = len(channel_output)
received_msg = np.empty(int(math.ceil(len(msg) / self.rate)), dtype=np.int8)
received_msg = np.empty(int(math.ceil(len(msg) / float(self.rate))), dtype=np.int8)
for i in range(nb_symb_vector):
received_msg[receive_size * i:receive_size * (i + 1)] = \
self.receive(channel_output[i], self.channel.channel_gains[i],
Expand Down Expand Up @@ -276,7 +282,7 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
Number of bits to be send at each iteration. This is also the frame length of the decoder if available
so it should be large enough regarding the code type.
*Default*: send_chunck = err_min
code_rate : float in (0,1]
code_rate : float or Fraction in (0,1]
Rate of the used code.
*Default*: 1 i.e. no code.
Returns
Expand All @@ -290,15 +296,18 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
# Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
if send_chunk is None:
send_chunk = err_min
divider = self.num_bits_symbol * self.channel.nb_tx
if type(code_rate) is float:
code_rate = Fraction(code_rate).limit_denominator(100)
self.rate = code_rate
divider = (Fraction(1, self.num_bits_symbol * self.channel.nb_tx) * 1 / code_rate).denominator
send_chunk = max(divider, send_chunk // divider * divider)

receive_size = self.channel.nb_tx * self.num_bits_symbol
full_args_decoder = len(getfullargspec(self.decoder).args) > 1

# Computations
for id_SNR in range(len(SNRs)):
self.channel.set_SNR_dB(SNRs[id_SNR], code_rate, self.Es)
self.channel.set_SNR_dB(SNRs[id_SNR], float(code_rate), self.Es)
bit_send = 0
bit_err = 0
while bit_send < send_max and bit_err < err_min:
Expand All @@ -310,7 +319,7 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
# Deals with MIMO channel
if isinstance(self.channel, MIMOFlatChannel):
nb_symb_vector = len(channel_output)
received_msg = np.empty(int(math.ceil(len(msg) / self.rate)), dtype=np.int8)
received_msg = np.empty(int(math.ceil(len(msg) / float(self.rate))), dtype=np.int8)
for i in range(nb_symb_vector):
received_msg[receive_size * i:receive_size * (i + 1)] = \
self.receive(channel_output[i], self.channel.channel_gains[i],
Expand Down

0 comments on commit 292b4e5

Please sign in to comment.