* 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:
parent
77057ede8a
commit
eb84fbeb79
|
@ -63,14 +63,16 @@ import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
|
import javax.swing.Action;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.Box;
|
import javax.swing.Box;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
|
@ -99,11 +101,12 @@ import org.jdom.Element;
|
||||||
import se.sics.cooja.ClassDescription;
|
import se.sics.cooja.ClassDescription;
|
||||||
import se.sics.cooja.GUI;
|
import se.sics.cooja.GUI;
|
||||||
import se.sics.cooja.PluginType;
|
import se.sics.cooja.PluginType;
|
||||||
import se.sics.cooja.RadioConnection;
|
|
||||||
import se.sics.cooja.Simulation;
|
import se.sics.cooja.Simulation;
|
||||||
import se.sics.cooja.VisPlugin;
|
import se.sics.cooja.VisPlugin;
|
||||||
|
import se.sics.cooja.interfaces.DirectionalAntennaRadio;
|
||||||
import se.sics.cooja.interfaces.Position;
|
import se.sics.cooja.interfaces.Position;
|
||||||
import se.sics.cooja.interfaces.Radio;
|
import se.sics.cooja.interfaces.Radio;
|
||||||
|
import se.sics.mrm.ChannelModel.TxPair;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class AreaViewer belongs to the MRM package.
|
* The class AreaViewer belongs to the MRM package.
|
||||||
|
@ -118,14 +121,13 @@ import se.sics.cooja.interfaces.Radio;
|
||||||
* @see MRM
|
* @see MRM
|
||||||
* @author Fredrik Osterlind
|
* @author Fredrik Osterlind
|
||||||
*/
|
*/
|
||||||
@ClassDescription("MRM - Area Viewer")
|
@ClassDescription("MRM Radio environment")
|
||||||
@PluginType(PluginType.SIM_PLUGIN)
|
@PluginType(PluginType.SIM_PLUGIN)
|
||||||
public class AreaViewer extends VisPlugin {
|
public class AreaViewer extends VisPlugin {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static Logger logger = Logger.getLogger(AreaViewer.class);
|
private static Logger logger = Logger.getLogger(AreaViewer.class);
|
||||||
|
|
||||||
private final JPanel canvas;
|
private final JPanel canvas;
|
||||||
private final VisPlugin thisPlugin;
|
|
||||||
|
|
||||||
ChannelModel.TransmissionData dataTypeToVisualize = ChannelModel.TransmissionData.SIGNAL_STRENGTH;
|
ChannelModel.TransmissionData dataTypeToVisualize = ChannelModel.TransmissionData.SIGNAL_STRENGTH;
|
||||||
ButtonGroup visTypeSelectionGroup;
|
ButtonGroup visTypeSelectionGroup;
|
||||||
|
@ -144,7 +146,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
private boolean drawCalculatedObstacles = true;
|
private boolean drawCalculatedObstacles = true;
|
||||||
private boolean drawChannelProbabilities = true;
|
private boolean drawChannelProbabilities = true;
|
||||||
private boolean drawRadios = true;
|
private boolean drawRadios = true;
|
||||||
private boolean drawRadioActivity = true;
|
//private boolean drawRadioActivity = true;
|
||||||
private boolean drawScaleArrow = true;
|
private boolean drawScaleArrow = true;
|
||||||
|
|
||||||
// Background drawing parameters (meters)
|
// Background drawing parameters (meters)
|
||||||
|
@ -171,7 +173,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
private Image channelImage = null;
|
private Image channelImage = null;
|
||||||
|
|
||||||
private JSlider resolutionSlider;
|
private JSlider resolutionSlider;
|
||||||
private JPanel controlPanel;
|
private Box controlPanel;
|
||||||
private JScrollPane scrollControlPanel;
|
private JScrollPane scrollControlPanel;
|
||||||
|
|
||||||
private Simulation currentSimulation;
|
private Simulation currentSimulation;
|
||||||
|
@ -200,20 +202,25 @@ public class AreaViewer extends VisPlugin {
|
||||||
private JCheckBox obstaclesCheckBox;
|
private JCheckBox obstaclesCheckBox;
|
||||||
private JCheckBox channelCheckBox;
|
private JCheckBox channelCheckBox;
|
||||||
private JCheckBox radiosCheckBox;
|
private JCheckBox radiosCheckBox;
|
||||||
private JCheckBox radioActivityCheckBox;
|
// private JCheckBox radioActivityCheckBox;
|
||||||
private JCheckBox arrowCheckBox;
|
private JCheckBox arrowCheckBox;
|
||||||
|
|
||||||
private JRadioButton noneButton = null;
|
private JRadioButton noneButton = null;
|
||||||
|
|
||||||
|
private JRadioButton selectModeButton;
|
||||||
|
private JRadioButton panModeButton;
|
||||||
|
private JRadioButton zoomModeButton;
|
||||||
private JRadioButton trackModeButton;
|
private JRadioButton trackModeButton;
|
||||||
|
|
||||||
|
private Action paintEnvironmentAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an AreaViewer.
|
* Initializes an AreaViewer.
|
||||||
*
|
*
|
||||||
* @param simulationToVisualize Simulation using MRM
|
* @param simulationToVisualize Simulation using MRM
|
||||||
*/
|
*/
|
||||||
public AreaViewer(Simulation simulationToVisualize, GUI gui) {
|
public AreaViewer(Simulation simulationToVisualize, GUI gui) {
|
||||||
super("MRM - Area Viewer", gui);
|
super("MRM Radio environment", gui);
|
||||||
|
|
||||||
currentSimulation = simulationToVisualize;
|
currentSimulation = simulationToVisualize;
|
||||||
currentRadioMedium = (MRM) currentSimulation.getRadioMedium();
|
currentRadioMedium = (MRM) currentSimulation.getRadioMedium();
|
||||||
|
@ -227,7 +234,6 @@ public class AreaViewer extends VisPlugin {
|
||||||
// Set initial size etc.
|
// Set initial size etc.
|
||||||
setSize(500, 500);
|
setSize(500, 500);
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
thisPlugin = this;
|
|
||||||
|
|
||||||
// Canvas mode radio buttons + show settings checkbox
|
// Canvas mode radio buttons + show settings checkbox
|
||||||
showSettingsBox = new JCheckBox ("settings", true);
|
showSettingsBox = new JCheckBox ("settings", true);
|
||||||
|
@ -236,20 +242,20 @@ public class AreaViewer extends VisPlugin {
|
||||||
showSettingsBox.setActionCommand("toggle show settings");
|
showSettingsBox.setActionCommand("toggle show settings");
|
||||||
showSettingsBox.addActionListener(canvasModeHandler);
|
showSettingsBox.addActionListener(canvasModeHandler);
|
||||||
|
|
||||||
JRadioButton selectModeButton = new JRadioButton ("select");
|
selectModeButton = new JRadioButton ("select");
|
||||||
selectModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
selectModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
||||||
selectModeButton.setContentAreaFilled(false);
|
selectModeButton.setContentAreaFilled(false);
|
||||||
selectModeButton.setActionCommand("set select mode");
|
selectModeButton.setActionCommand("set select mode");
|
||||||
selectModeButton.addActionListener(canvasModeHandler);
|
selectModeButton.addActionListener(canvasModeHandler);
|
||||||
selectModeButton.setSelected(true);
|
selectModeButton.setSelected(true);
|
||||||
|
|
||||||
JRadioButton panModeButton = new JRadioButton ("pan");
|
panModeButton = new JRadioButton ("pan");
|
||||||
panModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
panModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
||||||
panModeButton.setContentAreaFilled(false);
|
panModeButton.setContentAreaFilled(false);
|
||||||
panModeButton.setActionCommand("set pan mode");
|
panModeButton.setActionCommand("set pan mode");
|
||||||
panModeButton.addActionListener(canvasModeHandler);
|
panModeButton.addActionListener(canvasModeHandler);
|
||||||
|
|
||||||
JRadioButton zoomModeButton = new JRadioButton ("zoom");
|
zoomModeButton = new JRadioButton ("zoom");
|
||||||
zoomModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
zoomModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
||||||
zoomModeButton.setContentAreaFilled(false);
|
zoomModeButton.setContentAreaFilled(false);
|
||||||
zoomModeButton.setActionCommand("set zoom mode");
|
zoomModeButton.setActionCommand("set zoom mode");
|
||||||
|
@ -322,10 +328,10 @@ public class AreaViewer extends VisPlugin {
|
||||||
radiosCheckBox.addActionListener(selectGraphicsHandler);
|
radiosCheckBox.addActionListener(selectGraphicsHandler);
|
||||||
graphicsComponentsPanel.add(radiosCheckBox);
|
graphicsComponentsPanel.add(radiosCheckBox);
|
||||||
|
|
||||||
radioActivityCheckBox = new JCheckBox("Radio Activity", true);
|
// radioActivityCheckBox = new JCheckBox("Radio Activity", true);
|
||||||
radioActivityCheckBox.setActionCommand("toggle radio activity");
|
// radioActivityCheckBox.setActionCommand("toggle radio activity");
|
||||||
radioActivityCheckBox.addActionListener(selectGraphicsHandler);
|
// radioActivityCheckBox.addActionListener(selectGraphicsHandler);
|
||||||
graphicsComponentsPanel.add(radioActivityCheckBox);
|
// graphicsComponentsPanel.add(radioActivityCheckBox);
|
||||||
|
|
||||||
arrowCheckBox = new JCheckBox("Scale arrow", true);
|
arrowCheckBox = new JCheckBox("Scale arrow", true);
|
||||||
arrowCheckBox.setActionCommand("toggle arrow");
|
arrowCheckBox.setActionCommand("toggle arrow");
|
||||||
|
@ -366,8 +372,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
graphicsComponentsPanel.add(customButton);
|
graphicsComponentsPanel.add(customButton);
|
||||||
|
|
||||||
// Create visualize channel output panel
|
// Create visualize channel output panel
|
||||||
JPanel visualizeChannelPanel = new JPanel();
|
Box visualizeChannelPanel = Box.createVerticalBox();
|
||||||
visualizeChannelPanel.setLayout(new BoxLayout(visualizeChannelPanel, BoxLayout.Y_AXIS));
|
|
||||||
visualizeChannelPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
|
visualizeChannelPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
|
||||||
visualizeChannelPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
visualizeChannelPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
|
||||||
|
@ -400,6 +405,8 @@ public class AreaViewer extends VisPlugin {
|
||||||
visualizeChannelPanel.add(fixedVsRelative);
|
visualizeChannelPanel.add(fixedVsRelative);
|
||||||
|
|
||||||
coloringIntervalPanel = new JPanel() {
|
coloringIntervalPanel = new JPanel() {
|
||||||
|
private static final long serialVersionUID = 8247374386307237940L;
|
||||||
|
|
||||||
public void paintComponent(Graphics g) {
|
public void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
|
|
||||||
|
@ -572,20 +579,22 @@ public class AreaViewer extends VisPlugin {
|
||||||
visualizeChannelPanel.add(Box.createRigidArea(new Dimension(0,20)));
|
visualizeChannelPanel.add(Box.createRigidArea(new Dimension(0,20)));
|
||||||
|
|
||||||
JButton recalculateVisibleButton = new JButton("Paint radio channel");
|
JButton recalculateVisibleButton = new JButton("Paint radio channel");
|
||||||
recalculateVisibleButton.setActionCommand("recalculate visible area");
|
paintEnvironmentAction = new AbstractAction("Paint radio channel") {
|
||||||
recalculateVisibleButton.addActionListener(formulaHandler);
|
private static final long serialVersionUID = 1L;
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
repaintRadioEnvironment();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
paintEnvironmentAction.setEnabled(false);
|
||||||
|
recalculateVisibleButton.setAction(paintEnvironmentAction);
|
||||||
visualizeChannelPanel.add(recalculateVisibleButton);
|
visualizeChannelPanel.add(recalculateVisibleButton);
|
||||||
|
|
||||||
// Create control panel
|
// Create control panel
|
||||||
controlPanel = new JPanel();
|
controlPanel = Box.createVerticalBox();
|
||||||
controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
|
|
||||||
graphicsComponentsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
graphicsComponentsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
controlPanel.add(graphicsComponentsPanel);
|
controlPanel.add(graphicsComponentsPanel);
|
||||||
controlPanel.add(new JSeparator());
|
controlPanel.add(new JSeparator());
|
||||||
controlPanel.add(Box.createRigidArea(new Dimension(0, 5)));
|
|
||||||
visualizeChannelPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
|
||||||
controlPanel.add(visualizeChannelPanel);
|
controlPanel.add(visualizeChannelPanel);
|
||||||
controlPanel.setPreferredSize(new Dimension(250,700));
|
|
||||||
controlPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
controlPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
scrollControlPanel = new JScrollPane(
|
scrollControlPanel = new JScrollPane(
|
||||||
controlPanel,
|
controlPanel,
|
||||||
|
@ -627,15 +636,47 @@ public class AreaViewer extends VisPlugin {
|
||||||
*/
|
*/
|
||||||
private MouseAdapter canvasMouseHandler = new MouseAdapter() {
|
private MouseAdapter canvasMouseHandler = new MouseAdapter() {
|
||||||
private Popup popUpToolTip = null;
|
private Popup popUpToolTip = null;
|
||||||
|
private boolean temporaryZoom = false;
|
||||||
|
private boolean temporaryPan = false;
|
||||||
|
private boolean trackedPreviously = false;
|
||||||
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
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) {
|
if (popUpToolTip != null) {
|
||||||
popUpToolTip.hide();
|
popUpToolTip.hide();
|
||||||
popUpToolTip = null;
|
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) {
|
if (popUpToolTip != null) {
|
||||||
popUpToolTip.hide();
|
popUpToolTip.hide();
|
||||||
popUpToolTip = null;
|
popUpToolTip = null;
|
||||||
|
@ -646,32 +687,40 @@ public class AreaViewer extends VisPlugin {
|
||||||
zoomCenterX = e.getX() / currentZoomX - currentPanX;
|
zoomCenterX = e.getX() / currentZoomX - currentPanX;
|
||||||
zoomCenterY = e.getY() / currentZoomY - currentPanY;
|
zoomCenterY = e.getY() / currentZoomY - currentPanY;
|
||||||
zoomCenterPoint = e.getPoint();
|
zoomCenterPoint = e.getPoint();
|
||||||
|
if (temporaryZoom || temporaryPan) {
|
||||||
|
e.consume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Select */
|
/* Select */
|
||||||
if (inSelectMode) {
|
if (inSelectMode) {
|
||||||
Vector<Radio> hitRadios = trackClickedRadio(e.getPoint());
|
ArrayList<Radio> hitRadios = trackClickedRadio(e.getPoint());
|
||||||
if (hitRadios == null || hitRadios.size() == 0) {
|
if (hitRadios == null || hitRadios.size() == 0) {
|
||||||
if (e.getButton() != MouseEvent.BUTTON1) {
|
if (e.getButton() != MouseEvent.BUTTON1) {
|
||||||
selectedRadio = null;
|
selectedRadio = null;
|
||||||
channelImage = null;
|
channelImage = null;
|
||||||
trackModeButton.setEnabled(false);
|
trackModeButton.setEnabled(false);
|
||||||
|
paintEnvironmentAction.setEnabled(false);
|
||||||
canvas.repaint();
|
canvas.repaint();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hitRadios.size() == 1 && hitRadios.firstElement() == selectedRadio) {
|
if (hitRadios.size() == 1 && hitRadios.get(0) == selectedRadio) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedRadio == null || !hitRadios.contains(selectedRadio)) {
|
if (selectedRadio == null || !hitRadios.contains(selectedRadio)) {
|
||||||
selectedRadio = hitRadios.firstElement();
|
selectedRadio = hitRadios.get(0);
|
||||||
trackModeButton.setEnabled(true);
|
trackModeButton.setEnabled(true);
|
||||||
|
paintEnvironmentAction.setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
selectedRadio = hitRadios.get(
|
selectedRadio = hitRadios.get(
|
||||||
(hitRadios.indexOf(selectedRadio)+1) % hitRadios.size()
|
(hitRadios.indexOf(selectedRadio)+1) % hitRadios.size()
|
||||||
);
|
);
|
||||||
|
|
||||||
trackModeButton.setEnabled(true);
|
trackModeButton.setEnabled(true);
|
||||||
|
paintEnvironmentAction.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
channelImage = null;
|
channelImage = null;
|
||||||
|
@ -681,30 +730,42 @@ public class AreaViewer extends VisPlugin {
|
||||||
|
|
||||||
/* Track */
|
/* Track */
|
||||||
if (inTrackMode && selectedRadio != null) {
|
if (inTrackMode && selectedRadio != null) {
|
||||||
double realClickedX = e.getX() / currentZoomX - currentPanX;
|
TxPair txPair = new TxPair() {
|
||||||
double realClickedY = e.getY() / currentZoomY - currentPanY;
|
public double getFromX() { return selectedRadio.getPosition().getXCoordinate(); }
|
||||||
|
public double getFromY() { return selectedRadio.getPosition().getYCoordinate(); }
|
||||||
Position radioPosition = selectedRadio.getPosition();
|
public double getToX() { return e.getX() / currentZoomX - currentPanX; }
|
||||||
final double radioX = radioPosition.getXCoordinate();
|
public double getToY() { return e.getY() / currentZoomY - currentPanY; }
|
||||||
final double radioY = radioPosition.getYCoordinate();
|
public double getTxPower() { return selectedRadio.getCurrentOutputPower(); }
|
||||||
|
public double getTxGain() {
|
||||||
trackedComponents = currentChannelModel.getRaysOfTransmission(radioX, radioY, realClickedX, realClickedY);
|
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();
|
canvas.repaint();
|
||||||
|
|
||||||
/* Show popup */
|
/* Show popup */
|
||||||
JToolTip t = AreaViewer.this.createToolTip();
|
JToolTip t = AreaViewer.this.createToolTip();
|
||||||
|
|
||||||
String logHtml =
|
String logHtml =
|
||||||
"<html>" +
|
"<html>" +
|
||||||
trackedComponents.log.replace("\n", "<br>").replace(" pi", " π") +
|
trackedComponents.log.replace("\n", "<br>").replace(" pi", " π") +
|
||||||
"</html>";
|
"</html>";
|
||||||
t.setTipText(logHtml);
|
t.setTipText(logHtml);
|
||||||
|
|
||||||
if (t.getTipText() == null || t.getTipText().equals("")) {
|
if (t.getTipText() == null || t.getTipText().equals("")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
popUpToolTip = PopupFactory.getSharedInstance().getPopup(
|
popUpToolTip = PopupFactory.getSharedInstance().getPopup(
|
||||||
AreaViewer.this, t, e.getXOnScreen(), e.getYOnScreen());
|
AreaViewer.this, t, e.getXOnScreen(), e.getYOnScreen());
|
||||||
popUpToolTip.show();
|
popUpToolTip.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -806,9 +867,8 @@ public class AreaViewer extends VisPlugin {
|
||||||
} else {
|
} else {
|
||||||
scrollControlPanel.setVisible(false);
|
scrollControlPanel.setVisible(false);
|
||||||
}
|
}
|
||||||
thisPlugin.invalidate();
|
AreaViewer.this.invalidate();
|
||||||
thisPlugin.revalidate();
|
AreaViewer.this.revalidate();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -826,8 +886,8 @@ public class AreaViewer extends VisPlugin {
|
||||||
drawChannelProbabilities = ((JCheckBox) e.getSource()).isSelected();
|
drawChannelProbabilities = ((JCheckBox) e.getSource()).isSelected();
|
||||||
} else if (e.getActionCommand().equals("toggle radios")) {
|
} else if (e.getActionCommand().equals("toggle radios")) {
|
||||||
drawRadios = ((JCheckBox) e.getSource()).isSelected();
|
drawRadios = ((JCheckBox) e.getSource()).isSelected();
|
||||||
} else if (e.getActionCommand().equals("toggle radio activity")) {
|
// } else if (e.getActionCommand().equals("toggle radio activity")) {
|
||||||
drawRadioActivity = ((JCheckBox) e.getSource()).isSelected();
|
// drawRadioActivity = ((JCheckBox) e.getSource()).isSelected();
|
||||||
} else if (e.getActionCommand().equals("toggle arrow")) {
|
} else if (e.getActionCommand().equals("toggle arrow")) {
|
||||||
drawScaleArrow = ((JCheckBox) e.getSource()).isSelected();
|
drawScaleArrow = ((JCheckBox) e.getSource()).isSelected();
|
||||||
}
|
}
|
||||||
|
@ -871,6 +931,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImageSettingsDialog extends JDialog {
|
class ImageSettingsDialog extends JDialog {
|
||||||
|
private static final long serialVersionUID = 3026474554976919518L;
|
||||||
|
|
||||||
private double
|
private double
|
||||||
virtualStartX = 0.0,
|
virtualStartX = 0.0,
|
||||||
|
@ -1205,7 +1266,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
currentChannelModel.notifySettingsChanged();
|
currentChannelModel.notifySettingsChanged();
|
||||||
thisPlugin.repaint();
|
AreaViewer.this.repaint();
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
if (pm.isCanceled()) {
|
if (pm.isCanceled()) {
|
||||||
|
@ -1230,6 +1291,8 @@ public class AreaViewer extends VisPlugin {
|
||||||
};
|
};
|
||||||
|
|
||||||
class ObstacleFinderDialog extends JDialog {
|
class ObstacleFinderDialog extends JDialog {
|
||||||
|
private static final long serialVersionUID = -8963997923536967296L;
|
||||||
|
|
||||||
private NumberFormat intFormat = NumberFormat.getIntegerInstance();
|
private NumberFormat intFormat = NumberFormat.getIntegerInstance();
|
||||||
private BufferedImage imageToAnalyze = null;
|
private BufferedImage imageToAnalyze = null;
|
||||||
private BufferedImage obstacleImage = null;
|
private BufferedImage obstacleImage = null;
|
||||||
|
@ -1449,6 +1512,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
|
|
||||||
// Preview image
|
// Preview image
|
||||||
tempPanel = new JPanel() {
|
tempPanel = new JPanel() {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
public void paintComponent(Graphics g) {
|
public void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
g.drawImage(imageToAnalyze, 0, 0, getWidth(), getHeight(), this);
|
g.drawImage(imageToAnalyze, 0, 0, getWidth(), getHeight(), this);
|
||||||
|
@ -1609,6 +1673,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
selectedRadio = null;
|
selectedRadio = null;
|
||||||
channelImage = null;
|
channelImage = null;
|
||||||
trackModeButton.setEnabled(false);
|
trackModeButton.setEnabled(false);
|
||||||
|
paintEnvironmentAction.setEnabled(false);
|
||||||
canvas.repaint();
|
canvas.repaint();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1675,13 +1740,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
return (alpha << 24) | (red << 16) | (green << 8) | blue;
|
return (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void repaintRadioEnvironment() {
|
||||||
* 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")) {
|
|
||||||
|
|
||||||
// Get resolution of new image
|
// Get resolution of new image
|
||||||
final Dimension resolution = new Dimension(
|
final Dimension resolution = new Dimension(
|
||||||
resolutionSlider.getValue(),
|
resolutionSlider.getValue(),
|
||||||
|
@ -1734,15 +1793,36 @@ public class AreaViewer extends VisPlugin {
|
||||||
double[][] imageValues = new double[resolution.width][resolution.height];
|
double[][] imageValues = new double[resolution.width][resolution.height];
|
||||||
for (int x=0; x < resolution.width; x++) {
|
for (int x=0; x < resolution.width; x++) {
|
||||||
for (int y=0; y < resolution.height; y++) {
|
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) {
|
if (dataTypeToVisualize == ChannelModel.TransmissionData.SIGNAL_STRENGTH) {
|
||||||
// Attenuate
|
// Attenuate
|
||||||
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(
|
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(txPair);
|
||||||
radioX,
|
|
||||||
radioY,
|
|
||||||
startX + width * x/resolution.width,
|
|
||||||
startY + height * y/resolution.height
|
|
||||||
);
|
|
||||||
|
|
||||||
// Collecting signal strengths
|
// Collecting signal strengths
|
||||||
if (signalStrength[0] < lowestImageValue) {
|
if (signalStrength[0] < lowestImageValue) {
|
||||||
|
@ -1756,12 +1836,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
|
|
||||||
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SIGNAL_STRENGTH_VAR) {
|
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SIGNAL_STRENGTH_VAR) {
|
||||||
// Attenuate
|
// Attenuate
|
||||||
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(
|
double[] signalStrength = currentChannelModel.getReceivedSignalStrength(txPair);
|
||||||
radioX,
|
|
||||||
radioY,
|
|
||||||
startX + width * x/resolution.width,
|
|
||||||
startY + height * y/resolution.height
|
|
||||||
);
|
|
||||||
|
|
||||||
// Collecting variances
|
// Collecting variances
|
||||||
if (signalStrength[1] < lowestImageValue) {
|
if (signalStrength[1] < lowestImageValue) {
|
||||||
|
@ -1776,10 +1851,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SNR) {
|
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SNR) {
|
||||||
// Get signal to noise ratio
|
// Get signal to noise ratio
|
||||||
double[] snr = currentChannelModel.getSINR(
|
double[] snr = currentChannelModel.getSINR(
|
||||||
radioX,
|
txPair,
|
||||||
radioY,
|
|
||||||
startX + width * x/resolution.width,
|
|
||||||
startY + height * y/resolution.height,
|
|
||||||
-Double.MAX_VALUE
|
-Double.MAX_VALUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1796,10 +1868,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SNR_VAR) {
|
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.SNR_VAR) {
|
||||||
// Get signal to noise ratio
|
// Get signal to noise ratio
|
||||||
double[] snr = currentChannelModel.getSINR(
|
double[] snr = currentChannelModel.getSINR(
|
||||||
radioX,
|
txPair,
|
||||||
radioY,
|
|
||||||
startX + width * x/resolution.width,
|
|
||||||
startY + height * y/resolution.height,
|
|
||||||
-Double.MAX_VALUE
|
-Double.MAX_VALUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1815,11 +1884,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.PROB_OF_RECEPTION) {
|
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.PROB_OF_RECEPTION) {
|
||||||
// Get probability of receiving a packet TODO What size? Does it matter?
|
// Get probability of receiving a packet TODO What size? Does it matter?
|
||||||
double probability = currentChannelModel.getProbability(
|
double probability = currentChannelModel.getProbability(
|
||||||
radioX,
|
txPair, -Double.MAX_VALUE
|
||||||
radioY,
|
|
||||||
startX + width * x/resolution.width,
|
|
||||||
startY + height * y/resolution.height,
|
|
||||||
-Double.MAX_VALUE
|
|
||||||
)[0];
|
)[0];
|
||||||
|
|
||||||
// Collecting variances
|
// Collecting variances
|
||||||
|
@ -1834,10 +1899,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.DELAY_SPREAD_RMS) {
|
} else if (dataTypeToVisualize == ChannelModel.TransmissionData.DELAY_SPREAD_RMS) {
|
||||||
// Get RMS delay spread of receiving a packet
|
// Get RMS delay spread of receiving a packet
|
||||||
double rmsDelaySpread = currentChannelModel.getRMSDelaySpread(
|
double rmsDelaySpread = currentChannelModel.getRMSDelaySpread(
|
||||||
radioX,
|
txPair
|
||||||
radioY,
|
|
||||||
startX + width * x/resolution.width,
|
|
||||||
startY + height * y/resolution.height
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Collecting variances
|
// Collecting variances
|
||||||
|
@ -1909,7 +1971,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
channelHeight = height;
|
channelHeight = height;
|
||||||
channelImage = tempChannelImage;
|
channelImage = tempChannelImage;
|
||||||
|
|
||||||
thisPlugin.repaint();
|
AreaViewer.this.repaint();
|
||||||
coloringIntervalPanel.repaint();
|
coloringIntervalPanel.repaint();
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
@ -1927,9 +1989,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
// Start thread
|
// Start thread
|
||||||
attenuatorThread = new Thread(runnable);
|
attenuatorThread = new Thread(runnable);
|
||||||
attenuatorThread.start();
|
attenuatorThread.start();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repaint the canvas
|
* Repaint the canvas
|
||||||
|
@ -2112,66 +2172,66 @@ public class AreaViewer extends VisPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Draw radio activity --
|
// -- Draw radio activity --
|
||||||
if (drawRadioActivity) {
|
// if (drawRadioActivity) {
|
||||||
for (RadioConnection connection: currentRadioMedium.getActiveConnections()) {
|
// for (RadioConnection connection: currentRadioMedium.getActiveConnections()) {
|
||||||
Position sourcePosition = connection.getSource().getPosition();
|
// Position sourcePosition = connection.getSource().getPosition();
|
||||||
|
//
|
||||||
// Paint scaled (otherwise bad rounding to integers may occur)
|
// // Paint scaled (otherwise bad rounding to integers may occur)
|
||||||
g2d.setTransform(realWorldTransformScaled);
|
// g2d.setTransform(realWorldTransformScaled);
|
||||||
g2d.setStroke(new BasicStroke((float) 0.0));
|
// g2d.setStroke(new BasicStroke((float) 0.0));
|
||||||
|
//
|
||||||
for (Radio receivingRadio: connection.getDestinations()) {
|
// for (Radio receivingRadio: connection.getDestinations()) {
|
||||||
g2d.setColor(Color.GREEN);
|
// g2d.setColor(Color.GREEN);
|
||||||
|
//
|
||||||
// Get source and destination coordinates
|
// // Get source and destination coordinates
|
||||||
Position destinationPosition = receivingRadio.getPosition();
|
// Position destinationPosition = receivingRadio.getPosition();
|
||||||
|
//
|
||||||
g2d.draw(new Line2D.Double(
|
// g2d.draw(new Line2D.Double(
|
||||||
sourcePosition.getXCoordinate()*100.0,
|
// sourcePosition.getXCoordinate()*100.0,
|
||||||
sourcePosition.getYCoordinate()*100.0,
|
// sourcePosition.getYCoordinate()*100.0,
|
||||||
destinationPosition.getXCoordinate()*100.0,
|
// destinationPosition.getXCoordinate()*100.0,
|
||||||
destinationPosition.getYCoordinate()*100.0
|
// destinationPosition.getYCoordinate()*100.0
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
for (Radio interferedRadio: connection.getInterfered()) {
|
// for (Radio interferedRadio: connection.getInterfered()) {
|
||||||
g2d.setColor(Color.RED);
|
// g2d.setColor(Color.RED);
|
||||||
|
//
|
||||||
// Get source and destination coordinates
|
// // Get source and destination coordinates
|
||||||
Position destinationPosition = interferedRadio.getPosition();
|
// Position destinationPosition = interferedRadio.getPosition();
|
||||||
|
//
|
||||||
g2d.draw(new Line2D.Double(
|
// g2d.draw(new Line2D.Double(
|
||||||
sourcePosition.getXCoordinate()*100.0,
|
// sourcePosition.getXCoordinate()*100.0,
|
||||||
sourcePosition.getYCoordinate()*100.0,
|
// sourcePosition.getYCoordinate()*100.0,
|
||||||
destinationPosition.getXCoordinate()*100.0,
|
// destinationPosition.getXCoordinate()*100.0,
|
||||||
destinationPosition.getYCoordinate()*100.0
|
// destinationPosition.getYCoordinate()*100.0
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
g2d.setColor(Color.BLUE);
|
// g2d.setColor(Color.BLUE);
|
||||||
g2d.setTransform(realWorldTransform);
|
// g2d.setTransform(realWorldTransform);
|
||||||
|
//
|
||||||
g2d.translate(
|
// g2d.translate(
|
||||||
sourcePosition.getXCoordinate(),
|
// sourcePosition.getXCoordinate(),
|
||||||
sourcePosition.getYCoordinate()
|
// sourcePosition.getYCoordinate()
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
// Fetch current translation
|
// // Fetch current translation
|
||||||
double xPos = g2d.getTransform().getTranslateX();
|
// double xPos = g2d.getTransform().getTranslateX();
|
||||||
double yPos = g2d.getTransform().getTranslateY();
|
// double yPos = g2d.getTransform().getTranslateY();
|
||||||
|
//
|
||||||
// Jump to identity transform and paint without scaling
|
// // Jump to identity transform and paint without scaling
|
||||||
g2d.setTransform(new AffineTransform());
|
// g2d.setTransform(new AffineTransform());
|
||||||
|
//
|
||||||
g2d.fillOval(
|
// g2d.fillOval(
|
||||||
(int) xPos,
|
// (int) xPos,
|
||||||
(int) yPos,
|
// (int) yPos,
|
||||||
5,
|
// 5,
|
||||||
5
|
// 5
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// -- Draw scale arrow --
|
// -- Draw scale arrow --
|
||||||
if (drawScaleArrow) {
|
if (drawScaleArrow) {
|
||||||
|
@ -2210,7 +2270,7 @@ public class AreaViewer extends VisPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Draw tracked components (if any) --
|
// -- Draw tracked components (if any) --
|
||||||
if (inTrackMode && trackedComponents != null) {
|
if (!currentSimulation.isRunning() && inTrackMode && trackedComponents != null) {
|
||||||
g2d.setTransform(realWorldTransformScaled);
|
g2d.setTransform(realWorldTransformScaled);
|
||||||
g2d.setStroke(new BasicStroke((float) 0.0));
|
g2d.setStroke(new BasicStroke((float) 0.0));
|
||||||
|
|
||||||
|
@ -2238,8 +2298,8 @@ public class AreaViewer extends VisPlugin {
|
||||||
* @param clickedPoint On-screen position
|
* @param clickedPoint On-screen position
|
||||||
* @return All hit radios
|
* @return All hit radios
|
||||||
*/
|
*/
|
||||||
protected Vector<Radio> trackClickedRadio(Point clickedPoint) {
|
protected ArrayList<Radio> trackClickedRadio(Point clickedPoint) {
|
||||||
Vector<Radio> hitRadios = new Vector<Radio>();
|
ArrayList<Radio> hitRadios = new ArrayList<Radio>();
|
||||||
if (currentRadioMedium.getRegisteredRadioCount() == 0) {
|
if (currentRadioMedium.getRegisteredRadioCount() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -2297,9 +2357,16 @@ public class AreaViewer extends VisPlugin {
|
||||||
* @return XML element collection
|
* @return XML element collection
|
||||||
*/
|
*/
|
||||||
public Collection<Element> getConfigXML() {
|
public Collection<Element> getConfigXML() {
|
||||||
Vector<Element> config = new Vector<Element>();
|
ArrayList<Element> config = new ArrayList<Element>();
|
||||||
Element element;
|
Element element;
|
||||||
|
|
||||||
|
/* Selected mote */
|
||||||
|
if (selectedRadio != null) {
|
||||||
|
element = new Element("selected");
|
||||||
|
element.setAttribute("mote", "" + selectedRadio.getMote().getID());
|
||||||
|
config.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
// Controls visible
|
// Controls visible
|
||||||
element = new Element("controls_visible");
|
element = new Element("controls_visible");
|
||||||
element.setText(Boolean.toString(showSettingsBox.isSelected()));
|
element.setText(Boolean.toString(showSettingsBox.isSelected()));
|
||||||
|
@ -2332,9 +2399,9 @@ public class AreaViewer extends VisPlugin {
|
||||||
element = new Element("show_radios");
|
element = new Element("show_radios");
|
||||||
element.setText(Boolean.toString(drawRadios));
|
element.setText(Boolean.toString(drawRadios));
|
||||||
config.add(element);
|
config.add(element);
|
||||||
element = new Element("show_activity");
|
// element = new Element("show_activity");
|
||||||
element.setText(Boolean.toString(drawRadioActivity));
|
// element.setText(Boolean.toString(drawRadioActivity));
|
||||||
config.add(element);
|
// config.add(element);
|
||||||
element = new Element("show_arrow");
|
element = new Element("show_arrow");
|
||||||
element.setText(Boolean.toString(drawScaleArrow));
|
element.setText(Boolean.toString(drawScaleArrow));
|
||||||
config.add(element);
|
config.add(element);
|
||||||
|
@ -2382,7 +2449,12 @@ public class AreaViewer extends VisPlugin {
|
||||||
*/
|
*/
|
||||||
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
||||||
for (Element element : configXML) {
|
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()));
|
showSettingsBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||||
canvasModeHandler.actionPerformed(new ActionEvent(showSettingsBox,
|
canvasModeHandler.actionPerformed(new ActionEvent(showSettingsBox,
|
||||||
ActionEvent.ACTION_PERFORMED, showSettingsBox.getActionCommand()));
|
ActionEvent.ACTION_PERFORMED, showSettingsBox.getActionCommand()));
|
||||||
|
@ -2411,9 +2483,9 @@ public class AreaViewer extends VisPlugin {
|
||||||
selectGraphicsHandler.actionPerformed(new ActionEvent(radiosCheckBox,
|
selectGraphicsHandler.actionPerformed(new ActionEvent(radiosCheckBox,
|
||||||
ActionEvent.ACTION_PERFORMED, radiosCheckBox.getActionCommand()));
|
ActionEvent.ACTION_PERFORMED, radiosCheckBox.getActionCommand()));
|
||||||
} else if (element.getName().equals("show_activity")) {
|
} else if (element.getName().equals("show_activity")) {
|
||||||
radioActivityCheckBox.setSelected(Boolean.parseBoolean(element.getText()));
|
// radioActivityCheckBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||||
selectGraphicsHandler.actionPerformed(new ActionEvent(radioActivityCheckBox,
|
// selectGraphicsHandler.actionPerformed(new ActionEvent(radioActivityCheckBox,
|
||||||
ActionEvent.ACTION_PERFORMED, radioActivityCheckBox.getActionCommand()));
|
// ActionEvent.ACTION_PERFORMED, radioActivityCheckBox.getActionCommand()));
|
||||||
} else if (element.getName().equals("show_arrow")) {
|
} else if (element.getName().equals("show_arrow")) {
|
||||||
arrowCheckBox.setSelected(Boolean.parseBoolean(element.getText()));
|
arrowCheckBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||||
selectGraphicsHandler.actionPerformed(new ActionEvent(arrowCheckBox,
|
selectGraphicsHandler.actionPerformed(new ActionEvent(arrowCheckBox,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
* Copyright (c) 2011, Swedish Institute of Computer Science.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -31,12 +31,29 @@
|
||||||
|
|
||||||
package se.sics.mrm;
|
package se.sics.mrm;
|
||||||
|
|
||||||
import java.awt.geom.*;
|
import java.awt.geom.GeneralPath;
|
||||||
import java.util.*;
|
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 javax.swing.tree.DefaultMutableTreeNode;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jdom.Element;
|
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;
|
import statistics.GaussianWrapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,9 +70,12 @@ import statistics.GaussianWrapper;
|
||||||
public class ChannelModel {
|
public class ChannelModel {
|
||||||
private static Logger logger = Logger.getLogger(ChannelModel.class);
|
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}
|
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();
|
private Properties parameterDescriptions = new Properties();
|
||||||
|
|
||||||
// Parameters used for speeding up calculations
|
// Parameters used for speeding up calculations
|
||||||
|
@ -71,6 +91,8 @@ public class ChannelModel {
|
||||||
private StringBuilder logInfo = null;
|
private StringBuilder logInfo = null;
|
||||||
private ArrayList<Line2D> loggedRays = null;
|
private ArrayList<Line2D> loggedRays = null;
|
||||||
|
|
||||||
|
private Simulation simulation;
|
||||||
|
|
||||||
|
|
||||||
// Ray tracing components temporary vector
|
// Ray tracing components temporary vector
|
||||||
private Vector<Vector<Line2D>> calculatedVisibleSides = new Vector<Vector<Line2D>>();
|
private Vector<Vector<Line2D>> calculatedVisibleSides = new Vector<Vector<Line2D>>();
|
||||||
|
@ -89,105 +111,180 @@ public class ChannelModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private SettingsObservable settingsObservable = new SettingsObservable();
|
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() {
|
public static Object getDefaultValue(Parameter p) {
|
||||||
// - Set initial parameter values -
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
// Using random variables
|
public static Parameter fromString(String name) {
|
||||||
parameters.put("apply_random", new Boolean(false)); // TODO Should not use random variables as default
|
/* Backwards compatability */
|
||||||
parameterDescriptions.put("apply_random", "Apply random values immediately");
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// Signal to noise reception threshold
|
public static String getDescription(Parameter p) {
|
||||||
parameters.put("snr_threshold", new Double(6));
|
switch (p) {
|
||||||
parameterDescriptions.put("snr_threshold", "SNR reception threshold (dB)");
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Background noise mean
|
public ChannelModel(Simulation simulation) {
|
||||||
parameters.put("bg_noise_mean", new Double(-150));
|
this.simulation = simulation;
|
||||||
parameterDescriptions.put("bg_noise_mean", "Background noise mean (dBm)");
|
|
||||||
|
|
||||||
// Background noise variance
|
/* Default values */
|
||||||
parameters.put("bg_noise_var", new Double(1));
|
for (Parameter p: Parameter.values()) {
|
||||||
parameterDescriptions.put("bg_noise_var", "Background noise variance (dB)");
|
parameters.put(p, Parameter.getDefaultValue(p));
|
||||||
|
}
|
||||||
|
|
||||||
// Extra system gain mean
|
parametersDefaults = (Hashtable<Parameter,Object>) parameters.clone();
|
||||||
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");
|
|
||||||
|
|
||||||
// Ray Tracer - Use scattering
|
// Ray Tracer - Use scattering
|
||||||
//parameters.put("rt_use_scattering", new Boolean(false)); // TODO Not used yet
|
//parameters.put(Parameters.rt_use_scattering, Parameter.getDefaultValue(Parameters.rt_use_scattering)); // TODO Not used yet
|
||||||
//parameterDescriptions.put("rt_use_scattering", "Use simple scattering");
|
//parameterDescriptions.put(Parameters.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)");
|
|
||||||
|
|
||||||
// Ray Tracer - Scattering coefficient
|
// Ray Tracer - Scattering coefficient
|
||||||
//parameters.put("rt_scatt_coefficient", new Double(-20)); // TODO Not used yet
|
//parameters.put(Parameters.rt_scatt_coefficient, Parameter.getDefaultValue(Parameters.rt_scatt_coefficient)); // TODO Not used yet
|
||||||
//parameterDescriptions.put("rt_scatt_coefficient", "!! Scattering coefficient (dB)");
|
//parameterDescriptions.put(Parameters.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)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -272,7 +369,7 @@ public class ChannelModel {
|
||||||
* @param identifier Parameter identifier
|
* @param identifier Parameter identifier
|
||||||
* @return Current parameter value
|
* @return Current parameter value
|
||||||
*/
|
*/
|
||||||
public Object getParameterValue(String id) {
|
public Object getParameterValue(Parameter id) {
|
||||||
Object value = parameters.get(id);
|
Object value = parameters.get(id);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
logger.fatal("No parameter with id:" + id + ", aborting");
|
logger.fatal("No parameter with id:" + id + ", aborting");
|
||||||
|
@ -287,7 +384,7 @@ public class ChannelModel {
|
||||||
* @param identifier Parameter identifier
|
* @param identifier Parameter identifier
|
||||||
* @return Current parameter value
|
* @return Current parameter value
|
||||||
*/
|
*/
|
||||||
public double getParameterDoubleValue(String id) {
|
public double getParameterDoubleValue(Parameter id) {
|
||||||
return ((Double) getParameterValue(id)).doubleValue();
|
return ((Double) getParameterValue(id)).doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +394,7 @@ public class ChannelModel {
|
||||||
* @param identifier Parameter identifier
|
* @param identifier Parameter identifier
|
||||||
* @return Current parameter value
|
* @return Current parameter value
|
||||||
*/
|
*/
|
||||||
public int getParameterIntegerValue(String id) {
|
public int getParameterIntegerValue(Parameter id) {
|
||||||
return ((Integer) getParameterValue(id)).intValue();
|
return ((Integer) getParameterValue(id)).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +404,7 @@ public class ChannelModel {
|
||||||
* @param identifier Parameter identifier
|
* @param identifier Parameter identifier
|
||||||
* @return Current parameter value
|
* @return Current parameter value
|
||||||
*/
|
*/
|
||||||
public boolean getParameterBooleanValue(String id) {
|
public boolean getParameterBooleanValue(Parameter id) {
|
||||||
return ((Boolean) getParameterValue(id)).booleanValue();
|
return ((Boolean) getParameterValue(id)).booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +414,7 @@ public class ChannelModel {
|
||||||
* @param id Parameter identifier
|
* @param id Parameter identifier
|
||||||
* @param newValue New parameter value
|
* @param newValue New parameter value
|
||||||
*/
|
*/
|
||||||
public void setParameterValue(String id, Object newValue) {
|
public void setParameterValue(Parameter id, Object newValue) {
|
||||||
if (!parameters.containsKey(id)) {
|
if (!parameters.containsKey(id)) {
|
||||||
logger.fatal("No parameter with id:" + id + ", aborting");
|
logger.fatal("No parameter with id:" + id + ", aborting");
|
||||||
return;
|
return;
|
||||||
|
@ -331,21 +428,6 @@ public class ChannelModel {
|
||||||
settingsObservable.notifySettingsChanged();
|
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
|
* When this method is called all settings observers
|
||||||
* will be notified.
|
* will be notified.
|
||||||
|
@ -355,27 +437,20 @@ public class ChannelModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Free Space Path Loss factor (in dB), by using
|
* Path loss component from Friis' transmission equation.
|
||||||
* parts of the Friis equation. (FSPL <= 0)
|
* Uses frequency and distance only.
|
||||||
*
|
*
|
||||||
* @param distance Distance from transmitter to receiver
|
* @param distance Transmitter-receiver distance
|
||||||
* @return FSPL factor
|
* @return Path loss (dB)
|
||||||
*/
|
*/
|
||||||
protected double getFSPL(double distance) {
|
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) {
|
if (needToPrecalculateFSPL) {
|
||||||
double w = getParameterDoubleValue("wavelength");
|
double f = getParameterDoubleValue(Parameter.frequency);
|
||||||
paramFSPL = 20*Math.log10(w) - 20*Math.log10(4*Math.PI);
|
paramFSPL = -32.44 -20*Math.log10(f /*mhz*/);
|
||||||
needToPrecalculateFSPL = false;
|
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
|
// Check if direct path exists
|
||||||
justBeforeDestination = sourcePoint;
|
justBeforeDestination = sourcePoint;
|
||||||
|
|
||||||
if (!getParameterBooleanValue("rt_disallow_direct_path")) {
|
if (!getParameterBooleanValue(Parameter.rt_disallow_direct_path)) {
|
||||||
directPathExists = isDirectPath(justBeforeDestination, dest);
|
directPathExists = isDirectPath(justBeforeDestination, dest);
|
||||||
} else {
|
} else {
|
||||||
directPathExists = false;
|
directPathExists = false;
|
||||||
|
@ -797,7 +872,7 @@ public class ChannelModel {
|
||||||
allPaths.add(currentPath);
|
allPaths.add(currentPath);
|
||||||
|
|
||||||
// Stop here if no other paths should be considered
|
// 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;
|
return allPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1326,17 +1401,15 @@ public class ChannelModel {
|
||||||
* @return Received signal strength (dBm) random variable. The first value is
|
* @return Received signal strength (dBm) random variable. The first value is
|
||||||
* the random variable mean, and the second is the variance.
|
* the random variable mean, and the second is the variance.
|
||||||
*/
|
*/
|
||||||
public double[] getReceivedSignalStrength(double sourceX, double sourceY, double destX, double destY) {
|
public double[] getReceivedSignalStrength(TxPair txPair) {
|
||||||
return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH, null);
|
return getTransmissionData(txPair, TransmissionData.SIGNAL_STRENGTH);
|
||||||
}
|
|
||||||
public double[] getReceivedSignalStrength(double sourceX, double sourceY, double destX, double destY, Double txPower) {
|
|
||||||
return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.SIGNAL_STRENGTH, txPower);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO Fix better data type support
|
// TODO Fix better data type support
|
||||||
private double[] getTransmissionData(double sourceX, double sourceY, double destX, double destY, TransmissionData dataType, Double txPower) {
|
private double[] getTransmissionData(TxPair txPair, TransmissionData dataType) {
|
||||||
Point2D source = new Point2D.Double(sourceX, sourceY);
|
Point2D source = txPair.getFrom();
|
||||||
Point2D dest = new Point2D.Double(destX, destY);
|
Point2D dest = txPair.getTo();
|
||||||
double accumulatedVariance = 0;
|
double accumulatedVariance = 0;
|
||||||
|
|
||||||
// - Get all ray paths from source to destination -
|
// - Get all ray paths from source to destination -
|
||||||
|
@ -1344,28 +1417,24 @@ public class ChannelModel {
|
||||||
RayData.RayType.ORIGIN,
|
RayData.RayType.ORIGIN,
|
||||||
source,
|
source,
|
||||||
null,
|
null,
|
||||||
getParameterIntegerValue("rt_max_rays"),
|
getParameterIntegerValue(Parameter.rt_max_rays),
|
||||||
getParameterIntegerValue("rt_max_refractions"),
|
getParameterIntegerValue(Parameter.rt_max_refractions),
|
||||||
getParameterIntegerValue("rt_max_reflections"),
|
getParameterIntegerValue(Parameter.rt_max_reflections),
|
||||||
getParameterIntegerValue("rt_max_diffractions")
|
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
|
// Check if origin tree is already calculated and saved
|
||||||
DefaultMutableTreeNode visibleLinesTree = null;
|
DefaultMutableTreeNode visibleLinesTree = buildVisibleLinesTree(originRayData);
|
||||||
visibleLinesTree =
|
|
||||||
buildVisibleLinesTree(originRayData);
|
|
||||||
|
|
||||||
// Calculate all paths from source to destination, using above calculated tree
|
// Calculate all paths from source to destination, using above calculated tree
|
||||||
Vector<RayPath> allPaths = getConnectingPaths(source, dest, visibleLinesTree);
|
Vector<RayPath> allPaths = getConnectingPaths(source, dest, visibleLinesTree);
|
||||||
|
|
||||||
if (logMode) {
|
if (logMode) {
|
||||||
logInfo.append("Signal components:\n");
|
logInfo.append("Signal components:\n");
|
||||||
Enumeration<RayPath> pathsEnum = allPaths.elements();
|
Enumeration<RayPath> pathsEnum = allPaths.elements();
|
||||||
while (pathsEnum.hasMoreElements()) {
|
while (pathsEnum.hasMoreElements()) {
|
||||||
RayPath currentPath = pathsEnum.nextElement();
|
RayPath currentPath = pathsEnum.nextElement();
|
||||||
logInfo.append("* " + currentPath + "\n");
|
logInfo.append("* " + currentPath + "\n");
|
||||||
for (int i=0; i < currentPath.getSubPathCount(); i++) {
|
for (int i=0; i < currentPath.getSubPathCount(); i++) {
|
||||||
loggedRays.add(currentPath.getSubPath(i));
|
loggedRays.add(currentPath.getSubPath(i));
|
||||||
}
|
}
|
||||||
|
@ -1389,20 +1458,20 @@ public class ChannelModel {
|
||||||
// Type specific losses
|
// Type specific losses
|
||||||
// TODO Type specific losses depends on angles as well!
|
// TODO Type specific losses depends on angles as well!
|
||||||
if (subPathStartType == RayData.RayType.REFRACTION) {
|
if (subPathStartType == RayData.RayType.REFRACTION) {
|
||||||
pathGain[i] += getParameterDoubleValue("rt_refrac_coefficient");
|
pathGain[i] += getParameterDoubleValue(Parameter.rt_refrac_coefficient);
|
||||||
} else if (subPathStartType == RayData.RayType.REFLECTION) {
|
} 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)
|
// 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);
|
pathGain[i] += getFSPL(accumulatedStraightLength);
|
||||||
}
|
}
|
||||||
accumulatedStraightLength = 0; // Reset straight length
|
accumulatedStraightLength = 0; // Reset straight length
|
||||||
} else if (subPathStartType == RayData.RayType.DIFFRACTION) {
|
} 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)
|
// 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);
|
pathGain[i] += getFSPL(accumulatedStraightLength);
|
||||||
}
|
}
|
||||||
accumulatedStraightLength = 0; // Reset straight length
|
accumulatedStraightLength = 0; // Reset straight length
|
||||||
|
@ -1414,7 +1483,7 @@ public class ChannelModel {
|
||||||
// Ray passes through a wall, calculate distance through that wall
|
// Ray passes through a wall, calculate distance through that wall
|
||||||
|
|
||||||
// Fetch attenuation constant
|
// Fetch attenuation constant
|
||||||
double attenuationConstant = getParameterDoubleValue("obstacle_attenuation");
|
double attenuationConstant = getParameterDoubleValue(Parameter.obstacle_attenuation);
|
||||||
|
|
||||||
Vector<Rectangle2D> allPossibleObstacles = myObstacleWorld.getAllObstaclesNear(subPath.getP1());
|
Vector<Rectangle2D> allPossibleObstacles = myObstacleWorld.getAllObstaclesNear(subPath.getP1());
|
||||||
|
|
||||||
|
@ -1434,9 +1503,7 @@ public class ChannelModel {
|
||||||
pathGain[i] += attenuationConstant * line.getP1().distance(line.getP2());
|
pathGain[i] += attenuationConstant * line.getP1().distance(line.getP2());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to total path length
|
// Add to total path length
|
||||||
|
@ -1444,12 +1511,12 @@ public class ChannelModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add FSPL from last rays (if FSPL on individual rays)
|
// 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);
|
pathGain[i] += getFSPL(accumulatedStraightLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free space path loss on total path length?
|
// 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]);
|
pathGain[i] += getFSPL(pathLengths[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1463,7 +1530,8 @@ public class ChannelModel {
|
||||||
double[] pathModdedLengths = new double[allPaths.size()];
|
double[] pathModdedLengths = new double[allPaths.size()];
|
||||||
double delaySpread = 0;
|
double delaySpread = 0;
|
||||||
double delaySpreadRMS = 0;
|
double delaySpreadRMS = 0;
|
||||||
double wavelength = getParameterDoubleValue("wavelength");
|
double freq = getParameterDoubleValue(Parameter.frequency);
|
||||||
|
double wavelength = C/(freq*1000000d);
|
||||||
double totalPathGain = 0;
|
double totalPathGain = 0;
|
||||||
double delaySpreadTotalWeight = 0;
|
double delaySpreadTotalWeight = 0;
|
||||||
double speedOfLight = 300; // Approximate value (m/us)
|
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)
|
// 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);
|
totalPathGain += Math.pow(10, pathGain[i]/10.0)*Math.cos(2*Math.PI * pathModdedLengths[i]/wavelength);
|
||||||
if (logMode) {
|
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) {
|
} else if (logMode) {
|
||||||
/* TODO Log mode affects result? */
|
/* TODO Log mode affects result? */
|
||||||
pathModdedLengths[i] = (pathLengths[i] - pathLengths[bestSignalNr]) % wavelength;
|
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));
|
totalPathGain = 10*Math.log10(Math.abs(totalPathGain));
|
||||||
|
|
||||||
if (logMode) {
|
if (logMode) {
|
||||||
logInfo.append("\nTotal path gain: " + String.format("%2.3f", totalPathGain) + " dB\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("Delay spread: " + String.format("%2.3f", delaySpread) + "\n");
|
||||||
logInfo.append("RMS delay spread: " + String.format("%2.3f", delaySpreadRMS) + "\n");
|
logInfo.append("RMS delay spread: " + String.format("%2.3f", delaySpreadRMS) + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Calculate received power -
|
// - Calculate received power -
|
||||||
// Using formula (dB)
|
// Using formula (dB)
|
||||||
// Received power = Output power + System gain + Transmitter gain + Path Loss + Receiver gain
|
// Received power = Output power + System gain + Transmitter gain + Path Loss + Receiver gain
|
||||||
// TODO Update formulas
|
// TODO Update formulas
|
||||||
double outputPower;
|
double outputPower = txPair.getTxPower();
|
||||||
if (txPower == null) {
|
double systemGain = getParameterDoubleValue(Parameter.system_gain_mean);
|
||||||
outputPower = getParameterDoubleValue("tx_power");
|
if (getParameterBooleanValue(Parameter.apply_random)) {
|
||||||
} else {
|
|
||||||
outputPower = txPower;
|
|
||||||
}
|
|
||||||
double systemGain = getParameterDoubleValue("system_gain_mean");
|
|
||||||
if (getParameterBooleanValue("apply_random")) {
|
|
||||||
Random random = new Random(); /* TODO Use main random generator? */
|
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 {
|
} 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;
|
double receivedPower = outputPower + systemGain + transmitterGain + totalPathGain;
|
||||||
if (logMode) {
|
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) {
|
if (dataType == TransmissionData.DELAY_SPREAD || dataType == TransmissionData.DELAY_SPREAD_RMS) {
|
||||||
|
@ -1546,8 +1613,8 @@ public class ChannelModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TrackedSignalComponents {
|
public class TrackedSignalComponents {
|
||||||
ArrayList<Line2D> components;
|
ArrayList<Line2D> components;
|
||||||
String log;
|
String log;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1561,7 +1628,7 @@ public class ChannelModel {
|
||||||
* @param destY Destination position Y
|
* @param destY Destination position Y
|
||||||
* @return Signal components and printable description
|
* @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();
|
TrackedSignalComponents tsc = new TrackedSignalComponents();
|
||||||
|
|
||||||
logInfo = new StringBuilder();
|
logInfo = new StringBuilder();
|
||||||
|
@ -1569,7 +1636,7 @@ public class ChannelModel {
|
||||||
|
|
||||||
/* TODO Include background noise? */
|
/* TODO Include background noise? */
|
||||||
logMode = true;
|
logMode = true;
|
||||||
getProbability(sourceX, sourceY, destX, destY, -Double.MAX_VALUE);
|
getProbability(txPair, -Double.MAX_VALUE);
|
||||||
logMode = false;
|
logMode = false;
|
||||||
|
|
||||||
tsc.log = logInfo.toString();
|
tsc.log = logInfo.toString();
|
||||||
|
@ -1596,27 +1663,26 @@ public class ChannelModel {
|
||||||
* The second is the variance.
|
* The second is the variance.
|
||||||
* The third value is the received signal strength which may be used in comparison with interference etc.
|
* 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) {
|
public double[] getSINR(TxPair txPair, double interference) {
|
||||||
/* TODO Cache values: called repeatedly with noise sources. */
|
/* TODO Cache values: called repeatedly with noise sources. */
|
||||||
|
|
||||||
|
|
||||||
// Calculate received signal strength
|
// 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 =
|
// Add antenna gain
|
||||||
new double[] { signalStrength[0], signalStrength[1], signalStrength[0] };
|
if (getParameterBooleanValue(Parameter.rx_with_gain)) {
|
||||||
|
snrData[0] += txPair.getRxGain();
|
||||||
|
}
|
||||||
|
|
||||||
// Add antenna gain TODO Should depend on angle
|
double noiseVariance = getParameterDoubleValue(Parameter.bg_noise_var);
|
||||||
snrData[0] += getParameterDoubleValue("rx_antenna_gain");
|
double noiseMean = getParameterDoubleValue(Parameter.bg_noise_mean);
|
||||||
|
|
||||||
double noiseVariance = getParameterDoubleValue("bg_noise_var");
|
|
||||||
double noiseMean = getParameterDoubleValue("bg_noise_mean");
|
|
||||||
|
|
||||||
if (interference > noiseMean) {
|
if (interference > noiseMean) {
|
||||||
noiseMean = interference;
|
noiseMean = interference;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getParameterBooleanValue("apply_random")) {
|
if (getParameterBooleanValue(Parameter.apply_random)) {
|
||||||
Random random = new Random(); /* TODO Use main random generator? */
|
Random random = new Random(); /* TODO Use main random generator? */
|
||||||
noiseMean += Math.sqrt(noiseVariance) * random.nextGaussian();
|
noiseMean += Math.sqrt(noiseVariance) * random.nextGaussian();
|
||||||
noiseVariance = 0;
|
noiseVariance = 0;
|
||||||
|
@ -1627,7 +1693,7 @@ public class ChannelModel {
|
||||||
snrData[1] += noiseVariance;
|
snrData[1] += noiseVariance;
|
||||||
|
|
||||||
if (logMode) {
|
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;
|
return snrData;
|
||||||
}
|
}
|
||||||
|
@ -1649,19 +1715,19 @@ public class ChannelModel {
|
||||||
* @param interference Current interference at destination (dBm)
|
* @param interference Current interference at destination (dBm)
|
||||||
* @return [Probability of reception, signal strength at destination]
|
* @return [Probability of reception, signal strength at destination]
|
||||||
*/
|
*/
|
||||||
public double[] getProbability(double sourceX, double sourceY, double destX, double destY, double interference) {
|
public double[] getProbability(TxPair txPair, double interference) {
|
||||||
double[] snrData = getSINR(sourceX, sourceY, destX, destY, interference);
|
double[] snrData = getSINR(txPair, interference);
|
||||||
double snrMean = snrData[0];
|
double snrMean = snrData[0];
|
||||||
double snrVariance = snrData[1];
|
double snrVariance = snrData[1];
|
||||||
double signalStrength = snrData[2];
|
double signalStrength = snrData[2];
|
||||||
double threshold = getParameterDoubleValue("snr_threshold");
|
double threshold = getParameterDoubleValue(Parameter.snr_threshold);
|
||||||
double rxSensitivity = getParameterDoubleValue("rx_sensitivity");
|
double rxSensitivity = getParameterDoubleValue(Parameter.rx_sensitivity);
|
||||||
|
|
||||||
// Check signal strength against receiver sensitivity and interference
|
// Check signal strength against receiver sensitivity and interference
|
||||||
if (rxSensitivity > signalStrength - snrMean &&
|
if (rxSensitivity > signalStrength - snrMean &&
|
||||||
threshold < rxSensitivity + snrMean - signalStrength) {
|
threshold < rxSensitivity + snrMean - signalStrength) {
|
||||||
if (logMode) {
|
if (logMode) {
|
||||||
logInfo.append("Weak signal: increasing threshold\n");
|
logInfo.append("Weak signal: increasing threshold\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keeping snr variance but increasing theshold to sensitivity
|
// Keeping snr variance but increasing theshold to sensitivity
|
||||||
|
@ -1707,8 +1773,8 @@ public class ChannelModel {
|
||||||
* Destination position Y
|
* Destination position Y
|
||||||
* @return RMS delay spread
|
* @return RMS delay spread
|
||||||
*/
|
*/
|
||||||
public double getRMSDelaySpread(double sourceX, double sourceY, double destX, double destY) {
|
public double getRMSDelaySpread(TxPair tx) {
|
||||||
return getTransmissionData(sourceX, sourceY, destX, destY, TransmissionData.DELAY_SPREAD, null)[1];
|
return getTransmissionData(tx, TransmissionData.DELAY_SPREAD)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1718,14 +1784,18 @@ public class ChannelModel {
|
||||||
* @return XML element collection
|
* @return XML element collection
|
||||||
*/
|
*/
|
||||||
public Collection<Element> getConfigXML() {
|
public Collection<Element> getConfigXML() {
|
||||||
Vector<Element> config = new Vector<Element>();
|
ArrayList<Element> config = new ArrayList<Element>();
|
||||||
Element element;
|
Element element;
|
||||||
|
|
||||||
Enumeration paramEnum = parameters.keys();
|
Enumeration<Parameter> paramEnum = parameters.keys();
|
||||||
while (paramEnum.hasMoreElements()) {
|
while (paramEnum.hasMoreElements()) {
|
||||||
String name = (String) paramEnum.nextElement();
|
Parameter p = (Parameter) paramEnum.nextElement();
|
||||||
element = new Element(name);
|
element = new Element(p.toString());
|
||||||
element.setText(parameters.get(name).toString());
|
if (parametersDefaults.get(p).equals(parameters.get(p))) {
|
||||||
|
/* Default value */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
element.setAttribute("value", parameters.get(p).toString());
|
||||||
config.add(element);
|
config.add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1749,19 +1819,47 @@ public class ChannelModel {
|
||||||
if (element.getName().equals("obstacles")) {
|
if (element.getName().equals("obstacles")) {
|
||||||
myObstacleWorld = new ObstacleWorld();
|
myObstacleWorld = new ObstacleWorld();
|
||||||
myObstacleWorld.setConfigXML(element.getChildren());
|
myObstacleWorld.setConfigXML(element.getChildren());
|
||||||
} else {
|
} else /* Parameter values */ {
|
||||||
// Assuming parameter value
|
String name = element.getName();
|
||||||
|
String value;
|
||||||
|
Parameter param = null;
|
||||||
|
|
||||||
// Fetch current class before applying saved value
|
if (name.equals("wavelength")) {
|
||||||
Object obj = parameters.get(element.getName());
|
/* Backwards compatability: ignored parameters */
|
||||||
Class paramClass = obj.getClass();
|
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 */
|
||||||
|
|
||||||
|
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) {
|
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) {
|
} else if (paramClass == Boolean.class) {
|
||||||
parameters.put(element.getName(), Boolean.parseBoolean(element.getText()));
|
parameters.put(param, Boolean.parseBoolean(value));
|
||||||
} else if (paramClass == Integer.class) {
|
} else if (paramClass == Integer.class) {
|
||||||
parameters.put(element.getName(), Integer.parseInt(element.getText()));
|
parameters.put(param, Integer.parseInt(value));
|
||||||
} else {
|
} else {
|
||||||
logger.fatal("Unsupported class type: " + paramClass);
|
logger.fatal("Unsupported class type: " + paramClass);
|
||||||
}
|
}
|
||||||
|
@ -1772,4 +1870,85 @@ public class ChannelModel {
|
||||||
settingsObservable.notifySettingsChanged();
|
settingsObservable.notifySettingsChanged();
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,29 +42,30 @@ import org.apache.log4j.Logger;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
import se.sics.cooja.*;
|
||||||
|
import se.sics.mrm.ChannelModel.Parameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This plugin allows a user to reconfigure current radio channel parameters.
|
* This plugin allows a user to reconfigure current radio channel parameters.
|
||||||
*
|
*
|
||||||
* @author Fredrik Osterlind
|
* @author Fredrik Osterlind
|
||||||
*/
|
*/
|
||||||
@ClassDescription("MRM - Formula Viewer")
|
@ClassDescription("MRM Settings")
|
||||||
@PluginType(PluginType.SIM_PLUGIN)
|
@PluginType(PluginType.SIM_PLUGIN)
|
||||||
public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static Logger logger = Logger.getLogger(FormulaViewer.class);
|
private static Logger logger = Logger.getLogger(FormulaViewer.class);
|
||||||
|
|
||||||
private Simulation currentSimulation;
|
private Simulation simulation;
|
||||||
private MRM currentRadioMedium;
|
private MRM radioMedium;
|
||||||
private ChannelModel currentChannelModel;
|
private ChannelModel channelModel;
|
||||||
|
|
||||||
private static Dimension labelDimension = new Dimension(240, 20);
|
private static Dimension labelDimension = new Dimension(240, 20);
|
||||||
private static NumberFormat doubleFormat = NumberFormat.getNumberInstance();
|
private static NumberFormat doubleFormat = NumberFormat.getNumberInstance();
|
||||||
private static NumberFormat integerFormat = NumberFormat.getIntegerInstance();
|
private static NumberFormat integerFormat = NumberFormat.getIntegerInstance();
|
||||||
|
|
||||||
private Vector<JFormattedTextField> allIntegerParameters = new Vector<JFormattedTextField>();
|
private ArrayList<JFormattedTextField> allIntegerParameters = new ArrayList<JFormattedTextField>();
|
||||||
private Vector<JFormattedTextField> allDoubleParameters = new Vector<JFormattedTextField>();
|
private ArrayList<JFormattedTextField> allDoubleParameters = new ArrayList<JFormattedTextField>();
|
||||||
private Vector<JCheckBox> allBooleanParameters = new Vector<JCheckBox>();
|
private ArrayList<JCheckBox> allBooleanParameters = new ArrayList<JCheckBox>();
|
||||||
|
|
||||||
private JPanel areaGeneral;
|
private JPanel areaGeneral;
|
||||||
private JPanel areaTransmitter;
|
private JPanel areaTransmitter;
|
||||||
|
@ -78,11 +79,11 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
* @param simulationToVisualize Simulation which holds the MRM channel model.
|
* @param simulationToVisualize Simulation which holds the MRM channel model.
|
||||||
*/
|
*/
|
||||||
public FormulaViewer(Simulation simulationToVisualize, GUI gui) {
|
public FormulaViewer(Simulation simulationToVisualize, GUI gui) {
|
||||||
super("MRM - Formula Viewer", gui);
|
super("MRM Settings", gui);
|
||||||
|
|
||||||
currentSimulation = simulationToVisualize;
|
simulation = simulationToVisualize;
|
||||||
currentRadioMedium = (MRM) currentSimulation.getRadioMedium();
|
radioMedium = (MRM) simulation.getRadioMedium();
|
||||||
currentChannelModel = currentRadioMedium.getChannelModel();
|
channelModel = radioMedium.getChannelModel();
|
||||||
|
|
||||||
// -- Create and add GUI components --
|
// -- Create and add GUI components --
|
||||||
JPanel allComponents = new JPanel();
|
JPanel allComponents = new JPanel();
|
||||||
|
@ -102,52 +103,52 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
areaGeneral = collapsableArea;
|
areaGeneral = collapsableArea;
|
||||||
|
|
||||||
addBooleanParameter(
|
addBooleanParameter(
|
||||||
"apply_random",
|
Parameter.apply_random,
|
||||||
currentChannelModel.getParameterDescription("apply_random"),
|
Parameter.getDescription(Parameter.apply_random),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterBooleanValue("apply_random")
|
channelModel.getParameterBooleanValue(Parameter.apply_random)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"snr_threshold",
|
Parameter.snr_threshold,
|
||||||
currentChannelModel.getParameterDescription("snr_threshold"),
|
Parameter.getDescription(Parameter.snr_threshold),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("snr_threshold")
|
channelModel.getParameterDoubleValue(Parameter.snr_threshold)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"bg_noise_mean",
|
Parameter.bg_noise_mean,
|
||||||
currentChannelModel.getParameterDescription("bg_noise_mean"),
|
Parameter.getDescription(Parameter.bg_noise_mean),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("bg_noise_mean")
|
channelModel.getParameterDoubleValue(Parameter.bg_noise_mean)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"bg_noise_var",
|
Parameter.bg_noise_var,
|
||||||
currentChannelModel.getParameterDescription("bg_noise_var"),
|
Parameter.getDescription(Parameter.bg_noise_var),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("bg_noise_var")
|
channelModel.getParameterDoubleValue(Parameter.bg_noise_var)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"system_gain_mean",
|
Parameter.system_gain_mean,
|
||||||
currentChannelModel.getParameterDescription("system_gain_mean"),
|
Parameter.getDescription(Parameter.system_gain_mean),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("system_gain_mean")
|
channelModel.getParameterDoubleValue(Parameter.system_gain_mean)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"system_gain_var",
|
Parameter.system_gain_var,
|
||||||
currentChannelModel.getParameterDescription("system_gain_var"),
|
Parameter.getDescription(Parameter.system_gain_var),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("system_gain_var")
|
channelModel.getParameterDoubleValue(Parameter.system_gain_var)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"wavelength",
|
Parameter.frequency,
|
||||||
currentChannelModel.getParameterDescription("wavelength"),
|
Parameter.getDescription(Parameter.frequency),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("wavelength")
|
channelModel.getParameterDoubleValue(Parameter.frequency)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transmitter parameters
|
// Transmitter parameters
|
||||||
|
@ -155,17 +156,17 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
areaTransmitter = collapsableArea;
|
areaTransmitter = collapsableArea;
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"tx_power",
|
Parameter.tx_power,
|
||||||
currentChannelModel.getParameterDescription("tx_power"),
|
Parameter.getDescription(Parameter.tx_power),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("tx_power")
|
channelModel.getParameterDoubleValue(Parameter.tx_power)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addBooleanParameter(
|
||||||
"tx_antenna_gain",
|
Parameter.tx_with_gain,
|
||||||
currentChannelModel.getParameterDescription("tx_antenna_gain"),
|
Parameter.getDescription(Parameter.tx_with_gain),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("tx_antenna_gain")
|
channelModel.getParameterBooleanValue(Parameter.tx_with_gain)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Receiver parameters
|
// Receiver parameters
|
||||||
|
@ -173,17 +174,17 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
areaReceiver = collapsableArea;
|
areaReceiver = collapsableArea;
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"rx_sensitivity",
|
Parameter.rx_sensitivity,
|
||||||
currentChannelModel.getParameterDescription("rx_sensitivity"),
|
Parameter.getDescription(Parameter.rx_sensitivity),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("rx_sensitivity")
|
channelModel.getParameterDoubleValue(Parameter.rx_sensitivity)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addBooleanParameter(
|
||||||
"rx_antenna_gain",
|
Parameter.rx_with_gain,
|
||||||
currentChannelModel.getParameterDescription("rx_antenna_gain"),
|
Parameter.getDescription(Parameter.rx_with_gain),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("rx_antenna_gain")
|
channelModel.getParameterBooleanValue(Parameter.rx_with_gain)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ray Tracer parameters
|
// Ray Tracer parameters
|
||||||
|
@ -191,87 +192,87 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
areaRayTracer = collapsableArea;
|
areaRayTracer = collapsableArea;
|
||||||
|
|
||||||
addBooleanParameter(
|
addBooleanParameter(
|
||||||
"rt_disallow_direct_path",
|
Parameter.rt_disallow_direct_path,
|
||||||
currentChannelModel.getParameterDescription("rt_disallow_direct_path"),
|
Parameter.getDescription(Parameter.rt_disallow_direct_path),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterBooleanValue("rt_disallow_direct_path")
|
channelModel.getParameterBooleanValue(Parameter.rt_disallow_direct_path)
|
||||||
);
|
);
|
||||||
|
|
||||||
addBooleanParameter(
|
addBooleanParameter(
|
||||||
"rt_ignore_non_direct",
|
Parameter.rt_ignore_non_direct,
|
||||||
currentChannelModel.getParameterDescription("rt_ignore_non_direct"),
|
Parameter.getDescription(Parameter.rt_ignore_non_direct),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterBooleanValue("rt_ignore_non_direct")
|
channelModel.getParameterBooleanValue(Parameter.rt_ignore_non_direct)
|
||||||
);
|
);
|
||||||
|
|
||||||
addBooleanParameter(
|
addBooleanParameter(
|
||||||
"rt_fspl_on_total_length",
|
Parameter.rt_fspl_on_total_length,
|
||||||
currentChannelModel.getParameterDescription("rt_fspl_on_total_length"),
|
Parameter.getDescription(Parameter.rt_fspl_on_total_length),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterBooleanValue("rt_fspl_on_total_length")
|
channelModel.getParameterBooleanValue(Parameter.rt_fspl_on_total_length)
|
||||||
);
|
);
|
||||||
|
|
||||||
addIntegerParameter(
|
addIntegerParameter(
|
||||||
"rt_max_rays",
|
Parameter.rt_max_rays,
|
||||||
currentChannelModel.getParameterDescription("rt_max_rays"),
|
Parameter.getDescription(Parameter.rt_max_rays),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterIntegerValue("rt_max_rays")
|
channelModel.getParameterIntegerValue(Parameter.rt_max_rays)
|
||||||
);
|
);
|
||||||
|
|
||||||
addIntegerParameter(
|
addIntegerParameter(
|
||||||
"rt_max_refractions",
|
Parameter.rt_max_refractions,
|
||||||
currentChannelModel.getParameterDescription("rt_max_refractions"),
|
Parameter.getDescription(Parameter.rt_max_refractions),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterIntegerValue("rt_max_refractions")
|
channelModel.getParameterIntegerValue(Parameter.rt_max_refractions)
|
||||||
);
|
);
|
||||||
|
|
||||||
addIntegerParameter(
|
addIntegerParameter(
|
||||||
"rt_max_reflections",
|
Parameter.rt_max_reflections,
|
||||||
currentChannelModel.getParameterDescription("rt_max_reflections"),
|
Parameter.getDescription(Parameter.rt_max_reflections),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterIntegerValue("rt_max_reflections")
|
channelModel.getParameterIntegerValue(Parameter.rt_max_reflections)
|
||||||
);
|
);
|
||||||
|
|
||||||
addIntegerParameter(
|
addIntegerParameter(
|
||||||
"rt_max_diffractions",
|
Parameter.rt_max_diffractions,
|
||||||
currentChannelModel.getParameterDescription("rt_max_diffractions"),
|
Parameter.getDescription(Parameter.rt_max_diffractions),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterIntegerValue("rt_max_diffractions")
|
channelModel.getParameterIntegerValue(Parameter.rt_max_diffractions)
|
||||||
);
|
);
|
||||||
|
|
||||||
/* addBooleanParameter(
|
/* addBooleanParameter(
|
||||||
"rt_use_scattering",
|
Parameters.rt_use_scattering,
|
||||||
currentChannelModel.getParameterDescription("rt_use_scattering"),
|
Parameter.getDescription(Parameters.rt_use_scattering),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterBooleanValue("rt_use_scattering")
|
currentChannelModel.getParameterBooleanValue(Parameters.rt_use_scattering)
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"rt_refrac_coefficient",
|
Parameter.rt_refrac_coefficient,
|
||||||
currentChannelModel.getParameterDescription("rt_refrac_coefficient"),
|
Parameter.getDescription(Parameter.rt_refrac_coefficient),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("rt_refrac_coefficient")
|
channelModel.getParameterDoubleValue(Parameter.rt_refrac_coefficient)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"rt_reflec_coefficient",
|
Parameter.rt_reflec_coefficient,
|
||||||
currentChannelModel.getParameterDescription("rt_reflec_coefficient"),
|
Parameter.getDescription(Parameter.rt_reflec_coefficient),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("rt_reflec_coefficient")
|
channelModel.getParameterDoubleValue(Parameter.rt_reflec_coefficient)
|
||||||
);
|
);
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"rt_diffr_coefficient",
|
Parameter.rt_diffr_coefficient,
|
||||||
currentChannelModel.getParameterDescription("rt_diffr_coefficient"),
|
Parameter.getDescription(Parameter.rt_diffr_coefficient),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("rt_diffr_coefficient")
|
channelModel.getParameterDoubleValue(Parameter.rt_diffr_coefficient)
|
||||||
);
|
);
|
||||||
|
|
||||||
/* addDoubleParameter(
|
/* addDoubleParameter(
|
||||||
"rt_scatt_coefficient",
|
Parameters.rt_scatt_coefficient,
|
||||||
currentChannelModel.getParameterDescription("rt_scatt_coefficient"),
|
Parameter.getDescription(Parameters.rt_scatt_coefficient),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("rt_scatt_coefficient")
|
currentChannelModel.getParameterDoubleValue(Parameters.rt_scatt_coefficient)
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
// Shadowing parameters
|
// Shadowing parameters
|
||||||
|
@ -279,16 +280,14 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
areaShadowing = collapsableArea;
|
areaShadowing = collapsableArea;
|
||||||
|
|
||||||
addDoubleParameter(
|
addDoubleParameter(
|
||||||
"obstacle_attenuation",
|
Parameter.obstacle_attenuation,
|
||||||
currentChannelModel.getParameterDescription("obstacle_attenuation"),
|
Parameter.getDescription(Parameter.obstacle_attenuation),
|
||||||
collapsableArea,
|
collapsableArea,
|
||||||
currentChannelModel.getParameterDoubleValue("obstacle_attenuation")
|
channelModel.getParameterDoubleValue(Parameter.obstacle_attenuation)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add channel model observer responsible to keep all GUI components synched
|
// Add channel model observer responsible to keep all GUI components synched
|
||||||
currentChannelModel.addSettingsObserver(channelModelSettingsObserver);
|
channelModel.addSettingsObserver(channelModelSettingsObserver);
|
||||||
|
|
||||||
// Set initial size etc.
|
// Set initial size etc.
|
||||||
pack();
|
pack();
|
||||||
|
@ -312,6 +311,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
private JPanel createCollapsableArea(String title, Container contentPane) {
|
private JPanel createCollapsableArea(String title, Container contentPane) {
|
||||||
// Create panels
|
// Create panels
|
||||||
JPanel holdingPanel = new JPanel() {
|
JPanel holdingPanel = new JPanel() {
|
||||||
|
private static final long serialVersionUID = -7925426641856424500L;
|
||||||
public Dimension getMaximumSize() {
|
public Dimension getMaximumSize() {
|
||||||
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
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));
|
holdingPanel.setLayout(new BoxLayout(holdingPanel, BoxLayout.Y_AXIS));
|
||||||
|
|
||||||
final JPanel collapsableArea = new JPanel() {
|
final JPanel collapsableArea = new JPanel() {
|
||||||
|
private static final long serialVersionUID = -1261182973911973773L;
|
||||||
public Dimension getMaximumSize() {
|
public Dimension getMaximumSize() {
|
||||||
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
||||||
}
|
}
|
||||||
|
@ -327,6 +328,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
collapsableArea.setVisible(false);
|
collapsableArea.setVisible(false);
|
||||||
|
|
||||||
JPanel titlePanel = new JPanel(new BorderLayout()) {
|
JPanel titlePanel = new JPanel(new BorderLayout()) {
|
||||||
|
private static final long serialVersionUID = -9121775806029887815L;
|
||||||
public Dimension getMaximumSize() {
|
public Dimension getMaximumSize() {
|
||||||
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
||||||
}
|
}
|
||||||
|
@ -369,7 +371,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
* @param initialValue Initial value
|
* @param initialValue Initial value
|
||||||
* @return Text field in created panel
|
* @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();
|
JPanel panel = new JPanel();
|
||||||
JLabel label;
|
JLabel label;
|
||||||
JFormattedTextField textField;
|
JFormattedTextField textField;
|
||||||
|
@ -386,12 +388,27 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
textField.putClientProperty("id", id);
|
textField.putClientProperty("id", id);
|
||||||
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
|
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
|
||||||
public void propertyChange(PropertyChangeEvent e) {
|
public void propertyChange(PropertyChangeEvent e) {
|
||||||
Object sourceObject = e.getSource();
|
JFormattedTextField textField = (JFormattedTextField) e.getSource();
|
||||||
Double newValue = ((Number) e.getNewValue()).doubleValue();
|
Parameter id = (Parameter) textField.getClientProperty("id");
|
||||||
String id = (String) ((JFormattedTextField) sourceObject).getClientProperty("id");
|
Double val = ((Number) e.getNewValue()).doubleValue();
|
||||||
currentChannelModel.setParameterValue(id, newValue);
|
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);
|
allDoubleParameters.add(textField);
|
||||||
|
|
||||||
contentPane.add(panel);
|
contentPane.add(panel);
|
||||||
|
@ -409,7 +426,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
* @param initialValue Initial value
|
* @param initialValue Initial value
|
||||||
* @return Text field in created panel
|
* @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();
|
JPanel panel = new JPanel();
|
||||||
JLabel label;
|
JLabel label;
|
||||||
JFormattedTextField textField;
|
JFormattedTextField textField;
|
||||||
|
@ -426,12 +443,26 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
textField.putClientProperty("id", id);
|
textField.putClientProperty("id", id);
|
||||||
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
|
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
|
||||||
public void propertyChange(PropertyChangeEvent e) {
|
public void propertyChange(PropertyChangeEvent e) {
|
||||||
Object sourceObject = e.getSource();
|
JFormattedTextField textField = (JFormattedTextField) e.getSource();
|
||||||
Integer newValue = ((Number) e.getNewValue()).intValue();
|
Parameter id = (Parameter) textField.getClientProperty("id");
|
||||||
String id = (String) ((JFormattedTextField) sourceObject).getClientProperty("id");
|
Integer val = ((Number) e.getNewValue()).intValue();
|
||||||
currentChannelModel.setParameterValue(id, newValue);
|
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);
|
allIntegerParameters.add(textField);
|
||||||
|
|
||||||
|
@ -450,7 +481,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
* @param initialValue Initial value
|
* @param initialValue Initial value
|
||||||
* @return Checkbox in created panel
|
* @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();
|
JPanel panel = new JPanel();
|
||||||
JLabel label;
|
JLabel label;
|
||||||
JCheckBox checkBox;
|
JCheckBox checkBox;
|
||||||
|
@ -466,13 +497,22 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
checkBox.putClientProperty("id", id);
|
checkBox.putClientProperty("id", id);
|
||||||
checkBox.addActionListener(new ActionListener() {
|
checkBox.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
JCheckBox source = (JCheckBox) e.getSource();
|
JCheckBox checkBox = (JCheckBox) e.getSource();
|
||||||
currentChannelModel.setParameterValue(
|
Parameter id = (Parameter) checkBox.getClientProperty("id");
|
||||||
(String) source.getClientProperty("id"),
|
Object val = new Boolean(checkBox.isSelected());
|
||||||
new Boolean(source.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);
|
allBooleanParameters.add(checkBox);
|
||||||
|
|
||||||
|
@ -481,29 +521,6 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
return checkBox;
|
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.
|
* Listens to settings changes in the channel model.
|
||||||
* If it changes, all GUI parameters are updated accordingly.
|
* If it changes, all GUI parameters are updated accordingly.
|
||||||
|
@ -513,22 +530,22 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
// Update all integers
|
// Update all integers
|
||||||
for (int i=0; i < allIntegerParameters.size(); i++) {
|
for (int i=0; i < allIntegerParameters.size(); i++) {
|
||||||
JFormattedTextField textField = allIntegerParameters.get(i);
|
JFormattedTextField textField = allIntegerParameters.get(i);
|
||||||
String id = (String) textField.getClientProperty("id");
|
Parameter id = (Parameter) textField.getClientProperty("id");
|
||||||
textField.setValue(currentChannelModel.getParameterValue(id));
|
textField.setValue(channelModel.getParameterValue(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update all doubles
|
// Update all doubles
|
||||||
for (int i=0; i < allDoubleParameters.size(); i++) {
|
for (int i=0; i < allDoubleParameters.size(); i++) {
|
||||||
JFormattedTextField textField = allDoubleParameters.get(i);
|
JFormattedTextField textField = allDoubleParameters.get(i);
|
||||||
String id = (String) textField.getClientProperty("id");
|
Parameter id = (Parameter) textField.getClientProperty("id");
|
||||||
textField.setValue(currentChannelModel.getParameterValue(id));
|
textField.setValue(channelModel.getParameterValue(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update all booleans
|
// Update all booleans
|
||||||
for (int i=0; i < allBooleanParameters.size(); i++) {
|
for (int i=0; i < allBooleanParameters.size(); i++) {
|
||||||
JCheckBox checkBox = allBooleanParameters.get(i);
|
JCheckBox checkBox = allBooleanParameters.get(i);
|
||||||
String id = (String) checkBox.getClientProperty("id");
|
Parameter id = (Parameter) checkBox.getClientProperty("id");
|
||||||
checkBox.setSelected(currentChannelModel.getParameterBooleanValue(id));
|
checkBox.setSelected(channelModel.getParameterBooleanValue(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
repaint();
|
repaint();
|
||||||
|
@ -536,12 +553,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
};
|
};
|
||||||
|
|
||||||
public void closePlugin() {
|
public void closePlugin() {
|
||||||
// Remove the channel model observer
|
channelModel.deleteSettingsObserver(channelModelSettingsObserver);
|
||||||
if (currentChannelModel != null && channelModelSettingsObserver != null) {
|
|
||||||
currentChannelModel.deleteSettingsObserver(channelModelSettingsObserver);
|
|
||||||
} else {
|
|
||||||
logger.fatal("Can't remove channel model observer: " + channelModelSettingsObserver);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -551,7 +563,7 @@ public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||||
* @return XML element collection
|
* @return XML element collection
|
||||||
*/
|
*/
|
||||||
public Collection<Element> getConfigXML() {
|
public Collection<Element> getConfigXML() {
|
||||||
Vector<Element> config = new Vector<Element>();
|
ArrayList<Element> config = new ArrayList<Element>();
|
||||||
Element element;
|
Element element;
|
||||||
|
|
||||||
element = new Element("show_general");
|
element = new Element("show_general");
|
||||||
|
|
|
@ -43,11 +43,16 @@ import org.jdom.Element;
|
||||||
import se.sics.cooja.ClassDescription;
|
import se.sics.cooja.ClassDescription;
|
||||||
import se.sics.cooja.RadioConnection;
|
import se.sics.cooja.RadioConnection;
|
||||||
import se.sics.cooja.Simulation;
|
import se.sics.cooja.Simulation;
|
||||||
|
import se.sics.cooja.interfaces.DirectionalAntennaRadio;
|
||||||
import se.sics.cooja.interfaces.NoiseSourceRadio;
|
import se.sics.cooja.interfaces.NoiseSourceRadio;
|
||||||
import se.sics.cooja.interfaces.NoiseSourceRadio.NoiseLevelListener;
|
import se.sics.cooja.interfaces.NoiseSourceRadio.NoiseLevelListener;
|
||||||
import se.sics.cooja.interfaces.Position;
|
import se.sics.cooja.interfaces.Position;
|
||||||
import se.sics.cooja.interfaces.Radio;
|
import se.sics.cooja.interfaces.Radio;
|
||||||
|
import se.sics.cooja.plugins.Visualizer;
|
||||||
import se.sics.cooja.radiomediums.AbstractRadioMedium;
|
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).
|
* 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.
|
* 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
|
* @see NoiseSourceRadio
|
||||||
* @author Fredrik Osterlind
|
* @author Fredrik Osterlind
|
||||||
*/
|
*/
|
||||||
|
@ -72,7 +78,8 @@ import se.sics.cooja.radiomediums.AbstractRadioMedium;
|
||||||
public class MRM extends AbstractRadioMedium {
|
public class MRM extends AbstractRadioMedium {
|
||||||
private static Logger logger = Logger.getLogger(MRM.class);
|
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;
|
public final static boolean WITH_CAPTURE_EFFECT = true;
|
||||||
|
|
||||||
private Simulation sim;
|
private Simulation sim;
|
||||||
|
@ -92,44 +99,46 @@ public class MRM extends AbstractRadioMedium {
|
||||||
|
|
||||||
sim = simulation;
|
sim = simulation;
|
||||||
random = simulation.getRandomGenerator();
|
random = simulation.getRandomGenerator();
|
||||||
currentChannelModel = new ChannelModel();
|
currentChannelModel = new ChannelModel(sim);
|
||||||
|
|
||||||
/* Register plugins */
|
/* Register plugins */
|
||||||
sim.getGUI().registerPlugin(AreaViewer.class);
|
sim.getGUI().registerPlugin(AreaViewer.class);
|
||||||
sim.getGUI().registerPlugin(FormulaViewer.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() {
|
public void removed() {
|
||||||
super.removed();
|
super.removed();
|
||||||
|
|
||||||
/* Unregister plugins */
|
/* Unregister plugins */
|
||||||
sim.getGUI().unregisterPlugin(AreaViewer.class);
|
sim.getGUI().unregisterPlugin(AreaViewer.class);
|
||||||
sim.getGUI().unregisterPlugin(FormulaViewer.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);
|
MRMRadioConnection newConnection = new MRMRadioConnection(sender);
|
||||||
Position senderPos = sender.getPosition();
|
final Position senderPos = sender.getPosition();
|
||||||
|
|
||||||
/* TODO Cache potential destination in DGRM */
|
/* TODO Cache potential destination in DGRM */
|
||||||
/* Loop through all potential destinations */
|
/* Loop through all potential destinations */
|
||||||
|
@ -144,21 +153,26 @@ public class MRM extends AbstractRadioMedium {
|
||||||
sender.getChannel() != recv.getChannel()) {
|
sender.getChannel() != recv.getChannel()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Position recvPos = recv.getPosition();
|
final Radio recvFinal = recv;
|
||||||
|
|
||||||
/* Calculate receive probability */
|
/* Calculate receive probability */
|
||||||
|
TxPair txPair = new RadioPair() {
|
||||||
|
public Radio getFromRadio() {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
public Radio getToRadio() {
|
||||||
|
return recvFinal;
|
||||||
|
}
|
||||||
|
};
|
||||||
double[] probData = currentChannelModel.getProbability(
|
double[] probData = currentChannelModel.getProbability(
|
||||||
senderPos.getXCoordinate(),
|
txPair,
|
||||||
senderPos.getYCoordinate(),
|
|
||||||
recvPos.getXCoordinate(),
|
|
||||||
recvPos.getYCoordinate(),
|
|
||||||
-Double.MAX_VALUE /* TODO Include interference */
|
-Double.MAX_VALUE /* TODO Include interference */
|
||||||
);
|
);
|
||||||
|
|
||||||
double recvProb = probData[0];
|
double recvProb = probData[0];
|
||||||
double recvSignalStrength = probData[1];
|
double recvSignalStrength = probData[1];
|
||||||
if (recvProb == 1.0 || random.nextDouble() < recvProb) {
|
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()) {
|
if (!recv.isReceiverOn()) {
|
||||||
newConnection.addInterfered(recv);
|
newConnection.addInterfered(recv);
|
||||||
recv.interfereAnyReception();
|
recv.interfereAnyReception();
|
||||||
|
@ -171,14 +185,14 @@ public class MRM extends AbstractRadioMedium {
|
||||||
/* Was already receiving: start interfering.
|
/* Was already receiving: start interfering.
|
||||||
* Assuming no continuous preambles checking */
|
* Assuming no continuous preambles checking */
|
||||||
|
|
||||||
double currSignal = recv.getCurrentSignalStrength();
|
double currSignal = recv.getCurrentSignalStrength();
|
||||||
/* Capture effect: recv-radio is already receiving.
|
/* Capture effect: recv-radio is already receiving.
|
||||||
* Are we strong enough to interfere? */
|
* Are we strong enough to interfere? */
|
||||||
if (WITH_CAPTURE_EFFECT &&
|
if (WITH_CAPTURE_EFFECT &&
|
||||||
recvSignalStrength < currSignal - 3 /* config */) {
|
recvSignalStrength < currSignal - 3 /* config */) {
|
||||||
/* No, we are too weak */
|
/* No, we are too weak */
|
||||||
} else {
|
} else {
|
||||||
newConnection.addInterfered(recv, recvSignalStrength);
|
newConnection.addInterfered(recv, recvSignalStrength);
|
||||||
recv.interfereAnyReception();
|
recv.interfereAnyReception();
|
||||||
|
|
||||||
/* Interfere receiver in all other active radio connections */
|
/* Interfere receiver in all other active radio connections */
|
||||||
|
@ -187,22 +201,22 @@ public class MRM extends AbstractRadioMedium {
|
||||||
conn.addInterfered(recv);
|
conn.addInterfered(recv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Success: radio starts receiving */
|
/* Success: radio starts receiving */
|
||||||
newConnection.addDestination(recv, recvSignalStrength);
|
newConnection.addDestination(recv, recvSignalStrength);
|
||||||
}
|
}
|
||||||
} else if (recvSignalStrength > currentChannelModel.getParameterDoubleValue("bg_noise_mean")) {
|
} else if (recvSignalStrength > currentChannelModel.getParameterDoubleValue(Parameter.bg_noise_mean)) {
|
||||||
/* The incoming signal is strong, but strong enough to interfere? */
|
/* The incoming signal is strong, but strong enough to interfere? */
|
||||||
|
|
||||||
if (!WITH_CAPTURE_EFFECT) {
|
if (!WITH_CAPTURE_EFFECT) {
|
||||||
newConnection.addInterfered(recv, recvSignalStrength);
|
newConnection.addInterfered(recv, recvSignalStrength);
|
||||||
recv.interfereAnyReception();
|
recv.interfereAnyReception();
|
||||||
} else {
|
} else {
|
||||||
/* TODO Implement new type: newConnection.addNoise()?
|
/* TODO Implement new type: newConnection.addNoise()?
|
||||||
* Currently, this connection will never disturb this radio... */
|
* Currently, this connection will never disturb this radio... */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -213,8 +227,8 @@ public class MRM extends AbstractRadioMedium {
|
||||||
public void updateSignalStrengths() {
|
public void updateSignalStrengths() {
|
||||||
|
|
||||||
/* Reset: Background noise */
|
/* Reset: Background noise */
|
||||||
double background =
|
double background =
|
||||||
currentChannelModel.getParameterDoubleValue(("bg_noise_mean"));
|
currentChannelModel.getParameterDoubleValue((Parameter.bg_noise_mean));
|
||||||
for (Radio radio : getRegisteredRadios()) {
|
for (Radio radio : getRegisteredRadios()) {
|
||||||
radio.setCurrentSignalStrength(background);
|
radio.setCurrentSignalStrength(background);
|
||||||
}
|
}
|
||||||
|
@ -235,12 +249,12 @@ public class MRM extends AbstractRadioMedium {
|
||||||
for (Radio intfRadio : ((MRMRadioConnection) conn).getInterfered()) {
|
for (Radio intfRadio : ((MRMRadioConnection) conn).getInterfered()) {
|
||||||
double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(intfRadio);
|
double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(intfRadio);
|
||||||
if (intfRadio.getCurrentSignalStrength() < signalStrength) {
|
if (intfRadio.getCurrentSignalStrength() < signalStrength) {
|
||||||
intfRadio.setCurrentSignalStrength(signalStrength);
|
intfRadio.setCurrentSignalStrength(signalStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!intfRadio.isInterfered()) {
|
if (!intfRadio.isInterfered()) {
|
||||||
/*logger.warn("Radio was not interfered: " + intfRadio);*/
|
/*logger.warn("Radio was not interfered: " + intfRadio);*/
|
||||||
intfRadio.interfereAnyReception();
|
intfRadio.interfereAnyReception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,53 +262,58 @@ public class MRM extends AbstractRadioMedium {
|
||||||
/* Check for noise sources */
|
/* Check for noise sources */
|
||||||
if (!WITH_NOISE) return;
|
if (!WITH_NOISE) return;
|
||||||
for (Radio noiseRadio: getRegisteredRadios()) {
|
for (Radio noiseRadio: getRegisteredRadios()) {
|
||||||
if (!(noiseRadio instanceof NoiseSourceRadio)) {
|
if (!(noiseRadio instanceof NoiseSourceRadio)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NoiseSourceRadio radio = (NoiseSourceRadio) noiseRadio;
|
final Radio fromRadio = noiseRadio;
|
||||||
int signalStrength = radio.getNoiseLevel();
|
NoiseSourceRadio radio = (NoiseSourceRadio) noiseRadio;
|
||||||
if (signalStrength == Integer.MIN_VALUE) {
|
int signalStrength = radio.getNoiseLevel();
|
||||||
continue;
|
if (signalStrength == Integer.MIN_VALUE) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate how noise source affects surrounding radios */
|
/* Calculate how noise source affects surrounding radios */
|
||||||
for (Radio affectedRadio : getRegisteredRadios()) {
|
for (Radio affectedRadio : getRegisteredRadios()) {
|
||||||
if (noiseRadio == affectedRadio) {
|
if (noiseRadio == affectedRadio) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update noise levels */
|
/* Update noise levels */
|
||||||
double[] signalMeanVar = currentChannelModel.getReceivedSignalStrength(
|
final Radio toRadio = affectedRadio;
|
||||||
noiseRadio.getPosition().getXCoordinate(),
|
TxPair txPair = new RadioPair() {
|
||||||
noiseRadio.getPosition().getYCoordinate(),
|
public Radio getFromRadio() {
|
||||||
affectedRadio.getPosition().getXCoordinate(),
|
return fromRadio;
|
||||||
affectedRadio.getPosition().getYCoordinate(),
|
}
|
||||||
(double) signalStrength); /* TODO Convert to dBm */
|
public Radio getToRadio() {
|
||||||
double signal = signalMeanVar[0];
|
return toRadio;
|
||||||
if (signal < background) {
|
}
|
||||||
continue;
|
};
|
||||||
}
|
double[] signalMeanVar = currentChannelModel.getReceivedSignalStrength(txPair);
|
||||||
|
double signal = signalMeanVar[0];
|
||||||
|
if (signal < background) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO Additive signals strengths? */
|
/* TODO Additive signals strengths? */
|
||||||
/* TODO XXX Consider radio channels */
|
/* TODO XXX Consider radio channels */
|
||||||
/* TODO XXX Potentially interfere even when signal is weaker (~3dB)...
|
/* TODO XXX Potentially interfere even when signal is weaker (~3dB)...
|
||||||
* (we may alternatively just use the getSINR method...) */
|
* (we may alternatively just use the getSINR method...) */
|
||||||
if (affectedRadio.getCurrentSignalStrength() < signal) {
|
if (affectedRadio.getCurrentSignalStrength() < signal) {
|
||||||
affectedRadio.setCurrentSignalStrength(signal);
|
affectedRadio.setCurrentSignalStrength(signal);
|
||||||
|
|
||||||
/* TODO Interfere with radio connections? */
|
/* TODO Interfere with radio connections? */
|
||||||
if (affectedRadio.isReceiving() && !affectedRadio.isInterfered()) {
|
if (affectedRadio.isReceiving() && !affectedRadio.isInterfered()) {
|
||||||
for (RadioConnection conn : conns) {
|
for (RadioConnection conn : conns) {
|
||||||
if (conn.isDestination(affectedRadio)) {
|
if (conn.isDestination(affectedRadio)) {
|
||||||
/* Intefere with current reception, mark radio as interfered */
|
/* Intefere with current reception, mark radio as interfered */
|
||||||
conn.addInterfered(affectedRadio);
|
conn.addInterfered(affectedRadio);
|
||||||
if (!affectedRadio.isInterfered()) {
|
if (!affectedRadio.isInterfered()) {
|
||||||
affectedRadio.interfereAnyReception();
|
affectedRadio.interfereAnyReception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,7 +353,7 @@ public class MRM extends AbstractRadioMedium {
|
||||||
* @return Number of registered radios.
|
* @return Number of registered radios.
|
||||||
*/
|
*/
|
||||||
public int getRegisteredRadioCount() {
|
public int getRegisteredRadioCount() {
|
||||||
/* TODO Expensive operation */
|
/* TODO Expensive operation */
|
||||||
return getRegisteredRadios().length;
|
return getRegisteredRadios().length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,16 +402,16 @@ public class MRM extends AbstractRadioMedium {
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getDestinationSignalStrength(Radio radio) {
|
public double getDestinationSignalStrength(Radio radio) {
|
||||||
if (signalStrengths.get(radio) == null) {
|
if (signalStrengths.get(radio) == null) {
|
||||||
return Double.MIN_VALUE;
|
return Double.MIN_VALUE;
|
||||||
}
|
}
|
||||||
return signalStrengths.get(radio);
|
return signalStrengths.get(radio);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getInterferenceSignalStrength(Radio radio) {
|
public double getInterferenceSignalStrength(Radio radio) {
|
||||||
if (signalStrengths.get(radio) == null) {
|
if (signalStrengths.get(radio) == null) {
|
||||||
return Double.MIN_VALUE;
|
return Double.MIN_VALUE;
|
||||||
}
|
}
|
||||||
return signalStrengths.get(radio);
|
return signalStrengths.get(radio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
157
tools/cooja/apps/mrm/java/se/sics/mrm/MRMVisualizerSkin.java
Normal file
157
tools/cooja/apps/mrm/java/se/sics/mrm/MRMVisualizerSkin.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue