Exemplo n.º 1
0
def calc_post_processing_SINRs(
        channel: np.ndarray,
        W: np.ndarray,
        G_H: np.ndarray,
        noise_var: Optional[float] = None) -> np.ndarray:
    """
    Calculate the post processing SINRs (in dB) of all streams for a given
    MIMO scheme.

    Parameters
    ----------
    channel : np.ndarray
        The MIMO channel. This should be a 2D numpy array.
    W : np.ndarray
        The precoder for the MIMO scheme. This should be a 2D numpy array.
    G_H : np.ndarray
        The receive filter for the MIMO scheme. This should be a 2D numpy
        array.
    noise_var : float
        The noise variance

    Returns
    -------
    np.ndarray
        The SINR of all streams (in linear scale).
    """
    return linear2dB(
        calc_post_processing_linear_SINRs(channel, W, G_H, noise_var))
Exemplo n.º 2
0
def simulate_for_a_given_ap_assoc(pl, ap_assoc, wall_losses_dB, Pt, noise_var):
    """
    Simulate and return the SINR for a given path loss and AP associations.

    This is an internal function called inside
    `perform_simulation_SINR_heatmap`

    Parameters
    ----------
    pl : 5D numpy float array
        The path loss (in LINEAR SCALE) from each discrete position in each
        room to each access point. Dimension: (n, n, d, d, a) where 'n' is
        the number of rooms per dimension, 'd' is the number of discrete
        positions in one room (per dimension) and 'a' is the number of
        access points.
    ap_assoc : 4D numpy int array
        The index of the access point that each discrete point in each room
        is associated with. Dimension: (n, n, d, d)
    wall_losses_dB : 5D numpy int array
        The wall losses (in dB) from each discrete user in each room to
        each access point. Dimension: (n, n, d, d, a)
    Pt : float
        Transmit power.
    noise_var : float
        Noise variance (power)

    Returns
    -------
    sinr_array_dB : 4D numpy array
        The SINR (in dB) of each discrete point of each room.
    """
    wall_losses = dB2Linear(-wall_losses_dB)

    # Number of APs is the last dimension in the path loss array
    num_aps = pl.shape[-1]

    # Output variable
    sinr_array = np.empty(ap_assoc.shape, dtype=float)

    for ap_idx in range(num_aps):
        # Mask of the users associated with the current access point
        mask = (ap_assoc == ap_idx)

        # # Mask of the users NOT associated with the current access point
        # mask_n = np.logical_not(mask)

        # Mask with all APs except the current one (that is, the
        # interfering APs)
        mask_i_aps = np.arange(num_aps) != ap_idx

        # Each element in desired_power is the desired power of one user
        # associated with the current access point
        desired_power = Pt * wall_losses[mask, ap_idx] * pl[mask, ap_idx]
        undesired_power = np.sum(Pt * wall_losses[mask][:, mask_i_aps] *
                                 pl[mask][:, mask_i_aps],
                                 axis=-1)

        sinr_array[mask] = (desired_power / (undesired_power + noise_var))

    return linear2dB(sinr_array)
Exemplo n.º 3
0
def simulate_for_a_given_ap_assoc(pl, ap_assoc, wall_losses_dB, Pt, noise_var):
    """
    Simulate and return the SINR for a given path loss and AP associations.

    This is an internal function called inside
    `perform_simulation_SINR_heatmap`

    Parameters
    ----------
    pl : 5D numpy float array
        The path loss (in LINEAR SCALE) from each discrete position in each
        room to each access point. Dimension: (n, n, d, d, a) where 'n' is
        the number of rooms per dimension, 'd' is the number of discrete
        positions in one room (per dimension) and 'a' is the number of
        access points.
    ap_assoc : 4D numpy int array
        The index of the access point that each discrete point in each room
        is associated with. Dimension: (n, n, d, d)
    wall_losses_dB : 5D numpy int array
        The wall losses (in dB) from each discrete user in each room to
        each access point. Dimension: (n, n, d, d, a)
    Pt : float
        Transmit power.
    noise_var : float
        Noise variance (power)

    Returns
    -------
    sinr_array_dB : 4D numpy array
        The SINR (in dB) of each discrete point of each room.
    """
    wall_losses = dB2Linear(-wall_losses_dB)

    # Number of APs is the last dimension in the path loss array
    num_aps = pl.shape[-1]

    # Output variable
    sinr_array = np.empty(ap_assoc.shape, dtype=float)

    for ap_idx in range(num_aps):
        # Mask of the users associated with the current access point
        mask = ap_assoc == ap_idx

        # # Mask of the users NOT associated with the current access point
        # mask_n = np.logical_not(mask)

        # Mask with all APs except the current one (that is, the
        # interfering APs)
        mask_i_aps = np.arange(num_aps) != ap_idx

        # Each element in desired_power is the desired power of one user
        # associated with the current access point
        desired_power = Pt * wall_losses[mask, ap_idx] * pl[mask, ap_idx]
        undesired_power = np.sum(Pt * wall_losses[mask][:, mask_i_aps] * pl[mask][:, mask_i_aps], axis=-1)

        sinr_array[mask] = desired_power / (undesired_power + noise_var)

    return linear2dB(sinr_array)
