@@ -60,7 +60,7 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
6060 """
6161 if not send_chunk :
6262 send_chunk = err_min
63- return link_model .link_performance (SNRs , math . ceil ( send_max / send_chunk ) , err_min , send_chunk , code_rate )
63+ return link_model .link_performance (SNRs , send_max , err_min , send_chunk , code_rate )
6464
6565
6666class LinkModel :
@@ -149,8 +149,8 @@ def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, E
149149 self .decoder = decoder
150150 self .full_simulation_results = None
151151
152- def link_performance (self , SNRs , tx_max , err_min , send_chunk = None , code_rate : float = 1. ,
153- number_chunks_per_send = 1 , stop_on_surpass_error = True ):
152+ def link_performance_full_metrics (self , SNRs , tx_max , err_min , send_chunk = None , code_rate : float = 1. ,
153+ number_chunks_per_send = 1 , stop_on_surpass_error = True ):
154154 """
155155 Estimate the BER performance of a link model with Monte Carlo simulation.
156156
@@ -184,8 +184,15 @@ def link_performance(self, SNRs, tx_max, err_min, send_chunk=None, code_rate: fl
184184
185185 Returns
186186 -------
187- BERs : 1d ndarray
188- Estimated Bit Error Ratio corresponding to each SNRs
187+ List[BERs, BEs, CEs, NCs]
188+ BERs : 1d ndarray
189+ Estimated Bit Error Ratio corresponding to each SNRs
190+ BEs : 2d ndarray
191+ Number of Estimated Bits with Error per transmission corresponding to each SNRs
192+ CEs : 2d ndarray
193+ Number of Estimated Chunks with Errors per transmission corresponding to each SNRs
194+ NCs : 2d ndarray
195+ Number of Chunks transmitted per transmission corresponding to each SNRs
189196 """
190197
191198 # Initialization
@@ -251,6 +258,78 @@ def link_performance(self, SNRs, tx_max, err_min, send_chunk=None, code_rate: fl
251258 if BEs [id_SNR ].sum () < err_min :
252259 break
253260 self .full_simulation_results = BERs , BEs , CEs , NCs
261+ return BERs , BEs , CEs , NCs
262+
263+ def link_performance (self , SNRs , send_max , err_min , send_chunk = None , code_rate = 1 ):
264+ """
265+ Estimate the BER performance of a link model with Monte Carlo simulation.
266+ Parameters
267+ ----------
268+ SNRs : 1D arraylike
269+ Signal to Noise ratio in dB defined as :math:`SNR_{dB} = (E_b/N_0)_{dB} + 10 \log_{10}(R_cM_c)`
270+ where :math:`Rc` is the code rate and :math:`Mc` the modulation rate.
271+ send_max : int
272+ Maximum number of bits send for each SNR.
273+ err_min : int
274+ link_performance send bits until it reach err_min errors (see also send_max).
275+ send_chunk : int
276+ Number of bits to be send at each iteration. This is also the frame length of the decoder if available
277+ so it should be large enough regarding the code type.
278+ *Default*: send_chunck = err_min
279+ code_rate : float in (0,1]
280+ Rate of the used code.
281+ *Default*: 1 i.e. no code.
282+ Returns
283+ -------
284+ BERs : 1d ndarray
285+ Estimated Bit Error Ratio corresponding to each SNRs
286+ """
287+
288+ # Initialization
289+ BERs = np .zeros_like (SNRs , dtype = float )
290+ # Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
291+ if send_chunk is None :
292+ send_chunk = err_min
293+ divider = self .num_bits_symbol * self .channel .nb_tx
294+ send_chunk = max (divider , send_chunk // divider * divider )
295+
296+ receive_size = self .channel .nb_tx * self .num_bits_symbol
297+ full_args_decoder = len (getfullargspec (self .decoder ).args ) > 1
298+
299+ # Computations
300+ for id_SNR in range (len (SNRs )):
301+ self .channel .set_SNR_dB (SNRs [id_SNR ], code_rate , self .Es )
302+ bit_send = 0
303+ bit_err = 0
304+ while bit_send < send_max and bit_err < err_min :
305+ # Propagate some bits
306+ msg = np .random .choice ((0 , 1 ), send_chunk )
307+ symbs = self .modulate (msg )
308+ channel_output = self .channel .propagate (symbs )
309+
310+ # Deals with MIMO channel
311+ if isinstance (self .channel , MIMOFlatChannel ):
312+ nb_symb_vector = len (channel_output )
313+ received_msg = np .empty (int (math .ceil (len (msg ) / self .rate )), dtype = np .int8 )
314+ for i in range (nb_symb_vector ):
315+ received_msg [receive_size * i :receive_size * (i + 1 )] = \
316+ self .receive (channel_output [i ], self .channel .channel_gains [i ],
317+ self .constellation , self .channel .noise_std ** 2 )
318+ else :
319+ received_msg = self .receive (channel_output , self .channel .channel_gains ,
320+ self .constellation , self .channel .noise_std ** 2 )
321+ # Count errors
322+ if full_args_decoder :
323+ decoded_bits = self .decoder (channel_output , self .channel .channel_gains ,
324+ self .constellation , self .channel .noise_std ** 2 ,
325+ received_msg , self .channel .nb_tx * self .num_bits_symbol )
326+ bit_err += np .bitwise_xor (msg , decoded_bits [:len (msg )]).sum ()
327+ else :
328+ bit_err += np .bitwise_xor (msg , self .decoder (received_msg )[:len (msg )]).sum ()
329+ bit_send += send_chunk
330+ BERs [id_SNR ] = bit_err / bit_send
331+ if bit_err < err_min :
332+ break
254333 return BERs
255334
256335
0 commit comments