Coverage Configuration |
This topic contains details pertaining to the configuration of a coverage calculation.
Note |
---|
The functionality described in this topic requires a license for the Spatial Analysis Library. |
There are two major pieces needed to successfully configure a coverage calculation: configuring the coverage target and specifying assets. With the single object coverage definition, configuring the coverage target merely requires the configuration of the single object of interest. In the case of gridded coverage definitions, this entails completely defining the geometrical grid that represents the coverage target.
The grid specifies how to discretize a continuous region into pieces in order to analyze which parts of the overall region are "covered" by any number of assets, and thus determine what percentage of the overall region satisfies mission requirements. In general, an asset is a resource such as a satellite, aircraft, sensor, or some other entity performing a mission involving several different visibility, communications, navigation, or other criteria to ensure success. In the Spatial Analysis Library, assets are not defined by a Platform representing a vehicle, for example, but are instead defined by the combination of mission constraints that determine whether that particular asset (or set of assets) "covers" any particular grid point. In order to use this system the user configures the grid and specifies Access Queries that represent one or more assets in addition to relationships and mission constraints involving those assets. The user then obtains results indicating which grid points are satisfied over time with which assets, and can further analyze the results using simple metrics called "figures of merit".
Gridding allows the user to specify the distribution and resolution of grid points in a given space. There are two major types of grids offered by the Spatial Analysis Library, GeometricPrimitiveCoverageGrid based grids, and CentralBodyCoverageGrid based grids. The first type of grid generates a list of grid points based upon the specified geometry and the ReferenceFrame (get) in which this geometry is defined. The second type of grid is also defined in this manner with the added attribute of a CentralBody (get / set) and optionally, ReferenceTerrain (get / set).
Some examples of available CentralBodyCoverageGrid grids include:
Global gridding on a central body - GlobalCoverageGrid
Latitude and longitude lines - LatitudeLineCoverageGrid and LongitudeLineCoverageGrid
Gridding specified between two lines of latitude - LatitudeBoundsCoverageGrid
Regular grid points bounded by one or more surface curves - SurfaceRegionsCoverageGrid
A list of grid points specified relative to a central body - SpecifiedCentralBodyCoverageGrid
This also provides a way to generate a set of grid points from another algorithm and store them to ensure they are only generated once. This is recommended in cases where the grid has a large number of points and there are several calls to compute coverage.
Custom gridding - Create your own kind of gridding algorithm using inheritance.
The following example shows gridding a central body with a cartographic extent, using a grid of the CentralBodyCoverageGrid type.
CartographicExtent extent = new CartographicExtent(Trig.degreesToRadians(-70.0), // west Trig.degreesToRadians(20.0), // south Trig.degreesToRadians(-60.0), // east Trig.degreesToRadians(40.0)); // north EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth(); EllipsoidSurfaceRegionBuilder regionBuilder = new SpecifiedExtentEllipsoidSurfaceRegionBuilder(earth.getShape(), extent); EllipsoidSurfaceRegion gridRegion = regionBuilder.getEllipsoidSurfaceRegion(); double resolution = Trig.degreesToRadians(0.1); SurfaceRegionsCoverageGrid coverageGrid = new SurfaceRegionsCoverageGrid(resolution, earth, gridRegion);
Some examples of available GeometricPrimitiveCoverageGrid grids include:
A cuboid grid, specified relative to an arbitrary reference frame - CuboidCoverageGrid
A cone grid - ConeCoverageGrid
A torus grid - TorusCoverageGrid
A spheroid grid - SpheroidCoverageGrid
A cylinder grid - CylinderCoverageGrid
Custom gridding - Create your own kind of gridding algorithm using inheritance.
The following example shows creating a spheroid grid on the Earth. This spheroid grid is then altered to become a hemispherical grid, thus demonstrating the ease in which many of the simple grid types may be altered and customized.
// Create the spheroid grid PointCartographic surfacePointGridOrigin = new PointCartographic(earth, Cartographic.getZero()); ReferenceFrame referenceFrameOnSurfaceOfEarth = new ReferenceFrame(surfacePointGridOrigin, new AxesEastNorthUp(earth, surfacePointGridOrigin)); double radius = 1000000; double radialResolution = 10000; double clockAngleResolution = Math.PI / 8.0; // azimuthal double coneAngleResolution = Math.PI / 8.0; // polar SpheroidCoverageGrid spheroidGrid = new SpheroidCoverageGrid(radius, clockAngleResolution, coneAngleResolution, radialResolution, referenceFrameOnSurfaceOfEarth); // The points in this list comprise a full spheroid List<CoverageGridPoint> pointsInFullSpheroid = spheroidGrid.generateGridPoints(); // Very simple alteration- remove all points where the cone (polar) angle is greater than pi /2.0 which translates to // removing all points where z < 0. After this alteration the result will be a hemispherical grid. spheroidGrid.setConeAngleBounds(new Bounds(0.0, Constants.HalfPi)); // The points in this list comprise a hemisphere List<CoverageGridPoint> pointsThatCompriseHalfDome = spheroidGrid.generateGridPoints();
All gridding algorithms will work with both standard and discrete versions of coverage.
When using a template based coverage definition, such as ParameterizedSpatiallyPartitionedCoverageDefinition or ParameterizedTemporallyPartitionedCoverageDefinition, configuration of the grid point properties involves setting up an archetypical object that defines grid properties in a generic manner. Typically one utilizes a template object that provides the usual services available on a Platform (like position and orientation), but if the constraints used require any additional services they must be added. In order to do this, the user defines an IServiceProvider for use with access.
If a simple platform providing position and orientation will suffice to define the properties of each grid point, both coverage definitions offer a default where the GridPointPlaceholder points to a Platform at each grid point with axes set to AxesEastNorthUp in the case of the grid being based upon CentralBodyCoverageGrid. If the grid is based upon GeometricPrimitiveCoverageGrid or any other grid that implements ICoverageGrid, then a default platform where the axes are set to the reference frame's axes is supplied. If different or more complex point setup is required then the user is responsible for making sure the GridPointPlaceholder points to an object that minimally provides an IServiceProvider that at least reflects the position of the given grid point. Otherwise the results will not coincide with the grid. The following example shows how to configure the grid for coverage using a template approach.
ParameterizedSpatiallyPartitionedCoverageDefinition coverage = new ParameterizedSpatiallyPartitionedCoverageDefinition(); // Create a sensor volume RectangularPyramid sensorView = new RectangularPyramid(); sensorView.setRadius(10000); sensorView.setXHalfAngle(Trig.degreesToRadians(15)); sensorView.setYHalfAngle(Trig.degreesToRadians(20)); // Create and configure a grid EllipsoidSurfaceRegionBuilder regionBuilder = new SpecifiedNodesEllipsoidSurfaceRegionBuilder(earth.getShape(), boundaryPoints); EllipsoidSurfaceRegion region = regionBuilder.getEllipsoidSurfaceRegion(); coverage.setGrid(new SurfaceRegionsCoverageGrid(gridResolution, earth, region)); // Create the platform template that will be used for each grid point in the coverage computation Platform templateGridPoint = new Platform(); templateGridPoint.setLocationPoint(coverage.getGridPoint()); templateGridPoint.setOrientationAxes(new AxesEastNorthUp(earth, templateGridPoint.getLocationPoint())); // Add a field of view extension for use with a SensorVolumeConstraint templateGridPoint.getExtensions().add(new FieldOfViewExtension(sensorView)); // Orient the grid point to point the sensor upward (always along the z-axis of the axes) // Make sure to use either the LocationPoint from the default or the Position of the grid point templateGridPoint.setOrientationAxes(new AxesEastNorthUp(earth, templateGridPoint.getLocationPoint())); // set the platform template coverage.setGridPointPlaceholder(templateGridPoint);
For the two callback based coverage definitions, MaterializedSpatiallyPartitionedCoverageDefinition and MaterializedTemporallyPartitionedCoverageDefinition, a ready-made simple platform, available in a constructor overload, provides the usual services found on a Platform object. If the constraints used in your particular analysis requires any additional services they must be added to each grid point. In order to do this, the user defines a delegate which can be used in conjunction with the GridPointPlaceholder property for use with access. (For more information on service providers, see the Access Queries and Service Providers topics.) The following example shows how to configure the coverage definition by creating a grid based on a region specified by a set of Cartographic vertices.
MaterializedSpatiallyPartitionedCoverageDefinition coverage = new MaterializedSpatiallyPartitionedCoverageDefinition(); // Create a sensor volume RectangularPyramid sensorView = new RectangularPyramid(); sensorView.setRadius(10000); sensorView.setXHalfAngle(Trig.degreesToRadians(15)); sensorView.setYHalfAngle(Trig.degreesToRadians(20)); // Create and configure a grid EllipsoidSurfaceRegionBuilder regionBuilder = new SpecifiedNodesEllipsoidSurfaceRegionBuilder(earth.getShape(), boundaryPoints); EllipsoidSurfaceRegion region = regionBuilder.getEllipsoidSurfaceRegion(); coverage.setGrid(new SurfaceRegionsCoverageGrid(gridResolution, earth, region)); coverage.setGridPointCreationCallback(CoverageGridPointCreationCallback.of(gridPointWithCoverageData -> { // Remember! Never modify or reference mutable variables here which are not in the local scope. // Create the Platform Platform defaultGridPoint = new Platform("example"); // Set the location point of the platform to the position of the grid point defaultGridPoint.setLocationPoint(gridPointWithCoverageData.getCoverageGridPoint().getPosition()); // Add a field of view extension for use with a SensorVolumeConstraint defaultGridPoint.getExtensions().add(new FieldOfViewExtension(sensorView)); // Orient the grid point to point the sensor upward (always along the z-axis of the axes) // Make sure to use either the LocationPoint from the default or the Position of the grid point defaultGridPoint.setOrientationAxes(new AxesEastNorthUp(earth, defaultGridPoint.getLocationPoint())); return defaultGridPoint; }));
The previously mentioned selectable ready-made option points to a method that creates a Platform at each grid point with axes set to AxesEastNorthUp in the case of a grid derived from CentralBodyCoverageGrid, otherwise, the axes used are those of the grid's reference frame. If different or more complex setup is required, then the user is responsible for making sure the callback points to a method that minimally provides an IServiceProvider that at least reflects the position of the given grid point. Otherwise, the results will not coincide with the grid. The object created by the callback may also provide services to be used in the coverage calculation, such as IOrientationAxesService and IKinematicStateService.
Since these points are created after the coverage calculation begins, the AccessConstraintsExtension or any other constraint definitions will be ignored. To add constraints to the grid, see the next section on creating Assets.
Caution |
---|
The grid point creation process occurs in a threaded context. So, the user is responsible for ensuring that any grid point creation callback delegate is threadsafe. In general, the method should not use any properties which might be changed inside or outside of the local scope. It is possible to share instances of variables in the local scope which are guaranteed not to change during the call to ComputeCoverageOverTheGrid. However, in general if you start to see strange effects or exceptions being thrown, avoid using any variables outside of the creation callback. |
An AssetDefinition represents spacecraft, aircraft, sensors, constellations, chains, or any other singular or grouped resource which performs some function relevant to the coverage target (grid or single object). An asset "provides coverage" to a grid point if it has access to a given number of these assets over a given time. Assets are defined by an Object reference (usually to the actual Platform modeling the asset) and an AccessQuery which defines when the asset provides coverage. The Object reference is used as a key when retrieving data after computation. The following example shows how to use links and access queries to set up a number of assets taken from a collection of spacecraft. Note that creating a LinkInstantaneous or LinkSpeedOfLight to the grid is as simple as treating the GridPointPlaceholder as the grid point of interest. This placeholder will be replaced dynamically at runtime with each point in the grid using the GridPointCreationCallback (get / set) in the case of callback-based coverage definitions, or the template set via GridPointPlaceholder (get / set) in the case of template-based coverage definitions. The following example shows how to set up a case representing sensors located at the grid points which may be tracking the given assets. A sensor volume represents the line of sight and an angular rate constraint represents a limitation on the ability of the sensor to track the satellite across its line of sight.
// Add Assets for (Platform spacecraft : gpsConstellation) { // Create a new link between your satellite and the grid by using the placeholder // satellite is the transmitter, grid is the receiver LinkInstantaneous newLink = new LinkInstantaneous(spacecraft, coverage.getGridPointPlaceholder()); // Apply a sensor volume constraint to the grid (receiver) SensorVolumeConstraint sensorConstraint = new SensorVolumeConstraint(); sensorConstraint.setConstrainedLink(newLink); sensorConstraint.setConstrainedLinkEnd(LinkRole.RECEIVER); // grid points // Apply a total angular rate constraint on the spacecraft motion (5 deg / sec) to the grid (receiver) TotalAngularRateConstraint angularRate = new TotalAngularRateConstraint(0, Trig.degreesToRadians(5)); angularRate.setConstrainedLink(newLink); angularRate.setConstrainedLinkEnd(LinkRole.RECEIVER); // grid points // Create the asset definition // Object to use as a key when indexing results Platform assetObject = spacecraft; // Combine constraints on the link into one AccessQuery AccessQuery query = AccessQuery.and(sensorConstraint, angularRate); // Indicate whether access to this asset is required, // meaning that this asset must be satisfied in order // for any others to be satisfied boolean isRequired = false; coverage.addAsset(new AssetDefinition(assetObject, query, isRequired)); }
Note that in order to add constraints to the grid, use the GridPointPlaceholder (get) on the coverage definition. Any services required by the constraints applied to the GridPointPlaceholder (get) should be added in the delegate or template. Otherwise, access will throw a ServiceNotAvailableException when the required services are not available.
Also note that, as is the case with Access Queries in general, having more information available about the precise nature of the satisfaction conditions will improve performance. This is especially true in cases where one constraint (e.g. terrain-related constraints) will tend to dominate the others. In these cases, having constraints combined using both AND and OR operations will allow the system to eliminate as much time as possible from the evaluation of the expensive constraints. So, for instance, if the local terrain for the grid is such that the minimum possibly visible elevation is 10 degrees but it's also known that for everywhere on the grid the maximum obscured elevation is 70 degrees, then it's possible to combine the terrain with a 10 degree minimum elevation constraint "or" a 70 degree minimum elevation constraint. The system will check the 70 degree minimum first and if the asset is satisfied (greater than 70 degrees elevation), no further evaluation is necessary since we know for certain the asset is visible (or 'satisfied'). If that isn't the case, then the system will check the 10 degree minimum and if the asset is below the minimum, no further evaluation is necessary since we know for certain that the asset is obscured.