Click or drag to resize

Basic Communications

The Communications Library contains several high level objects which make modeling a communications system easy. These objects are configurable and are easily added to your communication scenario.

Note Note

The functionality described in this topic requires a license for the Communications Library.

Transmitters and Receivers

The communications library has transmitter and receiver models for both the radio frequency (RF) and optical bands.

The RF transmitters come in two types, analog and digital, each type with a simple and complex version:

The optical transmitter is a complex digital model:

Digital transmitters provide a way to model data modulation on the transmitted signal, whereas analog transmitters do not have that capability. The simple transmitters have a fixed configuration, providing for a constant power radiated isotropically. Complex transmitters allow you to configure what type of antenna gain pattern and, in the case of digital transmitters, the type of modulation used in the transmitter. Additionally, complex transmitters allow you to access the internal configuration details. A complex transmitter also can be created from an existing simple transmitter. This upgrade capability is nice if you find that the simple transmitter you already created isn't flexible enough.

The RF receivers come in both simple and complex versions:

The optical receiver is a complex model:

The simple receiver provides a fixed configuration, providing for a constant amplifier gain and an isotropic antenna gain. Complex receivers allow you to configure the type of antenna gain pattern and the type of amplifier that are used in the receiver. Additionally, complex receivers allow you to access the internal configuration details. A complex receiver also can be created from an existing simple receiver. This is nice if you need a more flexible receiver and you already have a simple receiver defined.

Transmitters and receivers are derived from Platform. This means that each transmitter or receiver has its own location and orientation behavior. When building a communication scenario, you can think of this location and orientation as belonging to the antenna, which can be located and pointed independent of the parent vehicle.

To aid in pointing transmitters and receivers, a new Axes type has been introduced: AxesTargetingLink. Setting the OrientationAxes (get / set) property of your communications objects to this type allows them to target the object defined in the link that they both share, and maintain that targeting over time.

When a transmitter and receiver are added to a CommunicationSystem, you can call getLinkBudgetEvaluator to get an evaluator for the link budget.

The following code shows how to create a transmitter and receiver and orient them towards each other.

Java
// Get a Reference to the Earth's CentralBody context
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();

// Create a simple digital transmitter in LA, then uplink to the satellite.
SimpleDigitalTransmitter policeTransmitter = new SimpleDigitalTransmitter();

// Let's change the transmitting power
policeTransmitter.setEffectiveIsotropicRadiatedPower(350);  // Watts

Cartographic losAngelesPD = new Cartographic(-2.0637416544, 0.5943235692, 30);
Cartographic losAngelesMedCenter = new Cartographic(-2.062997065, 0.594448304, 40);
policeTransmitter.setLocationPoint(new PointCartographic(earth, losAngelesPD));

// Create a reference direction vector, used in the AxesTargetingLink type.
// By using PlatformLocationPoint instead of specifying policeTransmitter.LocationPoint directly, 
// we will always get the current policeTransmitter.LocationPoint property, even if we change its
// value later on, the Vector will refer to the new value.
Vector localZAxis = new VectorFixed(new AxesEastNorthUp(earth, new PlatformLocationPoint(policeTransmitter)), Cartesian.toCartesian(UnitCartesian.getUnitZ()));

// Create a receiver
SimpleReceiver medCenterReceiver = new SimpleReceiver();
medCenterReceiver.setLocationPoint(new PointCartographic(earth, losAngelesMedCenter));
// Add noise to the Receiver
medCenterReceiver.setNoiseFactor(2);

// Create a link between them
CommunicationSystem commSys = new CommunicationSystem();
IServiceProvider link = commSys.getLinks().add(policeTransmitter, medCenterReceiver);

// Orient them towards each other.
// Note that we could allow the CommunicationSystem to orient these towards each other
// by calling commSys.configureAntennaTargeting(),  this just shows how to perform targeting manually.      
policeTransmitter.setOrientationAxes(new AxesTargetingLink(link, LinkRole.TRANSMITTER, localZAxis));
medCenterReceiver.setOrientationAxes(new AxesTargetingLink(link, LinkRole.RECEIVER, localZAxis));

// In order to access the resulting link budget, we call GetLinkBudgetEvaluator.  We can then
// use the returned evaluator to request results at any specified time.  Note that GetLinkBudgetEvaluator
// is an expensive call, so you should only reacquire a new evaluator if one of your objects' definition
// has changed.  Otherwise, store lbEval in a member variable and use it when you need results.
// For more information on evaluators, see the "Evaluators And Evaluator Groups" topic under "Patterns".
Evaluator<LinkBudget> lbEval = commSys.getLinkBudgetEvaluator(link, new IntendedSignalByTransmitter(policeTransmitter));
LinkBudget lb = lbEval.evaluate(new JulianDate(new GregorianDate(2011, 7, 28, 13, 49, 43)));

