Skip to content

Commit 17ebf24

Browse files
committed
Plotting method in Modem and bit-level representation.
* Add a method plotCons in the class modem that plots the constellation. * Give an example for plotCons. * Add a method bit_lvl_repr that convert channel matrix to Bit-level representation.
1 parent c21e8c9 commit 17ebf24

File tree

4 files changed

+105
-14
lines changed

4 files changed

+105
-14
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Modulation/Demodulation
5454
- OFDM Tx/Rx signal processing
5555
- MIMO Maximum Likelihood (ML) Detection.
5656
- MIMO K-best Schnorr-Euchner Detection.
57+
- Convert channel matrix to Bit-level representation.
5758

5859
Sequences
5960
---------

commpy/examples/plotConsModem.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Authors: Youness Akourim <akourim97@gmail.com>
2+
# License: BSD 3-Clause
3+
4+
from commpy.modulation import PSKModem, QAMModem
5+
6+
# =============================================================================
7+
# Example constellation plot of Modem
8+
# =============================================================================
9+
10+
# PSK corresponding to PSKModem for 4 bits
11+
psk = PSKModem(16)
12+
psk.plotCons()
13+
14+
# QAM corresponding to QAMModem for 2bits
15+
Qam = QAMModem(4)
16+
Qam.plotCons()

commpy/links.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
6565
link_model.channel.set_SNR_dB(SNRs[id_SNR], code_rate, link_model.Es)
6666
bit_send = 0
6767
bit_err = 0
68+
receive_size = link_model.channel.nb_tx * link_model.num_bits_symbol
6869
while bit_send < send_max and bit_err < err_min:
6970
# Propagate some bits
7071
msg = np.random.choice((0, 1), send_chunk)
@@ -74,14 +75,14 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
7475
# Deals with MIMO channel
7576
if isinstance(link_model.channel, MIMOFlatChannel):
7677
nb_symb_vector = len(channel_output)
77-
received_msg = np.empty(nb_symb_vector * link_model.channel.nb_tx, dtype=channel_output.dtype)
78+
received_msg = np.empty_like(msg, int)
7879
for i in range(nb_symb_vector):
79-
received_msg[link_model.channel.nb_tx * i:link_model.channel.nb_tx * (i+1)] = \
80+
received_msg[receive_size * i:receive_size * (i+1)] = \
8081
link_model.receive(channel_output[i], link_model.channel.channel_gains[i], link_model.constellation)
8182
else:
8283
received_msg = channel_output
8384
# Count errors
84-
bit_err += (msg != received_msg[:len(msg)]).sum() # Remove MIMO padding
85+
bit_err += (msg != received_msg).sum() # Remove MIMO padding
8586
bit_send += send_chunk
8687
BERs[id_SNR] = bit_err / bit_send
8788
return BERs
@@ -98,13 +99,13 @@ class linkModel:
9899
channel : _FlatChannel object
99100
100101
receive : function with prototype receive(y, H, constellation) that return a binary array.
101-
y : 1D ndarray of floats
102+
y : 1D ndarray
102103
Received complex symbols (shape: num_receive_antennas x 1)
103104
104-
h : 2D ndarray of floats
105+
h : 2D ndarray
105106
Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
106107
107-
constellation : 1D ndarray of floats
108+
constellation : 1D ndarray
108109
109110
num_bits_symbols : int
110111

commpy/modulation.py

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Authors: Veeresh Taranalli <veeresht@gmail.com> & Bastien Trotobas <bastien.trotobas@gmail.com>
1+
# Authors: Veeresh Taranalli <veeresht@gmail.com> & Bastien Trotobas <bastien.trotobas@gmail.com> & Youness Akourim <akourim97@gmail.com>
22
# License: BSD 3-Clause
33

44
"""
@@ -15,19 +15,20 @@
1515
ofdm_rx -- OFDM Receive Signal Processing
1616
mimo_ml -- MIMO Maximum Likelihood (ML) Detection.
1717
kbest -- MIMO K-best Schnorr-Euchner Detection.
18+
bit_lvl_repr -- Bit level representation
1819
1920
"""
2021
from itertools import product
2122

23+
import matplotlib.pyplot as plt
24+
from commpy.utilities import bitarray2dec, dec2bitarray
2225
from numpy import arange, array, zeros, pi, cos, sin, sqrt, log2, argmin, \
2326
hstack, repeat, tile, dot, sum, shape, concatenate, exp, \
24-
log, vectorize, empty
27+
log, vectorize, empty, eye, kron
2528
from numpy.fft import fft, ifft
2629
from numpy.linalg import qr
2730

28-
from commpy.utilities import bitarray2dec, dec2bitarray
29-
30-
__all__ = ['PSKModem', 'QAMModem', 'ofdm_tx', 'ofdm_rx', 'mimo_ml', 'kbest']
31+
__all__ = ['PSKModem', 'QAMModem', 'ofdm_tx', 'ofdm_rx', 'mimo_ml', 'kbest', 'bit_lvl_repr']
3132

3233

3334
class Modem:
@@ -99,6 +100,44 @@ def demodulate(self, input_symbols, demod_type, noise_var=0):
99100

100101
return demod_bits
101102

103+
def plotCons(self):
104+
""" Plot the constellation """
105+
# init some arrays
106+
beta = self.num_bits_symbol
107+
numbit = '0' + str(beta) + 'b'
108+
Bin = []
109+
mot = []
110+
const = []
111+
112+
# creation of w array
113+
reel = [pow(2, i) for i in range(beta // 2 - 1, -1, -1)]
114+
im = [1j * pow(2, i) for i in range(beta // 2 - 1, -1, -1)]
115+
w = concatenate((reel, im), axis=None)
116+
117+
listBin = [format(i, numbit) for i in range(2 ** beta)]
118+
for e in listBin:
119+
for i in range(beta):
120+
Bin.append(ord(e[i]) - 48)
121+
if (ord(e[i]) - 48 == 0):
122+
mot.append(-1)
123+
else:
124+
mot.append(1)
125+
const.append(dot(w, mot))
126+
mot = []
127+
symb = self.modulate(Bin)
128+
129+
# plot the symbols
130+
x = symb.real
131+
y = symb.imag
132+
133+
plt.plot(x, y, '+',linewidth=4)
134+
for i in range(len(x)):
135+
plt.text(x[i], y[i] , listBin[i])
136+
137+
plt.title('Constellation')
138+
plt.grid()
139+
plt.show()
140+
102141

103142
class PSKModem(Modem):
104143
""" Creates a Phase Shift Keying (PSK) Modem object. """
@@ -225,27 +264,35 @@ def kbest(y, h, constellation, K):
225264
226265
K : positive integer
227266
Number of candidates kept at each step
267+
268+
raises
269+
------
270+
ValueError
271+
If h has more columns than rows.
228272
"""
273+
nb_tx, nb_rx = h.shape
274+
if nb_rx > nb_tx:
275+
raise ValueError('h has more columns than rows')
276+
229277
# QR decomposition
230278
q, r = qr(h)
231279
yt = q.conj().T.dot(y)
232280

233281
# Initialization
234282
m = len(constellation)
235-
n = len(yt)
236283
nb_can = 1
237284

238285
if isinstance(constellation[0], complex):
239286
const_type = complex
240287
else:
241288
const_type = float
242-
X = empty((n, K * m), dtype=const_type) # Set of current candidates
289+
X = empty((nb_rx, K * m), dtype=const_type) # Set of current candidates
243290
d = tile(yt[:, None], (1, K * m)) # Corresponding distance vector
244291
d_tot = zeros(K * m, dtype=float) # Corresponding total distance
245292
hyp = empty(K * m, dtype=const_type) # Hypothesis vector
246293

247294
# Processing
248-
for coor in range(n-1, -1, -1):
295+
for coor in range(nb_rx-1, -1, -1):
249296
nb_hyp = nb_can * m
250297

251298
# Copy best candidates m times
@@ -269,3 +316,29 @@ def kbest(y, h, constellation, K):
269316
d[:coor, :nb_can] -= r[:coor, coor, None] * hyp[argsort[:nb_can]]
270317
d_tot[:nb_can] = d_tot[argsort[:nb_can]]
271318
return X[:, 0]
319+
320+
321+
def bit_lvl_repr(H, w):
322+
""" Bit-level representation of matrix H with weights w.
323+
324+
parameters
325+
----------
326+
H : 2D ndarray (shape : nb_rx, nb_tx)
327+
Channel Matrix.
328+
329+
w : 1D ndarray of complex (length : beta)
330+
Bit level representation weights. The length must be even.
331+
332+
return
333+
------
334+
A : 2D nbarray (shape : nb_rx, nb_tx*beta)
335+
Channel matrix adapted to the bit-level representation.
336+
"""
337+
beta = len(w)
338+
if beta%2 == 0:
339+
m, n = H.shape
340+
In = eye(n,n)
341+
kr = kron(In,w)
342+
return dot(H,kr)
343+
else:
344+
raise ValueError('Beta must be even.')

0 commit comments

Comments
 (0)