Skip to content

Commit 21ad840

Browse files
authored
Merge branch 'master' into Release_v0.6
2 parents 4013d31 + 47433d6 commit 21ad840

18 files changed

+619
-87
lines changed

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ install:
2626
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib nose
2727
- source activate test-environment
2828
#- conda install --yes -c dan_blanchard python-coveralls nose-cov
29-
- pip install python-coveralls
29+
- pip install coveralls
3030
- pip install coverage
3131
- python setup.py install
3232
script:
3333
# Your test script goes here
34-
- nosetests -a '!slow' --with-coverage --cover-package=commpy --logging-level=INFO
34+
- nosetests --with-coverage --cover-package=commpy --logging-level=INFO
3535
# Calculate coverage
3636
after_success:
3737
- coveralls

THANKS.txt

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ Please add names as needed so that we can keep up with all the contributors.
22

33
Veeresh Taranalli for initial creation and contribution of CommPy.
44
Bastien Trotobas for adding some features, bugfixes, maintenance.
5+
Eduardo Soares (@eSoares) for several enhancements including WiFi 802.11 class and code speedups.
56
Vladimir Fadeev for bugfixes, addition of convolutional code puncturing and readme explanation of codings.
67
Youness Akourim for adding features and fixing some bugs.
78
Rey Tucker for python3 compatibility fixes.

commpy/channelcoding/README.md

