RENEWLab  1.1.0
RENEW project
channel_analysis Namespace Reference

Functions

def calCond (userCSI)
 
def calDemmel (userCSI)
 
def calCapacity (userCSI, noise, beamweights, downlink=False)
 
def calContCapacity (csi, conj=True, downlink=False, offset=1)
 
def calExpectedCapacity (csi, user=0, max_delay=100, conj=True, downlink=False)
 
def find_bad_nodes (csi, corr_thresh=0.32, user=0)
 
def calCorr (userCSI, corr_vec)
 
def demult (csi, data, method='zf')
 

Detailed Description

 channel_analysis.py

 CSI analysis API file

 Author(s): Clay Shepard: cws@rice.edu
        Rahman Doost-Mohamamdy: doost@rice.edu
        Oscar Bejarano: obejarano@rice.edu

---------------------------------------------------------------------
 Copyright © 2018-2019. Rice University.
 RENEW OPEN SOURCE LICENSE: http://renew-wireless.org/license
---------------------------------------------------------------------

Function Documentation

◆ calCapacity()

def channel_analysis.calCapacity (   userCSI,
  noise,
  beamweights,
  downlink = False 
)
Calculate the capacity of a trace with static beamweights.

Apply a set of beamweights to a set of wideband user channels and calculate the shannon capacity of the resulting channel for every Frame.

Note that if the beamweights are calculated with a frame from the trace, that frame will have unrealistic capacity since it will correlate noise as signal.

Args:
        userCSI: Complex numpy array with [Frame, User, BS Ant, Subcarrier]
        noise: Complex numpy array with [Frame, BS Ant, Subcarrier]
        beamweights: Set of beamweights to apply to userCSI [BS Ant, User, Subcarrier]
        downlink: (Boolean) Compute downlink capacity if True, else Uplink

Returns:
        cap_total: Total capacity across all users averaged over subarriers in bps/hz [Frame]
        cap_u: Capacity per user across averaged over subcarriers in bps/hz [Frame, User]
        cap_sc: Capacity per user and subcarrier in bps/hz [Frame, User, Subcarrier]
        SINR: Signtal to interference and noise ratio for each frame user and subcarrier [Frame, User, Subcarrier]
        cap_su_sc: Single user (no interference) capacity per subcarrier in bps/hz  [Frame, User, Subcarrier]
        cap_su_u: Single user (no interference) capacity averaged over subcarriers in bps/hz [Frame, User]
        SNR: Signtal to noise ratio for each frame user and subcarrier [Frame, User, Subcarrier]
Here is the caller graph for this function:

◆ calCond()

def channel_analysis.calCond (   userCSI)
Calculate the standard matrix condition number.

Args:
        userCSI: Complex numpy array with [Frame, User, BS Ant, Subcarrier]

Returns:
        condNumber_ave: The average condition number across all users and subcarriers.
        condNumber: Numpy array of condition number [Frame, Subcarrier]. 

◆ calContCapacity()

def channel_analysis.calContCapacity (   csi,
  conj = True,
  downlink = False,
  offset = 1 
)
Calculate the capacity of a trace with continuous beamforming.

For every frame in a trace, calculate beamweights (either conjugate or ZF),
apply them to a set of wideband user channels either from the same frame or some constant offset (delay),
then calculate the shannon capacity of the resulting channel.

