Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(perception): simplified configuration for perception index #351

Merged
merged 12 commits into from
Oct 4, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"messageCacheTime": "30s",
"encodePayloads": true,
"eventSchedulerThreads": 1,
"navigationConfiguration": {
"type": "database"
},
"perceptionConfiguration": {
"vehicleIndex": {
"enabled": true
},
"trafficLightIndex": {
"enabled": true
},
"wallIndex": {
"enabled": false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,10 @@ this, new StartApplications(chargingStationUnit.getId(), chargingStationRegistra
* @param trafficLightRegistration traffic light
*/
public void registerTrafficLight(TrafficLightRegistration trafficLightRegistration) {
if (!trafficLightRegistration.getMapping().hasApplication()
&& SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex == null) {
// if traffic light index is enabled, we need traffic light state information for all traffic lights via subscriptions
boolean isTrafficLightIndexEnabled = SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex != null &&
SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex.enabled;
if (!trafficLightRegistration.getMapping().hasApplication() && !isTrafficLightIndexEnabled) {
kschrab marked this conversation as resolved.
Show resolved Hide resolved
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,13 @@ public VehicleUnit(String vehicleName, VehicleType vehicleType, final GeoPoint i
.getCentralNavigationComponent().getRouting()).getScenarioDatabase();
}

if (SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.vehicleIndex != null) {
perceptionModule = SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.vehicleIndex
.createPerceptionModule(this, database, getOsLog());
if (SimulationKernel.SimulationKernel.getCentralPerceptionComponent().getTrafficObjectIndex() != null) {
perceptionModule = SimulationKernel.SimulationKernel.getCentralPerceptionComponent()
.getTrafficObjectIndex().createPerceptionModule(this, database, getOsLog());
} else {
perceptionModule = new NopPerceptionModule(this, database, getOsLog());
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,21 @@

import org.eclipse.mosaic.fed.application.ambassador.SimulationKernel;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.TrafficObjectIndex;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.TrafficLightObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.VehicleObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.providers.TrafficLightMap;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.providers.VehicleMap;
import org.eclipse.mosaic.fed.application.config.CApplicationAmbassador;
import org.eclipse.mosaic.fed.application.config.CPerception;
import org.eclipse.mosaic.interactions.traffic.TrafficLightUpdates;
import org.eclipse.mosaic.interactions.traffic.VehicleUpdates;
import org.eclipse.mosaic.lib.database.Database;
import org.eclipse.mosaic.lib.geo.CartesianRectangle;
import org.eclipse.mosaic.lib.math.Vector3d;
import org.eclipse.mosaic.lib.objects.trafficlight.TrafficLightGroup;
import org.eclipse.mosaic.lib.objects.trafficlight.TrafficLightGroupInfo;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleData;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleType;
import org.eclipse.mosaic.lib.routing.Routing;
import org.eclipse.mosaic.lib.spatial.Edge;
import org.eclipse.mosaic.lib.util.PerformanceMonitor;
import org.eclipse.mosaic.rti.api.InternalFederateException;

import com.google.common.collect.Iterables;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
* The {@link CentralPerceptionComponent} is responsible for keeping a spatial index of all vehicles,
* which allows fast querying of nearby vehicles.
Expand All @@ -57,7 +44,7 @@ public class CentralPerceptionComponent {
/**
* Configuration containing parameters for setting up the spatial indexes.
*/
private final CApplicationAmbassador.CPerception configuration;
private final CPerception configuration;

/**
* The spatial index used to store and find objects by their positions.
Expand All @@ -84,7 +71,7 @@ public class CentralPerceptionComponent {
*/
private boolean updateTrafficLightIndex = false;

public CentralPerceptionComponent(CApplicationAmbassador.CPerception perceptionConfiguration) {
public CentralPerceptionComponent(CPerception perceptionConfiguration) {
this.configuration = Validate.notNull(perceptionConfiguration, "perceptionConfiguration must not be null");
}

Expand All @@ -99,38 +86,21 @@ public void initialize() throws InternalFederateException {
// evaluate bounding box for perception
scenarioBounds = configuration.perceptionArea == null
? routing.getScenarioBounds() : configuration.perceptionArea.toCartesian();
// see what backends are configured
boolean vehicleIndexConfigured = configuration.vehicleIndex != null;
boolean trafficLightIndexConfigured = configuration.trafficLightIndex != null;

TrafficObjectIndex.Builder indexBuilder = new TrafficObjectIndex.Builder(LOG);
if (scenarioBounds.getArea() <= 0) {
LOG.warn("The bounding area of the scenario could not be determined. Defaulting to low performance spatial index.");
if (vehicleIndexConfigured) { // if configured default to map index
indexBuilder.withVehicleIndex(new VehicleMap());
}
if (trafficLightIndexConfigured) { // if configured default to map index
indexBuilder.withTrafficLightIndex(new TrafficLightMap());
}
} else {
if (vehicleIndexConfigured) {
indexBuilder.withVehicleIndex(configuration.vehicleIndex);
}
if (trafficLightIndexConfigured) {
indexBuilder.withTrafficLightIndex(configuration.trafficLightIndex);
}
if (configuration.vehicleIndex != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We lost the validation of the scenarioBounds here, but maybe this isn't really necessary in the first place

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I also didn't see the reason for this check.

indexBuilder.withVehicleIndex(configuration.vehicleIndex.create());
}
if (configuration.trafficLightIndex != null) {
indexBuilder.withTrafficLightIndex(configuration.trafficLightIndex.create());
}
if (routing instanceof Database) {
Database dbRouting = (Database) routing;
if (!dbRouting.getBuildings().isEmpty()) {
indexBuilder.withWallIndex(configuration.wallIndex, (Database) routing);
if (!dbRouting.getBuildings().isEmpty() && configuration.wallIndex != null) {
indexBuilder.withWallIndex(configuration.wallIndex.create(), (Database) routing);
}
}
trafficObjectIndex = indexBuilder.build();

if (configuration.measurePerformance) {
trafficObjectIndex = new MonitoringTrafficObjectIndexProvider(trafficObjectIndex, PerformanceMonitor.getInstance());
}
} catch (Exception e) {
throw new InternalFederateException("Couldn't initialize CentralPerceptionComponent", e);
}
Expand Down Expand Up @@ -212,63 +182,4 @@ public void updateTrafficLights(TrafficLightUpdates trafficLightUpdates) {
updateTrafficLightIndex = true;
}

/**
* Wrapper class to measure atomic calls of update, search and remove of the used spatial index.
*/
static class MonitoringTrafficObjectIndexProvider extends TrafficObjectIndex {
private final PerformanceMonitor monitor;

MonitoringTrafficObjectIndexProvider(TrafficObjectIndex parent, PerformanceMonitor monitor) {
super(parent);
this.monitor = monitor;
}

@Override
public List<VehicleObject> getVehiclesInRange(PerceptionModel searchRange) {
try (PerformanceMonitor.Measurement m = monitor.start("search-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getVehiclesInRange(searchRange);
}
}

@Override
public void removeVehicles(Iterable<String> vehiclesToRemove) {
try (PerformanceMonitor.Measurement m = monitor.start("remove-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.removeVehicles(vehiclesToRemove);
}
}

@Override
public void updateVehicles(Iterable<VehicleData> vehiclesToUpdate) {
try (PerformanceMonitor.Measurement m = monitor.start("update-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.updateVehicles(vehiclesToUpdate);
}
}

@Override
public List<TrafficLightObject> getTrafficLightsInRange(PerceptionModel perceptionModel) {
try (PerformanceMonitor.Measurement m = monitor.start("search-traffic-light")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getTrafficLightsInRange(perceptionModel);
}
}

@Override
public void updateTrafficLights(Map<String, TrafficLightGroupInfo> trafficLightsToUpdate) {
try (PerformanceMonitor.Measurement m = monitor.start("update-traffic-light")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.updateTrafficLights(trafficLightsToUpdate);
}
}

@Override
public Collection<Edge<Vector3d>> getSurroundingWalls(PerceptionModel perceptionModel) {
try (PerformanceMonitor.Measurement m = monitor.start("search-walls")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getSurroundingWalls(perceptionModel);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2022 Fraunhofer FOKUS and others. All rights reserved.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contact: [email protected]
*/

package org.eclipse.mosaic.fed.application.ambassador.simulation.perception.errormodels;

import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.PerceptionModuleOwner;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.SpatialObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.VehicleObject;
import org.eclipse.mosaic.lib.math.RandomNumberGenerator;
import org.eclipse.mosaic.lib.math.Vector3d;

import java.util.List;

public class DimensionsModifier implements PerceptionModifier {
schwepmo marked this conversation as resolved.
Show resolved Hide resolved

private static final double SIGMA_WIDTH_OFFSET = 0.2; // given in m
private static final double SIGMA_HEIGHT_OFFSET = 0.2; // given in m
private static final double SIGMA_LENGTH_OFFSET = 0.5; // given in m

private final double heightOffset;
private final double widthOffset;
private final double lengthOffset;

private final RandomNumberGenerator rng;


public DimensionsModifier(RandomNumberGenerator rng, double heightOffset, double widthOffset, double lengthOffset) {
this.rng = rng;
this.heightOffset = heightOffset;
this.widthOffset = widthOffset;
this.lengthOffset = lengthOffset;
}

public DimensionsModifier(RandomNumberGenerator rng) {
this.rng = rng;
this.heightOffset = SIGMA_HEIGHT_OFFSET;
this.widthOffset = SIGMA_WIDTH_OFFSET;
this.lengthOffset = SIGMA_LENGTH_OFFSET;
}

@Override
public <T extends SpatialObject> List<T> apply(PerceptionModuleOwner owner, List<T> spatialObjects) {
final Vector3d ownerPosition = owner.getVehicleData().getProjectedPosition().toVector3d();

spatialObjects.stream()
.filter(o -> o instanceof VehicleObject)
.forEach(o -> adjustDimensionsOfVehicle((VehicleObject) o));

return spatialObjects;
}

private void adjustDimensionsOfVehicle(VehicleObject vehicleObject) {
vehicleObject.setDimensions(
Math.abs(rng.nextGaussian(vehicleObject.getLength(), lengthOffset)),
Math.abs(rng.nextGaussian(vehicleObject.getHeight(), heightOffset)),
Math.abs(rng.nextGaussian(vehicleObject.getWidth(), widthOffset))
);
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2022 Fraunhofer FOKUS and others. All rights reserved.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contact: [email protected]
*/

package org.eclipse.mosaic.fed.application.ambassador.simulation.perception.errormodels;

import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.PerceptionModuleOwner;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.SpatialObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.VehicleObject;
import org.eclipse.mosaic.lib.math.RandomNumberGenerator;
import org.eclipse.mosaic.lib.math.Vector3d;
import org.eclipse.mosaic.lib.math.VectorUtils;

import java.util.List;


public class HeadingModifier implements PerceptionModifier {
schwepmo marked this conversation as resolved.
Show resolved Hide resolved

/**
* Default standard deviation for heading error
*/
private static final double SIGMA_HEADING_OFFSET = 4; // given in degree

/**
* Default chance of the car being perceived heading in the complete other direction (180° error)
*/
private static final double DEFAULT_CHANCE_WRONG_DIR = 0.01;

private final RandomNumberGenerator rng;

/**
* Standard deviation for heading error.
*/
private final double headingStandardDeviation;

private final double chanceOfWrongDirection;

public HeadingModifier(RandomNumberGenerator rng) {
this.rng = rng;
this.headingStandardDeviation = SIGMA_HEADING_OFFSET;
this.chanceOfWrongDirection = DEFAULT_CHANCE_WRONG_DIR;
}

public HeadingModifier(RandomNumberGenerator rng, double headingStandardDeviation, double chanceOfWrongDirection) {
this.rng = rng;
schwepmo marked this conversation as resolved.
Show resolved Hide resolved
this.headingStandardDeviation = headingStandardDeviation;
this.chanceOfWrongDirection = chanceOfWrongDirection;
}

@Override
public <T extends SpatialObject> List<T> apply(PerceptionModuleOwner owner, List<T> spatialObjects) {
final Vector3d ownerPosition = owner.getVehicleData().getProjectedPosition().toVector3d();

spatialObjects.stream()
.filter(o -> o instanceof VehicleObject)
.forEach(o -> adjustHeadingOfVehicle(ownerPosition, (VehicleObject) o));

return spatialObjects;
}

private void adjustHeadingOfVehicle(Vector3d ownerPosition, VehicleObject vehicleObject) {

double oldHeading = vehicleObject.getHeading();

if (rng.nextDouble() < chanceOfWrongDirection) {
vehicleObject.setHeading(rotatedVehicleHeading(vehicleObject.getHeading()));
}
vehicleObject.setHeading(rng.nextGaussian(vehicleObject.getHeading(), headingStandardDeviation) % 360);

double newHeading = vehicleObject.getHeading();

Vector3d oldHeadingVector = VectorUtils.getDirectionVectorFromHeading(oldHeading, new Vector3d());
Vector3d newHeadingVector = VectorUtils.getDirectionVectorFromHeading(newHeading, new Vector3d());

Vector3d newPosition = new Vector3d(vehicleObject.getPosition())
.subtract(oldHeadingVector.multiply(vehicleObject.getLength() / 2))
.add(newHeadingVector.multiply(vehicleObject.getLength() / 2));
vehicleObject.setPosition(newPosition.x, newPosition.y, newPosition.z);
}

private static double rotatedVehicleHeading(double heading) {
return (heading + 180.0) % 360.0;
}
}
Loading