Transponders and Transceivers

A Transceiver models a device with a receiver, an amplifier, and a transmitter that acts as an active bent pipe for a signal. Internally, the receiver is connected to the transmitter via a LinkInstantaneous. The transceiver will demodulate and optionally filter the incoming signals. Once demodulated, the intended signal is then remodulated, with a possibly different modulation scheme, amplified and retransmitted with the transceiver's transmitter.

A Transponder acts similarly, except it does not demodulate or remodulate the signal. Optional filtering can be used on a transponder as well.

Both Transceiver and Transponder model their receiving and transmitting antennas as a Platform. This allows for independent positioning and targeting of the transceiver's and transponder's reception and transmission capabilities.

The following code shows how to create a transceiver and add a signal filter to it.

Java
// This relay transceiver has an isotropic receiver antenna gain pattern and accepts a BPSK modulation scheme.
// On retransmisson of the received signal, it uses a GaussianGainPattern and a QPSK modulation scheme.
Transceiver relay = new Transceiver();
relay.setName("Relay Transceiver");
relay.setModulation(new ModulationBpsk());
relay.setInputAntennaGainPattern(new IsotropicGainPattern());
relay.setCarrierFrequency(policeTransmitter.getCarrierFrequency());

GaussianGainPattern transmitterPattern = new GaussianGainPattern();
transmitterPattern.setBacklobeGain(0.001); // decimal
transmitterPattern.setDiameter(1.0); // meters
transmitterPattern.setEfficiency(0.55); // percent as a fraction
relay.setOutputAntennaGainPattern(transmitterPattern);

// Change the output gain to 10
relay.setOutputGain(10);

// Create a location for the Transceiver - 970 meters above the Police station, which is 30 meters high
Cartographic transceiverLocation = new Cartographic(-2.0637416544, 0.5943235692, 1000);
relay.getInputAntenna().setLocationPoint(new PointCartographic(earth, transceiverLocation));

// Offset the transceiver's transmitter from the receiver by 1 meter east.
// First create a reference frame that is east, north and up from the input antenna.
ReferenceFrame enuFrame = new ReferenceFrame(relay.getInputAntenna().getLocationPoint(), new AxesEastNorthUp(earth, relay.getInputAntenna().getLocationPoint()));
// Now create a fixed offset from that frame and assign it to the output antenna.
relay.getOutputAntenna().setLocationPoint(new PointFixedOffset(enuFrame, new Cartesian(1, 0, 0)));

// Hook up a filter on the relay
relay.setFilter(new RectangularFilter());
// Set the filters Frequency to the frequency that will be retransmitted.
relay.getFilter().setFrequency(policeTransmitter.getCarrierFrequency());
// Define a 2 MHz bandwidth for the filter.
relay.getFilter().setLowerBandwidthLimit(-1e6);
relay.getFilter().setUpperBandwidthLimit(1e6);
Communication System

A CommunicationSystem is used to collect and manage all of the transmitters, receivers, transponders, transceivers and links in a communication scenario. Links are added to the system via the Links (get) property. You can create your own links, using a LinkSpeedOfLight, for example, or simply add your receivers and transmitters to the collection using the overloaded add methods. If you do decide to create your own links, they must also provide the ITransmittedSignalService and IPropagatedSignalService services, usually added to the link via the WirelessLinkExtension.

Links created for you will use the same default propagation models specified by WirelessLinkExtension. You can change these using DefaultPropagationModels (get).

The communication system also has an automatic orientation feature. When you call the configureAntennaTargeting method, it will automatically orient transmitters and receivers to point to each other along the links in which they are defined. It's worth reading the documentation for this method to understand how and when it will orient your objects, and what the method returns. This automatic orientation allows for easier setup of a system, but retains user flexibility where needed. Automatic orientation sets the OrientationAxes (get / set) property to an AxesTargetingLink for each object in a link, using the DefaultReferenceVector (get / set) property of the CommunicationSystem. You can change this vector's definition in the CommunicationSystem to meet your needs. Once set, the object's OrientationAxes (get / set) can be modified to support special circumstances.

There are two collections that are used for adding interference sources and sinks. When you create a transmitter that you intend to be used as an interference source in the CommunicationSystem, add it to the TransmitToAll (get) collection. This will create links from the transmitter to every receiver in the system. Conversely, if you have a receiver that should accept interference from all sources, add it to the ReceiveFromAll (get) collection.

