Skip to content

Commit c21e8c9

Browse files
committed
Create a new object link_model !
1 parent 3e8dc2f commit c21e8c9

File tree

6 files changed

+159
-90
lines changed

6 files changed

+159
-90
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ Utilities
6666
- Hamming distance, Euclidean distance.
6767
- Upsample
6868
- Power of a discrete-time signal
69+
70+
Links
71+
-----
6972
- Estimate the BER performance of a link model with Monte Carlo simulation.
73+
- Link model object.
7074

7175
FAQs
7276
----

commpy/links.py

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Authors: Youness Akourim <akourim97@gmail.com> & Bastien Trotobas <bastien.trotobas@gmail.com>
2+
# License: BSD 3-Clause
3+
4+
"""
5+
============================================
6+
Links (:mod:`commpy.links`)
7+
============================================
8+
9+
.. autosummary::
10+
:toctree: generated/
11+
12+
link_performance -- Estimate the BER performance of a link model with Monte Carlo simulation.
13+
linkModel -- Link model object.
14+
"""
15+
from __future__ import division # Python 2 compatibility
16+
17+
import numpy as np
18+
from commpy.channels import MIMOFlatChannel
19+
20+
__all__ = ['link_performance', 'linkModel']
21+
22+
23+
def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_rate=1):
24+
"""
25+
Estimate the BER performance of a link model with Monte Carlo simulation.
26+
27+
Parameters
28+
----------
29+
link_model : linkModel object.
30+
31+
SNRs : 1D arraylike
32+
Signal to Noise ratio in dB defined as :math:`SNR_{dB} = (E_b/N_0)_{dB} + 10 \log_{10}(R_cM_c)`
33+
where :math:`Rc` is the code rate and :math:`Mc` the modulation rate.
34+
35+
send_max : int
36+
Maximum number of bits send for each SNR.
37+
38+
err_min : int
39+
link_performance send bits until it reach err_min errors (see also send_max).
40+
41+
send_chunk : int
42+
Number of bits to be send at each iteration.
43+
*Default*: send_chunck = err_min
44+
45+
code_rate : float in (0,1]
46+
Rate of the used code.
47+
*Default*: 1 i.e. no code.
48+
49+
Returns
50+
-------
51+
BERs : 1d ndarray
52+
Estimated Bit Error Ratio corresponding to each SNRs
53+
"""
54+
55+
# Initialization
56+
BERs = np.empty_like(SNRs, dtype=float)
57+
# Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
58+
if send_chunk is None:
59+
send_chunk = err_min
60+
divider = link_model.num_bits_symbol * link_model.channel.nb_tx
61+
send_chunk = max(divider, send_chunk // divider * divider)
62+
63+
# Computations
64+
for id_SNR in range(len(SNRs)):
65+
link_model.channel.set_SNR_dB(SNRs[id_SNR], code_rate, link_model.Es)
66+
bit_send = 0
67+
bit_err = 0
68+
while bit_send < send_max and bit_err < err_min:
69+
# Propagate some bits
70+
msg = np.random.choice((0, 1), send_chunk)
71+
symbs = link_model.modulate(msg)
72+
channel_output = link_model.channel.propagate(symbs)
73+
74+
# Deals with MIMO channel
75+
if isinstance(link_model.channel, MIMOFlatChannel):
76+
nb_symb_vector = len(channel_output)
77+
received_msg = np.empty(nb_symb_vector * link_model.channel.nb_tx, dtype=channel_output.dtype)
78+
for i in range(nb_symb_vector):
79+
received_msg[link_model.channel.nb_tx * i:link_model.channel.nb_tx * (i+1)] = \
80+
link_model.receive(channel_output[i], link_model.channel.channel_gains[i], link_model.constellation)
81+
else:
82+
received_msg = channel_output
83+
# Count errors
84+
bit_err += (msg != received_msg[:len(msg)]).sum() # Remove MIMO padding
85+
bit_send += send_chunk
86+
BERs[id_SNR] = bit_err / bit_send
87+
return BERs
88+
89+
90+
class linkModel:
91+
"""
92+
Construct a link model.
93+
94+
Parameters
95+
----------
96+
modulate : function with same prototype as Modem.modulate
97+
98+
channel : _FlatChannel object
99+
100+
receive : function with prototype receive(y, H, constellation) that return a binary array.
101+
y : 1D ndarray of floats
102+
Received complex symbols (shape: num_receive_antennas x 1)
103+
104+
h : 2D ndarray of floats
105+
Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
106+
107+
constellation : 1D ndarray of floats
108+
109+
num_bits_symbols : int
110+
111+
constellation : array of float or complex
112+
113+
Es : float
114+
Average energy per symbols.
115+
*Default* Es=1.
116+
117+
Attributes
118+
----------
119+
modulate : function with same prototype as Modem.modulate
120+
121+
channel : _FlatChannel object
122+
123+
receive : function with prototype receive(y, H, constellation) that return a binary array.
124+
y : 1D ndarray of floats
125+
Received complex symbols (shape: num_receive_antennas x 1)
126+
127+
h : 2D ndarray of floats
128+
Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
129+
130+
constellation : 1D ndarray of floats
131+
132+
num_bits_symbols : int
133+
134+
constellation : array of float or complex
135+
136+
Es : float
137+
Average energy per symbols.
138+
*Default* Es=1.
139+
"""
140+
def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, Es=1):
141+
self.modulate = modulate
142+
self.channel = channel
143+
self.receive = receive
144+
self.num_bits_symbol = num_bits_symbol
145+
self.constellation = constellation
146+
self.Es = Es