Exemplo n.º 4
0
def simulate_for_a_given_ap_assoc(pl_plus_wl_tx_aps, ap_assoc,
                                  transmitting_aps, Pt, noise_var):
    """
    Perform the simulation for a given AP association.

    Parameters
    ----------
    pl_plus_wl_tx_aps : np.ndarray
    ap_assoc : np.ndarray
    transmitting_aps : np.ndarray
    Pt : float | np.ndarray
    noise_var : float
        The noise variance.

    Returns
    -------
    (np.ndarray, np.ndarray)
        A tuple with the SINRs and the capacity.
    """
    # Output variables
    sinr_array = np.empty(ap_assoc.shape, dtype=float)
    capacity = np.empty(ap_assoc.shape, dtype=float)

    num_users, = ap_assoc.shape

    # For each transmitting AP
    for index, ap in enumerate(transmitting_aps):
        # 'ap' is the index of the current AP in the list of all APs
        # (including the non transmitting APs), while 'index' is the index
        # or the current AP in transmitting_aps

        # Index of the users associated with the current AP
        current_ap_users_idx = np.arange(num_users)[ap_assoc == ap]

        # Mask to get the interfering APs
        mask_i_aps = np.ones(len(transmitting_aps), dtype=bool)
        mask_i_aps[index] = False

        # Desired power of these users
        desired_power = (Pt * pl_plus_wl_tx_aps[current_ap_users_idx, index])

        undesired_power = np.sum(
            Pt * pl_plus_wl_tx_aps[current_ap_users_idx][:, mask_i_aps],
            axis=-1)

        sinr_array[current_ap_users_idx] = (desired_power /
                                            (undesired_power + noise_var))

        # The capacity (actually, the spectral efficiency since we didn't
        # multiply by the bandwidth) is calculated from the SINR. However,
        # if there is more then one user associated with the current AP we
        # assume bandwidth will be equally divided among all of them.
        capacity[current_ap_users_idx] = (
            np.log2(1 + sinr_array[current_ap_users_idx]) /
            len(current_ap_users_idx))

    return linear2dB(sinr_array), capacity
Exemplo n.º 5
0
def plot_true_and_estimated_channel_with_bokeh(true_channel,
                                               estimated_channel,
                                               title='',
                                               antenna=0):
    true_channel_time = np.fft.ifft(true_channel[:, antenna], axis=0)

    num_subcarriers = true_channel.shape[0]

    data = {
        'index': np.r_[0:num_subcarriers],
        'channel_time': np.abs(true_channel_time),
        'channel': np.abs(true_channel[:, antenna]),
        'estimated_channel': np.abs(estimated_channel[:, antenna]),
        'error': linear2dB(
            np.abs(true_channel[:, antenna] - estimated_channel[:, antenna]) / \
            np.abs(true_channel[:, antenna]))}
    source00 = bp.ColumnDataSource(data=data)

    # Specify the tools by name. This does not allow us to set parameters
    # for the tools
    TOOLS = "pan,wheel_zoom,box_zoom,reset,resize,crosshair"
    # Create a hover tool and tell it to only show for a curve with name
    # 'estimated'
    hover_tool = HoverTool(names=['estimated'],
                           tooltips=[('True Channel', ''),
                                     ('Error (in dB)', '@error')])
    # p1 = bp.figure(tools=TOOLS, width=600, height=200)
    # p1.circle('index', 'channel_time', source=source00)
    # p1.title = title

    p2 = bp.figure(tools=TOOLS, plot_width=400, plot_height=300)
    p2.add_tools(hover_tool)

    p2.line('index', 'channel', source=source00, legend='True Channel')
    # We specify the 'name' attribute so that we can specify the 'names'
    # attribute for the hover tool and tell it to only show for the
    # estimated channel curve.
    p2.line('index',
            'estimated_channel',
            source=source00,
            color='red',
            name='estimated',
            legend='Estimated Channel')

    p2.title = title

    # p = bp.vplot(p1, p2)
    # return p
    return p2
