Exemplo n.º 1
0
    def get_total_rss(rssi_a: int, rssi_b: int, rssi_c: int, agc: int) -> float:
        # Calculates the Received Signal Strength (RSS) in dBm
        # Careful here: rssis could be zero

        rssi_mag = 0
        if rssi_a != 0:
            rssi_mag = rssi_mag + dbinv(rssi_a)
        if rssi_b != 0:
            rssi_mag = rssi_mag + dbinv(rssi_b)
        if rssi_c != 0:
            rssi_mag = rssi_mag + dbinv(rssi_c)

        #Interpreting RSS magnitude as power for RSS/dBm conversion.
        #This is consistent with Linux 802.11n CSI Tool's MATLAB implementation.
        #As seen in get_total_rss.m.
        return db(rssi_mag, "pow") - 44 - agc
Exemplo n.º 2
0
def scale_csi_frame(csi: np.array, rss: int) -> np.array:
    # This is not a true SNR ratio as is the case for the Intel scaling.
    # We do not have agc or noise values so it's just about establishing a scale against RSS.

    subcarrier_count = csi.shape[0]

    rss_pwr = dbinv(rss)

    csi_sq = np.multiply(csi, np.conj(csi))
    csi_pwr = np.sum(csi_sq)
    csi_pwr = np.real(csi_pwr)

    # This implementation is based on the equation shown in https://doi.org/10.1109/JIOT.2020.3022573.
    # scaling_coefficient = sqrt(10^(RSS/10) / sum(CSIi^2))

    scale = rss_pwr / (csi_pwr / subcarrier_count)

    return csi * np.sqrt(scale)
Exemplo n.º 3
0
    def scale_csi_entry(csi: np.array, header: list) -> np.array:
        """
            This function performs scaling on the retrieved CSI data to account for automatic gain control and other factors.
            Code within this section is largely based on the Linux 802.11n CSI Tool's MATLAB implementation (get_scaled_csi.m).

            Parameters:
                frame {dict} -- CSI frame object for which CSI is to be scaled.
        """

        n_rx = header[3]
        n_tx = header[4]

        rssi_a = header[5]
        rssi_b = header[6]
        rssi_c = header[7]

        noise = header[8]
        agc = header[9]
        
        #Calculate the scale factor between normalized CSI and RSSI (mW).
        csi_sq = np.multiply(csi, np.conj(csi))
        csi_pwr = np.sum(csi_sq)
        csi_pwr = np.real(csi_pwr)

        rssi_pwr_db = IWLBeamformReader.get_total_rss(rssi_a, rssi_b, rssi_c, agc)
        rssi_pwr = dbinv(rssi_pwr_db)
        #Scale CSI -> Signal power : rssi_pwr / (mean of csi_pwr)
        scale = rssi_pwr / (csi_pwr / 30)

        #Thermal noise may be undefined if the trace was captured in monitor mode.
        #If so, set it to 92.
        noise_db = noise
        if (noise == -127):
            noise_db = -92

        noise_db = np.float(noise_db)
        thermal_noise_pwr = dbinv(noise_db)

        #Quantization error: the coefficients in the matrices are 8-bit signed numbers,
        #max 127/-128 to min 0/1. Given that Intel only uses a 6-bit ADC, I expect every
        #entry to be off by about +/- 1 (total across real and complex parts) per entry.

        #The total power is then 1^2 = 1 per entry, and there are Nrx*Ntx entries per
        #carrier. We only want one carrier's worth of error, since we only computed one
        #carrier's worth of signal above.
        quant_error_pwr = scale * (n_rx * n_tx)

        #Noise and error power.
        total_noise_pwr = thermal_noise_pwr + quant_error_pwr

        # ret now has units of sqrt(SNR) just like H in textbooks.
        ret = csi * np.sqrt(scale / total_noise_pwr)
        if n_tx == 2:
            ret = ret * np.sqrt(2)
        elif n_tx == 3:
            #Note: this should be sqrt(3)~ 4.77dB. But 4.5dB is how
            #Intel and other makers approximate a factor of 3.
            #You may need to change this if your card does the right thing.
            ret = ret * np.sqrt(dbinv(4.5))

        return ret