@@ -58,7 +58,8 @@ def link_performance(link_model, SNRs, send_max, err_min, send_chunk=None, code_
5858 BERs : 1d ndarray
5959 Estimated Bit Error Ratio corresponding to each SNRs
6060 """
61-
61+ if not send_chunk :
62+ send_chunk = err_min
6263 return link_model .link_performance (SNRs , send_max , err_min , send_chunk , code_rate )
6364
6465
@@ -133,7 +134,7 @@ class LinkModel:
133134 *Default* is 1.
134135 """
135136
136- def __init__ (self , modulate , channel , receive , num_bits_symbol , constellation , Es = 1 , decoder = None , rate = 1 ):
137+ def __init__ (self , modulate , channel , receive , num_bits_symbol , constellation , Es = 1 , decoder = None , rate = 1. ):
137138 self .modulate = modulate
138139 self .channel = channel
139140 self .receive = receive
@@ -146,8 +147,10 @@ def __init__(self, modulate, channel, receive, num_bits_symbol, constellation, E
146147 self .decoder = lambda msg : msg
147148 else :
148149 self .decoder = decoder
150+ self .full_simulation_results = None
149151
150- def link_performance (self , SNRs , send_max , err_min , send_chunk = None , code_rate = 1 ):
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 ):
151154 """
152155 Estimate the BER performance of a link model with Monte Carlo simulation.
153156
@@ -157,8 +160,8 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
157160 Signal to Noise ratio in dB defined as :math:`SNR_{dB} = (E_b/N_0)_{dB} + 10 \log_{10}(R_cM_c)`
158161 where :math:`Rc` is the code rate and :math:`Mc` the modulation rate.
159162
160- send_max : int
161- Maximum number of bits send for each SNR.
163+ tx_max : int
164+ Maximum number of transmissions for each SNR.
162165
163166 err_min : int
164167 link_performance send bits until it reach err_min errors (see also send_max).
@@ -172,6 +175,110 @@ def link_performance(self, SNRs, send_max, err_min, send_chunk=None, code_rate=1
172175 Rate of the used code.
173176 *Default*: 1 i.e. no code.
174177
178+ number_chunks_per_send : int
179+ Number of chunks per transmission
180+
181+ stop_on_surpass_error : bool
182+ Controls if during simulation of a SNR it should break and move to the next SNR when
183+ the bit error is above the err_min parameter
184+
185+ Returns
186+ -------
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
196+ """
197+
198+ # Initialization
199+ BERs = np .zeros_like (SNRs , dtype = float )
200+ BEs = np .zeros ((len (SNRs ), tx_max ), dtype = int ) # Bit errors per tx
201+ CEs = np .zeros ((len (SNRs ), tx_max ), dtype = int ) # Chunk Errors per tx
202+ NCs = np .zeros ((len (SNRs ), tx_max ), dtype = int ) # Number of Chunks per tx
203+ # Set chunk size and round it to be a multiple of num_bits_symbol*nb_tx to avoid padding
204+ if send_chunk is None :
205+ send_chunk = err_min
206+ divider = self .num_bits_symbol * self .channel .nb_tx
207+ send_chunk = max (divider , send_chunk // divider * divider )
208+
209+ receive_size = self .channel .nb_tx * self .num_bits_symbol
210+ full_args_decoder = len (getfullargspec (self .decoder ).args ) > 1
211+
212+ # Computations
213+ for id_SNR in range (len (SNRs )):
214+ self .channel .set_SNR_dB (SNRs [id_SNR ], code_rate , self .Es )
215+ total_tx_send = 0
216+ bit_err = np .zeros (tx_max , dtype = int )
217+ chunk_loss = np .zeros (tx_max , dtype = int )
218+ chunk_count = np .zeros (tx_max , dtype = int )
219+ for id_tx in range (tx_max ):
220+ if stop_on_surpass_error and bit_err .sum () > err_min :
221+ break
222+ # Propagate some bits
223+ msg = np .random .choice ((0 , 1 ), send_chunk * number_chunks_per_send )
224+ symbs = self .modulate (msg )
225+ channel_output = self .channel .propagate (symbs )
226+
227+ # Deals with MIMO channel
228+ if isinstance (self .channel , MIMOFlatChannel ):
229+ nb_symb_vector = len (channel_output )
230+ received_msg = np .empty (int (math .ceil (len (msg ) / self .rate )), dtype = np .int8 )
231+ for i in range (nb_symb_vector ):
232+ received_msg [receive_size * i :receive_size * (i + 1 )] = \
233+ self .receive (channel_output [i ], self .channel .channel_gains [i ],
234+ self .constellation , self .channel .noise_std ** 2 )
235+ else :
236+ received_msg = self .receive (channel_output , self .channel .channel_gains ,
237+ self .constellation , self .channel .noise_std ** 2 )
238+ # Count errors
239+ if full_args_decoder :
240+ decoded_bits = self .decoder (channel_output , self .channel .channel_gains ,
241+ self .constellation , self .channel .noise_std ** 2 ,
242+ received_msg , self .channel .nb_tx * self .num_bits_symbol )
243+ else :
244+ decoded_bits = self .decoder (received_msg )
245+ # calculate number of error frames
246+ for i in range (number_chunks_per_send ):
247+ errors = np .bitwise_xor (msg [send_chunk * i :send_chunk * (i + 1 )],
248+ decoded_bits [send_chunk * i :send_chunk * (i + 1 )]).sum ()
249+ bit_err [id_tx ] += errors
250+ chunk_loss [id_tx ] += 1 if errors > 0 else 0
251+
252+ chunk_count [id_tx ] += number_chunks_per_send
253+ total_tx_send += 1
254+ BERs [id_SNR ] = bit_err .sum () / (total_tx_send * send_chunk )
255+ BEs [id_SNR ] = bit_err
256+ CEs [id_SNR ] = np .where (bit_err > 0 , 1 , 0 )
257+ NCs [id_SNR ] = chunk_count
258+ if BEs [id_SNR ].sum () < err_min :
259+ break
260+ 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.
175282 Returns
176283 -------
177284 BERs : 1d ndarray
0 commit comments