diff --git a/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java b/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java
index 4024af655..b90d6de0e 100644
--- a/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java
+++ b/tools/cooja/apps/mrm/java/se/sics/mrm/AreaViewer.java
@@ -696,7 +696,7 @@ public class AreaViewer extends VisPlugin {
String logHtml =
"" +
- trackedComponents.log.replace("\n", "
") +
+ trackedComponents.log.replace("\n", "
").replace(" pi", " π") +
"";
t.setTipText(logHtml);
diff --git a/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java b/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java
index ee564dad9..0babcf6e2 100644
--- a/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java
+++ b/tools/cooja/apps/mrm/java/se/sics/mrm/ChannelModel.java
@@ -1327,11 +1327,14 @@ public class ChannelModel {
* the random variable mean, and the second is the variance.
*/
public double[] getReceivedSignalStrength(double sourceX, double sourceY, double destX, double destY) {
- return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH);
+ return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH, null);
}
-
+ public double[] getReceivedSignalStrength(double sourceX, double sourceY, double destX, double destY, Double txPower) {
+ return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH, txPower);
+ }
+
// TODO Fix better data type support
- private double[] getTransmissionData(double sourceX, double sourceY, double destX, double destY, TransmissionData dataType) {
+ private double[] getTransmissionData(double sourceX, double sourceY, double destX, double destY, TransmissionData dataType, Double txPower) {
Point2D source = new Point2D.Double(sourceX, sourceY);
Point2D dest = new Point2D.Double(destX, destY);
double accumulatedVariance = 0;
@@ -1515,7 +1518,12 @@ public class ChannelModel {
// Using formula (dB)
// Received power = Output power + System gain + Transmitter gain + Path Loss + Receiver gain
// TODO Update formulas
- double outputPower = getParameterDoubleValue("tx_power");
+ double outputPower;
+ if (txPower == null) {
+ outputPower = getParameterDoubleValue("tx_power");
+ } else {
+ outputPower = txPower;
+ }
double systemGain = getParameterDoubleValue("system_gain_mean");
if (getParameterBooleanValue("apply_random")) {
Random random = new Random(); /* TODO Use main random generator? */
@@ -1579,19 +1587,19 @@ public class ChannelModel {
* variable. This method uses current parameters such as transmitted power,
* obstacles, overall system loss etc.
*
- * @param sourceX
- * Source position X
- * @param sourceY
- * Source position Y
- * @param destX
- * Destination position X
- * @param destY
- * Destination position Y
- * @return Received SNR (dB) random variable. The first value is the random
- * variable mean, and the second is the variance. The third value is the received signal strength which may be used in comparison with interference etc.
+ * @param sourceX Source position X
+ * @param sourceY Source position Y
+ * @param destX Destination position X
+ * @param destY Destination position Y
+ * @return Received SNR (dB) random variable:
+ * The first value in the array is the random variable mean.
+ * The second is the variance.
+ * The third value is the received signal strength which may be used in comparison with interference etc.
*/
public double[] getSINR(double sourceX, double sourceY, double destX, double destY, double interference) {
-
+ /* TODO Cache values: called repeatedly with noise sources. */
+
+
// Calculate received signal strength
double[] signalStrength = getReceivedSignalStrength(sourceX, sourceY, destX, destY);
@@ -1619,27 +1627,26 @@ public class ChannelModel {
snrData[1] += noiseVariance;
if (logMode) {
- logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " (variance " + snrData[1] + ")\n");
+ logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " dB (variance " + snrData[1] + ")\n");
}
return snrData;
}
/**
- * Calculates and returns probability that a receiver at given destination receives a packet from a transmitter at given source.
+ * Calculates probability that a receiver at given destination receives
+ * a packet from a transmitter at given source.
* This method uses current parameters such as transmitted power,
- * obstacles, overall system loss, packet size etc. TODO Packet size?! TODO Interfering signal strength
+ * obstacles, overall system loss, packet size etc.
+ *
+ * TODO Packet size
+ * TODO External interference/Background noise
*
- * @param sourceX
- * Source position X
- * @param sourceY
- * Source position Y
- * @param destX
- * Destination position X
- * @param destY
- * Destination position Y
- * @param interference
- * Current interference at destination (dBm)
+ * @param sourceX Source position X
+ * @param sourceY Source position Y
+ * @param destX Destination position X
+ * @param destY Destination position Y
+ * @param interference Current interference at destination (dBm)
* @return [Probability of reception, signal strength at destination]
*/
public double[] getProbability(double sourceX, double sourceY, double destX, double destY, double interference) {
@@ -1675,11 +1682,9 @@ public class ChannelModel {
// current threshold.
// (Using error algorithm method, much faster than taylor approximation!)
- double probReception = 1 - GaussianWrapper.cdfErrorAlgo(
- threshold, snrMean, snrStdDev);
+ double probReception = 1 - GaussianWrapper.cdfErrorAlgo(threshold, snrMean, snrStdDev);
if (logMode) {
- logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " (variance " + snrData[1] + ")\n");
logInfo.append("Reception probability: " + String.format("%1.1f%%", 100*probReception) + "\n");
}
@@ -1703,7 +1708,7 @@ public class ChannelModel {
* @return RMS delay spread
*/
public double getRMSDelaySpread(double sourceX, double sourceY, double destX, double destY) {
- return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.DELAY_SPREAD)[1];
+ return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.DELAY_SPREAD, null)[1];
}
/**
diff --git a/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java b/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java
index e44264579..383562221 100644
--- a/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java
+++ b/tools/cooja/apps/mrm/java/se/sics/mrm/MRM.java
@@ -43,13 +43,14 @@ import org.jdom.Element;
import se.sics.cooja.ClassDescription;
import se.sics.cooja.RadioConnection;
import se.sics.cooja.Simulation;
+import se.sics.cooja.interfaces.NoiseSourceRadio;
+import se.sics.cooja.interfaces.NoiseSourceRadio.NoiseLevelListener;
import se.sics.cooja.interfaces.Position;
import se.sics.cooja.interfaces.Radio;
import se.sics.cooja.radiomediums.AbstractRadioMedium;
/**
- * This is the main class of the COOJA Multi-path Ray-tracing Medium (MRM)
- * package.
+ * Multi-path Ray-tracing radio medium (MRM).
*
* MRM is an alternative to the simpler radio mediums available in
* COOJA. It is packet based and uses a 2D ray-tracing approach to approximate
@@ -57,22 +58,27 @@ import se.sics.cooja.radiomediums.AbstractRadioMedium;
* ray-tracing only supports reflections and refractions through homogeneous
* obstacles.
*
- * MRM registers two plugins: a plugin for visualizing the radio
- * environments, and a plugin for configuring the radio medium parameters.
+ * MRM provides two plugins: one for visualizing the radio environment,
+ * and one for configuring the radio medium parameters.
*
* Future work includes adding support for diffraction and scattering.
*
+ * MRM supports noise source radios.
+ *
+ * @see NoiseSourceRadio
* @author Fredrik Osterlind
*/
@ClassDescription("Multi-path Ray-tracer Medium (MRM)")
public class MRM extends AbstractRadioMedium {
private static Logger logger = Logger.getLogger(MRM.class);
- private ChannelModel currentChannelModel = null;
-
- private Random random = null;
+ public final static boolean WITH_NOISE = true; /* NoiseSourceRadio:s */
+ public final static boolean WITH_CAPTURE_EFFECT = true;
private Simulation sim;
+ private Random random = null;
+ private ChannelModel currentChannelModel = null;
+
/**
* Notifies observers when this radio medium has changed settings.
*/
@@ -83,11 +89,9 @@ public class MRM extends AbstractRadioMedium {
*/
public MRM(Simulation simulation) {
super(simulation);
- sim = simulation;
-
- random = simulation.getRandomGenerator();
- // Create the channel model
+ sim = simulation;
+ random = simulation.getRandomGenerator();
currentChannelModel = new ChannelModel();
/* Register plugins */
@@ -95,6 +99,26 @@ public class MRM extends AbstractRadioMedium {
sim.getGUI().registerPlugin(FormulaViewer.class);
}
+ private NoiseLevelListener noiseListener = new NoiseLevelListener() {
+ public void noiseLevelChanged(NoiseSourceRadio radio, int signal) {
+ updateSignalStrengths();
+ };
+ };
+ public void registerRadioInterface(Radio radio, Simulation sim) {
+ super.registerRadioInterface(radio, sim);
+
+ if (radio instanceof NoiseSourceRadio) {
+ ((NoiseSourceRadio)radio).addNoiseLevelListener(noiseListener);
+ }
+ }
+ public void unregisterRadioInterface(Radio radio, Simulation sim) {
+ super.unregisterRadioInterface(radio, sim);
+
+ if (radio instanceof NoiseSourceRadio) {
+ ((NoiseSourceRadio)radio).removeNoiseLevelListener(noiseListener);
+ }
+ }
+
public void removed() {
super.removed();
@@ -103,90 +127,82 @@ public class MRM extends AbstractRadioMedium {
sim.getGUI().unregisterPlugin(FormulaViewer.class);
}
- public MRMRadioConnection createConnections(Radio sendingRadio) {
- Position sendingPosition = sendingRadio.getPosition();
- MRMRadioConnection newConnection = new MRMRadioConnection(sendingRadio);
+ public MRMRadioConnection createConnections(Radio sender) {
+ MRMRadioConnection newConnection = new MRMRadioConnection(sender);
+ Position senderPos = sender.getPosition();
- // Loop through all radios
- for (Radio listeningRadio: getRegisteredRadios()) {
- // Ignore sending radio and radios on different channels
- if (sendingRadio == listeningRadio) {
- continue;
- }
- if (sendingRadio.getChannel() >= 0 &&
- listeningRadio.getChannel() >= 0 &&
- sendingRadio.getChannel() != listeningRadio.getChannel()) {
+ /* TODO Cache potential destination in DGRM */
+ /* Loop through all potential destinations */
+ for (Radio recv: getRegisteredRadios()) {
+ if (sender == recv) {
continue;
}
- /* TODO Use DGRM to cache link information.
- * (No need to loop over all receivers) */
-
- double listeningPositionX = listeningRadio.getPosition().getXCoordinate();
- double listeningPositionY = listeningRadio.getPosition().getYCoordinate();
+ /* Fail if radios are on different (but configured) channels */
+ if (sender.getChannel() >= 0 &&
+ recv.getChannel() >= 0 &&
+ sender.getChannel() != recv.getChannel()) {
+ continue;
+ }
+ Position recvPos = recv.getPosition();
- // Calculate probability of reception of listening radio
+ /* Calculate receive probability */
double[] probData = currentChannelModel.getProbability(
- sendingPosition.getXCoordinate(),
- sendingPosition.getYCoordinate(),
- listeningPositionX,
- listeningPositionY,
- -Double.MAX_VALUE
+ senderPos.getXCoordinate(),
+ senderPos.getYCoordinate(),
+ recvPos.getXCoordinate(),
+ recvPos.getYCoordinate(),
+ -Double.MAX_VALUE /* TODO Include interference */
);
- //logger.info("Probability of reception is " + probData[0]);
- //logger.info("Signal strength at destination is " + probData[1]);
- if (random.nextFloat() < probData[0]) {
- // Check if this radio is able to receive transmission
- if (listeningRadio.isInterfered()) {
- // Keep interfering radio
- newConnection.addInterfered(listeningRadio, probData[1]);
+ double recvProb = probData[0];
+ double recvSignalStrength = probData[1];
+ if (recvProb == 1.0 || random.nextDouble() < recvProb) {
+ /* Yes, the receiver *may* receive this packet (it's strong enough) */
+ if (!recv.isReceiverOn()) {
+ newConnection.addInterfered(recv);
+ recv.interfereAnyReception();
+ } else if (recv.isInterfered()) {
+ /* Was interfered: keep interfering */
+ newConnection.addInterfered(recv, recvSignalStrength);
+ } else if (recv.isTransmitting()) {
+ newConnection.addInterfered(recv, recvSignalStrength);
+ } else if (recv.isReceiving()) {
+ /* Was already receiving: start interfering.
+ * Assuming no continuous preambles checking */
+
+ double currSignal = recv.getCurrentSignalStrength();
+ /* Capture effect: recv-radio is already receiving.
+ * Are we strong enough to interfere? */
+ if (WITH_CAPTURE_EFFECT &&
+ recvSignalStrength < currSignal - 3 /* config */) {
+ /* No, we are too weak */
+ } else {
+ newConnection.addInterfered(recv, recvSignalStrength);
+ recv.interfereAnyReception();
- } else if (listeningRadio.isReceiving()) {
- newConnection.addInterfered(listeningRadio, probData[1]);
-
- // Start interfering radio
- listeningRadio.interfereAnyReception();
-
- // Update connection that is transmitting to this radio
- MRMRadioConnection existingConn = null;
- for (RadioConnection conn : getActiveConnections()) {
- for (Radio dstRadio : ((MRMRadioConnection) conn).getDestinations()) {
- if (dstRadio == listeningRadio) {
- existingConn = (MRMRadioConnection) conn;
- break;
+ /* Interfere receiver in all other active radio connections */
+ for (RadioConnection conn : getActiveConnections()) {
+ if (conn.isDestination(recv)) {
+ conn.addInterfered(recv);
}
}
- }
- if (existingConn != null) {
- /* Flag radio as interfered */
- existingConn.addInterfered(listeningRadio);
- listeningRadio.interfereAnyReception();
- }
+ }
+
} else {
- // Radio OK to receive
- //logger.info("OK, creating connection and starting to transmit");
- newConnection.addDestination(listeningRadio, probData[1]);
+ /* Success: radio starts receiving */
+ newConnection.addDestination(recv, recvSignalStrength);
}
- } else if (probData[1] > currentChannelModel.getParameterDoubleValue("bg_noise_mean")) {
- // Interfere radio
- newConnection.addInterfered(listeningRadio, probData[1]);
- listeningRadio.interfereAnyReception();
-
- // TODO Radios always get interfered right now, should recalculate probability
-// if (maxInterferenceSignalStrength + SOME_RELEVANT_LIMIT > transmissionSignalStrength) {
-// // Recalculating probability of delivery
-// double[] probData = currentChannelModel.getProbability(
-// mySource.source.position.getXCoordinate(),
-// mySource.source.position.getYCoordinate(),
-// myDestination.position.getXCoordinate(),
-// myDestination.position.getYCoordinate(),
-// maxInterferenceSignalStrength);
-//
-// if (new Random().nextFloat() >= probData[0]) {
-// return true;
-// }
+ } else if (recvSignalStrength > currentChannelModel.getParameterDoubleValue("bg_noise_mean")) {
+ /* The incoming signal is strong, but strong enough to interfere? */
+ if (!WITH_CAPTURE_EFFECT) {
+ newConnection.addInterfered(recv, recvSignalStrength);
+ recv.interfereAnyReception();
+ } else {
+ /* TODO Implement new type: newConnection.addNoise()?
+ * Currently, this connection will never disturb this radio... */
+ }
}
}
@@ -195,57 +211,92 @@ public class MRM extends AbstractRadioMedium {
}
public void updateSignalStrengths() {
- // // Save old signal strengths
- // double[] oldSignalStrengths = new double[registeredRadios.size()];
- // for (int i = 0; i < registeredRadios.size(); i++) {
- // oldSignalStrengths[i] = registeredRadios.get(i)
- // .getCurrentSignalStrength();
- // }
- // Reset signal strength on all radios
+ /* Reset: Background noise */
+ double background =
+ currentChannelModel.getParameterDoubleValue(("bg_noise_mean"));
for (Radio radio : getRegisteredRadios()) {
- radio.setCurrentSignalStrength(currentChannelModel.getParameterDoubleValue(("bg_noise_mean")));
+ radio.setCurrentSignalStrength(background);
}
- // Set signal strength on all OK transmissions
- for (RadioConnection conn : getActiveConnections()) {
-// ((MRMRadioConnection) conn).getSource().setCurrentSignalStrength(12345); // TODO Set signal strength on source?
+ /* Active radio connections */
+ RadioConnection[] conns = getActiveConnections();
+ for (RadioConnection conn : conns) {
for (Radio dstRadio : ((MRMRadioConnection) conn).getDestinations()) {
double signalStrength = ((MRMRadioConnection) conn).getDestinationSignalStrength(dstRadio);
- if (signalStrength > dstRadio.getCurrentSignalStrength()) {
+ if (dstRadio.getCurrentSignalStrength() < signalStrength) {
dstRadio.setCurrentSignalStrength(signalStrength);
}
}
}
- // Set signal strength on all interferences
- for (RadioConnection conn : getActiveConnections()) {
- for (Radio interferedRadio : ((MRMRadioConnection) conn).getInterfered()) {
- double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(interferedRadio);
- if (signalStrength > interferedRadio.getCurrentSignalStrength()) {
- interferedRadio.setCurrentSignalStrength(signalStrength);
+ /* Interfering/colliding radio connections */
+ for (RadioConnection conn : conns) {
+ for (Radio intfRadio : ((MRMRadioConnection) conn).getInterfered()) {
+ double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(intfRadio);
+ if (intfRadio.getCurrentSignalStrength() < signalStrength) {
+ intfRadio.setCurrentSignalStrength(signalStrength);
}
- if (!interferedRadio.isInterfered()) {
- // Set to interfered again
- interferedRadio.interfereAnyReception();
+ if (!intfRadio.isInterfered()) {
+ /*logger.warn("Radio was not interfered: " + intfRadio);*/
+ intfRadio.interfereAnyReception();
}
}
}
- // // Fetch new signal strengths
- // double[] newSignalStrengths = new double[registeredRadios.size()];
- // for (int i = 0; i < registeredRadios.size(); i++) {
- // newSignalStrengths[i] = registeredRadios.get(i)
- // .getCurrentSignalStrength();
- // }
- //
- // // Compare new and old signal strengths
- // for (int i = 0; i < registeredRadios.size(); i++) {
- // if (oldSignalStrengths[i] != newSignalStrengths[i])
- // logger.warn("Signal strengths changed on radio[" + i + "]: "
- // + oldSignalStrengths[i] + " -> " + newSignalStrengths[i]);
- // }
+ /* Check for noise sources */
+ if (!WITH_NOISE) return;
+ for (Radio noiseRadio: getRegisteredRadios()) {
+ if (!(noiseRadio instanceof NoiseSourceRadio)) {
+ continue;
+ }
+ NoiseSourceRadio radio = (NoiseSourceRadio) noiseRadio;
+ int signalStrength = radio.getNoiseLevel();
+ if (signalStrength == Integer.MIN_VALUE) {
+ continue;
+ }
+
+ /* Calculate how noise source affects surrounding radios */
+ for (Radio affectedRadio : getRegisteredRadios()) {
+ if (noiseRadio == affectedRadio) {
+ continue;
+ }
+
+ /* Update noise levels */
+ double[] signalMeanVar = currentChannelModel.getReceivedSignalStrength(
+ noiseRadio.getPosition().getXCoordinate(),
+ noiseRadio.getPosition().getYCoordinate(),
+ affectedRadio.getPosition().getXCoordinate(),
+ affectedRadio.getPosition().getYCoordinate(),
+ (double) signalStrength); /* TODO Convert to dBm */
+ double signal = signalMeanVar[0];
+ if (signal < background) {
+ continue;
+ }
+
+ /* TODO Additive signals strengths? */
+ /* TODO XXX Consider radio channels */
+ /* TODO XXX Potentially interfere even when signal is weaker (~3dB)...
+ * (we may alternatively just use the getSINR method...) */
+ if (affectedRadio.getCurrentSignalStrength() < signal) {
+ affectedRadio.setCurrentSignalStrength(signal);
+
+ /* TODO Interfere with radio connections? */
+ if (affectedRadio.isReceiving() && !affectedRadio.isInterfered()) {
+ for (RadioConnection conn : conns) {
+ if (conn.isDestination(affectedRadio)) {
+ /* Intefere with current reception, mark radio as interfered */
+ conn.addInterfered(affectedRadio);
+ if (!affectedRadio.isInterfered()) {
+ affectedRadio.interfereAnyReception();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
public Collection getConfigXML() {
@@ -279,20 +330,11 @@ public class MRM extends AbstractRadioMedium {
settingsObservable.deleteObserver(obs);
}
- /**
- * Returns position of given radio.
- *
- * @param radio Registered radio
- * @return Position of given radio
- */
- public Position getRadioPosition(Radio radio) {
- return radio.getPosition();
- }
-
/**
* @return Number of registered radios.
*/
public int getRegisteredRadioCount() {
+ /* TODO Expensive operation */
return getRegisteredRadios().length;
}