Exemplo n.º 6
0
    def calc_SINRs(self, noise_var):
        """
        Calculate the SINRs (in dB) of the multiple streams.

        Parameters
        ----------
        noise_var : float
            The noise variance.

        Returns
        -------
        SINRs : np.ndarray
            The SINRs (in dB) of the multiple streams.
        """
        return linear2dB(self.calc_linear_SINRs(noise_var))
Exemplo n.º 7
0
    def calc_SINRs(self, noise_var):
        """
        Calculate the SINRs (in dB) of the multiple streams.

        Parameters
        ----------
        noise_var : float
            The noise variance.

        Returns
        -------
        SINRs : 1D numpy array
            The SINRs (in dB) of the multiple streams.
        """
        return linear2dB(self.calc_linear_SINRs(noise_var))
Exemplo n.º 8
0
    def which_distance(self, pl):  # pragma: no cover
        """
        Calculates the required distance (in meters) to achieve the given path
        loss. It is the inverse of the calc_path_loss function.

        Parameters
        ----------
        pl : float or numpy array
            Path loss (in linear scale).

        Returns
        -------
        d : float or numpy array
            Distance(s) that will yield the path loss `pl`.
        """
        d = self.which_distance_dB(-conversion.linear2dB(pl))
        return d
Exemplo n.º 9
0
    def test_calc_post_processing_SINRs(self):
        Nr = 1
        Nt = 2
        noise_var = 0.01
        channel = randn_c(Nr, Nt)
        self.alamouti_object.set_channel_matrix(channel)

        # W = self.alamouti_object._calc_precoder(channel)
        # G_H = self.alamouti_object._calc_receive_filter(channel, noise_var)

        expected_sinrs = linear2dB(
            (np.linalg.norm(channel, 'fro')**2)/noise_var)

        # Calculate the SINR using method in the Alamouti class. Note that
        # we only need to pass the noise variance, since the mimo object
        # knows the channel.
        sinrs = self.alamouti_object.calc_SINRs(noise_var)
        np.testing.assert_array_almost_equal(sinrs, expected_sinrs, 2)
Exemplo n.º 10
0
def plot_true_and_estimated_channel_with_bokeh(
        true_channel, estimated_channel, title='', antenna=0):
    true_channel_time = np.fft.ifft(true_channel[:, antenna], axis=0)

    num_subcarriers = true_channel.shape[0]

    data = {
        'index': np.r_[0:num_subcarriers],
        'channel_time': np.abs(true_channel_time),
        'channel': np.abs(true_channel[:,antenna]),
        'estimated_channel':np.abs(estimated_channel[:,antenna]),
        'error':linear2dB(
            np.abs(true_channel[:,antenna] - estimated_channel[:,antenna]) / \
            np.abs(true_channel[:,antenna]))}
    source00 = bp.ColumnDataSource(data=data)

    # Specify the tools by name. This does not allow us to set parameters
    # for the tools
    TOOLS = "pan,wheel_zoom,box_zoom,reset,resize,crosshair"
    # Create a hover tool and tell it to only show for a curve with name
    # 'estimated'
    hover_tool = HoverTool(
        names=['estimated'],
        tooltips = [('True Channel', ''), ('Error (in dB)', '@error')])
    # p1 = bp.figure(tools=TOOLS, width=600, height=200)
    # p1.circle('index', 'channel_time', source=source00)
    # p1.title = title

    p2 = bp.figure(tools=TOOLS, plot_width=400, plot_height=300)
    p2.add_tools(hover_tool)

    p2.line('index', 'channel', source=source00, legend='True Channel')
    # We specify the 'name' attribute so that we can specify the 'names'
    # attribute for the hover tool and tell it to only show for the
    # estimated channel curve.
    p2.line('index', 'estimated_channel', source=source00, color='red',
           name='estimated', legend='Estimated Channel')

    p2.title = title

    # p = bp.vplot(p1, p2)
    # return p
    return p2
