1111
1212 link_performance -- Estimate the BER performance of a link model with Monte Carlo simulation.
1313 LinkModel -- Link model object.
14+ idd_decoder -- Produce the decoder function to model a MIMO IDD decoder.
1415"""
1516from __future__ import division # Python 2 compatibility
1617
1718import math
19+ from inspect import getfullargspec
1820
1921import numpy as np
2022
2123from commpy .channels import MIMOFlatChannel
2224
23- __all__ = ['link_performance' , 'LinkModel' ]
25+ __all__ = ['link_performance' , 'LinkModel' , 'idd_decoder' ]
2426
2527
2628def 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_
6567 send_chunk = max (divider , send_chunk // divider * divider )
6668
6769 receive_size = link_model .channel .nb_tx * link_model .num_bits_symbol
70+ full_args_decoder = len (getfullargspec (link_model .decoder ).args ) > 1
6871
6972 # Computations
7073 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_
8992 received_msg = link_model .receive (channel_output , link_model .channel .channel_gains ,
9093 link_model .constellation , link_model .channel .noise_std ** 2 )
9194 # 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 ()
93102 bit_send += send_chunk
94103 BERs [id_SNR ] = bit_err / bit_send
95104 return BERs
96105
97106
98107class LinkModel :
99108 """
100- Construct a link model.
109+ Construct a link model.
110+
111+ Parameters
112+ ----------
113+ modulate : function with same prototype as Modem.modulate
101114
102- Parameters
103- ----------
104- modulate : function with same prototype as Modem.modulate
115+ channel : FlatChannel object
105116
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)
107120
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)
111123
112- h : 2D ndarray
113- Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
124+ constellation : 1D ndarray
114125
115- constellation : 1D ndarray
126+ noise_var : positive float
127+ Noise variance
116128
117- noise_var : positive float
118- Noise variance
129+ num_bits_symbols : int
119130
120- num_bits_symbols : int
131+ constellation : array of float or complex
121132
122- constellation : array of float or complex
133+ Es : float
134+ Average energy per symbols.
135+ *Default* Es=1.
123136
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 .
127140
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.
130144
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
134150
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)
136154
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)
140157
141- h : 2D ndarray of floats
142- Channel Matrix (shape: num_receive_antennas x num_transmit_antennas)
158+ constellation : 1D ndarray
143159
144- constellation : 1D ndarray of floats
160+ noise_var : positive float
161+ Noise variance
145162
146- num_bits_symbols : int
163+ num_bits_symbols : int
147164
148- constellation : array of float or complex
165+ constellation : array of float or complex
149166
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+ """
154177
155178 def __init__ (self , modulate , channel , receive , num_bits_symbol , constellation , Es = 1 , decoder = None , rate = 1 ):
156179 self .modulate = modulate
@@ -165,3 +188,65 @@ def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, E
165188 self .decoder = lambda msg : msg
166189 else :
167190 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