1-
21# Authors: Veeresh Taranalli <veeresht@gmail.com> & Bastien Trotobas <bastien.trotobas@gmail.com>
32# License: BSD 3-Clause
43
2019
2120from __future__ import division , print_function # Python 2 compatibility
2221
23- from numpy import complex , abs , sqrt , sum , zeros , identity , hstack , einsum , trace , kron , absolute
22+ from numpy import complex , abs , sqrt , sum , zeros , identity , hstack , einsum , trace , kron , absolute , fromiter
2423from numpy .random import randn , random , standard_normal
2524from scipy .linalg import sqrtm
2625
@@ -71,7 +70,7 @@ def set_SNR_dB(self, SNR_dB, code_rate=1, Es=1):
7170 Average symbol energy
7271 """
7372
74- self .noise_std = sqrt ((self .isComplex + 1 ) * self .nb_tx * Es / (code_rate * 10 ** (SNR_dB / 10 )))
73+ self .noise_std = sqrt ((self .isComplex + 1 ) * self .nb_tx * Es / (code_rate * 10 ** (SNR_dB / 10 )))
7574
7675 def set_SNR_lin (self , SNR_lin , code_rate = 1 , Es = 1 ):
7776
@@ -99,7 +98,6 @@ def isComplex(self):
9998
10099
101100class SISOFlatChannel (_FlatChannel ):
102-
103101 """
104102 Constructs a SISO channel with a flat fading.
105103 The channel coefficient are normalized i.e. the mean magnitude is 1.
@@ -108,10 +106,11 @@ class SISOFlatChannel(_FlatChannel):
108106 ----------
109107 noise_std : float, optional
110108 Noise standard deviation.
111- Default value is None and then the value must set later.
109+ * Default* value is None and then the value must set later.
112110
113111 fading_param : tuple of 2 floats, optional
114- Parameters of the fading (see attribute for details). Default value is (1,0) i.e. no fading.
112+ Parameters of the fading (see attribute for details).
113+ *Default* value is (1,0) i.e. no fading.
115114
116115 Attributes
117116 ----------
@@ -240,7 +239,6 @@ def k_factor(self):
240239
241240
242241class MIMOFlatChannel (_FlatChannel ):
243-
244242 """
245243 Constructs a MIMO channel with a flat fading based on the Kronecker model.
246244 The channel coefficient are normalized i.e. the mean magnitude is 1.
@@ -255,15 +253,15 @@ class MIMOFlatChannel(_FlatChannel):
255253
256254 noise_std : float, optional
257255 Noise standard deviation.
258- Default value is None and then the value must set later.
256+ * Default* value is None and then the value must set later.
259257
260258 fading_param : tuple of 3 floats, optional
261259 Parameters of the fading. The complete tuple must be set each time.
262- Default value is (zeros((nb_rx, nb_tx)), identity(nb_tx), identity(nb_rx)) i.e. Rayleigh fading.
260+ * Default* value is (zeros((nb_rx, nb_tx)), identity(nb_tx), identity(nb_rx)) i.e. Rayleigh fading.
263261
264262 Attributes
265263 ----------
266- fading_param : tuple of 2 floats
264+ fading_param : tuple of 3 2D ndarray
267265 Parameters of the fading.
268266 Raise ValueError when sets with value that would lead to a non-normalized channel.
269267
@@ -275,9 +273,7 @@ class MIMOFlatChannel(_FlatChannel):
275273
276274 Classical fadings:
277275
278- * (zeros((nb_rx, nb_tx)), identity(nb_tx), identity(nb_rx)): Rayleigh fading.
279-
280- * Others: rician fading.
276+ * (zeros((nb_rx, nb_tx)), identity(nb_tx), identity(nb_rx)): Uncorrelated Rayleigh fading.
281277
282278 noise_std : float
283279 Noise standard deviation. None is the value has not been set yet.
@@ -407,6 +403,119 @@ def k_factor(self):
407403 LOS_gain = einsum ('ij,ij->' , absolute (self .fading_param [0 ]), absolute (self .fading_param [0 ]))
408404 return LOS_gain / NLOS_gain
409405
406+ def uncorr_rayleigh_fading (self , dtype ):
407+ """ Set the fading parameters to an uncorrelated Rayleigh channel.
408+
409+ Parameters
410+ ----------
411+ dtype : dtype
412+ Type of the channel
413+ """
414+ self .fading_param = zeros ((self .nb_rx , self .nb_tx ), dtype ), identity (self .nb_tx ), identity (self .nb_rx )
415+
416+ def expo_corr_rayleigh_fading (self , t , r ):
417+ """ Set the fading parameters to a complex correlated Rayleigh channel following the exponential model.
418+
419+ See: S. L. Loyka, "Channel capacity if MIMO architecture using the exponential correlation matrix ", IEEE
420+ Commun. Lett., vol.5, n. 9, p. 369-371, sept. 2001.
421+
422+ Parameters
423+ ----------
424+ t : complex with abs(t) = 1
425+ Correlation coefficient for the transceiver.
426+
427+ r : complex with abs(r) = 1
428+ Correlation coefficient for the receiver.
429+
430+ Raises
431+ ------
432+ ValueError
433+ If abs(t) != 1 or abs(r) != 1
434+ """
435+ # Check inputs
436+ if abs (t ) - 1 > 1e-4 :
437+ raise ValueError ('abs(t) must be one.' )
438+ if abs (r ) - 1 > 1e-4 :
439+ raise ValueError ('abs(r) must be one.' )
440+
441+ # Construct the exponent matrix
442+ expo_tx = fromiter ((j - i for i in range (self .nb_tx ) for j in range (self .nb_tx )), int , self .nb_tx ** 2 )
443+ expo_rx = fromiter ((j - i for i in range (self .nb_rx ) for j in range (self .nb_rx )), int , self .nb_rx ** 2 )
444+
445+ # Reshape
446+ expo_tx = expo_tx .reshape (self .nb_tx , self .nb_tx )
447+ expo_rx = expo_rx .reshape (self .nb_rx , self .nb_rx )
448+
449+ # Set fading
450+ self .fading_param = zeros ((self .nb_rx , self .nb_tx ), complex ), t ** expo_tx , r ** expo_rx
451+
452+ def uncorr_rician_fading (self , mean , k_factor ):
453+ """ Set the fading parameters to an uncorrelated rician channel.
454+
455+ mean will be scaled to fit the required k-factor.
456+
457+ Parameters
458+ ----------
459+ mean : ndarray (shape: nb_rx x nb_tx)
460+ Mean of the channel gain.
461+
462+ k_factor : positive float
463+ Requested k-factor (the power ratio between LOS and NLOS).
464+ """
465+ nb_antennas = mean .size
466+ NLOS_gain = nb_antennas / (k_factor + 1 )
467+ mean = mean * sqrt (k_factor * NLOS_gain / einsum ('ij,ij->' , absolute (mean ), absolute (mean )))
468+ self .fading_param = mean , identity (self .nb_tx ) * NLOS_gain / nb_antennas , identity (self .nb_rx )
469+
470+ def expo_corr_rician_fading (self , mean , k_factor , t , r ):
471+ """ Set the fading parameters to a complex correlated rician channel following the exponential model.
472+
473+ See: S. L. Loyka, "Channel capacity if MIMO architecture using the exponential correlation matrix ", IEEE
474+ Commun. Lett., vol.5, n. 9, p. 369-371, sept. 2001.
475+
476+ mean and correlation matricies will be scaled to fit the required k-factor.
477+
478+ Parameters
479+ ----------
480+ mean : ndarray (shape: nb_rx x nb_tx)
481+ Mean of the channel gain.
482+
483+ k_factor : positive float
484+ Requested k-factor (the power ratio between LOS and NLOS).
485+
486+ t : complex with abs(t) = 1
487+ Correlation coefficient for the transceiver.
488+
489+ r : complex with abs(r) = 1
490+ Correlation coefficient for the receiver.
491+
492+ Raises
493+ ------
494+ ValueError
495+ If abs(t) != 1 or abs(r) != 1
496+ """
497+ # Check inputs
498+ if abs (t ) - 1 > 1e-4 :
499+ raise ValueError ('abs(t) must be one.' )
500+ if abs (r ) - 1 > 1e-4 :
501+ raise ValueError ('abs(r) must be one.' )
502+
503+ # Scaling
504+ nb_antennas = mean .size
505+ NLOS_gain = nb_antennas / (k_factor + 1 )
506+ mean = mean * sqrt (k_factor * NLOS_gain / einsum ('ij,ij->' , absolute (mean ), absolute (mean )))
507+
508+ # Construct the exponent matrix
509+ expo_tx = fromiter ((j - i for i in range (self .nb_tx ) for j in range (self .nb_tx )), int , self .nb_tx ** 2 )
510+ expo_rx = fromiter ((j - i for i in range (self .nb_rx ) for j in range (self .nb_rx )), int , self .nb_rx ** 2 )
511+
512+ # Reshape
513+ expo_tx = expo_tx .reshape (self .nb_tx , self .nb_tx )
514+ expo_rx = expo_rx .reshape (self .nb_rx , self .nb_rx )
515+
516+ # Set fading
517+ self .fading_param = mean , t ** expo_tx * NLOS_gain / nb_antennas , r ** expo_rx
518+
410519
411520def bec (input_bits , p_e ):
412521 """
@@ -475,14 +584,14 @@ def awgn(input_signal, snr_dB, rate=1.0):
475584 Output signal from the channel with the specified SNR.
476585 """
477586
478- avg_energy = sum (abs (input_signal ) * abs (input_signal ))/ len (input_signal )
479- snr_linear = 10 ** (snr_dB / 10.0 )
480- noise_variance = avg_energy / ( 2 * rate * snr_linear )
587+ avg_energy = sum (abs (input_signal ) * abs (input_signal )) / len (input_signal )
588+ snr_linear = 10 ** (snr_dB / 10.0 )
589+ noise_variance = avg_energy / ( 2 * rate * snr_linear )
481590
482591 if isinstance (input_signal [0 ], complex ):
483592 noise = (sqrt (noise_variance ) * randn (len (input_signal ))) + (sqrt (noise_variance ) * randn (len (input_signal ))* 1j )
484593 else :
485- noise = sqrt (2 * noise_variance ) * randn (len (input_signal ))
594+ noise = sqrt (2 * noise_variance ) * randn (len (input_signal ))
486595
487596 output_signal = input_signal + noise
488597
0 commit comments