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