commpy/modulation.py

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232

3333
class Modem:
34-
3534
def modulate(self, input_bits):
3635
""" Modulate (map) an array of bits to constellation symbols.
3736

commpy/utilities.py

+1-88
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,13 @@
1515
euclid_dist -- Squared Euclidean distance.
1616
upsample -- Upsample by an integral factor (zero insertion).
1717
signal_power -- Compute the power of a discrete time signal.
18-
link_performance -- Estimate the BER performance of a link model with Monte Carlo simulation.
19-
2018
"""
2119
from __future__ import division # Python 2 compatibility
2220

2321
import numpy as np
2422

25-
from commpy.channels import MIMOFlatChannel
26-
2723
__all__ = ['dec2bitarray', 'bitarray2dec', 'hamming_dist', 'euclid_dist', 'upsample',
28-
'signal_power', 'link_performance']
29-
24+
'signal_power']
3025

3126
def dec2bitarray(in_number, bit_width):
3227
"""
@@ -174,85 +169,3 @@ def square_abs(s):
174169

175170
P = np.mean(square_abs(signal))
176171
return P
177-
178-
179-
def link_performance(modem, channel, detector, SNRs, send_max, err_min, send_chunk=None, code_rate=1):
180-
"""
181-
Estimate the BER performance of a link model with Monte Carlo simulation.
182-
183-
Parameters
184-
----------
185-
modem : modem object
186-
Modem used to modulate and demodulate.
187-
188-
channel : channel object
189-
Channel through which the message is propagated.
190-
191-
detector : function with prototype detector(y, h, constellation) or None
192-
Detector to decode channel output. See detectors in commpy.modulation for details on the prototype.
193-
194-
SNRs : 1D arraylike
195-
Signal to Noise ratio in dB defined as :math:`SNR_{dB} = (E_b/N_0)_{dB} + 10 \log_{10}(R_cM_c)`
196-
where :math:`Rc` is the code rate and :math:`Mc` the modulation rate.
197-
198-
send_max : int
199-
Maximum number of bits send for each SNR.
200-
201-
err_min : int
202-
link_performance send bits until it reach err_min errors (see also send_max).
203-
204-
send_chunk : int
205-
Number of bits to be send at each iteration.
206-
*Default*: send_chunck = err_min
207-
208-
code_rate : float in (0,1]
209-
Rate of the used code.
210-
*Default*: 1 i.e. no code.
211-
212-
Returns
213-
-------
214-
BERs : 1d ndarray
215-
Estimated Bit Error Ratio corresponding to each SNRs
216-
"""
217-
218-
# Initialization
219-
BERs = np.empty_like(SNRs, dtype=float)
220-
221-
# Handles the case detector is None
222-
if detector is None:
223-
def detector(y, H, constellation):
224-
return y
225-
226-
# Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
227-
if send_chunk is None:
228-
send_chunk = err_min
229-
divider = modem.num_bits_symbol * channel.nb_tx
230-
send_chunk = max(divider, send_chunk // divider * divider)
231-
232-
# Computations
233-
for id_SNR in range(len(SNRs)):
234-
channel.set_SNR_dB(SNRs[id_SNR], code_rate, modem.Es)
235-
bit_send = 0
236-
bit_err = 0
237-
while bit_send < send_max and bit_err < err_min:
238-
# Propagate some bits
239-
msg = np.random.choice((0, 1), send_chunk)
240-
symbs = modem.modulate(msg)
241-
channel_output = channel.propagate(symbs)
242-
243-
# Deals with MIMO channel
244-
if isinstance(channel, MIMOFlatChannel):
245-
nb_symb_vector = len(channel_output)
246-
detected_msg = np.empty(nb_symb_vector * channel.nb_tx, dtype=channel_output.dtype)
247-
for i in range(nb_symb_vector):
248-
detected_msg[channel.nb_tx * i:channel.nb_tx * (i+1)] = \
249-
detector(channel_output[i], channel.channel_gains[i], modem.constellation)
250-
else:
251-
detected_msg = channel_output
252-
253-
# Count errors
254-
received_msg = modem.demodulate(detected_msg, 'hard')
255-
bit_err += (msg != received_msg[:len(msg)]).sum() # Remove MIMO padding
256-
bit_send += send_chunk
257-
BERs[id_SNR] = bit_err / bit_send
258-
return BERs

doc/index.rst

+6-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Modulation/Demodulation
4545
- Phase Shift Keying (PSK)
4646
- Quadrature Amplitude Modulation (QAM)
4747
- OFDM Tx/Rx signal processing
48+
- MIMO Maximum Likelihood (ML) Detection.
49+
- MIMO K-best Schnorr-Euchner Detection.
4850

4951
Sequences
5052
~~~~~~~~~
@@ -58,7 +60,10 @@ Utilities
5860
- Upsample
5961
- Power of a discrete-time signal
6062

61-
63+
Links
64+
~~~~~
65+
- Estimate the BER performance of a link model with Monte Carlo simulation.
66+
- Link model object.
6267

6368
Reference
6469
---------

doc/links.rst

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.. automodule:: commpy.links
2+
:members:

0 commit comments

Comments
 (0)