Exemplo n.º 11
0
    def test_calc_post_processing_SINRs(self):
        Nr = 3
        Nt = 3
        noise_var = 0.01
        channel = randn_c(Nr, Nt)
        self.svdmimo_object.set_channel_matrix(channel)

        W = self.svdmimo_object._calc_precoder(channel)
        G_H = self.svdmimo_object._calc_receive_filter(channel, noise_var)
        expected_sinrs = linear2dB(calc_SINRs(channel, W, G_H, noise_var))

        # Calculate the SINR using the function in the mimo module. Note
        # that we need to pass the channel, the precoder, the receive
        # filter and the noise variance.
        sinrs = calc_post_processing_SINRs(channel, W, G_H, noise_var)
        np.testing.assert_array_almost_equal(sinrs, expected_sinrs, 2)

        # Calculate the SINR using method in the MIMO class. Note that we
        # only need to pass the noise variance, since the mimo object knows
        # the channel and it can calculate the precoder and receive filter.
        sinrs_other = self.svdmimo_object.calc_linear_SINRs(noise_var)
        np.testing.assert_array_almost_equal(sinrs_other, expected_sinrs, 2)
Exemplo n.º 12
0
def calc_post_processing_SINRs(channel, W, G_H, noise_var=None):
    """
    Calculate the post processing SINRs (in dB) of all streams for a given
    MIMO scheme.

    Parameters
    ----------
    channel : 2D numpy array
        The MIMO channel.
    W : 2D numpy array
        The precoder for the MIMO scheme.
    G_H : 2D numpy array
        The receive filter for the MIMO scheme.
    noise_var : float
        The noise variance

    Returns
    -------
    sinrs : 1D numpy array
        The SINR of all streams (in linear scale).
    """
    return linear2dB(
        calc_post_processing_linear_SINRs(channel, W, G_H, noise_var))
Exemplo n.º 13
0
def get_ebn0_vec(results):
    """
    Get the Eb/N0 vector suitable for the plot.

    Parameters
    ----------
    results : A SimulationResults object
        The results from a simulation.
    """
    SNR = np.array(results.params['SNR'])

    modulator = results.params['modulator']
    if modulator == 'BPSK':
        K = 1
    elif modulator == 'QPSK':
        K = 2
    else:
        M = results.params['M']
        K = np.round(np.log2(M))

    ebn0 = SNR + linear2dB(1./K)

    return ebn0
Exemplo n.º 14
0
def simulate_for_a_given_ap_assoc(pl_plus_wl_tx_aps, ap_assoc, transmitting_aps, Pt, noise_var):
    """
    Perform the simulation for a given AP association.
    """
    # Output variables
    sinr_array = np.empty(ap_assoc.shape, dtype=float)
    capacity = np.empty(ap_assoc.shape, dtype=float)

    num_users, = ap_assoc.shape

    # For each transmitting AP
    for index, ap in enumerate(transmitting_aps):
        # 'ap' is the index of the current AP in the list of all APs
        # (including the non transmitting APs), while 'index' is the index
        # or the current AP in transmitting_aps

        # Index of the users associated with the current AP
        current_ap_users_idx = np.arange(num_users)[ap_assoc == ap]

        # Mask to get the interfering APs
        mask_i_aps = np.ones(len(transmitting_aps), dtype=bool)
        mask_i_aps[index] = False

        # Desired power of these users
        desired_power = Pt * pl_plus_wl_tx_aps[current_ap_users_idx, index]

        undesired_power = np.sum(Pt * pl_plus_wl_tx_aps[current_ap_users_idx][:, mask_i_aps], axis=-1)

        sinr_array[current_ap_users_idx] = desired_power / (undesired_power + noise_var)

        # The capacity (actually, the spectral efficiency since we didn't
        # multiply by the bandwidth) is calculated from the SINR. However,
        # if there is more then one user associated with the current AP we
        # assume bandwidth will be equally divided among all of them.
        capacity[current_ap_users_idx] = np.log2(1 + sinr_array[current_ap_users_idx]) / len(current_ap_users_idx)

    return linear2dB(sinr_array), capacity
Exemplo n.º 15
0
 def test_linear2dB(self):
     self.assertAlmostEqual(conversion.linear2dB(1000), 30.0)
Exemplo n.º 16
0
def compute_channel_estimation_error_dB(H, Hest):
    return np.mean(linear2dB(np.abs(Hest - H) / np.abs(H)))
