Skip to content

Commit 292b4e5

Browse files
authored
Merge pull request #86 from eSoares/fix-coding-rate-send-chunk-rounding-error
Fix coding rate send chunk rounding error
2 parents 7ae3bb8 + 3bc2faf commit 292b4e5

File tree

3 files changed

+29
-19
lines changed

3 files changed

+29
-19
lines changed

commpy/channelcoding/convcode.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -695,12 +695,13 @@ def viterbi_decode(coded_bits, trellis, tb_depth=None, decoding_type='hard'):
695695
rate = k/n
696696
total_memory = trellis.total_memory
697697

698-
if tb_depth is None:
699-
tb_depth = 5*total_memory
700-
701698
# Number of message bits after decoding
702699
L = int(len(coded_bits)*rate)
703700

701+
if tb_depth is None:
702+
tb_depth = min(5 * total_memory, L)
703+
704+
704705
path_metrics = np.full((trellis.number_states, 2), np.inf)
705706
path_metrics[0][0] = 0
706707
paths = np.empty((trellis.number_states, tb_depth), 'int')

commpy/channels.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def generate_noises(self, dims):
5454
else:
5555
self.noises = standard_normal(dims) * self.noise_std
5656

57-
def set_SNR_dB(self, SNR_dB, code_rate=1, Es=1):
57+
def set_SNR_dB(self, SNR_dB, code_rate: float = 1., Es=1):
5858

5959
"""
6060
Sets the the noise standard deviation based on SNR expressed in dB.

commpy/links.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import math
1919
from inspect import getfullargspec
20+
from fractions import Fraction
2021

2122
import numpy as np
2223

@@ -49,7 +50,7 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
4950
so it should be large enough regarding the code type.
5051
*Default*: send_chunck = err_min
5152
52-
code_rate : float in (0,1]
53+
code_rate : float or Fraction in (0,1]
5354
Rate of the used code.
5455
*Default*: 1 i.e. no code.
5556
@@ -97,9 +98,9 @@ class LinkModel:
9798
binary array.
9899
*Default* is no process.
99100
100-
rate : float
101-
Code rate.
102-
*Default* is 1.
101+
rate : float or Fraction in (0,1]
102+
Rate of the used code.
103+
*Default*: 1 i.e. no code.
103104
104105
Attributes
105106
----------
@@ -134,13 +135,15 @@ class LinkModel:
134135
*Default* is 1.
135136
"""
136137

137-
def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, Es=1, decoder=None, rate=1.):
138+
def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, Es=1, decoder=None, rate=Fraction(1, 1)):
138139
self.modulate = modulate
139140
self.channel = channel
140141
self.receive = receive
141142
self.num_bits_symbol = num_bits_symbol
142143
self.constellation = constellation
143144
self.Es = Es
145+
if type(rate) is float:
146+
rate = Fraction(rate).limit_denominator(100)
144147
self.rate = rate
145148

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

152-
def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None, code_rate: float = 1.,
155+
def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None, code_rate: Fraction = Fraction(1, 1),
153156
number_chunks_per_send=1, stop_on_surpass_error=True):
154157
"""
155158
Estimate the BER performance of a link model with Monte Carlo simulation.
@@ -171,7 +174,7 @@ def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None,
171174
so it should be large enough regarding the code type.
172175
*Default*: send_chunck = err_min
173176
174-
code_rate : float in (0,1]
177+
code_rate : Fraction in (0,1]
175178
Rate of the used code.
176179
*Default*: 1 i.e. no code.
177180
@@ -200,18 +203,21 @@ def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None,
200203
BEs = np.zeros((len(SNRs), tx_max), dtype=int) # Bit errors per tx
201204
CEs = np.zeros((len(SNRs), tx_max), dtype=int) # Chunk Errors per tx
202205
NCs = np.zeros((len(SNRs), tx_max), dtype=int) # Number of Chunks per tx
203-
# Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
206+
# 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
204207
if send_chunk is None:
205208
send_chunk = err_min
206-
divider = self.num_bits_symbol * self.channel.nb_tx
209+
if type(code_rate) is float:
210+
code_rate = Fraction(code_rate).limit_denominator(100)
211+
self.rate = code_rate
212+
divider = (Fraction(1, self.num_bits_symbol * self.channel.nb_tx) * 1 / code_rate).denominator
207213
send_chunk = max(divider, send_chunk // divider * divider)
208214

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

212218
# Computations
213219
for id_SNR in range(len(SNRs)):
214-
self.channel.set_SNR_dB(SNRs[id_SNR], code_rate, self.Es)
220+
self.channel.set_SNR_dB(SNRs[id_SNR], float(code_rate), self.Es)
215221
total_tx_send = 0
216222
bit_err = np.zeros(tx_max, dtype=int)
217223
chunk_loss = np.zeros(tx_max, dtype=int)
@@ -227,7 +233,7 @@ def link_performance_full_metrics(self, SNRs, tx_max, err_min, send_chunk=None,
227233
# Deals with MIMO channel
228234
if isinstance(self.channel, MIMOFlatChannel):
229235
nb_symb_vector = len(channel_output)
230-
received_msg = np.empty(int(math.ceil(len(msg) / self.rate)), dtype=np.int8)
236+
received_msg = np.empty(int(math.ceil(len(msg) / float(self.rate))), dtype=np.int8)
231237
for i in range(nb_symb_vector):
232238
received_msg[receive_size * i:receive_size * (i + 1)] = \
233239
self.receive(channel_output[i], self.channel.channel_gains[i],
@@ -276,7 +282,7 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
276282
Number of bits to be send at each iteration. This is also the frame length of the decoder if available
277283
so it should be large enough regarding the code type.
278284
*Default*: send_chunck = err_min
279-
code_rate : float in (0,1]
285+
code_rate : float or Fraction in (0,1]
280286
Rate of the used code.
281287
*Default*: 1 i.e. no code.
282288
Returns
@@ -290,15 +296,18 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
290296
# Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
291297
if send_chunk is None:
292298
send_chunk = err_min
293-
divider = self.num_bits_symbol * self.channel.nb_tx
299+
if type(code_rate) is float:
300+
code_rate = Fraction(code_rate).limit_denominator(100)
301+
self.rate = code_rate
302+
divider = (Fraction(1, self.num_bits_symbol * self.channel.nb_tx) * 1 / code_rate).denominator
294303
send_chunk = max(divider, send_chunk // divider * divider)
295304

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

299308
# Computations
300309
for id_SNR in range(len(SNRs)):
301-
self.channel.set_SNR_dB(SNRs[id_SNR], code_rate, self.Es)
310+
self.channel.set_SNR_dB(SNRs[id_SNR], float(code_rate), self.Es)
302311
bit_send = 0
303312
bit_err = 0
304313
while bit_send < send_max and bit_err < err_min:
@@ -310,7 +319,7 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
310319
# Deals with MIMO channel
311320
if isinstance(self.channel, MIMOFlatChannel):
312321
nb_symb_vector = len(channel_output)
313-
received_msg = np.empty(int(math.ceil(len(msg) / self.rate)), dtype=np.int8)
322+
received_msg = np.empty(int(math.ceil(len(msg) / float(self.rate))), dtype=np.int8)
314323
for i in range(nb_symb_vector):
315324
received_msg[receive_size * i:receive_size * (i + 1)] = \
316325
self.receive(channel_output[i], self.channel.channel_gains[i],

0 commit comments

Comments
 (0)