The main difference in uplink/downlink is the source of interference (and power allocation).
In uplink the intended user's interference is a result of every other user's signal passed through that user's beamweights.
In downlink the inteded user's interference is a result of every other user's signal passed through their beamweights (applied to the intended user's channel).

Note that every user has a full 802.11 LTS, which is a repitition of the same symbol.
This method uses the first half of the LTS to make beamweights, then applies them to the second half.
Otherwise, noise is correlated, resulting in inaccurate results.

Args:
        csi: Full complex numpy array with separate LTSs and noise [Frame, User, BS Ant, Subcarrier] (noise is last user)
        conj: (Boolean) If True use conjugate beamforming, else use zeroforcing beamforming.
        downlink: (Boolean) Compute downlink capacity if True, else Uplink
        offset: Number of frames to delay beamweight application.

Returns:
        cap_total: Total capacity across all users averaged over subarriers in bps/hz [Frame]
        cap_u: Capacity per user across averaged over subcarriers in bps/hz [Frame, User]
        cap_sc: Capacity per user and subcarrier in bps/hz [Frame, User, Subcarrier]
        SINR: Signtal to interference and noise ratio for each frame user and subcarrier [Frame, User, Subcarrier]
        cap_su_sc: Single user (no interference) capacity per subcarrier in bps/hz  [Frame, User, Subcarrier]
        cap_su_u: Single user (no interference) capacity averaged over subcarriers in bps/hz [Frame, User]
        SNR: Signtal to noise ratio for each frame user and subcarrier [Frame, User, Subcarrier]
Here is the caller graph for this function:

◆ calCorr()

def channel_analysis.calCorr (   userCSI,
  corr_vec 
)
Calculate instantaneous correlation with a correlation vector.

Sub-samples userCSI in the time/user/subcarrier slice before 
passing it. If slicing just one user, dimensionality has to be 
maintained, i.e. slice like userCSI[:,[2],:,:].

Args:
    userCSI: Complex numpy array [Frame, User, BS Ant, Subcarrier].
    corr_vec: Vector to correlate with [BS Ant, User, Subcarrier].

Returns:
    corr_total: Average correlation across subcarriers [Frame,User].
    sig_sc: Correlation on every [Frame, User, Subcarrier].

Typical usage example:
    corr_total,sig_sc = calCorr(userCSI, 
        np.transpose(np.conj(userCSI[frame,:,:,:]),(1,0,2)))
Here is the caller graph for this function:

◆ calDemmel()

def channel_analysis.calDemmel (   userCSI)
Calculate the Demmel condition number.

Args:
        userCSI: Complex numpy array with [Frame, User, BS Ant, Subcarrier]

Returns:
        demmelNumber_ave: The average condition number across all users and subcarriers.
        demmelNumber: Numpy array of condition number [Frame, Subcarrier].
Here is the caller graph for this function:

◆ calExpectedCapacity()

def channel_analysis.calExpectedCapacity (   csi,
  user = 0,
  max_delay = 100,
  conj = True,
  downlink = False 
)
Calculate the expected capacity for beamweights calculated with delayed stale CSI.


Args:
        csi: Full complex numpy array with separate LTSs and noise [Frame, User, BS Ant, Subcarrier] (noise is last user)
        user: Index of user to compute for (note that other users still affect capacity due to their interference)
        max_delay: Maximum delay (in frames) to delay the beamweight computation.
        conj: (Boolean) If True use conjugate beamforming, else use zeroforcing beamforming.
        downlink: (Boolean) Compute downlink capacity if True, else Uplink

Returns:
        cap: Average capacity across all frames for a given delay (in frames) in bps/hz [Delay]
Here is the call graph for this function:

◆ demult()

def channel_analysis.demult (   csi,
  data,
  method = 'zf' 
)
csi: Frame, User, Antenna, Subcarrier
data: Frame, Uplink Syms, Antenna, Subcarrier
Here is the caller graph for this function:

◆ find_bad_nodes()

def channel_analysis.find_bad_nodes (   csi,
  corr_thresh = 0.32,
  user = 0 
)
Find bad Iris nodes.

Find bad nodes based on the correlation between a reference node 
and every other node. If all nodes are 'bad' then the reference 
node is assumed to be bad, and a new reference node is chosen. The 
reference node is picked sequentially from the list of BS antennas.

Note: 
    csi should be a channel trace taken in a stable environment. 
    If AGC is used, csi should be taken after AGC has settled.

Note:
    By only correlating one node with another, the decorrelation 
    is maximized when there is a sync issue. (If you use more 
    antennas for reference, the impact of the time sync is less. 
    If you use fewer, the bad antennas, which have all of the same 
    phase shift, dominate correlation.)
    
    An important trick is to normalize amplitudes of the CSI so 
    that the phase shift always has the same impact, regardless of 
    channel gains (i.e. if the reference node has low or high 
    signal strength relative to the bad node it would decrease the 
    impact of a time sync issue). 
    
    This also allows a fixed threshold to work well as a single 
    sample shift of 4 antennas out of 8 relatively consistently 
    causes a decorrelation of .25. If half the samples (worst 
    case), this is a .125 deviation from the mean.

Args:
    csi: Complex array [Frame, User, Pilot Rep, BS Ant, Subcarrier]
    thresh: Lower threshold means more sensitivity to deviation in 
        correlation. Higher shall give more false negatives, lower 
        shall give more false positives.
    user: The index of the user to use for correlation.
    
Returns:
    bad_nodes: A list of indices of nodes determined to be bad.
Here is the call graph for this function:
Here is the caller graph for this function: