diff --git a/src/main/java/ipos/project/Functionality/SensorDataFusion.java b/src/main/java/ipos/project/Functionality/SensorDataFusion.java new file mode 100644 index 0000000000000000000000000000000000000000..ed20c0d265c8e41b8141f4a605c6268f02f825c0 --- /dev/null +++ b/src/main/java/ipos/project/Functionality/SensorDataFusion.java @@ -0,0 +1,98 @@ +package ipos.project.Functionality; + +import ipos.project.DataModellntegration.iPos_Datamodel.Agent; +import ipos.project.DataModellntegration.iPos_Datamodel.Gaussian; +import ipos.project.DataModellntegration.iPos_Datamodel.PositionEvent; +import ipos.project.UseCaseController.PositionMonitoring; +import org.apache.logging.log4j.LogManager; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +public class SensorDataFusion { + + private static Map<String, List<PositionEvent>> recentEventStorage = new HashMap<>(); + private static org.apache.logging.log4j.Logger LOG = LogManager.getLogger(); + + /** + * Side-effect: calls updates recent-event storage + * + * @param positionEvent + * @return + */ + public static boolean isMostAccuratePositionAvailable(PositionEvent positionEvent) { + try { + Agent agent = DataServices.getAgentForLocalizableObject(positionEvent.getLObjectId()); + List<PositionEvent> eventsForAgent = getEventStorageForAgentOrCreate(agent.getId()); + updateRecentEventStorage(eventsForAgent, positionEvent); + return hasHighestAccuracyAmongStoredEvents(positionEvent, eventsForAgent); + + } catch (IllegalArgumentException e) { + LOG.warn("Sensor-data-fusion could not be applied to position-event as no LocalizableObject with " + + "the provided sensor-id could be found, or no agent" + + "is associated to the LocalizableObject that has been found."); + return false; + } + } + + /** + * Assumption: The larger the accuracy-value the worse is the accuracy. + * Accuracy == 0 is the best possible accuracy. + * Note: the accuracy-value corresponds conceptually to the radius of + * the circle that indicates the potential positions of the agent. + * @param positionEvent + * @param eventsForAgent + * @return + */ + private static boolean hasHighestAccuracyAmongStoredEvents(PositionEvent positionEvent, List<PositionEvent> eventsForAgent) { + for (PositionEvent storedEvent : eventsForAgent){ + float storedAccuracy = ((Gaussian) storedEvent.getPlacing().getPosition().getAccuracy()).getConfidenceInterval(); + float eventAccuracy = ((Gaussian) positionEvent.getPlacing().getPosition().getAccuracy()).getConfidenceInterval();; + if (storedAccuracy < eventAccuracy){ // it is important not to use <= here, as at least the current position event itself is contained in the list + LOG.info("SensorDataFusion rejected position-event: " + positionEvent.toString()); + return false; + } + } + return true; + } + + private static void updateRecentEventStorage(List<PositionEvent> eventsForAgent, PositionEvent positionEvent) throws IllegalArgumentException { + eventsForAgent.add(0, positionEvent); + removeOldEvents(eventsForAgent); + } + + /** + * Removes all position-events older than SDF_TIME_INTERVAL from the recentEventStorage. + * @param eventsForAgent + */ + private static void removeOldEvents(List<PositionEvent> eventsForAgent) { + LocalDateTime now = LocalDateTime.now(); + boolean removeSubsequentElements = false; + for (Iterator<PositionEvent> eventIt = eventsForAgent.iterator(); eventIt.hasNext();){ + PositionEvent currEvent = eventIt.next(); + if (removeSubsequentElements){ + eventIt.remove(); // removes element of the list that was returned by the last call to next() + continue; + } + LocalDateTime eventTime = LocalDateTime.parse(currEvent.getTimeStamp(), DateTimeFormatter.ISO_OFFSET_DATE_TIME); + long eventAge = Duration.between(eventTime, now).toMillis(); + if ( eventAge > PositionMonitoring.SDF_TIME_INTERVAL){ + eventIt.remove(); + removeSubsequentElements = true; + } + } + } + + private static List<PositionEvent> getEventStorageForAgentOrCreate(String agentId) { + List<PositionEvent> eventsForAgent = recentEventStorage.get(agentId); + if (eventsForAgent == null){ + eventsForAgent = new ArrayList<PositionEvent>(); + recentEventStorage.put(agentId, eventsForAgent); + } + return eventsForAgent; + } + + +}