Exemplo n.º 17
0
    def test_block_diagonalize_no_waterfilling(self):
        Nr = np.array([2, 2])
        Nt = np.array([2, 2])
        K = Nt.size
        Nti = 1
        iPu = 1e-1  # Power for each user (linear scale)
        pe = 1e-3  # External interference power (in linear scale)
        noise_var = 1e-1

        # The modulator and packet_length are required in the
        # effective_throughput metric case
        psk_obj = fundamental.PSK(4)
        packet_length = 120

        multiUserChannel = multiuser.MultiUserChannelMatrixExtInt()
        multiUserChannel.randomize(Nr, Nt, K, Nti)
        multiUserChannel.noise_var = noise_var

        # Channel from all transmitters to the first receiver
        H1 = multiUserChannel.get_Hk_without_ext_int(0)
        # Channel from all transmitters to the second receiver
        H2 = multiUserChannel.get_Hk_without_ext_int(1)

        # Create the enhancedBD object
        enhancedBD_obj = blockdiagonalization.EnhancedBD(K, iPu, noise_var, pe)

        noise_plus_int_cov_matrix \
            = multiUserChannel.calc_cov_matrix_extint_plus_noise(pe)

        # xxxxx First we test without ext. int. handling xxxxxxxxxxxxxxxxxx
        enhancedBD_obj.set_ext_int_handling_metric(None)
        (Ms_all, Wk_all, Ns_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
                multiUserChannel)
        Ms1 = Ms_all[0]
        Ms2 = Ms_all[1]

        self.assertEqual(Ms1.shape[1], Ns_all[0])
        self.assertEqual(Ms2.shape[1], Ns_all[1])

        # Most likelly only one base station (the one with the worst
        # channel) will employ a precoder with total power of `Pu`,
        # while the other base stations will use less power.
        tol = 1e-10
        self.assertGreaterEqual(iPu + tol,
                                np.linalg.norm(Ms1, 'fro') ** 2)
        # 1e-12 is included to avoid false test fails due to small
        # precision errors
        self.assertGreaterEqual(iPu + tol,
                                np.linalg.norm(Ms2, 'fro') ** 2)

        # Test if the precoder block diagonalizes the channel
        self.assertNotAlmostEqual(np.linalg.norm(np.dot(H1, Ms1), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H1, Ms2), 'fro'), 0)
        self.assertNotAlmostEqual(np.linalg.norm(np.dot(H2, Ms2), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H2, Ms1), 'fro'), 0)

        # Equivalent sinrs (in linear scale)
        sinrs = np.empty(K, dtype=np.ndarray)
        sinrs[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, Ms1),
            Wk_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, Ms2),
            Wk_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        se = (
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs[0]),
                packet_length))
            +
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs[1]),
                packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Now with the Naive Stream Reduction xxxxxxxxxxxxxxxxxxxxxxx
        num_streams = 1
        enhancedBD_obj.set_ext_int_handling_metric(
            'naive',
            {'num_streams': num_streams})

        (MsPk_naive_all, Wk_naive_all, Ns_naive_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
                multiUserChannel)
        MsPk_naive_1 = MsPk_naive_all[0]
        MsPk_naive_2 = MsPk_naive_all[1]

        self.assertEqual(MsPk_naive_1.shape[1], Ns_naive_all[0])
        self.assertEqual(MsPk_naive_2.shape[1], Ns_naive_all[1])
        self.assertEqual(Ns_naive_all[0], num_streams)
        self.assertEqual(Ns_naive_all[1], num_streams)

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_naive_1, 'fro') ** 2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_naive_2, 'fro') ** 2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_naive_1), 'fro'),
            0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_naive_2), 'fro'),
            0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_naive_2), 'fro'),
            0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_naive_1), 'fro'),
            0)

        sinrs4 = np.empty(K, dtype=np.ndarray)
        sinrs4[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_naive_1),
            Wk_naive_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs4[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_naive_2),
            Wk_naive_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        se4 = (
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs4[0]),
                packet_length))
            +
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs4[1]),
                packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Now with the Fixed Stream Reduction xxxxxxxxxxxxxxxxxxxxxxx
        # The 'fixed' metric requires that metric_func_extra_args_dict is
        # provided and has the 'num_streams' key. If this is not the case
        # an exception is raised
        with self.assertRaises(AttributeError):
            enhancedBD_obj.set_ext_int_handling_metric('fixed')

        # Now let's test the fixed metric
        num_streams = 1
        enhancedBD_obj.set_ext_int_handling_metric(
            'fixed',
            {'num_streams': num_streams})

        (MsPk_fixed_all, Wk_fixed_all, Ns_fixed_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
                multiUserChannel)
        MsPk_fixed_1 = MsPk_fixed_all[0]
        MsPk_fixed_2 = MsPk_fixed_all[1]

        self.assertEqual(MsPk_fixed_1.shape[1], Ns_fixed_all[0])
        self.assertEqual(MsPk_fixed_2.shape[1], Ns_fixed_all[1])
        self.assertEqual(Ns_fixed_all[0], num_streams)
        self.assertEqual(Ns_fixed_all[1], num_streams)

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_fixed_1, 'fro') ** 2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_fixed_2, 'fro') ** 2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_fixed_1), 'fro'),
            0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_fixed_2), 'fro'),
            0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_fixed_2), 'fro'),
            0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_fixed_1), 'fro'),
            0)

        sinrs5 = np.empty(K, dtype=np.ndarray)
        sinrs5[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_fixed_1),
            Wk_fixed_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs5[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_fixed_2),
            Wk_fixed_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        se5 = (
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs5[0]),
                packet_length))
            +
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs5[1]),
                packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Handling external interference xxxxxxxxxxxxxxxxxxxxxxxxxxxx
        # Handling external interference using the capacity metric
        enhancedBD_obj.set_ext_int_handling_metric('capacity')
        (MsPk_all, Wk_cap_all, Ns_cap_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
                multiUserChannel)
        MsPk_cap_1 = MsPk_all[0]
        MsPk_cap_2 = MsPk_all[1]

        self.assertEqual(MsPk_cap_1.shape[1], Ns_cap_all[0])
        self.assertEqual(MsPk_cap_2.shape[1], Ns_cap_all[1])

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_cap_1, 'fro') ** 2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_cap_2, 'fro') ** 2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_cap_1), 'fro'), 0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_cap_2), 'fro'), 0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_cap_2), 'fro'), 0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_cap_1), 'fro'), 0)

        sinrs2 = np.empty(K, dtype=np.ndarray)
        sinrs2[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_cap_1),
            Wk_cap_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs2[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_cap_2),
            Wk_cap_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        se2 = (
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs2[0]),
                packet_length))
            +
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs2[1]),
                packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Handling external interference xxxxxxxxxxxxxxxxxxxxxxxxxxxx
        # Handling external interference using the effective_throughput metric
        enhancedBD_obj.set_ext_int_handling_metric(
            'effective_throughput',
            {'modulator': psk_obj,
             'packet_length': packet_length})

        (MsPk_effec_all, Wk_effec_all, Ns_effec_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
                multiUserChannel)
        MsPk_effec_1 = MsPk_effec_all[0]
        MsPk_effec_2 = MsPk_effec_all[1]

        self.assertEqual(MsPk_effec_1.shape[1], Ns_effec_all[0])
        self.assertEqual(MsPk_effec_2.shape[1], Ns_effec_all[1])

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_effec_1, 'fro') ** 2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_effec_2, 'fro') ** 2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_effec_1), 'fro'),
            0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_effec_2), 'fro'),
            0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_effec_2), 'fro'),
            0)
        self.assertAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_effec_1), 'fro'),
            0)

        sinrs3 = np.empty(K, dtype=np.ndarray)
        sinrs3[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_effec_1),
            Wk_effec_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs3[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_effec_2),
            Wk_effec_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        se3 = (
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs3[0]),
                packet_length))
            +
            np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
                linear2dB(sinrs3[1]),
                packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # Test if the effective_throughput obtains a better spectral
        # efficiency then the capacity and not handling interference.
        self.assertGreater(se3 + tol, se2)
        self.assertGreater(se3 + tol, se)
