* bugfixed and rewrote MRM to improve configurability

* improved MRM GUI, including MRM visualizer skin that shows prr and rss
* added experimental support for directional antennas
This commit is contained in:
Fredrik Osterlind 2011-11-01 11:37:19 +01:00
parent 77057ede8a
commit eb84fbeb79
6 changed files with 1126 additions and 622 deletions

View file

@ -63,14 +63,16 @@ import java.io.File;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
@ -99,11 +101,12 @@ import org.jdom.Element;
import se.sics.cooja.ClassDescription;
import se.sics.cooja.GUI;
import se.sics.cooja.PluginType;
import se.sics.cooja.RadioConnection;
import se.sics.cooja.Simulation;
import se.sics.cooja.VisPlugin;
import se.sics.cooja.interfaces.DirectionalAntennaRadio;
import se.sics.cooja.interfaces.Position;
import se.sics.cooja.interfaces.Radio;
import se.sics.mrm.ChannelModel.TxPair;
/**
* The class AreaViewer belongs to the MRM package.
@ -118,14 +121,13 @@ import se.sics.cooja.interfaces.Radio;
* @see MRM
* @author Fredrik Osterlind
*/
@ClassDescription("MRM - Area Viewer")
@ClassDescription("MRM Radio environment")
@PluginType(PluginType.SIM_PLUGIN)
public class AreaViewer extends VisPlugin {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(AreaViewer.class);
private final JPanel canvas;
private final VisPlugin thisPlugin;
ChannelModel.TransmissionData dataTypeToVisualize = ChannelModel.TransmissionData.SIGNAL_STRENGTH;
ButtonGroup visTypeSelectionGroup;
@ -144,7 +146,7 @@ public class AreaViewer extends VisPlugin {
private boolean drawCalculatedObstacles = true;
private boolean drawChannelProbabilities = true;
private boolean drawRadios = true;
private boolean drawRadioActivity = true;
//private boolean drawRadioActivity = true;
private boolean drawScaleArrow = true;
// Background drawing parameters (meters)
@ -171,7 +173,7 @@ public class AreaViewer extends VisPlugin {
private Image channelImage = null;
private JSlider resolutionSlider;
private JPanel controlPanel;
private Box controlPanel;
private JScrollPane scrollControlPanel;
private Simulation currentSimulation;
@ -200,20 +202,25 @@ public class AreaViewer extends VisPlugin {
private JCheckBox obstaclesCheckBox;
private JCheckBox channelCheckBox;
private JCheckBox radiosCheckBox;
private JCheckBox radioActivityCheckBox;
// private JCheckBox radioActivityCheckBox;
private JCheckBox arrowCheckBox;
private JRadioButton noneButton = null;
private JRadioButton selectModeButton;
private JRadioButton panModeButton;
private JRadioButton zoomModeButton;
private JRadioButton trackModeButton;
private Action paintEnvironmentAction;
/**
* Initializes an AreaViewer.
*
* @param simulationToVisualize Simulation using MRM
*/
public AreaViewer(Simulation simulationToVisualize, GUI gui) {
super("MRM - Area Viewer", gui);
super("MRM Radio environment", gui);
currentSimulation = simulationToVisualize;
currentRadioMedium = (MRM) currentSimulation.getRadioMedium();
@ -227,7 +234,6 @@ public class AreaViewer extends VisPlugin {
// Set initial size etc.
setSize(500, 500);
setVisible(true);
thisPlugin = this;
// Canvas mode radio buttons + show settings checkbox
showSettingsBox = new JCheckBox ("settings", true);
@ -236,20 +242,20 @@ public class AreaViewer extends VisPlugin {
showSettingsBox.setActionCommand("toggle show settings");
showSettingsBox.addActionListener(canvasModeHandler);
JRadioButton selectModeButton = new JRadioButton ("select");
selectModeButton = new JRadioButton ("select");
selectModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
selectModeButton.setContentAreaFilled(false);
selectModeButton.setActionCommand("set select mode");
selectModeButton.addActionListener(canvasModeHandler);
selectModeButton.setSelected(true);
JRadioButton panModeButton = new JRadioButton ("pan");
panModeButton = new JRadioButton ("pan");
panModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
panModeButton.setContentAreaFilled(false);
panModeButton.setActionCommand("set pan mode");
panModeButton.addActionListener(canvasModeHandler);
JRadioButton zoomModeButton = new JRadioButton ("zoom");
zoomModeButton = new JRadioButton ("zoom");
zoomModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
zoomModeButton.setContentAreaFilled(false);
zoomModeButton.setActionCommand("set zoom mode");
@ -322,10 +328,10 @@ public class AreaViewer extends VisPlugin {
radiosCheckBox.addActionListener(selectGraphicsHandler);
graphicsComponentsPanel.add(radiosCheckBox);
radioActivityCheckBox = new JCheckBox("Radio Activity", true);
radioActivityCheckBox.setActionCommand("toggle radio activity");
radioActivityCheckBox.addActionListener(selectGraphicsHandler);
graphicsComponentsPanel.add(radioActivityCheckBox);
// radioActivityCheckBox = new JCheckBox("Radio Activity", true);
// radioActivityCheckBox.setActionCommand("toggle radio activity");
// radioActivityCheckBox.addActionListener(selectGraphicsHandler);
// graphicsComponentsPanel.add(radioActivityCheckBox);
arrowCheckBox = new JCheckBox("Scale arrow", true);
arrowCheckBox.setActionCommand("toggle arrow");
@ -366,8 +372,7 @@ public class AreaViewer extends VisPlugin {
graphicsComponentsPanel.add(customButton);
// Create visualize channel output panel
JPanel visualizeChannelPanel = new JPanel();
visualizeChannelPanel.setLayout(new BoxLayout(visualizeChannelPanel, BoxLayout.Y_AXIS));
Box visualizeChannelPanel = Box.createVerticalBox();
visualizeChannelPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
visualizeChannelPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
@ -400,6 +405,8 @@ public class AreaViewer extends VisPlugin {
visualizeChannelPanel.add(fixedVsRelative);
coloringIntervalPanel = new JPanel() {
private static final long serialVersionUID = 8247374386307237940L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
@ -572,20 +579,22 @@ public class AreaViewer extends VisPlugin {
visualizeChannelPanel.add(Box.createRigidArea(new Dimension(0,20)));
JButton recalculateVisibleButton = new JButton("Paint radio channel");
recalculateVisibleButton.setActionCommand("recalculate visible area");
recalculateVisibleButton.addActionListener(formulaHandler);
paintEnvironmentAction = new AbstractAction("Paint radio channel") {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
repaintRadioEnvironment();
}
};
paintEnvironmentAction.setEnabled(false);
recalculateVisibleButton.setAction(paintEnvironmentAction);
visualizeChannelPanel.add(recalculateVisibleButton);
// Create control panel
controlPanel = new JPanel();
controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
controlPanel = Box.createVerticalBox();
graphicsComponentsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
controlPanel.add(graphicsComponentsPanel);
controlPanel.add(new JSeparator());
controlPanel.add(Box.createRigidArea(new Dimension(0, 5)));
visualizeChannelPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
controlPanel.add(visualizeChannelPanel);
controlPanel.setPreferredSize(new Dimension(250,700));
controlPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
scrollControlPanel = new JScrollPane(
controlPanel,
@ -627,15 +636,47 @@ public class AreaViewer extends VisPlugin {
*/
private MouseAdapter canvasMouseHandler = new MouseAdapter() {
private Popup popUpToolTip = null;
private boolean temporaryZoom = false;
private boolean temporaryPan = false;
private boolean trackedPreviously = false;
public void mouseReleased(MouseEvent e) {
if (temporaryZoom) {
temporaryZoom = false;
if (trackedPreviously) {
trackModeButton.doClick();
} else {
selectModeButton.doClick();
}
}
if (temporaryPan) {
temporaryPan = false;
if (trackedPreviously) {
trackModeButton.doClick();
} else {
selectModeButton.doClick();
}
}
if (popUpToolTip != null) {
popUpToolTip.hide();
popUpToolTip = null;
}
}
public void mousePressed(MouseEvent e) {
public void mousePressed(final MouseEvent e) {
if (e.isControlDown()) {
temporaryZoom = true;
trackedPreviously = inTrackMode;
zoomModeButton.doClick();
}
if (e.isAltDown()) {
temporaryPan = true;
trackedPreviously = inTrackMode;
panModeButton.doClick();
//canvasModeHandler.actionPerformed(new ActionEvent(e, 0, "set zoom mode"));
}
if (popUpToolTip != null) {
popUpToolTip.hide();
popUpToolTip = null;
@ -646,32 +687,40 @@ public class AreaViewer extends VisPlugin {
zoomCenterX = e.getX() / currentZoomX - currentPanX;
zoomCenterY = e.getY() / currentZoomY - currentPanY;
zoomCenterPoint = e.getPoint();
if (temporaryZoom || temporaryPan) {
e.consume();
return;
}
/* Select */
if (inSelectMode) {
Vector<Radio> hitRadios = trackClickedRadio(e.getPoint());
ArrayList<Radio> hitRadios = trackClickedRadio(e.getPoint());
if (hitRadios == null || hitRadios.size() == 0) {
if (e.getButton() != MouseEvent.BUTTON1) {
selectedRadio = null;
channelImage = null;
trackModeButton.setEnabled(false);
paintEnvironmentAction.setEnabled(false);
canvas.repaint();
}
return;
}
if (hitRadios.size() == 1 && hitRadios.firstElement() == selectedRadio) {
if (hitRadios.size() == 1 && hitRadios.get(0) == selectedRadio) {
return;
}
if (selectedRadio == null || !hitRadios.contains(selectedRadio)) {
selectedRadio = hitRadios.firstElement();
selectedRadio = hitRadios.get(0);
trackModeButton.setEnabled(true);
paintEnvironmentAction.setEnabled(true);
} else {
selectedRadio = hitRadios.get(
(hitRadios.indexOf(selectedRadio)+1) % hitRadios.size()
);
trackModeButton.setEnabled(true);
paintEnvironmentAction.setEnabled(true);
}
channelImage = null;
@ -681,30 +730,42 @@ public class AreaViewer extends VisPlugin {
/* Track */
if (inTrackMode && selectedRadio != null) {
double realClickedX = e.getX() / currentZoomX - currentPanX;
double realClickedY = e.getY() / currentZoomY - currentPanY;
Position radioPosition = selectedRadio.getPosition();
final double radioX = radioPosition.getXCoordinate();
final double radioY = radioPosition.getYCoordinate();
trackedComponents = currentChannelModel.getRaysOfTransmission(radioX, radioY, realClickedX, realClickedY);
TxPair txPair = new TxPair() {
public double getFromX() { return selectedRadio.getPosition().getXCoordinate(); }
public double getFromY() { return selectedRadio.getPosition().getYCoordinate(); }
public double getToX() { return e.getX() / currentZoomX - currentPanX; }
public double getToY() { return e.getY() / currentZoomY - currentPanY; }
public double getTxPower() { return selectedRadio.getCurrentOutputPower(); }
public double getTxGain() {
if (!(selectedRadio instanceof DirectionalAntennaRadio)) {
return 0;
}
DirectionalAntennaRadio r = (DirectionalAntennaRadio)selectedRadio;
double txGain = r.getRelativeGain(r.getDirection() + getAngle(), getDistance());
//logger.debug("tx gain: " + txGain + " (angle " + String.format("%1.1f", Math.toDegrees(r.getDirection() + getAngle())) + ")");
return txGain;
}
public double getRxGain() {
return 0;
}
};
trackedComponents = currentChannelModel.getRaysOfTransmission(txPair);
canvas.repaint();
/* Show popup */
JToolTip t = AreaViewer.this.createToolTip();
String logHtml =
"<html>" +
trackedComponents.log.replace("\n", "<br>").replace(" pi", " &pi;") +
"</html>";
"<html>" +
trackedComponents.log.replace("\n", "<br>").replace(" pi", " &pi;") +
"</html>";
t.setTipText(logHtml);
if (t.getTipText() == null || t.getTipText().equals("")) {
return;
}
popUpToolTip = PopupFactory.getSharedInstance().getPopup(
AreaViewer.this, t, e.getXOnScreen(), e.getYOnScreen());
AreaViewer.this, t, e.getXOnScreen(), e.getYOnScreen());
popUpToolTip.show();
}
}
@ -806,9 +867,8 @@ public class AreaViewer extends VisPlugin {
} else {
scrollControlPanel.setVisible(false);
}
thisPlugin.invalidate();
thisPlugin.revalidate();
AreaViewer.this.invalidate();
AreaViewer.this.revalidate();
}
}
};
@ -826,8 +886,8 @@ public class AreaViewer extends VisPlugin {
drawChannelProbabilities = ((JCheckBox) e.getSource()).isSelected();
} else if (e.getActionCommand().equals("toggle radios")) {
drawRadios = ((JCheckBox) e.getSource()).isSelected();
} else if (e.getActionCommand().equals("toggle radio activity")) {
drawRadioActivity = ((JCheckBox) e.getSource()).isSelected();
// } else if (e.getActionCommand().equals("toggle radio activity")) {
// drawRadioActivity = ((JCheckBox) e.getSource()).isSelected();
} else if (e.getActionCommand().equals("toggle arrow")) {
drawScaleArrow = ((JCheckBox) e.getSource()).isSelected();
}
@ -871,6 +931,7 @@ public class AreaViewer extends VisPlugin {
}
class ImageSettingsDialog extends JDialog {
private static final long serialVersionUID = 3026474554976919518L;
private double
virtualStartX = 0.0,
@ -1205,7 +1266,7 @@ public class AreaViewer extends VisPlugin {
}
currentChannelModel.notifySettingsChanged();
thisPlugin.repaint();
AreaViewer.this.repaint();
} catch (Exception ex) {
if (pm.isCanceled()) {
@ -1230,6 +1291,8 @@ public class AreaViewer extends VisPlugin {
};
class ObstacleFinderDialog extends JDialog {
private static final long serialVersionUID = -8963997923536967296L;
private NumberFormat intFormat = NumberFormat.getIntegerInstance();
private BufferedImage imageToAnalyze = null;
private BufferedImage obstacleImage = null;
@ -1449,6 +1512,7 @@ public class AreaViewer extends VisPlugin {
// Preview image
tempPanel = new JPanel() {
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(imageToAnalyze, 0, 0, getWidth(), getHeight(), this);
@ -1609,6 +1673,7 @@ public class AreaViewer extends VisPlugin {
selectedRadio = null;
channelImage = null;
trackModeButton.setEnabled(false);
paintEnvironmentAction.setEnabled(false);
canvas.repaint();
}
};
@ -1675,13 +1740,7 @@ public class AreaViewer extends VisPlugin {
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
/**
* Helps user adjust and calculate the channel propagation formula
*/
private ActionListener formulaHandler = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("recalculate visible area")) {
private void repaintRadioEnvironment() {
// Get resolution of new image
final Dimension resolution = new Dimension(
resolutionSlider.getValue(),
@ -1734,15 +1793,36 @@ public class AreaViewer extends VisPlugin {
double[][] imageValues = new double[resolution.width][resolution.height];
for (int x=0; x < resolution.width; x++) {
for (int y=0; y < resolution.height; y++) {
final double xx = x;
final double yy = y;
TxPair txPair = new TxPair() {
public double getDistance() {
double w = getFromX() - getToX();
double h = getFromY() - getToY();
return Math.sqrt(w*w+h*h);
}
public double getFromX() { return radioX; }
public double getFromY() { return radioY; }
public double getToX() { return startX + width * xx/resolution.width; }
public double getToY() { return startY + height * yy/resolution.height; }
public double getTxPower() { return selectedRadio.getCurrentOutputPower(); }
public double getTxGain() {
if (!(selectedRadio instanceof DirectionalAntennaRadio)) {
return 0;
}
DirectionalAntennaRadio r = (DirectionalAntennaRadio)selectedRadio;
double txGain = r.getRelativeGain(r.getDirection() + getAngle(), getDistance());
//logger.debug("tx gain: " + txGain + " (angle " + String.format("%1.1f", Math.toDegrees(r.getDirection() + getAngle())) + ")");
return txGain;
}
public double getRxGain() {
return 0;
}
};
if (dataTypeToVisualize == ChannelModel.TransmissionData.SIGNAL_STRENGTH) {
// Attenuate
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(
radioX,
radioY,
startX + width * x/resolution.width,
startY + height * y/resolution.height
);
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(txPair);
// Collecting signal strengths
if (signalStrength[0] < lowestImageValue) {
@ -1756,12 +1836,7 @@ public class AreaViewer extends VisPlugin {
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SIGNAL_STRENGTH_VAR) {
// Attenuate
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(
radioX,
radioY,
startX + width * x/resolution.width,
startY + height * y/resolution.height
);
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(txPair);
// Collecting variances
if (signalStrength[1] < lowestImageValue) {
@ -1776,10 +1851,7 @@ public class AreaViewer extends VisPlugin {
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SNR) {
// Get signal to noise ratio
double[] snr = currentChannelModel.getSINR(
radioX,
radioY,
startX + width * x/resolution.width,
startY + height * y/resolution.height,
txPair,
-Double.MAX_VALUE
);
@ -1796,10 +1868,7 @@ public class AreaViewer extends VisPlugin {
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SNR_VAR) {
// Get signal to noise ratio
double[] snr = currentChannelModel.getSINR(
radioX,
radioY,
startX + width * x/resolution.width,
startY + height * y/resolution.height,
txPair,
-Double.MAX_VALUE
);
@ -1815,11 +1884,7 @@ public class AreaViewer extends VisPlugin {
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.PROB_OF_RECEPTION) {
// Get probability of receiving a packet TODO What size? Does it matter?
double probability = currentChannelModel.getProbability(
radioX,
radioY,
startX + width * x/resolution.width,
startY + height * y/resolution.height,
-Double.MAX_VALUE
txPair, -Double.MAX_VALUE
)[0];
// Collecting variances
@ -1834,10 +1899,7 @@ public class AreaViewer extends VisPlugin {
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.DELAY_SPREAD_RMS) {
// Get RMS delay spread of receiving a packet
double rmsDelaySpread = currentChannelModel.getRMSDelaySpread(
radioX,
radioY,
startX + width * x/resolution.width,
startY + height * y/resolution.height
txPair
);
// Collecting variances
@ -1909,7 +1971,7 @@ public class AreaViewer extends VisPlugin {
channelHeight = height;
channelImage = tempChannelImage;
thisPlugin.repaint();
AreaViewer.this.repaint();
coloringIntervalPanel.repaint();
} catch (Exception ex) {
@ -1927,9 +1989,7 @@ public class AreaViewer extends VisPlugin {
// Start thread
attenuatorThread = new Thread(runnable);
attenuatorThread.start();
}
}
};
}
/**
* Repaint the canvas
@ -2112,66 +2172,66 @@ public class AreaViewer extends VisPlugin {
}
// -- Draw radio activity --
if (drawRadioActivity) {
for (RadioConnection connection: currentRadioMedium.getActiveConnections()) {
Position sourcePosition = connection.getSource().getPosition();
// Paint scaled (otherwise bad rounding to integers may occur)
g2d.setTransform(realWorldTransformScaled);
g2d.setStroke(new BasicStroke((float) 0.0));
for (Radio receivingRadio: connection.getDestinations()) {
g2d.setColor(Color.GREEN);
// Get source and destination coordinates
Position destinationPosition = receivingRadio.getPosition();
g2d.draw(new Line2D.Double(
sourcePosition.getXCoordinate()*100.0,
sourcePosition.getYCoordinate()*100.0,
destinationPosition.getXCoordinate()*100.0,
destinationPosition.getYCoordinate()*100.0
));
}
for (Radio interferedRadio: connection.getInterfered()) {
g2d.setColor(Color.RED);
// Get source and destination coordinates
Position destinationPosition = interferedRadio.getPosition();
g2d.draw(new Line2D.Double(
sourcePosition.getXCoordinate()*100.0,
sourcePosition.getYCoordinate()*100.0,
destinationPosition.getXCoordinate()*100.0,
destinationPosition.getYCoordinate()*100.0
));
}
g2d.setColor(Color.BLUE);
g2d.setTransform(realWorldTransform);
g2d.translate(
sourcePosition.getXCoordinate(),
sourcePosition.getYCoordinate()
);
// Fetch current translation
double xPos = g2d.getTransform().getTranslateX();
double yPos = g2d.getTransform().getTranslateY();
// Jump to identity transform and paint without scaling
g2d.setTransform(new AffineTransform());
g2d.fillOval(
(int) xPos,
(int) yPos,
5,
5
);
}
}
// if (drawRadioActivity) {
// for (RadioConnection connection: currentRadioMedium.getActiveConnections()) {
// Position sourcePosition = connection.getSource().getPosition();
//
// // Paint scaled (otherwise bad rounding to integers may occur)
// g2d.setTransform(realWorldTransformScaled);
// g2d.setStroke(new BasicStroke((float) 0.0));
//
// for (Radio receivingRadio: connection.getDestinations()) {
// g2d.setColor(Color.GREEN);
//
// // Get source and destination coordinates
// Position destinationPosition = receivingRadio.getPosition();
//
// g2d.draw(new Line2D.Double(
// sourcePosition.getXCoordinate()*100.0,
// sourcePosition.getYCoordinate()*100.0,
// destinationPosition.getXCoordinate()*100.0,
// destinationPosition.getYCoordinate()*100.0
// ));
// }
//
// for (Radio interferedRadio: connection.getInterfered()) {
// g2d.setColor(Color.RED);
//
// // Get source and destination coordinates
// Position destinationPosition = interferedRadio.getPosition();
//
// g2d.draw(new Line2D.Double(
// sourcePosition.getXCoordinate()*100.0,
// sourcePosition.getYCoordinate()*100.0,
// destinationPosition.getXCoordinate()*100.0,
// destinationPosition.getYCoordinate()*100.0
// ));
// }
//
// g2d.setColor(Color.BLUE);
// g2d.setTransform(realWorldTransform);
//
// g2d.translate(
// sourcePosition.getXCoordinate(),
// sourcePosition.getYCoordinate()
// );
//
// // Fetch current translation
// double xPos = g2d.getTransform().getTranslateX();
// double yPos = g2d.getTransform().getTranslateY();
//
// // Jump to identity transform and paint without scaling
// g2d.setTransform(new AffineTransform());
//
// g2d.fillOval(
// (int) xPos,
// (int) yPos,
// 5,
// 5
// );
//
// }
// }
// -- Draw scale arrow --
if (drawScaleArrow) {
@ -2210,7 +2270,7 @@ public class AreaViewer extends VisPlugin {
}
// -- Draw tracked components (if any) --
if (inTrackMode && trackedComponents != null) {
if (!currentSimulation.isRunning() && inTrackMode && trackedComponents != null) {
g2d.setTransform(realWorldTransformScaled);
g2d.setStroke(new BasicStroke((float) 0.0));
@ -2238,8 +2298,8 @@ public class AreaViewer extends VisPlugin {
* @param clickedPoint On-screen position
* @return All hit radios
*/
protected Vector<Radio> trackClickedRadio(Point clickedPoint) {
Vector<Radio> hitRadios = new Vector<Radio>();
protected ArrayList<Radio> trackClickedRadio(Point clickedPoint) {
ArrayList<Radio> hitRadios = new ArrayList<Radio>();
if (currentRadioMedium.getRegisteredRadioCount() == 0) {
return null;
}
@ -2297,9 +2357,16 @@ public class AreaViewer extends VisPlugin {
* @return XML element collection
*/
public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
ArrayList<Element> config = new ArrayList<Element>();
Element element;
/* Selected mote */
if (selectedRadio != null) {
element = new Element("selected");
element.setAttribute("mote", "" + selectedRadio.getMote().getID());
config.add(element);
}
// Controls visible
element = new Element("controls_visible");
element.setText(Boolean.toString(showSettingsBox.isSelected()));
@ -2332,9 +2399,9 @@ public class AreaViewer extends VisPlugin {
element = new Element("show_radios");
element.setText(Boolean.toString(drawRadios));
config.add(element);
element = new Element("show_activity");
element.setText(Boolean.toString(drawRadioActivity));
config.add(element);
// element = new Element("show_activity");
// element.setText(Boolean.toString(drawRadioActivity));
// config.add(element);
element = new Element("show_arrow");
element.setText(Boolean.toString(drawScaleArrow));
config.add(element);
@ -2382,7 +2449,12 @@ public class AreaViewer extends VisPlugin {
*/
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("controls_visible")) {
if (element.getName().equals("selected")) {
int id = Integer.parseInt(element.getAttributeValue("mote"));
selectedRadio = currentSimulation.getMoteWithID(id).getInterfaces().getRadio();
trackModeButton.setEnabled(true);
paintEnvironmentAction.setEnabled(true);
} else if (element.getName().equals("controls_visible")) {
showSettingsBox.setSelected(Boolean.parseBoolean(element.getText()));
canvasModeHandler.actionPerformed(new ActionEvent(showSettingsBox,
ActionEvent.ACTION_PERFORMED, showSettingsBox.getActionCommand()));
@ -2411,9 +2483,9 @@ public class AreaViewer extends VisPlugin {
selectGraphicsHandler.actionPerformed(new ActionEvent(radiosCheckBox,
ActionEvent.ACTION_PERFORMED, radiosCheckBox.getActionCommand()));
} else if (element.getName().equals("show_activity")) {
radioActivityCheckBox.setSelected(Boolean.parseBoolean(element.getText()));
selectGraphicsHandler.actionPerformed(new ActionEvent(radioActivityCheckBox,
ActionEvent.ACTION_PERFORMED, radioActivityCheckBox.getActionCommand()));
// radioActivityCheckBox.setSelected(Boolean.parseBoolean(element.getText()));
// selectGraphicsHandler.actionPerformed(new ActionEvent(radioActivityCheckBox,
// ActionEvent.ACTION_PERFORMED, radioActivityCheckBox.getActionCommand()));
} else if (element.getName().equals("show_arrow")) {
arrowCheckBox.setSelected(Boolean.parseBoolean(element.getText()));
selectGraphicsHandler.actionPerformed(new ActionEvent(arrowCheckBox,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, Swedish Institute of Computer Science.
* Copyright (c) 2011, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,12 +31,29 @@
package se.sics.mrm;
import java.awt.geom.*;
import java.util.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Observable;
import java.util.Observer;
import java.util.Properties;
import java.util.Random;
import java.util.Vector;
import javax.swing.tree.DefaultMutableTreeNode;
import org.apache.log4j.Logger;
import org.jdom.Element;
import se.sics.cooja.Simulation;
import se.sics.cooja.interfaces.DirectionalAntennaRadio;
import se.sics.cooja.interfaces.Radio;
import se.sics.cooja.radiomediums.AbstractRadioMedium;
import statistics.GaussianWrapper;
/**
@ -53,9 +70,12 @@ import statistics.GaussianWrapper;
public class ChannelModel {
private static Logger logger = Logger.getLogger(ChannelModel.class);
private static final double C = 299792458; /* m/s */
enum TransmissionData { SIGNAL_STRENGTH, SIGNAL_STRENGTH_VAR, SNR, SNR_VAR, PROB_OF_RECEPTION, DELAY_SPREAD, DELAY_SPREAD_RMS}
private Properties parameters = new Properties();
private Hashtable<Parameter,Object> parametersDefaults = new Hashtable<Parameter,Object>();
private Hashtable<Parameter,Object> parameters = new Hashtable<Parameter,Object>();
private Properties parameterDescriptions = new Properties();
// Parameters used for speeding up calculations
@ -71,6 +91,8 @@ public class ChannelModel {
private StringBuilder logInfo = null;
private ArrayList<Line2D> loggedRays = null;
private Simulation simulation;
// Ray tracing components temporary vector
private Vector<Vector<Line2D>> calculatedVisibleSides = new Vector<Vector<Line2D>>();
@ -89,105 +111,180 @@ public class ChannelModel {
}
}
private SettingsObservable settingsObservable = new SettingsObservable();
public enum Parameter {
apply_random,
snr_threshold,
bg_noise_mean,
bg_noise_var,
system_gain_mean,
system_gain_var,
frequency,
tx_power,
tx_with_gain,
rx_sensitivity,
rx_with_gain,
rt_disallow_direct_path,
rt_ignore_non_direct,
rt_fspl_on_total_length,
rt_max_rays,
rt_max_refractions,
rt_max_reflections,
rt_max_diffractions,
rt_use_scattering,
rt_refrac_coefficient,
rt_reflec_coefficient,
rt_diffr_coefficient,
rt_scatt_coefficient,
obstacle_attenuation;
public ChannelModel() {
// - Set initial parameter values -
public static Object getDefaultValue(Parameter p) {
switch (p) {
case apply_random:
return new Boolean(false);
case snr_threshold:
return new Double(6);
case bg_noise_mean:
return new Double(AbstractRadioMedium.SS_NOTHING);
case bg_noise_var:
return new Double(1);
case system_gain_mean:
return new Double(0);
case system_gain_var:
return new Double(4);
case frequency: /* MHz */
return new Double(2400);
case tx_power:
return new Double(1.5);
case tx_with_gain:
return new Boolean(true);
case rx_sensitivity:
return new Double(-100);
case rx_with_gain:
return new Boolean(false);
case rt_disallow_direct_path:
return new Boolean(false);
case rt_ignore_non_direct:
return new Boolean(false);
case rt_fspl_on_total_length:
return new Boolean(true);
case rt_max_rays:
return new Integer(1);
case rt_max_refractions:
return new Integer(1);
case rt_max_reflections:
return new Integer(1);
case rt_max_diffractions:
return new Integer(0);
case rt_use_scattering:
return new Boolean(false);
case rt_refrac_coefficient:
return new Double(-3);
case rt_reflec_coefficient:
return new Double(-5);
case rt_diffr_coefficient:
return new Double(-10);
case rt_scatt_coefficient:
return new Double(-20);
case obstacle_attenuation:
return new Double(-3);
}
throw new RuntimeException("Unknown default value: " + p);
}
public static Parameter fromString(String name) {
/* Backwards compatability */
if (name.equals("apply_random")) {
return apply_random;
} else if (name.equals("snr_threshold")) {
return snr_threshold;
} else if (name.equals("bg_noise_mean")) {
return bg_noise_mean;
} else if (name.equals("bg_noise_var")) {
return bg_noise_var;
} else if (name.equals("system_gain_mean")) {
return system_gain_mean;
} else if (name.equals("system_gain_var")) {
return system_gain_var;
} else if (name.equals("tx_power")) {
return tx_power;
} else if (name.equals("rx_sensitivity")) {
return rx_sensitivity;
} else if (name.equals("rt_disallow_direct_path")) {
return rt_disallow_direct_path;
} else if (name.equals("rt_ignore_non_direct")) {
return rt_ignore_non_direct;
} else if (name.equals("rt_fspl_on_total_length")) {
return rt_fspl_on_total_length;
} else if (name.equals("rt_max_rays")) {
return rt_max_rays;
} else if (name.equals("rt_max_refractions")) {
return rt_max_refractions;
} else if (name.equals("rt_max_reflections")) {
return rt_max_reflections;
} else if (name.equals("rt_max_diffractions")) {
return rt_max_diffractions;
} else if (name.equals("rt_use_scattering")) {
return rt_use_scattering;
} else if (name.equals("rt_refrac_coefficient")) {
return rt_refrac_coefficient;
} else if (name.equals("rt_reflec_coefficient")) {
return rt_reflec_coefficient;
} else if (name.equals("rt_diffr_coefficient")) {
return rt_diffr_coefficient;
} else if (name.equals("rt_scatt_coefficient")) {
return rt_scatt_coefficient;
} else if (name.equals("obstacle_attenuation")) {
return obstacle_attenuation;
}
return null;
}
// Using random variables
parameters.put("apply_random", new Boolean(false)); // TODO Should not use random variables as default
parameterDescriptions.put("apply_random", "Apply random values immediately");
public static String getDescription(Parameter p) {
switch (p) {
case apply_random: return "(DEBUG) Apply random values";
case snr_threshold: return "SNR reception threshold (dB)";
case bg_noise_mean: return "Background noise mean (dBm)";
case bg_noise_var: return "Background noise variance (dB)";
case system_gain_mean: return "Extra system gain mean (dB)";
case system_gain_var: return "Extra system gain variance (dB)";
case frequency: return "Frequency (MHz)";
case tx_power: return "Default transmitter output power (dBm)";
case tx_with_gain: return "Directional antennas: with TX gain";
case rx_sensitivity: return "Receiver sensitivity (dBm)";
case rx_with_gain: return "Directional antennas: with RX gain";
case rt_disallow_direct_path: return "Disallow direct path";
case rt_ignore_non_direct: return "If existing: return only use direct path";
case rt_fspl_on_total_length: return "Use FSPL on total path lengths only";
case rt_max_rays: return "Max path rays";
case rt_max_refractions: return "Max refractions";
case rt_max_reflections: return "Max reflections";
case rt_max_diffractions: return "Max diffractions";
case rt_refrac_coefficient: return "Refraction coefficient (dB)";
case rt_reflec_coefficient: return "Reflection coefficient (dB)";
case rt_diffr_coefficient: return "Diffraction coefficient (dB)";
case obstacle_attenuation: return "Obstacle attenuation (dB/m)";
}
throw new RuntimeException("Unknown decrption: " + p);
}
}
public ChannelModel(Simulation simulation) {
this.simulation = simulation;
/* Default values */
for (Parameter p: Parameter.values()) {
parameters.put(p, Parameter.getDefaultValue(p));
}
// Signal to noise reception threshold
parameters.put("snr_threshold", new Double(6));
parameterDescriptions.put("snr_threshold", "SNR reception threshold (dB)");
// Background noise mean
parameters.put("bg_noise_mean", new Double(-150));
parameterDescriptions.put("bg_noise_mean", "Background noise mean (dBm)");
// Background noise variance
parameters.put("bg_noise_var", new Double(1));
parameterDescriptions.put("bg_noise_var", "Background noise variance (dB)");
// Extra system gain mean
parameters.put("system_gain_mean", new Double(0));
parameterDescriptions.put("system_gain_mean", "Extra system gain mean (dB)");
// Extra system gain variance
parameters.put("system_gain_var", new Double(4)); // TODO Should probably be default 0 or 1
parameterDescriptions.put("system_gain_var", "Extra system gain variance (dB)");
// Transmission wavelength
parameters.put("wavelength", new Double(0.346)); // ~868 MHz (RFM TR1001)
parameterDescriptions.put("wavelength", "Wavelength w (m)");
// Transmitter output power
parameters.put("tx_power", new Double(1.5)); // dBm (deciBel milliwatts)
parameterDescriptions.put("tx_power", "Transmitter output power (dBm)");
// Transmitter antenna gain
parameters.put("tx_antenna_gain", new Double(0)); // TODO Should use angle
parameterDescriptions.put("tx_antenna_gain", "Transmitter antenna gain (dB)");
// Receiver sensitivity
parameters.put("rx_sensitivity", new Double(-100));
parameterDescriptions.put("rx_sensitivity", "Receiver sensitivity (dBm)");
// Receiver antenna gain
parameters.put("rx_antenna_gain", new Double(0)); // TODO Should use angle
parameterDescriptions.put("rx_antenna_gain", "Receiver antenna gain (dB)");
// Ray Tracer - Disallow direct path
parameters.put("rt_disallow_direct_path", new Boolean(false));
parameterDescriptions.put("rt_disallow_direct_path", "Disallow direct path");
// Ray Tracer - If direct path exists, ignore the non-direct (used for debugging)
parameters.put("rt_ignore_non_direct", new Boolean(false));
parameterDescriptions.put("rt_ignore_non_direct", "If existing, only use direct path");
// Ray Tracer - Use FSPL on total length only
parameters.put("rt_fspl_on_total_length", new Boolean(true));
parameterDescriptions.put("rt_fspl_on_total_length", "Use FSPL on total path lengths only");
// Ray Tracer - Max number of subrays
parameters.put("rt_max_rays", new Integer(1));
parameterDescriptions.put("rt_max_rays", "Max path rays");
// Ray Tracer - Max number of refractions
parameters.put("rt_max_refractions", new Integer(1));
parameterDescriptions.put("rt_max_refractions", "Max refractions");
// Ray Tracer - Max number of reflections
parameters.put("rt_max_reflections", new Integer(1));
parameterDescriptions.put("rt_max_reflections", "Max reflections");
// Ray Tracer - Max number of diffractions
parameters.put("rt_max_diffractions", new Integer(0));
parameterDescriptions.put("rt_max_diffractions", "Max diffractions");
parametersDefaults = (Hashtable<Parameter,Object>) parameters.clone();
// Ray Tracer - Use scattering
//parameters.put("rt_use_scattering", new Boolean(false)); // TODO Not used yet
//parameterDescriptions.put("rt_use_scattering", "Use simple scattering");
// Ray Tracer - Refraction coefficient
parameters.put("rt_refrac_coefficient", new Double(-3));
parameterDescriptions.put("rt_refrac_coefficient", "Refraction coefficient (dB)");
// Ray Tracer - Reflection coefficient
parameters.put("rt_reflec_coefficient", new Double(-5));
parameterDescriptions.put("rt_reflec_coefficient", "Reflection coefficient (dB)");
// Ray Tracer - Diffraction coefficient
parameters.put("rt_diffr_coefficient", new Double(-10));
parameterDescriptions.put("rt_diffr_coefficient", "Diffraction coefficient (dB)");
//parameters.put(Parameters.rt_use_scattering, Parameter.getDefaultValue(Parameters.rt_use_scattering)); // TODO Not used yet
//parameterDescriptions.put(Parameters.rt_use_scattering, "Use simple scattering");
// Ray Tracer - Scattering coefficient
//parameters.put("rt_scatt_coefficient", new Double(-20)); // TODO Not used yet
//parameterDescriptions.put("rt_scatt_coefficient", "!! Scattering coefficient (dB)");
// Shadowing - Obstacle Attenuation constant
parameters.put("obstacle_attenuation", new Double(-3));
parameterDescriptions.put("obstacle_attenuation", "Obstacle attenuation (dB/m)");
//parameters.put(Parameters.rt_scatt_coefficient, Parameter.getDefaultValue(Parameters.rt_scatt_coefficient)); // TODO Not used yet
//parameterDescriptions.put(Parameters.rt_scatt_coefficient, "!! Scattering coefficient (dB)");
}
/**
@ -272,7 +369,7 @@ public class ChannelModel {
* @param identifier Parameter identifier
* @return Current parameter value
*/
public Object getParameterValue(String id) {
public Object getParameterValue(Parameter id) {
Object value = parameters.get(id);
if (value == null) {
logger.fatal("No parameter with id:" + id + ", aborting");
@ -287,7 +384,7 @@ public class ChannelModel {
* @param identifier Parameter identifier
* @return Current parameter value
*/
public double getParameterDoubleValue(String id) {
public double getParameterDoubleValue(Parameter id) {
return ((Double) getParameterValue(id)).doubleValue();
}
@ -297,7 +394,7 @@ public class ChannelModel {
* @param identifier Parameter identifier
* @return Current parameter value
*/
public int getParameterIntegerValue(String id) {
public int getParameterIntegerValue(Parameter id) {
return ((Integer) getParameterValue(id)).intValue();
}
@ -307,7 +404,7 @@ public class ChannelModel {
* @param identifier Parameter identifier
* @return Current parameter value
*/
public boolean getParameterBooleanValue(String id) {
public boolean getParameterBooleanValue(Parameter id) {
return ((Boolean) getParameterValue(id)).booleanValue();
}
@ -317,7 +414,7 @@ public class ChannelModel {
* @param id Parameter identifier
* @param newValue New parameter value
*/
public void setParameterValue(String id, Object newValue) {
public void setParameterValue(Parameter id, Object newValue) {
if (!parameters.containsKey(id)) {
logger.fatal("No parameter with id:" + id + ", aborting");
return;
@ -331,21 +428,6 @@ public class ChannelModel {
settingsObservable.notifySettingsChanged();
}
/**
* Returns a parameter description
*
* @param identifier Parameter identifier
* @return Current parameter description
*/
public String getParameterDescription(String id) {
Object value = parameterDescriptions.get(id);
if (value == null) {
logger.fatal("No parameter description with id:" + id + ", aborting");
return null;
}
return ((String) value);
}
/**
* When this method is called all settings observers
* will be notified.
@ -355,27 +437,20 @@ public class ChannelModel {
}
/**
* Returns the Free Space Path Loss factor (in dB), by using
* parts of the Friis equation. (FSPL <= 0)
* Path loss component from Friis' transmission equation.
* Uses frequency and distance only.
*
* @param distance Distance from transmitter to receiver
* @return FSPL factor
* @param distance Transmitter-receiver distance
* @return Path loss (dB)
*/
protected double getFSPL(double distance) {
// From Friis equation:
// Pr(d) = Pt * (Gt * Gr * w2) / ( (4*PI)2 * d2 * L)
// For FSPL, ignoring Pt, Gt, Gr, L:
// Pr(d) = 1 * (1 * 1 * w2) / ( (4*PI)2 * d2 * 1)
// Pr(d) = w2 / ( (4*PI)2 * d2)
// Pr_dB(d) = 20*log10(w) - 20*log10(4*PI) - 20*log10(d)
if (needToPrecalculateFSPL) {
double w = getParameterDoubleValue("wavelength");
paramFSPL = 20*Math.log10(w) - 20*Math.log10(4*Math.PI);
double f = getParameterDoubleValue(Parameter.frequency);
paramFSPL = -32.44 -20*Math.log10(f /*mhz*/);
needToPrecalculateFSPL = false;
}
return Math.min(0.0, paramFSPL - 20*Math.log10(distance));
return Math.min(0.0, paramFSPL - 20*Math.log10(distance/1000.0 /*km*/));
}
@ -674,7 +749,7 @@ public class ChannelModel {
// Check if direct path exists
justBeforeDestination = sourcePoint;
if (!getParameterBooleanValue("rt_disallow_direct_path")) {
if (!getParameterBooleanValue(Parameter.rt_disallow_direct_path)) {
directPathExists = isDirectPath(justBeforeDestination, dest);
} else {
directPathExists = false;
@ -797,7 +872,7 @@ public class ChannelModel {
allPaths.add(currentPath);
// Stop here if no other paths should be considered
if (type == RayData.RayType.ORIGIN && getParameterBooleanValue("rt_ignore_non_direct")) {
if (type == RayData.RayType.ORIGIN && getParameterBooleanValue(Parameter.rt_ignore_non_direct)) {
return allPaths;
}
@ -1326,17 +1401,15 @@ public class ChannelModel {
* @return Received signal strength (dBm) random variable. The first value is
* 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, null);
}
public double[] getReceivedSignalStrength(double sourceX, double sourceY, double destX, double destY, Double txPower) {
return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH, txPower);
public double[] getReceivedSignalStrength(TxPair txPair) {
return getTransmissionData(txPair, TransmissionData.SIGNAL_STRENGTH);
}
// TODO Fix better data type support
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);
private double[] getTransmissionData(TxPair txPair, TransmissionData dataType) {
Point2D source = txPair.getFrom();
Point2D dest = txPair.getTo();
double accumulatedVariance = 0;
// - Get all ray paths from source to destination -
@ -1344,28 +1417,24 @@ public class ChannelModel {
RayData.RayType.ORIGIN,
source,
null,
getParameterIntegerValue("rt_max_rays"),
getParameterIntegerValue("rt_max_refractions"),
getParameterIntegerValue("rt_max_reflections"),
getParameterIntegerValue("rt_max_diffractions")
getParameterIntegerValue(Parameter.rt_max_rays),
getParameterIntegerValue(Parameter.rt_max_refractions),
getParameterIntegerValue(Parameter.rt_max_reflections),
getParameterIntegerValue(Parameter.rt_max_diffractions)
);
// TODO Current (changing) signal strength should be built into 'build visible lines' to speed up things!
// Check if origin tree is already calculated and saved
DefaultMutableTreeNode visibleLinesTree = null;
visibleLinesTree =
buildVisibleLinesTree(originRayData);
DefaultMutableTreeNode visibleLinesTree = buildVisibleLinesTree(originRayData);
// Calculate all paths from source to destination, using above calculated tree
Vector<RayPath> allPaths = getConnectingPaths(source, dest, visibleLinesTree);
if (logMode) {
logInfo.append("Signal components:\n");
logInfo.append("Signal components:\n");
Enumeration<RayPath> pathsEnum = allPaths.elements();
while (pathsEnum.hasMoreElements()) {
RayPath currentPath = pathsEnum.nextElement();
logInfo.append("* " + currentPath + "\n");
logInfo.append("* " + currentPath + "\n");
for (int i=0; i < currentPath.getSubPathCount(); i++) {
loggedRays.add(currentPath.getSubPath(i));
}
@ -1389,20 +1458,20 @@ public class ChannelModel {
// Type specific losses
// TODO Type specific losses depends on angles as well!
if (subPathStartType == RayData.RayType.REFRACTION) {
pathGain[i] += getParameterDoubleValue("rt_refrac_coefficient");
pathGain[i] += getParameterDoubleValue(Parameter.rt_refrac_coefficient);
} else if (subPathStartType == RayData.RayType.REFLECTION) {
pathGain[i] += getParameterDoubleValue("rt_reflec_coefficient");
pathGain[i] += getParameterDoubleValue(Parameter.rt_reflec_coefficient);
// Add FSPL from last subpaths (if FSPL on individual rays)
if (!getParameterBooleanValue("rt_fspl_on_total_length") && accumulatedStraightLength > 0) {
if (!getParameterBooleanValue(Parameter.rt_fspl_on_total_length) && accumulatedStraightLength > 0) {
pathGain[i] += getFSPL(accumulatedStraightLength);
}
accumulatedStraightLength = 0; // Reset straight length
} else if (subPathStartType == RayData.RayType.DIFFRACTION) {
pathGain[i] += getParameterDoubleValue("rt_diffr_coefficient");
pathGain[i] += getParameterDoubleValue(Parameter.rt_diffr_coefficient);
// Add FSPL from last subpaths (if FSPL on individual rays)
if (!getParameterBooleanValue("rt_fspl_on_total_length") && accumulatedStraightLength > 0) {
if (!getParameterBooleanValue(Parameter.rt_fspl_on_total_length) && accumulatedStraightLength > 0) {
pathGain[i] += getFSPL(accumulatedStraightLength);
}
accumulatedStraightLength = 0; // Reset straight length
@ -1414,7 +1483,7 @@ public class ChannelModel {
// Ray passes through a wall, calculate distance through that wall
// Fetch attenuation constant
double attenuationConstant = getParameterDoubleValue("obstacle_attenuation");
double attenuationConstant = getParameterDoubleValue(Parameter.obstacle_attenuation);
Vector<Rectangle2D> allPossibleObstacles = myObstacleWorld.getAllObstaclesNear(subPath.getP1());
@ -1434,9 +1503,7 @@ public class ChannelModel {
pathGain[i] += attenuationConstant * line.getP1().distance(line.getP2());
break;
}
}
}
// Add to total path length
@ -1444,12 +1511,12 @@ public class ChannelModel {
}
// Add FSPL from last rays (if FSPL on individual rays)
if (!getParameterBooleanValue("rt_fspl_on_total_length") && accumulatedStraightLength > 0) {
if (!getParameterBooleanValue(Parameter.rt_fspl_on_total_length) && accumulatedStraightLength > 0) {
pathGain[i] += getFSPL(accumulatedStraightLength);
}
// Free space path loss on total path length?
if (getParameterBooleanValue("rt_fspl_on_total_length")) {
if (getParameterBooleanValue(Parameter.rt_fspl_on_total_length)) {
pathGain[i] += getFSPL(pathLengths[i]);
}
@ -1463,7 +1530,8 @@ public class ChannelModel {
double[] pathModdedLengths = new double[allPaths.size()];
double delaySpread = 0;
double delaySpreadRMS = 0;
double wavelength = getParameterDoubleValue("wavelength");
double freq = getParameterDoubleValue(Parameter.frequency);
double wavelength = C/(freq*1000000d);
double totalPathGain = 0;
double delaySpreadTotalWeight = 0;
double speedOfLight = 300; // Approximate value (m/us)
@ -1490,12 +1558,12 @@ public class ChannelModel {
// Using Rician fading approach, TODO Only one best signal considered - combine these? (need two limits)
totalPathGain += Math.pow(10, pathGain[i]/10.0)*Math.cos(2*Math.PI * pathModdedLengths[i]/wavelength);
if (logMode) {
logInfo.append("Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n");
logInfo.append("Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n");
}
} else if (logMode) {
/* TODO Log mode affects result? */
/* TODO Log mode affects result? */
pathModdedLengths[i] = (pathLengths[i] - pathLengths[bestSignalNr]) % wavelength;
logInfo.append("(IGNORED) Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n");
logInfo.append("(IGNORED) Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n");
}
}
@ -1509,33 +1577,32 @@ public class ChannelModel {
totalPathGain = 10*Math.log10(Math.abs(totalPathGain));
if (logMode) {
logInfo.append("\nTotal path gain: " + String.format("%2.3f", totalPathGain) + " dB\n");
logInfo.append("Delay spread: " + String.format("%2.3f", delaySpread) + "\n");
logInfo.append("RMS delay spread: " + String.format("%2.3f", delaySpreadRMS) + "\n");
logInfo.append("\nTotal path gain: " + String.format("%2.3f", totalPathGain) + " dB\n");
logInfo.append("Delay spread: " + String.format("%2.3f", delaySpread) + "\n");
logInfo.append("RMS delay spread: " + String.format("%2.3f", delaySpreadRMS) + "\n");
}
// - Calculate received power -
// Using formula (dB)
// Received power = Output power + System gain + Transmitter gain + Path Loss + Receiver gain
// TODO Update formulas
double outputPower;
if (txPower == null) {
outputPower = getParameterDoubleValue("tx_power");
} else {
outputPower = txPower;
}
double systemGain = getParameterDoubleValue("system_gain_mean");
if (getParameterBooleanValue("apply_random")) {
double outputPower = txPair.getTxPower();
double systemGain = getParameterDoubleValue(Parameter.system_gain_mean);
if (getParameterBooleanValue(Parameter.apply_random)) {
Random random = new Random(); /* TODO Use main random generator? */
systemGain += Math.sqrt(getParameterDoubleValue("system_gain_var")) * random.nextGaussian();
systemGain += Math.sqrt(getParameterDoubleValue(Parameter.system_gain_var)) * random.nextGaussian();
} else {
accumulatedVariance += getParameterDoubleValue("system_gain_var");
accumulatedVariance += getParameterDoubleValue(Parameter.system_gain_var);
}
double transmitterGain = 0;
if (getParameterBooleanValue(Parameter.tx_with_gain)) {
transmitterGain = txPair.getTxGain();
}
double transmitterGain = getParameterDoubleValue("tx_antenna_gain"); // TODO Should depend on angle
double receivedPower = outputPower + systemGain + transmitterGain + totalPathGain;
if (logMode) {
logInfo.append("\nReceived signal strength: " + String.format("%2.3f", receivedPower) + " dB (variance " + accumulatedVariance + ")\n");
logInfo.append("\nReceived signal strength: " + String.format("%2.3f", receivedPower) + " dB (variance " + accumulatedVariance + ")\n");
}
if (dataType == TransmissionData.DELAY_SPREAD || dataType == TransmissionData.DELAY_SPREAD_RMS) {
@ -1546,8 +1613,8 @@ public class ChannelModel {
}
public class TrackedSignalComponents {
ArrayList<Line2D> components;
String log;
ArrayList<Line2D> components;
String log;
}
/**
@ -1561,7 +1628,7 @@ public class ChannelModel {
* @param destY Destination position Y
* @return Signal components and printable description
*/
public TrackedSignalComponents getRaysOfTransmission(double sourceX, double sourceY, double destX, double destY) {
public TrackedSignalComponents getRaysOfTransmission(TxPair txPair) {
TrackedSignalComponents tsc = new TrackedSignalComponents();
logInfo = new StringBuilder();
@ -1569,7 +1636,7 @@ public class ChannelModel {
/* TODO Include background noise? */
logMode = true;
getProbability(sourceX, sourceY, destX, destY, -Double.MAX_VALUE);
getProbability(txPair, -Double.MAX_VALUE);
logMode = false;
tsc.log = logInfo.toString();
@ -1596,27 +1663,26 @@ public class ChannelModel {
* 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. */
public double[] getSINR(TxPair txPair, double interference) {
/* TODO Cache values: called repeatedly with noise sources. */
// Calculate received signal strength
double[] signalStrength = getReceivedSignalStrength(sourceX, sourceY, destX, destY);
double[] signalStrength = getReceivedSignalStrength(txPair);
double[] snrData = new double[] { signalStrength[0], signalStrength[1], signalStrength[0] };
double[] snrData =
new double[] { signalStrength[0], signalStrength[1], signalStrength[0] };
// Add antenna gain
if (getParameterBooleanValue(Parameter.rx_with_gain)) {
snrData[0] += txPair.getRxGain();
}
// Add antenna gain TODO Should depend on angle
snrData[0] += getParameterDoubleValue("rx_antenna_gain");
double noiseVariance = getParameterDoubleValue("bg_noise_var");
double noiseMean = getParameterDoubleValue("bg_noise_mean");
double noiseVariance = getParameterDoubleValue(Parameter.bg_noise_var);
double noiseMean = getParameterDoubleValue(Parameter.bg_noise_mean);
if (interference > noiseMean) {
noiseMean = interference;
}
if (getParameterBooleanValue("apply_random")) {
if (getParameterBooleanValue(Parameter.apply_random)) {
Random random = new Random(); /* TODO Use main random generator? */
noiseMean += Math.sqrt(noiseVariance) * random.nextGaussian();
noiseVariance = 0;
@ -1627,7 +1693,7 @@ public class ChannelModel {
snrData[1] += noiseVariance;
if (logMode) {
logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " dB (variance " + snrData[1] + ")\n");
logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " dB (variance " + snrData[1] + ")\n");
}
return snrData;
}
@ -1649,19 +1715,19 @@ public class ChannelModel {
* @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) {
double[] snrData = getSINR(sourceX, sourceY, destX, destY, interference);
public double[] getProbability(TxPair txPair, double interference) {
double[] snrData = getSINR(txPair, interference);
double snrMean = snrData[0];
double snrVariance = snrData[1];
double signalStrength = snrData[2];
double threshold = getParameterDoubleValue("snr_threshold");
double rxSensitivity = getParameterDoubleValue("rx_sensitivity");
double threshold = getParameterDoubleValue(Parameter.snr_threshold);
double rxSensitivity = getParameterDoubleValue(Parameter.rx_sensitivity);
// Check signal strength against receiver sensitivity and interference
if (rxSensitivity > signalStrength - snrMean &&
threshold < rxSensitivity + snrMean - signalStrength) {
threshold < rxSensitivity + snrMean - signalStrength) {
if (logMode) {
logInfo.append("Weak signal: increasing threshold\n");
logInfo.append("Weak signal: increasing threshold\n");
}
// Keeping snr variance but increasing theshold to sensitivity
@ -1707,8 +1773,8 @@ public class ChannelModel {
* Destination position Y
* @return RMS delay spread
*/
public double getRMSDelaySpread(double sourceX, double sourceY, double destX, double destY) {
return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.DELAY_SPREAD, null)[1];
public double getRMSDelaySpread(TxPair tx) {
return getTransmissionData(tx, TransmissionData.DELAY_SPREAD)[1];
}
/**
@ -1718,14 +1784,18 @@ public class ChannelModel {
* @return XML element collection
*/
public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
ArrayList<Element> config = new ArrayList<Element>();
Element element;
Enumeration paramEnum = parameters.keys();
Enumeration<Parameter> paramEnum = parameters.keys();
while (paramEnum.hasMoreElements()) {
String name = (String) paramEnum.nextElement();
element = new Element(name);
element.setText(parameters.get(name).toString());
Parameter p = (Parameter) paramEnum.nextElement();
element = new Element(p.toString());
if (parametersDefaults.get(p).equals(parameters.get(p))) {
/* Default value */
continue;
}
element.setAttribute("value", parameters.get(p).toString());
config.add(element);
}
@ -1749,19 +1819,47 @@ public class ChannelModel {
if (element.getName().equals("obstacles")) {
myObstacleWorld = new ObstacleWorld();
myObstacleWorld.setConfigXML(element.getChildren());
} else {
// Assuming parameter value
} else /* Parameter values */ {
String name = element.getName();
String value;
Parameter param = null;
if (name.equals("wavelength")) {
/* Backwards compatability: ignored parameters */
value = element.getAttributeValue("value");
if (value == null) {
value = element.getText();
}
// private static final double C = 299792458; /* m/s */
double frequency = C/Double.parseDouble(value);
frequency /= 1000000.0; /* mhz */
parameters.put(Parameter.frequency, frequency); /* mhz */
// Fetch current class before applying saved value
Object obj = parameters.get(element.getName());
Class paramClass = obj.getClass();
logger.warn("MRM parameter converted from wavelength to frequency: " + String.format("%1.1f MHz", frequency));
continue;
} else if (name.equals("tx_antenna_gain") || name.equals("rx_antenna_gain")) {
logger.warn("MRM parameter \"" + name + "\" was removed");
continue;
} else if (Parameter.fromString(name) != null) {
/* Backwards compatability: renamed parameters */
param = Parameter.fromString(name);
} else {
param = Parameter.valueOf(name);
}
value = element.getAttributeValue("value");
if (value == null || value.isEmpty()) {
/* Backwards compatability: renamed parameters */
value = element.getText();
}
Class<?> paramClass = parameters.get(param).getClass();
if (paramClass == Double.class) {
parameters.put(element.getName(), new Double(Double.parseDouble(element.getText())));
parameters.put(param, new Double(Double.parseDouble(value)));
} else if (paramClass == Boolean.class) {
parameters.put(element.getName(), Boolean.parseBoolean(element.getText()));
parameters.put(param, Boolean.parseBoolean(value));
} else if (paramClass == Integer.class) {
parameters.put(element.getName(), Integer.parseInt(element.getText()));
parameters.put(param, Integer.parseInt(value));
} else {
logger.fatal("Unsupported class type: " + paramClass);
}
@ -1772,4 +1870,85 @@ public class ChannelModel {
settingsObservable.notifySettingsChanged();
return true;
}
public static abstract class TxPair {
public abstract double getFromX();
public abstract double getFromY();
public abstract double getToX();
public abstract double getToY();
public abstract double getTxPower();
public double getDistance() {
double w = getFromX() - getToX();
double h = getFromY() - getToY();
return Math.sqrt(w*w+h*h);
}
/**
* @return Radians
*/
public double getAngle() {
return Math.atan2(getToY()-getFromY(), getToX()-getFromX());
}
public Point2D getFrom() {
return new Point2D.Double(getFromX(), getFromY());
}
public Point2D getTo() {
return new Point2D.Double(getToX(), getToY());
}
/**
* @return Relative transmitter gain (zero for omnidirectional radios)
*/
public abstract double getTxGain();
/**
* @return Relative receiver gain (zero for omnidirectional radios)
*/
public abstract double getRxGain();
}
public static abstract class RadioPair extends TxPair {
public abstract Radio getFromRadio();
public abstract Radio getToRadio();
public double getDistance() {
double w = getFromX() - getToX();
double h = getFromY() - getToY();
return Math.sqrt(w*w+h*h);
}
public double getFromX() {
return getFromRadio().getPosition().getXCoordinate();
}
public double getFromY() {
return getFromRadio().getPosition().getYCoordinate();
}
public double getToX() {
return getToRadio().getPosition().getXCoordinate();
}
public double getToY() {
return getToRadio().getPosition().getYCoordinate();
}
public double getTxPower() {
return getFromRadio().getCurrentOutputPower();
}
public double getTxGain() {
if (!(getFromRadio() instanceof DirectionalAntennaRadio)) {
return 0;
}
DirectionalAntennaRadio r = (DirectionalAntennaRadio)getFromRadio();
double txGain = r.getRelativeGain(r.getDirection() + getAngle(), getAngle());
//logger.debug("tx gain: " + txGain + " (angle " + String.format("%1.1f", Math.toDegrees(r.getDirection() + getAngle())) + ")");
return txGain;
}
public double getRxGain() {
if (!(getToRadio() instanceof DirectionalAntennaRadio)) {
return 0;
}
DirectionalAntennaRadio r = (DirectionalAntennaRadio)getFromRadio();
double txGain = r.getRelativeGain(r.getDirection() + getAngle() + Math.PI, getDistance());
//logger.debug("rx gain: " + txGain + " (angle " + String.format("%1.1f", Math.toDegrees(r.getDirection() + getAngle() + Math.PI)) + ")");
return txGain;
}
}
}

View file

@ -42,29 +42,30 @@ import org.apache.log4j.Logger;
import org.jdom.Element;
import se.sics.cooja.*;
import se.sics.mrm.ChannelModel.Parameter;
/**
* This plugin allows a user to reconfigure current radio channel parameters.
*
* @author Fredrik Osterlind
*/
@ClassDescription("MRM - Formula Viewer")
@ClassDescription("MRM Settings")
@PluginType(PluginType.SIM_PLUGIN)
public class FormulaViewer extends se.sics.cooja.VisPlugin {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(FormulaViewer.class);
private Simulation currentSimulation;
private MRM currentRadioMedium;
private ChannelModel currentChannelModel;
private Simulation simulation;
private MRM radioMedium;
private ChannelModel channelModel;
private static Dimension labelDimension = new Dimension(240, 20);
private static NumberFormat doubleFormat = NumberFormat.getNumberInstance();
private static NumberFormat integerFormat = NumberFormat.getIntegerInstance();
private Vector<JFormattedTextField> allIntegerParameters = new Vector<JFormattedTextField>();
private Vector<JFormattedTextField> allDoubleParameters = new Vector<JFormattedTextField>();
private Vector<JCheckBox> allBooleanParameters = new Vector<JCheckBox>();
private ArrayList<JFormattedTextField> allIntegerParameters = new ArrayList<JFormattedTextField>();
private ArrayList<JFormattedTextField> allDoubleParameters = new ArrayList<JFormattedTextField>();
private ArrayList<JCheckBox> allBooleanParameters = new ArrayList<JCheckBox>();
private JPanel areaGeneral;
private JPanel areaTransmitter;
@ -78,11 +79,11 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
* @param simulationToVisualize Simulation which holds the MRM channel model.
*/
public FormulaViewer(Simulation simulationToVisualize, GUI gui) {
super("MRM - Formula Viewer", gui);
super("MRM Settings", gui);
currentSimulation = simulationToVisualize;
currentRadioMedium = (MRM) currentSimulation.getRadioMedium();
currentChannelModel = currentRadioMedium.getChannelModel();
simulation = simulationToVisualize;
radioMedium = (MRM) simulation.getRadioMedium();
channelModel = radioMedium.getChannelModel();
// -- Create and add GUI components --
JPanel allComponents = new JPanel();
@ -102,52 +103,52 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
areaGeneral = collapsableArea;
addBooleanParameter(
"apply_random",
currentChannelModel.getParameterDescription("apply_random"),
Parameter.apply_random,
Parameter.getDescription(Parameter.apply_random),
collapsableArea,
currentChannelModel.getParameterBooleanValue("apply_random")
channelModel.getParameterBooleanValue(Parameter.apply_random)
);
addDoubleParameter(
"snr_threshold",
currentChannelModel.getParameterDescription("snr_threshold"),
Parameter.snr_threshold,
Parameter.getDescription(Parameter.snr_threshold),
collapsableArea,
currentChannelModel.getParameterDoubleValue("snr_threshold")
channelModel.getParameterDoubleValue(Parameter.snr_threshold)
);
addDoubleParameter(
"bg_noise_mean",
currentChannelModel.getParameterDescription("bg_noise_mean"),
Parameter.bg_noise_mean,
Parameter.getDescription(Parameter.bg_noise_mean),
collapsableArea,
currentChannelModel.getParameterDoubleValue("bg_noise_mean")
channelModel.getParameterDoubleValue(Parameter.bg_noise_mean)
);
addDoubleParameter(
"bg_noise_var",
currentChannelModel.getParameterDescription("bg_noise_var"),
Parameter.bg_noise_var,
Parameter.getDescription(Parameter.bg_noise_var),
collapsableArea,
currentChannelModel.getParameterDoubleValue("bg_noise_var")
channelModel.getParameterDoubleValue(Parameter.bg_noise_var)
);
addDoubleParameter(
"system_gain_mean",
currentChannelModel.getParameterDescription("system_gain_mean"),
Parameter.system_gain_mean,
Parameter.getDescription(Parameter.system_gain_mean),
collapsableArea,
currentChannelModel.getParameterDoubleValue("system_gain_mean")
channelModel.getParameterDoubleValue(Parameter.system_gain_mean)
);
addDoubleParameter(
"system_gain_var",
currentChannelModel.getParameterDescription("system_gain_var"),
Parameter.system_gain_var,
Parameter.getDescription(Parameter.system_gain_var),
collapsableArea,
currentChannelModel.getParameterDoubleValue("system_gain_var")
channelModel.getParameterDoubleValue(Parameter.system_gain_var)
);
addDoubleParameter(
"wavelength",
currentChannelModel.getParameterDescription("wavelength"),
Parameter.frequency,
Parameter.getDescription(Parameter.frequency),
collapsableArea,
currentChannelModel.getParameterDoubleValue("wavelength")
channelModel.getParameterDoubleValue(Parameter.frequency)
);
// Transmitter parameters
@ -155,17 +156,17 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
areaTransmitter = collapsableArea;
addDoubleParameter(
"tx_power",
currentChannelModel.getParameterDescription("tx_power"),
Parameter.tx_power,
Parameter.getDescription(Parameter.tx_power),
collapsableArea,
currentChannelModel.getParameterDoubleValue("tx_power")
channelModel.getParameterDoubleValue(Parameter.tx_power)
);
addDoubleParameter(
"tx_antenna_gain",
currentChannelModel.getParameterDescription("tx_antenna_gain"),
addBooleanParameter(
Parameter.tx_with_gain,
Parameter.getDescription(Parameter.tx_with_gain),
collapsableArea,
currentChannelModel.getParameterDoubleValue("tx_antenna_gain")
channelModel.getParameterBooleanValue(Parameter.tx_with_gain)
);
// Receiver parameters
@ -173,17 +174,17 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
areaReceiver = collapsableArea;
addDoubleParameter(
"rx_sensitivity",
currentChannelModel.getParameterDescription("rx_sensitivity"),
Parameter.rx_sensitivity,
Parameter.getDescription(Parameter.rx_sensitivity),
collapsableArea,
currentChannelModel.getParameterDoubleValue("rx_sensitivity")
channelModel.getParameterDoubleValue(Parameter.rx_sensitivity)
);
addDoubleParameter(
"rx_antenna_gain",
currentChannelModel.getParameterDescription("rx_antenna_gain"),
addBooleanParameter(
Parameter.rx_with_gain,
Parameter.getDescription(Parameter.rx_with_gain),
collapsableArea,
currentChannelModel.getParameterDoubleValue("rx_antenna_gain")
channelModel.getParameterBooleanValue(Parameter.rx_with_gain)
);
// Ray Tracer parameters
@ -191,87 +192,87 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
areaRayTracer = collapsableArea;
addBooleanParameter(
"rt_disallow_direct_path",
currentChannelModel.getParameterDescription("rt_disallow_direct_path"),
Parameter.rt_disallow_direct_path,
Parameter.getDescription(Parameter.rt_disallow_direct_path),
collapsableArea,
currentChannelModel.getParameterBooleanValue("rt_disallow_direct_path")
channelModel.getParameterBooleanValue(Parameter.rt_disallow_direct_path)
);
addBooleanParameter(
"rt_ignore_non_direct",
currentChannelModel.getParameterDescription("rt_ignore_non_direct"),
Parameter.rt_ignore_non_direct,
Parameter.getDescription(Parameter.rt_ignore_non_direct),
collapsableArea,
currentChannelModel.getParameterBooleanValue("rt_ignore_non_direct")
channelModel.getParameterBooleanValue(Parameter.rt_ignore_non_direct)
);
addBooleanParameter(
"rt_fspl_on_total_length",
currentChannelModel.getParameterDescription("rt_fspl_on_total_length"),
Parameter.rt_fspl_on_total_length,
Parameter.getDescription(Parameter.rt_fspl_on_total_length),
collapsableArea,
currentChannelModel.getParameterBooleanValue("rt_fspl_on_total_length")
channelModel.getParameterBooleanValue(Parameter.rt_fspl_on_total_length)
);
addIntegerParameter(
"rt_max_rays",
currentChannelModel.getParameterDescription("rt_max_rays"),
Parameter.rt_max_rays,
Parameter.getDescription(Parameter.rt_max_rays),
collapsableArea,
currentChannelModel.getParameterIntegerValue("rt_max_rays")
channelModel.getParameterIntegerValue(Parameter.rt_max_rays)
);
addIntegerParameter(
"rt_max_refractions",
currentChannelModel.getParameterDescription("rt_max_refractions"),
Parameter.rt_max_refractions,
Parameter.getDescription(Parameter.rt_max_refractions),
collapsableArea,
currentChannelModel.getParameterIntegerValue("rt_max_refractions")
channelModel.getParameterIntegerValue(Parameter.rt_max_refractions)
);
addIntegerParameter(
"rt_max_reflections",
currentChannelModel.getParameterDescription("rt_max_reflections"),
Parameter.rt_max_reflections,
Parameter.getDescription(Parameter.rt_max_reflections),
collapsableArea,
currentChannelModel.getParameterIntegerValue("rt_max_reflections")
channelModel.getParameterIntegerValue(Parameter.rt_max_reflections)
);
addIntegerParameter(
"rt_max_diffractions",
currentChannelModel.getParameterDescription("rt_max_diffractions"),
Parameter.rt_max_diffractions,
Parameter.getDescription(Parameter.rt_max_diffractions),
collapsableArea,
currentChannelModel.getParameterIntegerValue("rt_max_diffractions")
channelModel.getParameterIntegerValue(Parameter.rt_max_diffractions)
);
/* addBooleanParameter(
"rt_use_scattering",
currentChannelModel.getParameterDescription("rt_use_scattering"),
Parameters.rt_use_scattering,
Parameter.getDescription(Parameters.rt_use_scattering),
collapsableArea,
currentChannelModel.getParameterBooleanValue("rt_use_scattering")
currentChannelModel.getParameterBooleanValue(Parameters.rt_use_scattering)
);
*/
addDoubleParameter(
"rt_refrac_coefficient",
currentChannelModel.getParameterDescription("rt_refrac_coefficient"),
Parameter.rt_refrac_coefficient,
Parameter.getDescription(Parameter.rt_refrac_coefficient),
collapsableArea,
currentChannelModel.getParameterDoubleValue("rt_refrac_coefficient")
channelModel.getParameterDoubleValue(Parameter.rt_refrac_coefficient)
);
addDoubleParameter(
"rt_reflec_coefficient",
currentChannelModel.getParameterDescription("rt_reflec_coefficient"),
Parameter.rt_reflec_coefficient,
Parameter.getDescription(Parameter.rt_reflec_coefficient),
collapsableArea,
currentChannelModel.getParameterDoubleValue("rt_reflec_coefficient")
channelModel.getParameterDoubleValue(Parameter.rt_reflec_coefficient)
);
addDoubleParameter(
"rt_diffr_coefficient",
currentChannelModel.getParameterDescription("rt_diffr_coefficient"),
Parameter.rt_diffr_coefficient,
Parameter.getDescription(Parameter.rt_diffr_coefficient),
collapsableArea,
currentChannelModel.getParameterDoubleValue("rt_diffr_coefficient")
channelModel.getParameterDoubleValue(Parameter.rt_diffr_coefficient)
);
/* addDoubleParameter(
"rt_scatt_coefficient",
currentChannelModel.getParameterDescription("rt_scatt_coefficient"),
Parameters.rt_scatt_coefficient,
Parameter.getDescription(Parameters.rt_scatt_coefficient),
collapsableArea,
currentChannelModel.getParameterDoubleValue("rt_scatt_coefficient")
currentChannelModel.getParameterDoubleValue(Parameters.rt_scatt_coefficient)
);
*/
// Shadowing parameters
@ -279,16 +280,14 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
areaShadowing = collapsableArea;
addDoubleParameter(
"obstacle_attenuation",
currentChannelModel.getParameterDescription("obstacle_attenuation"),
Parameter.obstacle_attenuation,
Parameter.getDescription(Parameter.obstacle_attenuation),
collapsableArea,
currentChannelModel.getParameterDoubleValue("obstacle_attenuation")
channelModel.getParameterDoubleValue(Parameter.obstacle_attenuation)
);
// Add channel model observer responsible to keep all GUI components synched
currentChannelModel.addSettingsObserver(channelModelSettingsObserver);
channelModel.addSettingsObserver(channelModelSettingsObserver);
// Set initial size etc.
pack();
@ -312,6 +311,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
private JPanel createCollapsableArea(String title, Container contentPane) {
// Create panels
JPanel holdingPanel = new JPanel() {
private static final long serialVersionUID = -7925426641856424500L;
public Dimension getMaximumSize() {
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
}
@ -319,6 +319,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
holdingPanel.setLayout(new BoxLayout(holdingPanel, BoxLayout.Y_AXIS));
final JPanel collapsableArea = new JPanel() {
private static final long serialVersionUID = -1261182973911973773L;
public Dimension getMaximumSize() {
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
}
@ -327,6 +328,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
collapsableArea.setVisible(false);
JPanel titlePanel = new JPanel(new BorderLayout()) {
private static final long serialVersionUID = -9121775806029887815L;
public Dimension getMaximumSize() {
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
}
@ -369,7 +371,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
* @param initialValue Initial value
* @return Text field in created panel
*/
private JFormattedTextField addDoubleParameter(String id, String description, Container contentPane, double initialValue) {
private JFormattedTextField addDoubleParameter(Parameter id, String description, Container contentPane, double initialValue) {
JPanel panel = new JPanel();
JLabel label;
JFormattedTextField textField;
@ -386,19 +388,34 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
textField.putClientProperty("id", id);
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
Object sourceObject = e.getSource();
Double newValue = ((Number) e.getNewValue()).doubleValue();
String id = (String) ((JFormattedTextField) sourceObject).getClientProperty("id");
currentChannelModel.setParameterValue(id, newValue);
JFormattedTextField textField = (JFormattedTextField) e.getSource();
Parameter id = (Parameter) textField.getClientProperty("id");
Double val = ((Number) e.getNewValue()).doubleValue();
channelModel.setParameterValue(id, val);
if (!Parameter.getDefaultValue(id).equals(val)) {
textField.setBackground(Color.LIGHT_GRAY);
textField.setToolTipText("Default value: " + Parameter.getDefaultValue(id));
} else {
textField.setBackground(null);
textField.setToolTipText(null);
}
}
});
if (!Parameter.getDefaultValue(id).equals(initialValue)) {
textField.setBackground(Color.LIGHT_GRAY);
textField.setToolTipText("Default value: " + Parameter.getDefaultValue(id));
} else {
textField.setBackground(null);
textField.setToolTipText(null);
}
allDoubleParameters.add(textField);
contentPane.add(panel);
return textField;
}
/**
* Creates and adds a panel with a label and a
* text field which accepts integers.
@ -409,7 +426,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
* @param initialValue Initial value
* @return Text field in created panel
*/
private JFormattedTextField addIntegerParameter(String id, String description, Container contentPane, int initialValue) {
private JFormattedTextField addIntegerParameter(Parameter id, String description, Container contentPane, int initialValue) {
JPanel panel = new JPanel();
JLabel label;
JFormattedTextField textField;
@ -426,12 +443,26 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
textField.putClientProperty("id", id);
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
Object sourceObject = e.getSource();
Integer newValue = ((Number) e.getNewValue()).intValue();
String id = (String) ((JFormattedTextField) sourceObject).getClientProperty("id");
currentChannelModel.setParameterValue(id, newValue);
JFormattedTextField textField = (JFormattedTextField) e.getSource();
Parameter id = (Parameter) textField.getClientProperty("id");
Integer val = ((Number) e.getNewValue()).intValue();
channelModel.setParameterValue(id, val);
if (!Parameter.getDefaultValue(id).equals(val)) {
textField.setBackground(Color.LIGHT_GRAY);
textField.setToolTipText("Default value: " + Parameter.getDefaultValue(id));
} else {
textField.setBackground(null);
textField.setToolTipText(null);
}
}
});
if (!Parameter.getDefaultValue(id).equals(initialValue)) {
textField.setBackground(Color.LIGHT_GRAY);
textField.setToolTipText("Default value: " + Parameter.getDefaultValue(id));
} else {
textField.setBackground(null);
textField.setToolTipText(null);
}
allIntegerParameters.add(textField);
@ -450,7 +481,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
* @param initialValue Initial value
* @return Checkbox in created panel
*/
private JCheckBox addBooleanParameter(String id, String description, Container contentPane, boolean initialValue) {
private JCheckBox addBooleanParameter(Parameter id, String description, Container contentPane, boolean initialValue) {
JPanel panel = new JPanel();
JLabel label;
JCheckBox checkBox;
@ -466,14 +497,23 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
checkBox.putClientProperty("id", id);
checkBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JCheckBox source = (JCheckBox) e.getSource();
currentChannelModel.setParameterValue(
(String) source.getClientProperty("id"),
new Boolean(source.isSelected())
);
JCheckBox checkBox = (JCheckBox) e.getSource();
Parameter id = (Parameter) checkBox.getClientProperty("id");
Object val = new Boolean(checkBox.isSelected());
channelModel.setParameterValue(id, val);
if (!Parameter.getDefaultValue(id).equals(val)) {
checkBox.setText("<");
} else {
checkBox.setText("");
}
}
});
if (!Parameter.getDefaultValue(id).equals(initialValue)) {
checkBox.setText("<");
} else {
checkBox.setText("");
}
allBooleanParameters.add(checkBox);
contentPane.add(panel);
@ -481,29 +521,6 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
return checkBox;
}
/**
* Creates and adds a panel with a description label.
*
* @param description Description of new parameter
* @param contentPane Where to add created panel
* @return Created label
*/
private JLabel addLabelParameter(String description, Container contentPane) {
JPanel panel = new JPanel();
JLabel label;
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setAlignmentY(Component.TOP_ALIGNMENT);
panel.add(Box.createHorizontalStrut(10));
panel.add(label = new JLabel(description));
label.setPreferredSize(labelDimension);
panel.add(Box.createHorizontalGlue());
contentPane.add(panel);
return label;
}
/**
* Listens to settings changes in the channel model.
* If it changes, all GUI parameters are updated accordingly.
@ -513,22 +530,22 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
// Update all integers
for (int i=0; i < allIntegerParameters.size(); i++) {
JFormattedTextField textField = allIntegerParameters.get(i);
String id = (String) textField.getClientProperty("id");
textField.setValue(currentChannelModel.getParameterValue(id));
Parameter id = (Parameter) textField.getClientProperty("id");
textField.setValue(channelModel.getParameterValue(id));
}
// Update all doubles
for (int i=0; i < allDoubleParameters.size(); i++) {
JFormattedTextField textField = allDoubleParameters.get(i);
String id = (String) textField.getClientProperty("id");
textField.setValue(currentChannelModel.getParameterValue(id));
Parameter id = (Parameter) textField.getClientProperty("id");
textField.setValue(channelModel.getParameterValue(id));
}
// Update all booleans
for (int i=0; i < allBooleanParameters.size(); i++) {
JCheckBox checkBox = allBooleanParameters.get(i);
String id = (String) checkBox.getClientProperty("id");
checkBox.setSelected(currentChannelModel.getParameterBooleanValue(id));
Parameter id = (Parameter) checkBox.getClientProperty("id");
checkBox.setSelected(channelModel.getParameterBooleanValue(id));
}
repaint();
@ -536,12 +553,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
};
public void closePlugin() {
// Remove the channel model observer
if (currentChannelModel != null && channelModelSettingsObserver != null) {
currentChannelModel.deleteSettingsObserver(channelModelSettingsObserver);
} else {
logger.fatal("Can't remove channel model observer: " + channelModelSettingsObserver);
}
channelModel.deleteSettingsObserver(channelModelSettingsObserver);
}
/**
@ -551,7 +563,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
* @return XML element collection
*/
public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
ArrayList<Element> config = new ArrayList<Element>();
Element element;
element = new Element("show_general");

View file

@ -43,11 +43,16 @@ import org.jdom.Element;
import se.sics.cooja.ClassDescription;
import se.sics.cooja.RadioConnection;
import se.sics.cooja.Simulation;
import se.sics.cooja.interfaces.DirectionalAntennaRadio;
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.plugins.Visualizer;
import se.sics.cooja.radiomediums.AbstractRadioMedium;
import se.sics.mrm.ChannelModel.Parameter;
import se.sics.mrm.ChannelModel.RadioPair;
import se.sics.mrm.ChannelModel.TxPair;
/**
* Multi-path Ray-tracing radio medium (MRM).
@ -63,8 +68,9 @@ import se.sics.cooja.radiomediums.AbstractRadioMedium;
*
* Future work includes adding support for diffraction and scattering.
*
* MRM supports noise source radios.
* MRM supports both noise source radios and directional antenna radios.
*
* @see DirectionalAntennaRadio
* @see NoiseSourceRadio
* @author Fredrik Osterlind
*/
@ -72,7 +78,8 @@ import se.sics.cooja.radiomediums.AbstractRadioMedium;
public class MRM extends AbstractRadioMedium {
private static Logger logger = Logger.getLogger(MRM.class);
public final static boolean WITH_NOISE = true; /* NoiseSourceRadio:s */
public final static boolean WITH_NOISE = true; /* NoiseSourceRadio */
public final static boolean WITH_DIRECTIONAL = true; /* DirectionalAntennaRadio */
public final static boolean WITH_CAPTURE_EFFECT = true;
private Simulation sim;
@ -92,44 +99,46 @@ public class MRM extends AbstractRadioMedium {
sim = simulation;
random = simulation.getRandomGenerator();
currentChannelModel = new ChannelModel();
currentChannelModel = new ChannelModel(sim);
/* Register plugins */
/* Register plugins */
sim.getGUI().registerPlugin(AreaViewer.class);
sim.getGUI().registerPlugin(FormulaViewer.class);
Visualizer.registerVisualizerSkin(MRMVisualizerSkin.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();
super.removed();
/* Unregister plugins */
/* Unregister plugins */
sim.getGUI().unregisterPlugin(AreaViewer.class);
sim.getGUI().unregisterPlugin(FormulaViewer.class);
Visualizer.unregisterVisualizerSkin(MRMVisualizerSkin.class);
}
public MRMRadioConnection createConnections(Radio sender) {
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 (WITH_NOISE && radio instanceof NoiseSourceRadio) {
((NoiseSourceRadio)radio).addNoiseLevelListener(noiseListener);
}
}
public void unregisterRadioInterface(Radio radio, Simulation sim) {
super.unregisterRadioInterface(radio, sim);
if (WITH_NOISE && radio instanceof NoiseSourceRadio) {
((NoiseSourceRadio)radio).removeNoiseLevelListener(noiseListener);
}
}
public MRMRadioConnection createConnections(final Radio sender) {
MRMRadioConnection newConnection = new MRMRadioConnection(sender);
Position senderPos = sender.getPosition();
final Position senderPos = sender.getPosition();
/* TODO Cache potential destination in DGRM */
/* Loop through all potential destinations */
@ -144,21 +153,26 @@ public class MRM extends AbstractRadioMedium {
sender.getChannel() != recv.getChannel()) {
continue;
}
Position recvPos = recv.getPosition();
final Radio recvFinal = recv;
/* Calculate receive probability */
TxPair txPair = new RadioPair() {
public Radio getFromRadio() {
return sender;
}
public Radio getToRadio() {
return recvFinal;
}
};
double[] probData = currentChannelModel.getProbability(
senderPos.getXCoordinate(),
senderPos.getYCoordinate(),
recvPos.getXCoordinate(),
recvPos.getYCoordinate(),
txPair,
-Double.MAX_VALUE /* TODO Include interference */
);
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) */
/* Yes, the receiver *may* receive this packet (it's strong enough) */
if (!recv.isReceiverOn()) {
newConnection.addInterfered(recv);
recv.interfereAnyReception();
@ -170,15 +184,15 @@ public class MRM extends AbstractRadioMedium {
} 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);
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();
/* Interfere receiver in all other active radio connections */
@ -187,22 +201,22 @@ public class MRM extends AbstractRadioMedium {
conn.addInterfered(recv);
}
}
}
}
} else {
/* Success: radio starts receiving */
newConnection.addDestination(recv, recvSignalStrength);
}
} else if (recvSignalStrength > currentChannelModel.getParameterDoubleValue("bg_noise_mean")) {
/* The incoming signal is strong, but strong enough to interfere? */
} else if (recvSignalStrength > currentChannelModel.getParameterDoubleValue(Parameter.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... */
}
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... */
}
}
}
@ -213,8 +227,8 @@ public class MRM extends AbstractRadioMedium {
public void updateSignalStrengths() {
/* Reset: Background noise */
double background =
currentChannelModel.getParameterDoubleValue(("bg_noise_mean"));
double background =
currentChannelModel.getParameterDoubleValue((Parameter.bg_noise_mean));
for (Radio radio : getRegisteredRadios()) {
radio.setCurrentSignalStrength(background);
}
@ -235,12 +249,12 @@ public class MRM extends AbstractRadioMedium {
for (Radio intfRadio : ((MRMRadioConnection) conn).getInterfered()) {
double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(intfRadio);
if (intfRadio.getCurrentSignalStrength() < signalStrength) {
intfRadio.setCurrentSignalStrength(signalStrength);
intfRadio.setCurrentSignalStrength(signalStrength);
}
if (!intfRadio.isInterfered()) {
/*logger.warn("Radio was not interfered: " + intfRadio);*/
intfRadio.interfereAnyReception();
intfRadio.interfereAnyReception();
}
}
}
@ -248,53 +262,58 @@ public class MRM extends AbstractRadioMedium {
/* 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;
}
if (!(noiseRadio instanceof NoiseSourceRadio)) {
continue;
}
final Radio fromRadio = noiseRadio;
NoiseSourceRadio radio = (NoiseSourceRadio) noiseRadio;
int signalStrength = radio.getNoiseLevel();
if (signalStrength == Integer.MIN_VALUE) {
continue;
}
/* Calculate how noise source affects surrounding radios */
/* Calculate how noise source affects surrounding radios */
for (Radio affectedRadio : getRegisteredRadios()) {
if (noiseRadio == affectedRadio) {
continue;
}
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;
}
/* Update noise levels */
final Radio toRadio = affectedRadio;
TxPair txPair = new RadioPair() {
public Radio getFromRadio() {
return fromRadio;
}
public Radio getToRadio() {
return toRadio;
}
};
double[] signalMeanVar = currentChannelModel.getReceivedSignalStrength(txPair);
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 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 */
/* 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();
affectedRadio.interfereAnyReception();
}
}
}
}
}
}
}
}
}
}
}
}
@ -334,7 +353,7 @@ public class MRM extends AbstractRadioMedium {
* @return Number of registered radios.
*/
public int getRegisteredRadioCount() {
/* TODO Expensive operation */
/* TODO Expensive operation */
return getRegisteredRadios().length;
}
@ -383,16 +402,16 @@ public class MRM extends AbstractRadioMedium {
}
public double getDestinationSignalStrength(Radio radio) {
if (signalStrengths.get(radio) == null) {
return Double.MIN_VALUE;
}
if (signalStrengths.get(radio) == null) {
return Double.MIN_VALUE;
}
return signalStrengths.get(radio);
}
public double getInterferenceSignalStrength(Radio radio) {
if (signalStrengths.get(radio) == null) {
return Double.MIN_VALUE;
}
if (signalStrengths.get(radio) == null) {
return Double.MIN_VALUE;
}
return signalStrengths.get(radio);
}
}

View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2011, Swedish Institute of Computer Science.
* 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 se.sics.mrm;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import org.apache.log4j.Logger;
import se.sics.cooja.ClassDescription;
import se.sics.cooja.Mote;
import se.sics.cooja.Simulation;
import se.sics.cooja.interfaces.Position;
import se.sics.cooja.interfaces.Radio;
import se.sics.cooja.plugins.Visualizer;
import se.sics.cooja.plugins.VisualizerSkin;
import se.sics.mrm.ChannelModel.RadioPair;
import se.sics.mrm.ChannelModel.TxPair;
@ClassDescription("Radio environment (MRM)")
public class MRMVisualizerSkin implements VisualizerSkin {
private static Logger logger = Logger.getLogger(MRMVisualizerSkin.class);
private Simulation simulation = null;
private Visualizer visualizer = null;
public void setActive(Simulation simulation, Visualizer vis) {
if (!(simulation.getRadioMedium() instanceof MRM)) {
logger.fatal("Cannot activate MRM skin for unknown radio medium: " + simulation.getRadioMedium());
return;
}
this.simulation = simulation;
this.visualizer = vis;
}
public void setInactive() {
if (simulation == null) {
/* Skin was never activated */
return;
}
}
public Color[] getColorOf(Mote mote) {
Mote selectedMote = visualizer.getSelectedMote();
if (mote == selectedMote) {
return new Color[] { Color.CYAN };
}
return null;
}
public void paintBeforeMotes(Graphics g) {
final Mote selectedMote = visualizer.getSelectedMote();
if (simulation == null
|| selectedMote == null
|| selectedMote.getInterfaces().getRadio() == null) {
return;
}
final Position sPos = selectedMote.getInterfaces().getPosition();
/* Paint transmission and interference range for selected mote */
Position motePos = selectedMote.getInterfaces().getPosition();
Point pixelCoord = visualizer.transformPositionToPixel(motePos);
int x = pixelCoord.x;
int y = pixelCoord.y;
FontMetrics fm = g.getFontMetrics();
g.setColor(Color.BLACK);
MRM radioMedium = (MRM) simulation.getRadioMedium();
/* Print transmission success probabilities */
Mote[] dests = simulation.getMotes();
if (dests == null || dests.length == 0) {
String msg = "No edges";
int msgWidth = fm.stringWidth(msg);
g.setColor(Color.BLACK);
g.drawString(msg, x - msgWidth/2, y + 2*Visualizer.MOTE_RADIUS + 3);
return;
}
g.setColor(Color.BLACK);
int edges = 0;
for (Mote d: dests) {
if (d == selectedMote) {
continue;
}
final Radio dRadio = d.getInterfaces().getRadio();
TxPair txPair = new RadioPair() {
public Radio getFromRadio() {
return selectedMote.getInterfaces().getRadio();
}
public Radio getToRadio() {
return dRadio;
}
};
double probArr[] = radioMedium.getChannelModel().getProbability(
txPair,
Double.NEGATIVE_INFINITY
);
double prob = probArr[0];
double ss = probArr[1];
if (prob == 0.0d) {
continue;
}
edges++;
String msg = String.format("%1.1f%%, %1.2fdB", 100.0*prob, ss);
Point pixel = visualizer.transformPositionToPixel(d.getInterfaces().getPosition());
int msgWidth = fm.stringWidth(msg);
g.setColor(new Color(1-(float)prob, (float)prob, 0.0f));
g.drawLine(x, y, pixel.x, pixel.y);
g.setColor(Color.BLACK);
g.drawString(msg, pixel.x - msgWidth/2, pixel.y + 2*Visualizer.MOTE_RADIUS + 3);
}
String msg = dests.length + " edges";
int msgWidth = fm.stringWidth(msg);
g.setColor(Color.BLACK);
g.drawString(msg, x - msgWidth/2, y + 2*Visualizer.MOTE_RADIUS + 3);
}
public void paintAfterMotes(Graphics g) {
}
public Visualizer getVisualizer() {
return visualizer;
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2011, Swedish Institute of Computer Science. 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 se.sics.cooja.interfaces;
/**
* Directional antenna.
*
* @see MRM
* @author Fredrik Osterlind
*/
public interface DirectionalAntennaRadio {
/**
* @return Current direction (radians). Typically direction 0 has the maximum
* relative gain.
*
* @see #getRelativeGain(double)
*/
public double getDirection();
/**
* Relative gain (dB) as compared to an omnidirectional antenna.
* Note that the given angle is relative to the current direction!
*
* @see #getDirection()
* @param radians Angle relative to current direction
* @param distance Distance from antenna
* @return
*/
public double getRelativeGain(double radians, double distance);
public void addDirectionChangeListener(DirectionChangeListener l);
public void removeDirectionChangeListener(DirectionChangeListener l);
public interface DirectionChangeListener {
public void newDirection(DirectionalAntennaRadio radio, double direction);
}
}