Once your communication system is set up and all of your communication objects are added, a link budget evaluator for an intended signal can be retrieved by calling the getLinkBudgetEvaluator method.

The following code shows how to create a communications system with a transmitter, transceiver and receiver and evaluate the LinkBudget for that system.

Java
// In the previous examples, we created a Transmitter from a Los Angeles Police Station, and a Receiver
// at a Medical Center.  We evaluated the Link Budget for the pair, but now we've added a Transceiver 1000 meters above the city.
// We've set the OrientationAxes of the transmitter and receiver back to null and will now let the Comm System autoOrient everything for us.
commSys = new CommunicationSystem();

// Add a chain of comm objects to the Links collection, in the order they communicate.
commSys.getLinks().addChain(policeTransmitter, relay, medCenterReceiver);
 // Let's set the DefaultReferenceVector to something different
commSys.setDefaultReferenceVector(localZAxis);
// Orient the antennas automatically.
commSys.configureAntennaTargeting();

// Now let's find a reference to the downlink, so we can get a Link Budget for it.
IServiceProvider myLink = commSys.getLinks().findFirst(medCenterReceiver, LinkRole.RECEIVER);

// Now we can get a Link Budget from the commSys, for the downlink
lbEval = commSys.getLinkBudgetEvaluator(myLink, new IntendedSignalByTransmitter(policeTransmitter));
lb = lbEval.evaluate(new JulianDate(new GregorianDate(2011, 7, 28, 13, 49, 43)));

The following code shows how to use the CommunicationSystem to compute link budget values for an optical communications link. The example also shows how to implement a custom sky spectral radiance SignalComputation, used for computing the optical detector background light noise contribution from the sky.

Java
// Optical transmitter configuration parameters
double xmtrDivergenceAngle = 75.0e-6; // radians
double xmtrApertureDiameter = 7.62e-2; // meters
double xmtrOpticalEfficiency = 1.0; // 100%
double xmtrOpticalPointingError = 0.0;
double xmtPower = 1.0; // Watts
double xmtrWavelength = 1550e-9;
double xmtrDataRate = 1.0e9;
ModulationOok xmtrDigitalModulation = new ModulationOok();

// Optical receiver configuration parameters
double rcvrApertureDiameter = 7.62e-2; // meters
double rcvrDivergenceAngle = 75.0e-6; // radians
double rcvrOpticalEfficiency = 1.0; // 100%
double rcvrOpticalPointingError = 0.0;
double rcvrFieldOfView = Trig.degreesToRadians(5.0);
double rcvrPhotodetectorQuantumEfficiency = 0.8; // 80%
double rcvrNoiseTemperature = 10.0; // Kelvin
double rcvrDarkCurrent = 1.0e-16; // amps
double rcvrLoadImpedance = 1.0e8; // ohms
double rcvrApdExcessNoiseFactor = 0.0;
double rcvrApdGain = 500.0;

// Ground terminal Lat, Lon, Alt
double gteLat = Trig.degreesToRadians(37.713717);
double gteLon = Trig.degreesToRadians(-121.702683);
double gteAlt = 152.0;

// Air terminal Lat, Lon, Alt
double ateLat = Trig.degreesToRadians(37.120803);
double ateLon = Trig.degreesToRadians(-119.924024);
double ateAlt = 1524.0;

// Maximum altitude used in atmospheric propagation computations
double maximumAltitude = 22860.0; // meters

// Beer-Lambert Law extinction coefficient model
double extinctionCoefficientModel = 0.00013;

EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();

// Construct the ground terminal's Point and Axes objects
Cartographic groundCart = new Cartographic(gteLon, gteLat, gteAlt);
PointCartographic groundPoint = new PointCartographic(earth, groundCart);
AxesEastNorthUp groundAxes = new AxesEastNorthUp(earth, groundPoint);

// Construct the air terminal's Point and Axes objects
Cartographic airCart = new Cartographic(ateLon, ateLat, ateAlt);
PointCartographic airPoint = new PointCartographic(earth, airCart);
AxesEastNorthUp airAxes = new AxesEastNorthUp(earth, airPoint);

// Construct the optics gain pattern for the transmitter
GaussianOpticalGainPattern xmtrAntennaPattern = new GaussianOpticalGainPattern(xmtrApertureDiameter, xmtrDivergenceAngle, xmtrOpticalEfficiency,
        xmtrOpticalPointingError);