Exemplo n.º 18
0
    def test_block_diagonalize_no_waterfilling(self):
        Nr = np.array([2, 2])
        Nt = np.array([2, 2])
        K = Nt.size
        Nti = 1
        iPu = 1e-1  # Power for each user (linear scale)
        pe = 1e-3  # External interference power (in linear scale)
        noise_var = 1e-1

        # The modulator and packet_length are required in the
        # effective_throughput metric case
        psk_obj = fundamental.PSK(4)
        packet_length = 120

        multiUserChannel = multiuser.MultiUserChannelMatrixExtInt()
        multiUserChannel.randomize(Nr, Nt, K, Nti)
        multiUserChannel.noise_var = noise_var

        # Channel from all transmitters to the first receiver
        H1 = multiUserChannel.get_Hk_without_ext_int(0)
        # Channel from all transmitters to the second receiver
        H2 = multiUserChannel.get_Hk_without_ext_int(1)

        # Create the enhancedBD object
        enhancedBD_obj = blockdiagonalization.EnhancedBD(K, iPu, noise_var, pe)

        noise_plus_int_cov_matrix \
            = multiUserChannel.calc_cov_matrix_extint_plus_noise(pe)

        # xxxxx First we test without ext. int. handling xxxxxxxxxxxxxxxxxx
        enhancedBD_obj.set_ext_int_handling_metric(None)
        (Ms_all, Wk_all, Ns_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
            multiUserChannel)
        Ms1 = Ms_all[0]
        Ms2 = Ms_all[1]

        self.assertEqual(Ms1.shape[1], Ns_all[0])
        self.assertEqual(Ms2.shape[1], Ns_all[1])

        # Most likely only one base station (the one with the worst
        # channel) will employ a precoder with total power of `Pu`,
        # while the other base stations will use less power.
        tol = 1e-10
        self.assertGreaterEqual(iPu + tol, np.linalg.norm(Ms1, 'fro')**2)
        # 1e-12 is included to avoid false test fails due to small
        # precision errors
        self.assertGreaterEqual(iPu + tol, np.linalg.norm(Ms2, 'fro')**2)

        # Test if the precoder block diagonalizes the channel
        self.assertNotAlmostEqual(np.linalg.norm(np.dot(H1, Ms1), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H1, Ms2), 'fro'), 0)
        self.assertNotAlmostEqual(np.linalg.norm(np.dot(H2, Ms2), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H2, Ms1), 'fro'), 0)

        # Equivalent sinrs (in linear scale)
        sinrs = np.empty(K, dtype=np.ndarray)
        sinrs[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, Ms1), Wk_all[0], noise_plus_int_cov_matrix[0])
        sinrs[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, Ms2), Wk_all[1], noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        # noinspection PyPep8
        se = (np.sum(
            psk_obj.calcTheoreticalSpectralEfficiency(linear2dB(
                sinrs[0]), packet_length)) + np.sum(
                    psk_obj.calcTheoreticalSpectralEfficiency(
                        linear2dB(sinrs[1]), packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Now with the Naive Stream Reduction xxxxxxxxxxxxxxxxxxxxxxx
        num_streams = 1
        enhancedBD_obj.set_ext_int_handling_metric(
            'naive', {'num_streams': num_streams})

        (MsPk_naive_all, Wk_naive_all, Ns_naive_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
            multiUserChannel)
        MsPk_naive_1 = MsPk_naive_all[0]
        MsPk_naive_2 = MsPk_naive_all[1]

        self.assertEqual(MsPk_naive_1.shape[1], Ns_naive_all[0])
        self.assertEqual(MsPk_naive_2.shape[1], Ns_naive_all[1])
        self.assertEqual(Ns_naive_all[0], num_streams)
        self.assertEqual(Ns_naive_all[1], num_streams)

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_naive_1, 'fro')**2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_naive_2, 'fro')**2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_naive_1), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_naive_2), 'fro'),
                               0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_naive_2), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_naive_1), 'fro'),
                               0)

        sinrs4 = np.empty(K, dtype=np.ndarray)
        sinrs4[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_naive_1), Wk_naive_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs4[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_naive_2), Wk_naive_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        # se4 = (
        #     np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
        #         linear2dB(sinrs4[0]),
        #         packet_length))
        #     +
        #     np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
        #         linear2dB(sinrs4[1]),
        #         packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Now with the Fixed Stream Reduction xxxxxxxxxxxxxxxxxxxxxxx
        # The 'fixed' metric requires that metric_func_extra_args_dict is
        # provided and has the 'num_streams' key. If this is not the case
        # an exception is raised
        with self.assertRaises(AttributeError):
            enhancedBD_obj.set_ext_int_handling_metric('fixed')

        # Now let's test the fixed metric
        num_streams = 1
        enhancedBD_obj.set_ext_int_handling_metric(
            'fixed', {'num_streams': num_streams})

        (MsPk_fixed_all, Wk_fixed_all, Ns_fixed_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
            multiUserChannel)
        MsPk_fixed_1 = MsPk_fixed_all[0]
        MsPk_fixed_2 = MsPk_fixed_all[1]

        self.assertEqual(MsPk_fixed_1.shape[1], Ns_fixed_all[0])
        self.assertEqual(MsPk_fixed_2.shape[1], Ns_fixed_all[1])
        self.assertEqual(Ns_fixed_all[0], num_streams)
        self.assertEqual(Ns_fixed_all[1], num_streams)

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_fixed_1, 'fro')**2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_fixed_2, 'fro')**2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_fixed_1), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_fixed_2), 'fro'),
                               0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_fixed_2), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_fixed_1), 'fro'),
                               0)

        sinrs5 = np.empty(K, dtype=np.ndarray)
        sinrs5[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_fixed_1), Wk_fixed_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs5[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_fixed_2), Wk_fixed_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        # se5 = (
        #     np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
        #         linear2dB(sinrs5[0]),
        #         packet_length))
        #     +
        #     np.sum(psk_obj.calcTheoreticalSpectralEfficiency(
        #         linear2dB(sinrs5[1]),
        #         packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Handling external interference xxxxxxxxxxxxxxxxxxxxxxxxxxxx
        # Handling external interference using the capacity metric
        enhancedBD_obj.set_ext_int_handling_metric('capacity')
        (MsPk_all, Wk_cap_all, Ns_cap_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
            multiUserChannel)
        MsPk_cap_1 = MsPk_all[0]
        MsPk_cap_2 = MsPk_all[1]

        self.assertEqual(MsPk_cap_1.shape[1], Ns_cap_all[0])
        self.assertEqual(MsPk_cap_2.shape[1], Ns_cap_all[1])

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_cap_1, 'fro')**2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_cap_2, 'fro')**2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_cap_1), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_cap_2), 'fro'),
                               0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_cap_2), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_cap_1), 'fro'),
                               0)

        sinrs2 = np.empty(K, dtype=np.ndarray)
        sinrs2[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_cap_1), Wk_cap_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs2[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_cap_2), Wk_cap_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        # noinspection PyPep8
        se2 = (np.sum(
            psk_obj.calcTheoreticalSpectralEfficiency(linear2dB(
                sinrs2[0]), packet_length)) + np.sum(
                    psk_obj.calcTheoreticalSpectralEfficiency(
                        linear2dB(sinrs2[1]), packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # xxxxx Handling external interference xxxxxxxxxxxxxxxxxxxxxxxxxxxx
        # Handling external interference using the effective_throughput metric
        enhancedBD_obj.set_ext_int_handling_metric(
            'effective_throughput', {
                'modulator': psk_obj,
                'packet_length': packet_length
            })

        (MsPk_effec_all, Wk_effec_all, Ns_effec_all) \
            = enhancedBD_obj.block_diagonalize_no_waterfilling(
            multiUserChannel)
        MsPk_effec_1 = MsPk_effec_all[0]
        MsPk_effec_2 = MsPk_effec_all[1]

        self.assertEqual(MsPk_effec_1.shape[1], Ns_effec_all[0])
        self.assertEqual(MsPk_effec_2.shape[1], Ns_effec_all[1])

        # Test if the square of the Frobenius norm of the precoder of each
        # user is equal to the power available to that user.
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_effec_1, 'fro')**2)
        self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_effec_2, 'fro')**2)

        # Test if MsPk really block diagonalizes the channel
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H1, MsPk_effec_1), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_effec_2), 'fro'),
                               0)
        self.assertNotAlmostEqual(
            np.linalg.norm(np.dot(H2, MsPk_effec_2), 'fro'), 0)
        self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_effec_1), 'fro'),
                               0)

        sinrs3 = np.empty(K, dtype=np.ndarray)
        sinrs3[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H1, MsPk_effec_1), Wk_effec_all[0],
            noise_plus_int_cov_matrix[0])
        sinrs3[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs(
            np.dot(H2, MsPk_effec_2), Wk_effec_all[1],
            noise_plus_int_cov_matrix[1])

        # Spectral efficiency
        # noinspection PyPep8
        se3 = (np.sum(
            psk_obj.calcTheoreticalSpectralEfficiency(linear2dB(
                sinrs3[0]), packet_length)) + np.sum(
                    psk_obj.calcTheoreticalSpectralEfficiency(
                        linear2dB(sinrs3[1]), packet_length)))
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        # Test if the effective_throughput obtains a better spectral
        # efficiency then the capacity and not handling interference.
        self.assertGreater(se3 + tol, se2)
        self.assertGreater(se3 + tol, se)
Exemplo n.º 19
0
def compute_channel_estimation_error_dB(H, Hest):
    return np.mean(linear2dB(np.abs(Hest - H) / np.abs(H)))
Exemplo n.º 20
0
 def test_linear2dB(self):
     self.assertAlmostEqual(conversion.linear2dB(1000),
                            30.0)