pyphysim.ia package¶
Submodules¶
pyphysim.ia.algorithms module¶
Module with implementation of Interference Alignment (IA) algorithms.
Note that all IA algorithms require the channel object and any change to the channel object must be performed before calling the solve method of the IA algorithm object. This includes generating the channel and setting the noise variance.
-
class
pyphysim.ia.algorithms.
AlternatingMinIASolver
(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]¶ Bases:
pyphysim.ia.algorithms.IterativeIASolverBaseClass
Implements the “Interference Alignment via Alternating Minimization” algorithm from the paper with the same name [PetersHeathAltMin2009].
This algorithm is applicable to a “K-user” scenario and it is very flexible in the sense that you can change the number of transmit antennas, receive antennas and streams per user, as well as the number of users involved in the IA process. However, note that alignment is only feasible for some cases configurations.
An example of a common scenario is a scenario with 3 pairs or transmitter/receiver with 2 antennas in each node and 1 stream transmitted per node.
You can determine the scenario of an AlternatingMinIASolver object by inferring the variables K, Nt, Nr and Ns.
- Parameters
multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.
Notes
- PetersHeathAltMin2009
Peters, S.W.; Heath, R.W., “Interference alignment via alternating minimization,” Acoustics, Speech and Signal Processing, 2009. ICASSP 2009. IEEE International Conference on, pp.2445,2448, 19-24 April 2009
-
_before_initialize_W_func
() → None[source]¶ Method run in any of the initialize methods after the precoder is initialized but before the receive filter is initialized.
-
_step
() → None[source]¶ Performs one iteration of the algorithm.
The step method is usually all you need to call to perform an iteration of the Alternating Minimization algorithm. It will update C, then update F and finally update W.
See also
-
_updateC
() → None[source]¶ Update the value of Ck for all K users.
Ck contains the orthogonal basis of the interference subspace of user k. It corresponds to the Nk-Sk dominant eigenvectors of
\(\sum_{l \neq k} \mtH_{k,l} \mtF_l \mtF_l^H \mtH_{k,l}^H\).
Notes
This method is called in the
_step()
method.See also
-
_updateF
() → None[source]¶ Update the value of the precoder of all K users.
Fl, the precoder of the l-th user, tries avoid as much as possible to send energy into the desired signal subspace of the other users. Fl contains the Sl least dominant eigenvectors of \(\sum_{k \neq l} H_{k,l}^H (I - C_k C_k^H)H_{k,l}\)
Notes
This method is called in the
_step()
method.See also
-
_updateW
() → None[source]¶ Update the zero-forcing filters.
The zero-forcing filter is calculated in the paper “MIMO Interference Alignment Over Correlated Channels with Imperfect CSI”.
Notes
This method is called in the
_step()
method.See also
-
get_cost
() → float[source]¶ Get the Cost of the algorithm for the current iteration of the precoder.
- Returns
cost – The Cost of the algorithm for the current iteration of the precoder. This is a real non-negative number.
- Return type
-
property
initialize_with
¶ Get method for the initialize_with property.
-
class
pyphysim.ia.algorithms.
BruteForceStreamIASolver
(iasolver_obj: pyphysim.ia.algorithms.IterativeIASolverBaseClass)[source]¶ Bases:
object
Implements the Brute Force Stream Interference Alignment algorithm variation.
This is not a new IA algorithm, but rather a variation of existing IA algorithms. The idea is to use another IA algorithm to find the IA solution for each possible stream configuration (number of streams for each user) and keep the best one.
Note: IA algorithms can provide different performance for the same number of streams but with different initializations. To reduce this variability we set the initialization method to ‘svd’ (see ‘initialize_with’ property in the IterativeIASolverBaseClass class) so that the initialization is always the same.
- Parameters
iasolver_obj (T <= IASolverBaseClass) – Must be an object of a derived class of IterativeIASolverBaseClass.
-
property
every_sum_capacity
¶ Get method for the every_sum_capacity property.
- Returns
Tuple containing the sum capacity for each stream combination in self.stream_combinations.
- Return type
-
property
runned_iterations
¶ Get method for the runned_iterations property.
- Returns
The number of runned iterations.
- Return type
-
solve
(Ns: IntOrIntSequence, P: Optional[FloatOrFloatSequence] = None) → int[source]¶ Find the IA solution.
This method updates the ‘F’ and ‘W’ member variables.
- Parameters
Ns (int | np.ndarray) – MAXIMUM number of streams of each user. All possible values from 1 to Ns (or Ns[k], if Ns is an array) will tried.
P (np.ndarray | List[float] | float, optional) – Power of each user. If not provided, a value of 1 will be used for each user.
- Returns
Number of iterations the iterative interference alignment algorithm run.
- Return type
-
class
pyphysim.ia.algorithms.
ClosedFormIASolver
(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix, use_best_init: bool = True)[source]¶ Bases:
pyphysim.ia.iabase.IASolverBaseClass
Implements the closed form Interference Alignment algorithm as described in the paper “Interference Alignment and Degrees of Freedom of the K User Interference Channel [CadambeDoF2008]”.
- Parameters
multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.
use_best_init (bool) – If true, all possible initializations (subsets of the eigenvectors of the ‘E’ matrix)for the first precoder will be tested and the best solution will be used. If false, the first initialization will be used.
Notes
- CadambeDoF2008
V. R. Cadambe and S. A. Jafar, “Interference Alignment and Degrees of Freedom of the K User Interference Channel,” IEEE Transactions on Information Theory 54, pp. 3425-3441, Aug. 2008.
-
_calc_E
() → numpy.ndarray[source]¶ Calculates the “E” matrix, given by
\(\mtE = \mtH_{31}^{-1}\mtH_{32}\mtH_{12}^{-1}\mtH_{13}\mtH_{23}^{-1}\mtH_{21}\).
- Returns
The “E” matrix.
- Return type
np.ndarray
-
_calc_all_F_initializations
(Ns: int) → List[numpy.ndarray][source]¶ Calculates all possible initializations for the first precoder (self._F[0]).
The precoder self._F[0] is initialized with a subset of the eigenvectors of the matrix ‘E’. Therefore, this method returns all possible subsets of the eigenvectors of the matrix ‘E’.
-
_updateF
(F0: Optional[numpy.ndarray] = None) → None[source]¶ Find the precoders.
- Parameters
F0 (np.ndarray) – The first precoder. If not provided, the matrix ‘E’ will be calculated (with the _calc_E method) and the the first Ns eigenvectors will be used as F0.
-
solve
(Ns: IntOrIntSequence, P: Optional[FloatOrFloatSequence] = None) → None[source]¶ Find the IA solution.
This method updates the ‘F’ and ‘W’ member variables.
- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (np.ndarray | List[float] | float, optional) – Power of each user. If not provided, a value of 1 will be used for each user.
-
class
pyphysim.ia.algorithms.
GreedStreamIASolver
(iasolver_obj: Type[pyphysim.ia.iabase.IASolverBaseClass])[source]¶ Bases:
object
Implements the Greed Stream Interference Alignment algorithm variation.
This is not a new IA algorithm, but rather a variation of existing IA algorithms. The idea is to use another IA algorithm to find the IA solution for the desired maximum number of streams. After the solution is found, we remove the worst stream and use the same algorithm again to find a new solution. If the solution after the stream reduction provided a larger sum capacity we remove the worst stream again and keep going until each user has only one stream or the sum capacity after stream reduction is lower. The final solution will be for the number of streams that yielded the largest sum capacity.
- Parameters
iasolver_obj (T <= IASolverBaseClass) – Must be an object of a derived class of IterativeIASolverBaseClass.
-
_find_index_stream_with_worst_sinr
() → Tuple[int, int][source]¶ Considering the current solution (precoders and receive filters) in self._iasolver, find the index of the user and stream corresponding to the worst SINR.
- Returns
user_idx (int) – The index of the user that has the stream with the worst SINR.
stream_idx (int) – The index of the stream (for user user_idx) with the worst SINR.
-
property
runned_iterations
¶ Get method for the runned_iterations property.
- Returns
The number of runned iterations.
- Return type
-
class
pyphysim.ia.algorithms.
IterativeIASolverBaseClass
(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]¶ Bases:
pyphysim.ia.iabase.IASolverBaseClass
Base class for all Iterative IA algorithms.
All subclasses of IterativeIASolverBaseClass must implement at least the _updateF and _updateW methods.
Solving an iterative algorithm usually involves some initialization and then performing a “step” a given number of times until convergence. The initialization code is performed in the _solve_init method while the “step” corresponds to the _step method.
The initialization code is defined here as simply initializing the precoder with a random matrix and then calling the _updateW method (which must be implemented in a subclass) to update the receive filter. This is usually what you want but any subclass can redefine _solve_init if a different initialization is required.
The “step” part usually involves updating the precoder and then updating the receive filters. The definition of _step here calls two methods that MUST be defined in subclasses, the _updateF method and the _updateW method. If anything else is required in the “step” part then the _step method can be redefined in a subclass, but even in that case it should call the _updateF and _updateW methods instead of implementing everything in your redefined _step method.
- Parameters
multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.
-
_before_initialize_W_func
() → None[source]¶ Method run in any of the initialize methods after the precoder is initialized but before the receive filter is initialized.
-
_dont_initialize_F_and_only_and_find_W
(*_: Any) → None[source]¶ Initialize the IA Solution from a random matrix.
The implementation here simple initializes the precoder variable and then calculates the initial receive filter.
Note: The dummy1 and dummy2 arguments have no effect. They only exist to keep the signature of this method equal to the signature of other initialize methods.
-
_initialize_F_and_W_from_alt_min
(Ns: IntOrIntSequence, P: numpy.ndarray) → None[source]¶ Initialize the IA Solution from the Alternating Minimizations IA solver.
- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.
-
_initialize_F_and_W_from_closed_form
(Ns: IntOrIntSequence, P: numpy.ndarray) → None[source]¶ Initialize the IA Solution from the closed form IA solver.
- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.
-
_initialize_F_randomly_and_find_W
(Ns: Sequence[int], P: numpy.ndarray) → None[source]¶ Initialize the IA Solution from a random matrix.
The implementation here simple initializes the precoder variable and then calculates the initial receive filter.
- Parameters
Ns (int np.ndarray) – Number of streams of each user.
P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.
-
_initialize_F_with_svd_and_find_W
(Ns: IntOrIntSequence, P: numpy.ndarray) → None[source]¶ Initialize the IA Solution from the most significant singular vectors of each user’s channel.
The implementation here simple initializes the precoder variable of each user as the most significant singular vector(s) of that user. After that, calculate the initial receive filters.
- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.
-
classmethod
_is_diff_significant
(F_old: numpy.ndarray, F_new: numpy.ndarray, relative_factor: float) → bool[source]¶ Test if there was any significant change from F_old to F_new.
This method is used internally in the solve method of the IterativeIASolverBaseClass to detect when the precoder of a given iteration didn’t change significantly from one iteration to another. This is used to stop the iterations of the algorithm and avoid unnecessary computations.
- Parameters
F_old (np.ndarray) – The precoder of all users (in a previous iteration). This is a 1D numpy array of numpy arrays.
F_new (np.ndarray) – The precoder of all users (in the current iteration). This is a 1D numpy array of numpy arrays.
relative_factor (float) – Relative change of the precoder in one iteration to the next one. If the relative change from one iteration to the next one is lower than this factor then the algorithm will stop the iterations before the max_iterations limit is reached.
- Returns
out – True if the difference is significant, False otherwise.
- Return type
Notes
A difference is considered significant if it is larger then 1/1000 of the minimum value in the precoder.
-
_solve_finalize
() → None[source]¶ Perform any post processing after the solution has been found.
Some of the found precoders may be a singular matrix. In that case, we need to remove the dimensions with zero energy from both the found precoder and the receive filter.
-
_solve_init
(Ns: IntOrIntSequence, P: FloatOrFloatSequence) → None[source]¶ Code run in the solve method before the loop that run the
_step()
method.The implementation here simple initializes the precoder variable and then calculates the initial receive filter.
- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (float | np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.
-
_step
() → None[source]¶ Performs one iteration of the algorithm.
This method does not return anything, but instead updates the precoder and receive filter.
-
abstract
_updateF
() → None[source]¶ Update the precoders.
Notes
This method should be implemented in the derived classes
See also
-
abstract
_updateW
() → None[source]¶ Update the receive filters.
Notes
This method should be implemented in the derived classes
See also
-
clear
() → None[source]¶ Clear the IA Solver object.
All member attributes that are updated during the solve method, such as the precoder and receive filters, will be cleared. The other attributes that correspond to “configuration” such as the channel object won’t be changed
Notes
You should overwrite this method in subclasses that pass parameters to the __init__ method, since here we call __init__ without arguments which is probably not what you want.
-
property
initialize_with
¶ Get method for the initialize_with property.
-
randomizeF
(Ns: Union[int, List[int], Sequence[int]], P: Optional[numpy.ndarray] = None) → None[source]¶ Generates a random precoder for each user.
- Parameters
Ns (int | list[int] | np.ndarray) – Number of streams of each user.
P (np.ndarray, optional) – Power of each user. If not provided, a value of 1 will be used for each user.
-
property
runned_iterations
¶ Get method for the runned_iterations property.
-
solve
(Ns: IntOrIntSequence, P: Optional[FloatOrFloatSequence] = None) → int[source]¶ Find the IA solution by performing the
_step()
method several times.The number of times the
_step()
method is run is controlled by the max_iterations member variable.Before calling the
_step()
method for the first time the _solve_init method is called to perform any required initializations. Since iterative IA algorithms usually starts with a random precoder then the _solve_init implementation in IterativeIASolverBaseClass calls randomizeF.- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (np.ndarray | List[float] | float, optional) – Power of each user. If not provided, a value of 1 will be used for each user.
- Returns
Number of iterations that the iterative interference alignment
algorithm run.
Notes
You probably should not overwrite this method in sub-classes of the IterativeIASolverBaseClass. If you want to change the initialization of the algorithm overwrite the _solve_init method instead.
Subclasses must implement the _updateF() and _updateW() methods. If something else besides calling these two methods is required in the “step” part of the algorithm, then reimplement also the _step() method.
-
class
pyphysim.ia.algorithms.
MMSEIASolver
(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]¶ Bases:
pyphysim.ia.algorithms.IterativeIASolverBaseClass
Implements the MMSE based Interference Alignment algorithm.
This algorithm is applicable to a “K-user” scenario and it is described in [Peters2011].
An example of a common scenario is a scenario with 3 pairs or transmitter/receiver with 2 antennas in each node and 1 stream transmitted per node.
You can determine the scenario of an MMSEIASolver object by inferring the variables K, Nt, Nr and Ns.
- Parameters
multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.
Notes
- Peters2011
S. W. Peters and R. W. Heath, “Cooperative Algorithms for MIMO Interference Channels,” vol. 60, no. 1, pp. 206-218, 2011.
-
_calc_Uk
(k: int) → numpy.ndarray[source]¶ Calculates the receive filter of the k-th user.
- Parameters
k (int) – User index
- Returns
Uk – The receive filter of the user ‘k’.
- Return type
np.ndarray
-
_calc_Vi
(i: int, mu_i: Optional[float] = None) → numpy.ndarray[source]¶ Calculates the precoder of the i-th user.
-
static
_calc_Vi_for_a_given_mu
(sum_term: numpy.ndarray, mu_i: float, H_herm_U: numpy.ndarray) → numpy.ndarray[source]¶ Calculates the value of Vi for the given parameters.
This method is called inside _calc_Vi.
- Parameters
sum_term (np.ndarray) – The summation term in the formula to calculate the precoder.
mu_i (float) – The value of the lagrange multiplier
H_herm_U (np.ndarray) – The value of \(H_ii^H U_i\)
- Returns
The Vi matrix for the given parameters.
- Return type
np.ndarray
-
static
_calc_Vi_for_a_given_mu2
(inv_sum_term: numpy.ndarray, mu_i: float, H_herm_U: numpy.ndarray) → numpy.ndarray[source]¶ Calculates the value of Vi for the given parameters.
This method is called inside _calc_Vi.
- Parameters
inv_sum_term (np.ndarray) – The inverse of the summation term in the formula to calculate the precoder when mu_i is equal to zero.
mu_i (float) – The value of the lagrange multiplier
H_herm_U (np.ndarray) – The value of \(H_ii^H U_i\)
- Returns
The Vi matrix for the given parameters.
- Return type
np.ndarray
-
_solve_init
(Ns: IntOrIntSequence, P: numpy.ndarray) → None[source]¶ Code run in the solve method before the loop that run the
IterativeIASolverBaseClass._step()
method.The implementation here simple initializes the precoder variable and then calculates the initial receive filter.
- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.
-
class
pyphysim.ia.algorithms.
MaxSinrIASolver
(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]¶ Bases:
pyphysim.ia.algorithms.IterativeIASolverBaseClass
Implements the “Interference Alignment via Max SINR” algorithm.
This algorithm is applicable to a “K-user” scenario and it is described in [Cadambe2008].
An example of a common scenario is a scenario with 3 pairs or transmitter/receiver with 2 antennas in each node and 1 stream transmitted per node.
You can determine the scenario of an MaxSinrIASolver object by inferring the variables K, Nt, Nr and Ns.
- Parameters
multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.
-
_calc_Bkl_cov_matrix_all_l_rev
(k: int) → numpy.ndarray[source]¶ Calculates the interference-plus-noise covariance matrix for all streams at “receiver” \(k\) for the reverse channel.
- Parameters
k (int) – Index of the desired user.
- Returns
Bkl_rev – Covariance matrix of all streams of user k. Each element of the returned 1D numpy array is a 2D numpy complex array corresponding to the covariance matrix of one stream of user k.
- Return type
np.ndarray
-
_calc_Bkl_cov_matrix_first_part_rev
(k: int) → numpy.ndarray[source]¶ Calculates the first part in the equation of the Blk covariance matrix of the reverse channel.
- Parameters
k (int) – Index of the desired user.
- Returns
Bkl_first_part_rev – First part in equation (28) of [Cadambe2008], but for the reverse channel.
- Return type
np.ndarray
-
_calc_Bkl_cov_matrix_second_part_rev
(k: int, l: int) → numpy.ndarray[source]¶ Calculates the second part in the equation of the Blk covariance matrix of the reverse channel..
The second part is given by
\(\frac{P^{[k]}}{d^{[k]}} \mtH^{[kk]} \mtV_{\star l}^{[k]} \mtV_{\star l}^{[k]\dagger} \mtH^{[kk]\dagger}\)
- Parameters
- Returns
second_part – Second part in equation (28) of [Cadambe2008].
- Return type
np.ndarray
-
classmethod
_calc_Uk
(Hkk: numpy.ndarray, Vk: numpy.ndarray, Bkl_all_l: numpy.ndarray) → numpy.ndarray[source]¶ Similar to the
_calc_Ukl()
method, but while_calc_Ukl()
calculates the receive filter (a vector) only for the \(l\)-th stream_calc_Uk()
calculates a receive filter (a matrix) for all streams.- Parameters
Hkk (np.ndarray) – Channel from transmitter K to receiver K.
Vk (np.ndarray) – Precoder of user k.
Bkl_all_l (np.ndarray) – Covariance matrix of all streams of user k. Each element of the returned 1D numpy array is a 2D numpy complex array corresponding to the covariance matrix of one stream of user k.
- Returns
Uk – The receive filter for all streams of user k.
- Return type
np.ndarray
-
_calc_Uk_all_k
() → numpy.ndarray[source]¶ Calculates the receive filter of all users.
- Returns
The receive filter of all users. This is a numpy array of numpy arrays.
- Return type
np.ndarray
-
_calc_Uk_all_k_rev
() → numpy.ndarray[source]¶ Calculates the receive filter of all users for the reverse channel.
Returns
- np.ndarray
The receive filter of all users for the reverse channel. This is a numpy array of numpy arrays.
-
classmethod
_calc_Ukl
(Hkk: numpy.ndarray, Vk: numpy.ndarray, Bkl: numpy.ndarray, l: int) → numpy.ndarray[source]¶ Calculates the Ukl matrix in equation (29) of [Cadambe2008].
- Parameters
Hkk (np.ndarray) – Channel from transmitter K to receiver K.
Vk (np.ndarray) – Precoder of user k.
Bkl (np.ndarray) – The previously calculates Bkl matrix in equation (28) of [Cadambe2008]
l (int) – Index of the desired stream
- Returns
Ukl – The calculated Ukl matrix. This is a 2D numpy array (with self.Nr[k] rows and a single column).
- Return type
np.ndarray
-
_updateF
() → None[source]¶ Update the precoders.
Notes
This method is called in the
IterativeIASolverBaseClass._step()
method.See also
-
_updateW
() → None[source]¶ Update the receive filters.
Notes
This method is called in the
IterativeIASolverBaseClass._step()
method.See also
-
class
pyphysim.ia.algorithms.
MinLeakageIASolver
(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]¶ Bases:
pyphysim.ia.algorithms.IterativeIASolverBaseClass
Implements the Minimum Leakage Interference Alignment algorithm as described in the paper “Approaching the Capacity of Wireless Networks through Distributed Interference Alignment [Cadambe2008]”.
- Parameters
multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.
-
_calc_Uk_all_k
() → numpy.ndarray[source]¶ Calculates the receive filter of all users.
- Returns
The Uk array of each user. This is a 1D numpy array of numpy arrays.
- Return type
np.ndarray
-
_calc_Uk_all_k_rev
() → numpy.ndarray[source]¶ Calculates the receive filter of all users in the reverse network.
- Returns
The Uk array of each user. This is a 1D numpy array of numpy arrays.
- Return type
np.ndarray
-
_updateF
() → None[source]¶ Update the precoders.
Notes
This method is called in the
IterativeIASolverBaseClass._step()
method.See also
-
_updateW
() → None[source]¶ Update the receive filters.
Notes
This method is called in the
IterativeIASolverBaseClass._step()
method.See also
-
get_cost
() → float[source]¶ Get the Cost of the algorithm for the current iteration of the precoder.
For the Minimum Leakage Interference Alignment algorithm the cost is equivalent to the sum of the interference that all users see after applying the receive filter. That is,
\(C = Tr[\mtU_k^H \mtQ_k \mtU_k]\)
- Returns
cost – The Cost of the algorithm for the current iteration of the precoder. This is a (real non-negative number).
- Return type
pyphysim.ia.iabase module¶
Module containing the base class for Interference Alignment (IA) Algorithms.
This module should probably only be imported in the other modules inside the ‘ia’ package that implement the IA algorithms.
-
class
pyphysim.ia.iabase.
IASolverBaseClass
(multiUserChannel: pyphysim.channels.multiuser.MultiUserChannelMatrix)[source]¶ Bases:
object
Base class for all Interference Alignment Algorithms.
At least the _updateW, _updateF and solve methods must be implemented in the subclasses of IASolverBaseClass, where the solve method uses the _updateW and _updateF methods in its implementation.
The implementation of the _updateW method should call the _clear_receive_filter method in the beginning and after that set either the _W or the _W_H variables with the correct value.
The implementation of the _updateF method should call the clear_precoder_filter in the beginning and after that set _W variable with the correct precoder (normalized to have a Frobenius norm equal to one.
The implementation of the _updateF method must set the _F variable with the correct value.
Another method that can be implemented is the get_cost method. It should return the cost of the current IA solution. What is considered “the cost” varies from one IA algorithm to another, but should always be a real non-negative number. If get_cost is not implemented a value of -1 is returned.
- Parameters
multiUserChannel (muchannels.MultiUserChannelMatrix) – The multiuser channel.
-
property
F
¶ Transmit precoder of all users.
- Returns
The precoders of all users (a 1D numpy array of 2D numpy arrays).
- Return type
np.ndarray
-
property
Nr
¶ Number of receive antennas of all users.
- Returns
Nr – Number of receive antennas of all users.
- Return type
np.ndarray
-
property
Ns
¶ Number of streams of all users.
- Returns
Ns – Number of streams of all users.
- Return type
np.ndarray
-
property
Nt
¶ Number of transmit antennas of all users.
- Returns
Nt – Number of transmit antennas of all users.
- Return type
np.ndarray
-
property
P
¶ Transmit power of all users.
- Returns
The power of all users.
- Return type
np.ndarray
-
property
W
¶ Receive filter of all users.
- Returns
The receive filter of all users. (a 1D numpy array of 2D numpy arrays).
- Return type
np.ndarray
-
property
W_H
¶ Get method for the W_H property.
- Returns
The conjugate of the receive filter of all users. (a 1D numpy array of 2D numpy arrays).
- Return type
np.ndarray
-
_calc_Bkl_cov_matrix_all_l
(k: int, noise_power: Optional[float] = None) → numpy.ndarray[source]¶ Calculates the interference-plus-noise covariance matrix for all streams at receiver \(k\) according to equation (28) in [Cadambe2008].
The interference-plus-noise covariance matrix for stream \(l\) of user \(k\) is given by Equation (28) in [Cadambe2008], which is reproduced below
\[\mtB^{[kl]} = \sum_{j=1}^{K} \frac{P^{[j]}}{d^{[j]}} \sum_{d=1}^{d^{[j]}} \mtH^{[kj]}\mtV_{\star l}^{[j]} \mtV_{\star l}^{[j]\dagger} \mtH^{[kj]\dagger} - \frac{P^{[k]}}{d^{[k]}} \mtH^{[kk]} \mtV_{\star l}^{[k]} \mtV_{\star l}^{[k]\dagger} \mtH^{[kk]\dagger} + \mtI_{N^{[k]}}\]where \(P^{[k]}\) is the transmit power of transmitter \(k\), \(d^{[k]}\) is the number of degrees of freedom of user \(k\), \(\mtH^{[kj]}\) is the channel between transmitter \(j\) and receiver \(k\), \(\mtV_{\star l}\) is the \(l\)-th column of the precoder of user \(k\) and \(\mtI_{N^{k}}\) is an identity matrix with size equal to the number of receive antennas of receiver \(k\).
- Parameters
- Returns
Bkl – Covariance matrix of all streams of user k. Each element of the returned 1D numpy array is a 2D numpy complex array corresponding to the covariance matrix of one stream of user k.
- Return type
np.ndarray
Notes
To be simple, a function that returns the covariance matrix of only a single stream “l” of the desired user “k” could be implemented, but in the order to calculate the max SINR algorithm we need the covariance matrix of all streams and returning them in single function as is done here allows us to calculate the first part in equation (28) of [Cadambe2008] only once, since it is the same for all streams.
-
_calc_Bkl_cov_matrix_first_part
(k: int) → numpy.ndarray[source]¶ Calculates the first part in the equation of the Blk covariance matrix in equation (28) of [Cadambe2008].
The first part is given by
\[\sum_{j=1}^{K} \frac{P^{[j]}}{d^{[j]}} \sum_{d=1}^{d^{[j]}} \mtH^{[kj]}\mtV_{\star d}^{[j]} \mtV_{\star d}^{[j]\dagger} \mtH^{[kj]\dagger}\]Note that it only depends on the value of \(k\).
- Parameters
k (int) – Index of the desired user.
- Returns
Bkl_first_part – First part in equation (28) of [Cadambe2008].
- Return type
np.ndarray
-
_calc_Bkl_cov_matrix_second_part
(k: int, l: int) → numpy.ndarray[source]¶ Calculates the second part in the equation of the Blk covariance matrix in equation (28) of [Cadambe2008] (note that it does not include the identity matrix).
The second part is given by
\[\frac{P^{[k]}}{d^{[k]}} \mtH^{[kk]} \mtV_{\star l}^{[k]} \mtV_{\star l}^{[k]\dagger} \mtH^{[kk]\dagger}\]- Parameters
- Returns
second_part – Second part in equation (28) of [Cadambe2008].
- Return type
np.ndarray
-
_calc_SINR_k
(k: int, Bkl_all_l: Sequence[numpy.ndarray]) → numpy.ndarray[source]¶ Calculates the SINR of all streams of user ‘k’.
-
_calc_equivalent_channel
(k: int) → numpy.ndarray[source]¶ Calculates the equivalent channel for user \(k\) considering the effect of the precoder (including transmit power), the actual channel, and the receive filter (without power compensation).
- Parameters
k (int) – The index of the desired user.
- Returns
Hk_eq – The equivalent channel.
- Return type
np.ndarray
Notes
This method is used only internally in order to calculate the “W” get property so that the returned filter W compensates the effect of the direct channel.
-
_clear_precoder_filter
() → None[source]¶ Clear the precoder filter.
This should be called in the beginning of the implementation of the _updateF method in subclasses.
-
_clear_receive_filter
() → None[source]¶ Clear the receive filter.
This should be called in the beginning of the implementation of the _updateW method in subclasses.
-
_get_channel
(k: int, l: int) → numpy.ndarray[source]¶ Get the channel from transmitter l to receiver k.
-
_get_channel_rev
(k: int, l: int) → numpy.ndarray[source]¶ Get the channel from transmitter l to receiver k in the reverse network.
Let the matrix \(\mtH_{kl}\) be the channel matrix between the transmitter \(l\) to receiver \(k\) in the direct network. The channel matrix between the transmitter \(l\) to receiver \(k\) in the reverse network, denoted as \(\overleftarrow{\mtH}_{kl}\), is then given by \(\overleftarrow{\mtH}_{kl} = \mtH_{lk}^\dagger\) where \(\mtA^\dagger\) is the conjugate transpose of \(\mtA\).
- Parameters
- Returns
H – The channel matrix between transmitter l and receiver k in the reverse network.
- Return type
np.ndarray
Notes
See Section III of [Cadambe2008] for details.
-
calc_Q
(k: int) → numpy.ndarray[source]¶ Calculates the interference covariance matrix at the \(k\)-th receiver.
The interference covariance matrix at the \(k\)-th receiver, \(\mtQ k\), is given by
\[\mtQ k = \sum_{j=1, j \neq k}^{K} \frac{P_j}{Ns_j} \mtH_{kj} \mtF_j \mtF_j^H \mtH_{kj}^H\]where \(P_j\) is the transmit power of transmitter \(j\), and \(Ns_j\) is the number of streams for user \(j\).
- Parameters
k (int) – Index of the desired receiver.
- Returns
Qk – The interference covariance matrix at receiver \(k\).
- Return type
np.ndarray
Notes
This is impacted by the self.P attribute.
-
calc_Q_rev
(k: int) → numpy.ndarray[source]¶ Calculates the interference covariance matrix at the \(k\)-th receiver in the reverse network.
- Parameters
k (int) – Index of the desired receiver.
- Returns
Qk_rev – The interference covariance matrix at receiver \(k\) in the reverse network.
- Return type
np.ndarray
See also
-
calc_SINR
() → numpy.ndarray[source]¶ Calculates the SINR values (in linear scale) of all streams of all users with the current IA solution.
The noise variance used will be the value of the noise_var property, which, if not explicitly set, will use the noise_var property of the multiuserchannel object.
- Returns
SINRs – The SINR (in linear scale) of all streams of all users. This is a 1D numpy array of 1D numpy arrays (of floats).
- Return type
np.ndarray
-
calc_SINR_in_dB
() → numpy.ndarray[source]¶ Calculates the SINR values (in dB scale) of all streams of all users with the current IA solution.
The noise variance used will be the value of the noise_var property, which, if not explicitly set, will use the noise_var property of the multiuserchannel object.
- Returns
SINRs – The SINR (in dB scale) of all streams of all users. This is a 1D numpy array of 1D numpy arrays (of floats).
- Return type
np.ndarray
-
calc_SINR_old
() → numpy.ndarray[source]¶ Calculates the SINR values (in linear scale) of all streams of all users with the current IA solution.
The noise variance used will be the value of the noise_var property, which, if not explicitly set, will use the noise_var property of the multiuserchannel object.
This method is deprecated since it’s not the correct way to calculate the SINR. Use the calc_SINR method instead.
- Returns
SINRs – The SINR (in linear scale) of all streams of all users. This is a 1D numpy array of 1D numpy arrays (of floats).
- Return type
np.ndarray
-
calc_remaining_interference_percentage
(k: int, Qk: Optional[numpy.ndarray] = None) → float[source]¶ Calculates the percentage of the interference in the desired signal space according to equation (30) in [Cadambe2008].
The percentage \(p_k\) of the interference in the desired signal space is given by
\[p_k = \frac{\sum_{j=1}^{Ns[k]} \lambda_j [\mtQ k]}{Tr[\mtQ k]}\]where \(\lambda_j[\mtA]\) denotes the \(j\)-th smallest eigenvalue of \(\mtA\).
- Parameters
k (int) – The index of the desired user.
Qk (np.ndarray) – The covariance matrix of the remaining interference at receiver k. If not provided, it will be automatically calculated. In that case, the P attribute will also be taken into account if it is set.
- Returns
The percentage of the interference in the desired signal space.
- Return type
Notes
Qk must be a symmetric matrix so that its eigenvalues are real and positive (any covariance matrix is a symmetric matrix).
-
calc_sum_capacity
() → float[source]¶ Calculates the sum capacity of the current solution.
The SINRs are estimated and applied to the Shannon capacity formula
- Returns
The sum capacity of the current solution.
- Return type
-
clear
() → None[source]¶ Clear the IA Solver object.
All member attributes that are updated during the solve method, such as the precoder and receive filters, will be cleared. The other attributes that correspond to “configuration” such as the channel object won’t be changed.
Notes
You should overwrite this method in subclasses that pass parameters to the __init__ method, since here we call __init__ without arguments which is probably not what you want.
-
property
full_F
¶ Transmit precoder of all users.
- Returns
The precoders of all users (a 1D numpy array of 2D numpy arrays).
- Return type
np.ndarray
-
property
full_W
¶ Get method for the full_W property.
The full_W property returns the equivalent filter of the IA filter plus the post processing filter.
- Returns
the equivalent filter of the IA filter plus the post processing filter.
- Return type
np.ndarray
-
property
full_W_H
¶ Get method for the full_W_H property.
The full_W_H property returns the equivalent filter of the IA filter plus the post processing filter.
- Returns
The equivalent filter of the IA filter plus the post processing filter.
- Return type
np.ndarray
-
get_cost
() → float[source]¶ Get the current cost of the IA Solution.
This method should be implemented in subclasses and return a number greater than or equal to zero..
- Returns
cost – The Cost of the current IA solution (a real non-negative number).
- Return type
-
property
noise_var
¶ Get method for the noise_var property.
- Returns
The noise variance (a real non-negative number).
- Return type
-
randomizeF
(Ns: Union[int, List[int], Sequence[int]], P: Optional[numpy.ndarray] = None) → None[source]¶ Generates a random precoder for each user.
- Parameters
Ns (int | list[int] | np.ndarray) – Number of streams of each user.
P (np.ndarray, optional) – Power of each user. If not provided, a value of 1 will be used for each user.
-
set_precoders
(F: Optional[Sequence[numpy.ndarray]] = None, full_F: Optional[Sequence[numpy.ndarray]] = None, P: Optional[numpy.ndarray] = None) → None[source]¶ Set the precoders of each user.
Either F or full_F (or both of them) must be provided.
If only full_F is provided then the value of F will be calculated from full_F.
In any case, the value of self.Ns will be updated according to the dimensions of the F or full_F.
- Parameters
F (np.ndarray | list[np.ndarray], optional) – A numpy array where each element is the (normalized) precoder (a 2D numpy array) of one user.
full_F (np.ndarray | list[np.ndarray], optional) – A numpy array where each element is the precoder (a 2D numpy array) of one user.
P (np.ndarray, optional) – The maximum transmit power. If not provided the current value of self.P will be kept as it is.
-
set_receive_filters
(W_H: Optional[Sequence[numpy.ndarray]] = None, W: Optional[Sequence[numpy.ndarray]] = None) → None[source]¶ Set the receive filters.
You only need to pass either W_H or W, but not both of them, since one is calculated from the other.
- Parameters
W_H (np.ndarray | list[np.ndarray]) – A numpy array where each element is the receive filter (a 2D numpy array) of one user. This is a 1D numpy array of 2D numpy arrays.
W (np.ndarray | list[np.ndarray]) – A numpy array where each element is the receive filter (a 2D numpy array) of one user. This is a 1D numpy array of 2D numpy arrays.
-
abstract
solve
(Ns: Union[int, numpy.ndarray], P: Optional[numpy.ndarray] = None) → Any[source]¶ Find the IA solution.
This method must be implemented in a subclass and should updates the ‘F’ and ‘W’ member variables.
- Parameters
Ns (int | np.ndarray) – Number of streams of each user.
P (np.ndarray) – Power of each user. If not provided, a value of 1 will be used for each user.
Notes
This function should be implemented in the derived classes
Module contents¶
Package with Interference Alignment (IA) algorithms.
Note that all IA algorithms require the channel object and any change to the channel object must be performed before calling the solve method of the IA algorithm object. This includes generating the channel and setting the noise variance.