// Construct the transmitter instance
OpticalTransmitter xmtr = new OpticalTransmitter("ATETransmitter", airPoint, airAxes, xmtrDigitalModulation, xmtrAntennaPattern, xmtrWavelength, xmtPower,
        xmtrDataRate, null);

// Construct the optics gain pattern for the receiver
GaussianOpticalGainPattern rcvrAntenna = new GaussianOpticalGainPattern(rcvrApertureDiameter, rcvrDivergenceAngle, rcvrOpticalEfficiency,
        rcvrOpticalPointingError);

// Construct the photodetector and receiver instance
AvalanchePhotodiode rcvrPhotodetector = new AvalanchePhotodiode();
OpticalReceiver rcvr = new OpticalReceiver("GTEReceiver", groundPoint, groundAxes, rcvrPhotodetector, rcvrAntenna);
rcvrPhotodetector.setParentReceiver(rcvr);
rcvrPhotodetector.setCentralBody(earth);
rcvrPhotodetector.setFieldOfView(rcvrFieldOfView);
rcvrPhotodetector.setWavelength(xmtrWavelength);
rcvrPhotodetector.setBandwidth(xmtrDataRate);
rcvrPhotodetector.setOpticalBandpassFilterBandwidth(2.0 * xmtrDataRate);
rcvrPhotodetector.setEfficiency(rcvrPhotodetectorQuantumEfficiency);
rcvrPhotodetector.setNoiseFactor(rcvrApdExcessNoiseFactor);
rcvrPhotodetector.setNoiseTemperature(rcvrNoiseTemperature);
rcvrPhotodetector.setDarkCurrent(rcvrDarkCurrent);
rcvrPhotodetector.setLoadImpedance(rcvrLoadImpedance);
rcvrPhotodetector.setGain(rcvrApdGain);
rcvrPhotodetector.setSkySpectralRadiance(new SkySpectralRadianceCurveFit()); // Construct our custom sky spectral radiance model 
rcvrPhotodetector.setSunSpectralRadiantEmittance(SignalComputation.toSignalComputation(0.0)); // We're not modeling sun spectral radiant emittance in this example, so set to zero

// Construct the CommunicationSystem instance
CommunicationSystem cs = new CommunicationSystem();

// Construct the refractive index structure parameter model
HufnagelValleyRefractiveIndexStructureParameterModel cn2Model = new HufnagelValleyRefractiveIndexStructureParameterModel();

// Tropospheric scintillation loss model
TropoScintAttenuationModelItuRP1814 scintModel = new TropoScintAttenuationModelItuRP1814(maximumAltitude, cn2Model, earth);

// Beer-Lamber Law Atmospheric Absorption Model configured with a constant extinction coefficient
BeerLambertLawAtmosphericAttenuationModel atmosLossModel = new BeerLambertLawAtmosphericAttenuationModel(SignalComputation
        .toSignalComputation(extinctionCoefficientModel), maximumAltitude, earth);

// Add the default propagation models to the CommunicationSystem instance
cs.getLinks().getDefaultPropagationModels().add(atmosLossModel);
cs.getLinks().getDefaultPropagationModels().add(scintModel);

// Using the CommSystem's Links collection, add a new link between the OpticalTransmitter and OpticalReceiver
cs.getLinks().add(xmtr, rcvr);

// Configure the optical antenna pointing
cs.configureAntennaTargeting();

// When retrieving evaluators, we need to specify our desired signal.
IntendedSignalByTransmitter intendedSignal = new IntendedSignalByTransmitter(xmtr);

// Create an Evaluator group to optimize the evaluator calculations.
// Since the CommunicationSystem has many evaluators within it, you should always create an EvaluatorGroup
EvaluatorGroup group = new EvaluatorGroup();

// Get the link budgets scalars object using the link that was created by the CommunicationSystem and the intended signal strategy
LinkBudgetScalars lbs = cs.getLinkBudgetScalars(cs.getLinks().get(0), intendedSignal);

// Get each of the desired evaluators passing the evaluator group for later optimization
ScalarEvaluator outputPowerEval = lbs.getPowerAtReceiverOutput().getEvaluator(group);
ScalarEvaluator xmtGainEval = lbs.getTransmitterAntennaGainInLinkDirection().getEvaluator(group);
ScalarEvaluator rcvGainEval = lbs.getReceiverAntennaGainInLinkDirection().getEvaluator(group);
ScalarEvaluator propLossEval = lbs.getPropagationLoss().getEvaluator(group);
ScalarEvaluator ripEval = lbs.getReceivedIsotropicPower().getEvaluator(group);
ScalarEvaluator cOverNEval = lbs.getCarrierToNoise().getEvaluator(group);
ScalarEvaluator berEval = lbs.getBitErrorRate().getEvaluator(group);

