11
11
12
12
link_performance -- Estimate the BER performance of a link model with Monte Carlo simulation.
13
13
LinkModel -- Link model object.
14
+ idd_decoder -- Produce the decoder function to model a MIMO IDD decoder.
14
15
"""
15
16
from __future__ import division # Python 2 compatibility
16
17
17
18
import math
19
+ from inspect import getfullargspec
18
20
19
21
import numpy as np
20
22
21
23
from commpy .channels import MIMOFlatChannel
22
24
23
- __all__ = ['link_performance' , 'LinkModel' ]
25
+ __all__ = ['link_performance' , 'LinkModel' , 'idd_decoder' ]
24
26
25
27
26
28
def link_performance (link_model , SNRs , send_max , err_min , send_chunk = None , code_rate = 1 ):
@@ -65,6 +67,7 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
65
67
send_chunk = max (divider , send_chunk // divider * divider )
66
68
67
69
receive_size = link_model .channel .nb_tx * link_model .num_bits_symbol
70
+ full_args_decoder = len (getfullargspec (link_model .decoder ).args ) > 1
68
71
69
72
# Computations
70
73
for id_SNR in range (len (SNRs )):
@@ -89,68 +92,88 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
89
92
received_msg = link_model .receive (channel_output , link_model .channel .channel_gains ,
90
93
link_model .constellation , link_model .channel .noise_std ** 2 )
91
94
# Count errors
92
- bit_err += (msg != link_model .decoder (received_msg )).sum ()
95
+ if full_args_decoder :
96
+ decoded_bits = link_model .decoder (channel_output , link_model .channel .channel_gains ,
97
+ link_model .constellation , link_model .channel .noise_std ** 2 ,
98
+ received_msg , link_model .channel .nb_tx * link_model .num_bits_symbol )
99
+ bit_err += (msg != decoded_bits [:len (msg )]).sum ()
100
+ else :
101
+ bit_err += (msg != link_model .decoder (received_msg )[:len (msg )]).sum ()
93
102
bit_send += send_chunk
94
103
BERs [id_SNR ] = bit_err / bit_send
95
104
return BERs
96
105
97
106
98
107
class LinkModel :
99
108
"""
100
- Construct a link model.
109
+ Construct a link model.
110
+
111
+ Parameters
112
+ ----------
113
+ modulate : function with same prototype as Modem.modulate
101
114
102
- Parameters
103
- ----------
104
- modulate : function with same prototype as Modem.modulate
115
+ channel : FlatChannel object
105
116
106
- channel : _FlatChannel object
117
+ receive : function with prototype receive(y, H, constellation, noise_var) that return a binary array.
118
+ y : 1D ndarray
119
+ Received complex symbols (shape: num_receive_antennas x 1)
107
120
108
- receive : function with prototype receive(y, H, constellation, noise_var) that return a binary array.
109
- y : 1D ndarray
110
- Received complex symbols (shape: num_receive_antennas x 1)
121
+ h : 2D ndarray
122
+ Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
111
123
112
- h : 2D ndarray
113
- Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
124
+ constellation : 1D ndarray
114
125
115
- constellation : 1D ndarray
126
+ noise_var : positive float
127
+ Noise variance
116
128
117
- noise_var : positive float
118
- Noise variance
129
+ num_bits_symbols : int
119
130
120
- num_bits_symbols : int
131
+ constellation : array of float or complex
121
132
122
- constellation : array of float or complex
133
+ Es : float
134
+ Average energy per symbols.
135
+ *Default* Es=1.
123
136
124
- Es : float
125
- Average energy per symbols .
126
- *Default* Es=1 .
137
+ decoder : function with prototype decoder(array) or decoder(y, H, constellation, noise_var, array) that return a
138
+ binary array .
139
+ *Default* is no process .
127
140
128
- decoder : function with prototype decoder(binary array) that return a binary array.
129
- *Default* is no process.
141
+ rate : float
142
+ Code rate.
143
+ *Default* is 1.
130
144
131
- Attributes
132
- ----------
133
- modulate : function with same prototype as Modem.modulate
145
+ Attributes
146
+ ----------
147
+ modulate : function with same prototype as Modem.modulate
148
+
149
+ channel : _FlatChannel object
134
150
135
- channel : _FlatChannel object
151
+ receive : function with prototype receive(y, H, constellation, noise_var) that return a binary array.
152
+ y : 1D ndarray
153
+ Received complex symbols (shape: num_receive_antennas x 1)
136
154
137
- receive : function with prototype receive(y, H, constellation) that return a binary array.
138
- y : 1D ndarray of floats
139
- Received complex symbols (shape: num_receive_antennas x 1)
155
+ h : 2D ndarray
156
+ Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
140
157
141
- h : 2D ndarray of floats
142
- Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
158
+ constellation : 1D ndarray
143
159
144
- constellation : 1D ndarray of floats
160
+ noise_var : positive float
161
+ Noise variance
145
162
146
- num_bits_symbols : int
163
+ num_bits_symbols : int
147
164
148
- constellation : array of float or complex
165
+ constellation : array of float or complex
149
166
150
- Es : float
151
- Average energy per symbols.
152
- *Default* Es=1.
153
- """
167
+ Es : float
168
+ Average energy per symbols.
169
+
170
+ decoder : function with prototype decoder(binary array) that return a binary array.
171
+ *Default* is no process.
172
+
173
+ rate : float
174
+ Code rate.
175
+ *Default* is 1.
176
+ """
154
177
155
178
def __init__ (self , modulate , channel , receive , num_bits_symbol , constellation , Es = 1 , decoder = None , rate = 1 ):
156
179
self .modulate = modulate
@@ -165,3 +188,65 @@ def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, E
165
188
self .decoder = lambda msg : msg
166
189
else :
167
190
self .decoder = decoder
191
+
192
+
193
+ def idd_decoder (word_size , detector , decoder , n_it ):
194
+ """
195
+ Produce a decoder function that model the specified MIMO iterative detection and decoding (IDD) process.
196
+ The returned function can be used as is to build a working LinkModel object.
197
+
198
+ Parameters
199
+ ----------
200
+ word_size : positive integer
201
+ Size of the words exchanged between the detector and the decoder.
202
+
203
+ detector : function with prototype detector(y, H, constellation, noise_var, a_priori) that return a LLRs array.
204
+ y : 1D ndarray
205
+ Received complex symbols (shape: num_receive_antennas x 1).
206
+
207
+ h : 2D ndarray
208
+ Channel Matrix (shape: num_receive_antennas x num_transmit_antennas).
209
+
210
+ constellation : 1D ndarray.
211
+
212
+ noise_var : positive float
213
+ Noise variance.
214
+
215
+ a_priori : 1D ndarray of floats
216
+ A priori as Log-Likelihood Ratios.
217
+
218
+ decoder : function with the same signature as detector.
219
+
220
+ n_it : positive integer
221
+ Number or iteration during the IDD process.
222
+
223
+ Returns
224
+ -------
225
+ decode : function useable as it is to build a LinkModel object that produce a bit array from the parameters
226
+ y : 1D ndarray
227
+ Received complex symbols (shape: num_receive_antennas x 1).
228
+
229
+ h : 2D ndarray
230
+ Channel Matrix (shape: num_receive_antennas x num_transmit_antennas).
231
+
232
+ constellation : 1D ndarray
233
+
234
+ noise_var : positive float
235
+ Noise variance.
236
+
237
+ bits_per_send : positive integer
238
+ Number or bit send at each symbol vector.
239
+ """
240
+ def decode (y , h , constellation , noise_var , a_priori , bits_per_send ):
241
+ a_priori_decoder = a_priori
242
+ nb_vect , nb_rx , nb_tx = h .shape
243
+ for iteration in range (n_it ):
244
+ a_priori_detector = (decoder (a_priori_decoder ) - a_priori_decoder )
245
+ for i in range (nb_vect ):
246
+ a_priori_decoder [i * bits_per_send :(i + 1 ) * bits_per_send ] = \
247
+ detector (y [i ], h [i ], constellation , noise_var ,
248
+ a_priori_detector [i * bits_per_send :(i + 1 ) * bits_per_send ])
249
+ a_priori_decoder -= a_priori_detector
250
+ return np .signbit (a_priori_decoder + a_priori_detector )
251
+
252
+ return decode
0 commit comments