Merge pull request #1575 from atiselsts/cooja_bit_errors

Cooja: add Msp802154BitErrorRadio interface
This commit is contained in:
Fredrik Österlind 2016-06-06 11:39:45 +02:00
commit 0313a429e2
2 changed files with 374 additions and 4 deletions

View File

@ -0,0 +1,370 @@
/*
* Copyright (c) 2014, Uppsala University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
package org.contikios.cooja.mspmote.interfaces;
import java.util.Random;
import org.apache.log4j.Logger;
import org.contikios.cooja.ClassDescription;
import org.contikios.cooja.Mote;
import org.contikios.cooja.Simulation;
import org.contikios.cooja.radiomediums.AbstractRadioMedium;
import org.contikios.cooja.mspmote.MspMoteTimeEvent;
import org.contikios.cooja.mspmote.interfaces.Msp802154Radio;
/**
* Extension of MSPSim 802.15.4 radio wrapper with bit-level errors.
*
* Only errors due to signal fading are supported (as opposed to errors to interference).
* Interesting modelling effects can obtained if this is used together with a dynamic
* channel fading model.
*
* @author Atis Elsts
*/
@ClassDescription("IEEE 802.15.4 Bit Error Radio")
public class Msp802154BitErrorRadio extends Msp802154Radio {
private static Logger logger = Logger.getLogger(Msp802154Radio.class);
private static final double NOISE_FLOOR = AbstractRadioMedium.SS_WEAK;
private static final double GOOD_SIGNAL = NOISE_FLOOR + 15.0;
private Random random = null;
public Msp802154BitErrorRadio(Mote m) {
super(m);
random = getMote().getSimulation().getRandomGenerator();
}
/* The MSK-transformed symbol-to-codeword table.
* It's used for mapping between symbols and codeword by some popular
* 802.15.4 radios such as CC2420 and CC2520. */
private static final int[] mskEncodeTable = {
1618456172,
1309113062,
1826650030,
1724778362,
778887287,
2061946375,
2007919840,
125494990,
529027475,
838370585,
320833617,
422705285,
1368596360,
85537272,
139563807,
2021988657
};
/* Calculates the Hamming distance between two words */
private int hammingDistance(int x1, int x2) {
return Integer.bitCount(x1 ^ x2);
}
/* Send a symbol over the air with a specific bit error rate */
private int transceiveSymbolWithErrors(int txSymbol, double bitErrorRate) {
/* First, transmit (encode and randomly corrupt) it */
int chipSequence = mskEncodeTable[txSymbol];
/* Note: loop until 31, not until 32 here, as the highest bit in the codeword
* is irrelevant for MSK encoded data, and therefore should not come into
* the Hamming distance calculations. */
for (int i = 0; i < 31; ++i) {
double p = random.nextDouble();
if (p < bitErrorRate) {
chipSequence ^= (1 << i);
}
}
/* Now receive (decode) it */
int bestRxSymbol = 0;
int bestHammingDistance = 32;
for (byte i = 0; i < 16; ++i) {
/* Resolve ties in a specific order:
* s7, s6, ... , s0, s15, s14 , ..., s8 */
int rxSymbol = i < 8 ? 7 - i : 15 - i + 8;
int hd = hammingDistance(chipSequence, mskEncodeTable[rxSymbol]);
if (hd < bestHammingDistance) {
bestRxSymbol = rxSymbol;
bestHammingDistance = hd;
if (hd == 0) {
break;
}
}
}
return bestRxSymbol;
}
/* This is the probability that a bit will received incorrectly, for
* -95.0, -94.9, -94.8, ..., -80.0 dBm signal levels.
* It is modelled as Additive White Gaussian Noise (AWGN) channel
* with constellation size = 4, and log2(4) = 2 bits per over-the-air symbol.
* (See "Digital Communications" by Proakis, page 311)
*
* The table was generated with the following Python code:
*
* noise_floor = -95.0
* good_signal = noise_floor + 15.0
*
* # chips per second / carrier frequency
* # In this case:
* # 250 kbps * symbols_per_bit / 5 MHz 802.15.4 channel bandwidth
* spectral_efficiency = 250000 * (32 / 4) / 5000000.
*
* def snr_from_rssi(signal):
* return signal - noise_floor
*
* def combinations(n, k):
* return math.factorial(n) / (math.factorial(k) * math.factorial(n - k))
*
* def chip_error_rate(signal):
* M_sk = 4 # constellation size
* K_b = 2 # bits per symbol
* snr = snr_from_rssi(signal) * spectral_efficiency # signal-noise ratio
* result = 0.0
* for k in range(1, M_sk):
* result += ((-1)**(k + 1) / (k + 1.0)) * combinations(M_sk - 1, k) * math.exp(- (k / (k + 1.0)) * K_b * snr)
* return result * (M_sk / 2) / (M_sk - 1)
*
* for signal in range(int(noise_floor), int(good_signal + 1)):
* for decimal_part in range(10):
* s = signal + decimal_part / 10.0
* print("{}: {:.16}".format(s, chip_error_rate(s)))
*/
private static final double[] bitErrorRateTable = {
0.5000000000000000,
0.4857075690874351,
0.4717195981917559,
0.4580362793082289,
0.4446572346573086,
0.4315815642818357,
0.4188078906959320,
0.4063344007440545,
0.3941588848209507,
0.3822787735959348,
0.3706911723779558,
0.3593928932511307,
0.3483804851041035,
0.3376502616704103,
0.3271983276911817,
0.3170206033059785,
0.3071128467721474,
0.2974706756080624,
0.2880895862507204,
0.2789649723135144,
0.2700921415256470,
0.2614663314303489,
0.2530827239151328,
0.2449364586434322,
0.2370226454533358,
0.2293363757856961,
0.2218727332005190,
0.2146268030374602,
0.2075936812732179,
0.2007684826257659,
0.1941463479526962,
0.1877224509883067,
0.1814920044616803,
0.1754502656356323,
0.1695925413041991,
0.1639141922842669,
0.1584106374348990,
0.1530773572360710,
0.1479098969566969,
0.1429038694401250,
0.1380549575336883,
0.1333589161873203,
0.1288115742448300,
0.1244088359500270,
0.1201466821885792,
0.1160211714852698,
0.1120284407751141,
0.1081647059657158,
0.1044262623071727,
0.1008094845848469,
0.0973108271493890,
0.0939268237974889,
0.0906540875160106,
0.0874893101013543,
0.0844292616651377,
0.0814707900365929,
0.0786108200713800,
0.0758463528759084,
0.0731744649556428,
0.0705923072953072,
0.0680971043783837,
0.0656861531527741,
0.0633568219490458,
0.0611065493572223,
0.0589328430676567,
0.0568332786811473,
0.0548054984930601,
0.0528472102558939,
0.0509561859243809,
0.0491302603869077,
0.0473673301867607,
0.0456653522364111,
0.0440223425278144,
0.0424363748414465,
0.0409055794565784,
0.0394281418650815,
0.0380023014908522,
0.0366263504167641,
0.0352986321208818,
0.0340175402235017,
0.0327815172464461,
0.0315890533858807,
0.0304386852998058,
0.0293289949112408,
0.0282586082280085,
0.0272261941799208,
0.0262304634740650,
0.0252701674687994,
0.0243440970669807,
0.0234510816288642,
0.0225899879050480,
0.0217597189897583,
0.0209592132947168,
0.0201874435437662,
0.0194434157883799,
0.0187261684441326,
0.0180347713481601,
0.0173683248375987,
0.0167259588489542,
0.0161068320383143,
0.0155101309222909,
0.0149350690395443,
0.0143808861327198,
0.0138468473506013,
0.0133322424702643,
0.0128363851389939,
0.0123586121357148,
0.0118982826516654,
0.0114547775900349,
0.0110274988842702,
0.0106158688347500,
0.0102193294635131,
0.0098373418867231,
0.0094693857045423,
0.0091149584080853,
0.0087735748031163,
0.0084447664501541,
0.0081280811206428,
0.0078230822688482,
0.0075293485191375,
0.0072464731683002,
0.0069740637025694,
0.0067117413290037,
0.0064591405208906,
0.0062159085768378,
0.0059817051932169,
0.0057562020496316,
0.0055390824070828,
0.0053300407185094,
0.0051287822513842,
0.0049350227220528,
0.0047484879415055,
0.0045689134722762,
0.0043960442961698,
0.0042296344925230,
0.0040694469267080,
0.0039152529485966,
0.0037668321007033,
0.0036239718357372,
0.0034864672432910,
0.0033541207854084,
0.0032267420407699,
0.0031041474572487,
0.0029861601125883,
0.0028726094829638,
0.0027633312191911,
0.0026581669303560,
0.0025569639746388,
0.0024595752571165,
0.0023658590343307,
0.0022756787254125
};
private double getBitErrorRate(double signal) {
if (signal <= NOISE_FLOOR) {
return 0.5;
} else if (signal >= GOOD_SIGNAL) {
return 0.0;
} else {
long position = Math.round((signal - NOISE_FLOOR) * 10.0);
return bitErrorRateTable[(int)position];
}
}
public void receiveCustomData(Object data) {
if (!(data instanceof Byte)) {
logger.fatal("Bad custom data: " + data);
return;
}
lastIncomingByte = (Byte) data;
final byte inputByte;
if (isInterfered()) {
inputByte = (byte)0xFF;
} else {
double bitErrorRate = getBitErrorRate(currentSignalStrength);
if (bitErrorRate == 0.0) {
inputByte = lastIncomingByte;
} else if (bitErrorRate >= 0.5) {
inputByte = (byte) 0xFF;
} else {
/* convert to an unsigned int in order to prettify subsequent operations with bits */
int incomingByteAsInt = lastIncomingByte;
if (incomingByteAsInt < 0) incomingByteAsInt += 256;
/* a byte consists of 2 symbols; independently transceive each of them */
int firstSymbol = transceiveSymbolWithErrors(incomingByteAsInt >> 4, bitErrorRate);
int secondSymbol = transceiveSymbolWithErrors(incomingByteAsInt & 0xf, bitErrorRate);
inputByte = (byte)((firstSymbol << 4) + secondSymbol);
}
}
mote.getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) {
public void execute(long t) {
super.execute(t);
radio.receivedByte(inputByte);
mote.requestImmediateWakeup();
}
}, mote.getSimulation().getSimulationTime());
}
}

View File

@ -69,16 +69,16 @@ public class Msp802154Radio extends Radio implements CustomDataRadio {
private RadioEvent lastEvent = RadioEvent.UNKNOWN;
private final MspMote mote;
private final Radio802154 radio;
protected final MspMote mote;
protected final Radio802154 radio;
private boolean isInterfered = false;
private boolean isTransmitting = false;
private boolean isReceiving = false;
private boolean isSynchronized = false;
private byte lastOutgoingByte;
private byte lastIncomingByte;
protected byte lastOutgoingByte;
protected byte lastIncomingByte;
private RadioPacket lastOutgoingPacket = null;
private RadioPacket lastIncomingPacket = null;