// Optimize the evaluators
group.optimizeEvaluators();

JulianDate time = new JulianDate(GregorianDate.parse("5 Oct 2015 22:35:00"));

// Evaluate each evaluator instance given the desired time.
double xmtGain = CommunicationAnalysis.toDecibels(xmtGainEval.evaluate(time));
double outputPower = CommunicationAnalysis.toDecibels(outputPowerEval.evaluate(time));
double rcvGain = CommunicationAnalysis.toDecibels(rcvGainEval.evaluate(time));
double propLoss = CommunicationAnalysis.toDecibels(propLossEval.evaluate(time));
double rip = CommunicationAnalysis.toDecibels(ripEval.evaluate(time));
double opticsOutputPower = rip + rcvGain;
double cOverN = CommunicationAnalysis.toDecibels(cOverNEval.evaluate(time));
double ber = berEval.evaluate(time);

The following code shows the custom SignalComputation used above to compute the sky spectral radiance for a given Signal parameter.

Java
public static final class SkySpectralRadianceCurveFit extends SignalComputation {
    public SkySpectralRadianceCurveFit() {}

    private SkySpectralRadianceCurveFit(SignalComputation existingInstance, CopyContext context) {
        super(existingInstance, context);
    }

    @Override
    protected boolean checkForSameDefinition(SignalComputation other) {
        return other instanceof SkySpectralRadianceCurveFit;
    }

    @Override
    public Object clone(CopyContext context) {
        return new SkySpectralRadianceCurveFit(this, context);
    }

    @Override
    public IEvaluator1<Double> getEvaluator(EvaluatorGroup group) {
        return group.createEvaluator(getEvaluatorCallback, getParameter());
    }

    private static IEvaluator1<Double> createEvaluator(EvaluatorGroup group, SignalParameter parameter) {
        return new SkySpectralRadianceEvaluator(group, parameter.getEvaluator(group));
    }

    private static final EvaluatorGroup.Callback1<IEvaluator1<Double>, SignalParameter> getEvaluatorCallback =
            EvaluatorGroup.Callback1.of(SkySpectralRadianceCurveFit::createEvaluator);

    private static final class SkySpectralRadianceEvaluator extends Evaluator<Double> {
        public SkySpectralRadianceEvaluator(EvaluatorGroup group, ParameterEvaluator<Signal> signalEvaluator) {
            super(group);
            m_signalEvaluator = signalEvaluator;
        }

        private SkySpectralRadianceEvaluator(SkySpectralRadianceEvaluator existingInstance, CopyContext context) {
            super(existingInstance, context);
            m_signalEvaluator = existingInstance.m_signalEvaluator;
            updateEvaluatorReferences(context);
        }

        @Override
        public void updateEvaluatorReferences(CopyContext context) {
            m_signalEvaluator = context.updateReference(m_signalEvaluator);
        }

        @Override
        public Double evaluate(JulianDate date) {
            Signal signal = m_signalEvaluator.evaluate(date);
            double waveLength = Constants.SpeedOfLight / signal.getFrequency() * 1.0e9; // in nm

            //Curve fit from section 6 of the ITU-R P.1814 recommendation
            return 8.97e-13 * Math.pow(waveLength, 5) -
                    4.65e-9 * Math.pow(waveLength, 4) + 
                    9.37e-6 * Math.pow(waveLength, 3) - 
                    9.067e-3 * waveLength * waveLength + 
                    4.05 * waveLength - 5.70;
        }

        @Override
        public boolean isAvailable(JulianDate date) {
            return m_signalEvaluator.isAvailable(date);
        }

        @Override
        public TimeIntervalCollection getAvailabilityIntervals(TimeIntervalCollection consideredIntervals) {
            return m_signalEvaluator.getAvailabilityIntervals(consideredIntervals);
        }

        @Override
        public boolean getIsThreadSafe() {
            return m_signalEvaluator.getIsThreadSafe();
        }

        @Override
        public Object clone(CopyContext context) {
            return new SkySpectralRadianceEvaluator(this, context);
        }

        @Override
        protected void dispose(boolean disposing) {
            if (disposing) {
                m_signalEvaluator.close();
            }
        }

        @Override
        public boolean getIsTimeVarying() {
            return m_signalEvaluator.getIsTimeVarying();
        }

        private ParameterEvaluator<Signal> m_signalEvaluator;
    }
}

Code Sample

The Basic Communications Code Sample topic contains further examples of using these classes.