+23-23
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,12 @@ The [following](https://en.wikipedia.org/wiki/File:Conv_code_177_133.png) convol
7878
Convolutional encoder parameters:
7979

8080
```python
81+
generator_matrix = np.array([[5, 7]]) # generator branches
82+
trellis = cc.Trellis(np.array([M]), generator_matrix) # Trellis structure
83+
8184
rate = 1/2 # code rate
8285
L = 7 # constraint length
8386
m = np.array([L-1]) # number of delay elements
84-
generator_matrix = np.array([[0o171, 0o133]]) # generator branches
85-
trellis = cc.Trellis(M, generator_matrix) # Trellis structure
8687
```
8788

8889
Viterbi decoder parameters:
@@ -106,9 +107,9 @@ noiseVar = 10**(-snrdB/10) # noise variance (power)
106107

107108
N_c = 10 # number of trials
108109

109-
BER_soft = np.empty((N_c,))
110-
BER_hard = np.empty((N_c,))
111-
BER_uncoded = np.empty((N_c,))
110+
BER_soft = np.zeros(N_c)
111+
BER_hard = np.zeros(N_c)
112+
BER_uncoded = np.zeros(N_c)
112113

113114
for cntr in range(N_c):
114115

@@ -136,31 +137,30 @@ for cntr in range(N_c):
136137
decoded_soft = cc.viterbi_decode(demodulated_soft, trellis, tb_depth, decoding_type='unquantized') # decoding (soft decision)
137138
decoded_hard = cc.viterbi_decode(demodulated_hard, trellis, tb_depth, decoding_type='hard') # decoding (hard decision)
138139

140+
NumErr, BER_soft[cntr] = BER_calc(message_bits, decoded_soft[:message_bits.size]) # bit-error ratio (soft decision)
141+
NumErr, BER_hard[cntr] = BER_calc(message_bits, decoded_hard[:message_bits.size]) # bit-error ratio (hard decision)
142+
NumErr, BER_uncoded[cntr] = BER_calc(message_bits, demodulated_uncoded[:message_bits.size]) # bit-error ratio (uncoded case)
139143

140-
NumErr, BER_soft[cntr] = BER_calc(message_bits, decoded_soft[:-(L-1)]) # bit-error ratio (soft decision)
141-
NumErr, BER_hard[cntr] = BER_calc(message_bits, decoded_hard[:-(L-1)]) # bit-error ratio (hard decision)
142-
NumErr, BER_uncoded[cntr] = BER_calc(message_bits, demodulated_uncoded) # bit-error ratio (uncoded case)
143-
144-
mean_BER_soft = np.mean(BER_soft) # averaged bit-error ratio (soft decision)
145-
mean_BER_hard = np.mean(BER_hard) # averaged bit-error ratio (hard decision)
146-
mean_BER_uncoded = np.mean(BER_uncoded) # averaged bit-error ratio (uncoded case)
144+
mean_BER_soft = BER_soft.mean() # averaged bit-error ratio (soft decision)
145+
mean_BER_hard = BER_hard.mean() # averaged bit-error ratio (hard decision)
146+
mean_BER_uncoded = BER_uncoded.mean() # averaged bit-error ratio (uncoded case)
147147

148-
print("Soft decision:\n"+str(mean_BER_soft)+"\n")
149-
print("Hard decision:\n"+str(mean_BER_hard)+"\n")
150-
print("Uncoded message:\n"+str(mean_BER_uncoded)+"\n")
148+
print("Soft decision:\n{}\n".format(mean_BER_soft))
149+
print("Hard decision:\n{}\n".format(mean_BER_hard))
150+
print("Uncoded message:\n{}\n".format(mean_BER_uncoded))
151151
```
152152

153153
Outputs:
154154

155155
```python
156-
>>> Soft decision:
157-
>>> 0.0
158-
>>>
159-
>>> Hard decision:
160-
>>> 3.0000000000000004e-05
161-
>>>
162-
>>> Uncoded message:
163-
>>> 0.008782
156+
Soft decision:
157+
2.8000000000000003e-05
158+
159+
Hard decision:
160+
0.0007809999999999999
161+
162+
Uncoded message:
163+
0.009064
164164
```
165165

166166
### Reference

commpy/channelcoding/convcode.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,9 @@ def _where_c(inarray, rows, cols, search_value, index_array):
573573

574574

575575
@functools.lru_cache(maxsize=128, typed=False)
576-
def _compute_branch_metrics(decoding_type, r_codeword, i_codeword_array):
576+
def _compute_branch_metrics(decoding_type, _r_codeword: tuple, _i_codeword_array: tuple):
577+
r_codeword = np.array(_r_codeword)
578+
i_codeword_array = np.array(_i_codeword_array)
577579
if decoding_type == 'hard':
578580
return hamming_dist(r_codeword.astype(int), i_codeword_array.astype(int))
579581
elif decoding_type == 'soft':
@@ -693,12 +695,13 @@ def viterbi_decode(coded_bits, trellis, tb_depth=None, decoding_type='hard'):
693695
rate = k/n
694696
total_memory = trellis.total_memory
695697

696-
if tb_depth is None:
697-
tb_depth = 5*total_memory
698-
699698
# Number of message bits after decoding
700699
L = int(len(coded_bits)*rate)
701700

701+
if tb_depth is None:
702+
tb_depth = min(5 * total_memory, L)
703+
704+
702705
path_metrics = np.full((trellis.number_states, 2), np.inf)
703706
path_metrics[0][0] = 0
704707
paths = np.empty((trellis.number_states, tb_depth), 'int')
@@ -745,7 +748,8 @@ def viterbi_decode(coded_bits, trellis, tb_depth=None, decoding_type='hard'):
745748

746749
return decoded_bits[:L]
747750

748-
def puncturing(message, punct_vec):
751+
752+
def puncturing(message: np.ndarray, punct_vec: np.ndarray) -> np.ndarray:
749753
"""
750754
Applying of the punctured procedure.
751755
Parameters
@@ -769,7 +773,8 @@ def puncturing(message, punct_vec):
769773
shift = shift + 1
770774
return np.array(punctured)
771775

772-
def depuncturing(punctured, punct_vec, shouldbe):
776+
777+
def depuncturing(punctured: np.ndarray, punct_vec: np.ndarray, shouldbe: int) -> np.ndarray:
773778
"""
774779
Applying of the inserting zeros procedure.
775780
Parameters
@@ -795,5 +800,5 @@ def depuncturing(punctured, punct_vec, shouldbe):
795800
else:
796801
shift2 = shift2 + 1
797802
if idx%N == 0:
798-
shift = shift + 1;
803+
shift = shift + 1
799804
return depunctured

commpy/channelcoding/gfields.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
""" Galois Fields """
55

6-
from fractions import gcd
6+
from math import gcd
77

88
from numpy import array, zeros, arange, convolve, ndarray, concatenate
99

@@ -52,7 +52,7 @@ def __init__(self, x, m):
5252
if type(x) is int and x >= 0 and x < pow(2, m):
5353
self.elements = array([x])
5454
elif type(x) is ndarray and len(x) >= 1:
55-
self.elements = x
55+
self.elements = x.astype(int)
5656

5757
# Overloading addition operator for Galois Field
5858
def __add__(self, x):

commpy/channelcoding/ldpc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,8 @@ def ldpc_bp_decode(llr_vec, ldpc_code_params, decoder_algorithm, n_iters):
241241

242242
# Variable Node Update
243243
msg_sum = np.array(message_matrix.sum(0)).squeeze()
244-
message_matrix *= -1
245-
message_matrix += parity_check_matrix.multiply(msg_sum + llr_vec[i_start:i_stop])
244+
message_matrix.data *= -1
245+
message_matrix.data += parity_check_matrix.multiply(msg_sum + llr_vec[i_start:i_stop]).data
246246

247247
out_llrs = msg_sum + llr_vec[i_start:i_stop]
248248
np.signbit(out_llrs, out=dec_word[i_start:i_stop])

commpy/channelcoding/tests/test_convcode.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ def test_viterbi_decode(self):
131131

132132
@dec.slow
133133
def test_conv_encode_viterbi_decode(self):
134+
# Set seed
135+
seed(17121996)
136+
134137
niters = 10
135138
blocklength = 1000
136139

@@ -176,6 +179,5 @@ def test_conv_encode_viterbi_decode(self):
176179

177180

178181
if __name__ == "__main__":
179-
seed(17121996)
180182
run_module_suite()
181183

commpy/channels.py

+1-1
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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Authors: CommPy contributors
2+
# License: BSD 3-Clause
3+
4+
import math
5+
6+
import matplotlib.pyplot as plt
7+
import numpy as np
8+
9+
import commpy.channels as chan
10+
# ==================================================================================================
11+
# Complete example using Commpy Wifi 802.11 physical parameters
12+
# ==================================================================================================
13+
from commpy.wifi80211 import Wifi80211
14+
15+
# AWGN channel
16+
channels = chan.SISOFlatChannel(None, (1 + 0j, 0j))
17+
18+
w2 = Wifi80211(mcs=2)
19+
w3 = Wifi80211(mcs=3)
20+
21+
# SNR range to test
22+
SNRs2 = np.arange(0, 6) + 10 * math.log10(w2.get_modem().num_bits_symbol)
23+
SNRs3 = np.arange(0, 6) + 10 * math.log10(w3.get_modem().num_bits_symbol)
24+
25+
BERs_mcs2 = w2.link_performance(channels, SNRs2, 10, 10, 600, stop_on_surpass_error=False)
26+
BERs_mcs3 = w3.link_performance(channels, SNRs3, 10, 10, 600, stop_on_surpass_error=False)
27+
28+
# Test
29+
plt.semilogy(SNRs2, BERs_mcs2, 'o-', SNRs3, BERs_mcs3, 'o-')
30+
plt.grid()
31+
plt.xlabel('Signal to Noise Ration (dB)')
32+
plt.ylabel('Bit Error Rate')
33+
plt.legend(('MCS 2', 'MCS 3'))
34+
plt.show()

0 commit comments

Comments
 (0)