#ifndef NAV_MESH_FILTER_H #define NAV_MESH_FILTER_H #include "mesh.h" #include "../Settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct MyState { /** the state's position (within the mesh) */ MyNavMeshLocation pos; /** the state's heading */ Heading heading; MyState() : pos(), heading(0) {;} MyState(Point3 p) : pos(p, nullptr), heading(0){;} MyState& operator += (const MyState& o) { pos.tria = nullptr; // impossible pos.pos += o.pos.pos; return *this; } MyState& operator /= (const double val) { pos.tria = nullptr; // impossible pos.pos /= val; return *this; } MyState operator * (const double val) const { MyState res; res.pos.pos = pos.pos * val; return res; } float getX(){ return pos.pos.x; } float getY() { return pos.pos.y; } float getBinValue(const int dim) const { switch (dim) { case 0: return this->pos.pos.x; case 1: return this->pos.pos.y; case 2: return this->pos.pos.z; case 3: return this->heading.getRAD(); } throw "cant find this value within the bin"; } }; struct MyControl { int numStepsSinceLastEval = 0; float headingChangeSinceLastEval = 0; void afterEval() { numStepsSinceLastEval = 0; headingChangeSinceLastEval = 0; } //wifi WiFiMeasurements wifi; //time Timestamp currentTime; //last estimation Point3 lastEstimate = Point3(26, 43, 7.5); }; struct MyObservation { // pressure float sigmaPressure = 0.10f; float relativePressure = 0; //wifi WiFiMeasurements wifi; //time Timestamp currentTime; //activity Activity activity; }; class MyPFInitUniform : public SMC::ParticleFilterInitializer { const MyNavMesh* mesh; public: MyPFInitUniform(const MyNavMesh* mesh) : mesh(mesh) { ; } virtual void initialize(std::vector>& particles) override { /** random position and heading within the mesh */ Distribution::Uniform dHead(0, 2*M_PI); MyNavMeshRandom rnd = mesh->getRandom(); for (SMC::Particle& p : particles) { p.state.pos = rnd.draw(); p.state.heading = dHead.draw(); p.weight = 1.0 / particles.size(); } } }; class MyPFInitFixed : public SMC::ParticleFilterInitializer { const MyNavMesh* mesh; const Point3 pos; public: MyPFInitFixed(const MyNavMesh* mesh, const Point3 pos) : mesh(mesh), pos(pos) { ; } virtual void initialize(std::vector>& particles) override { /** random position and heading within the mesh */ Distribution::Uniform dHead(0, 2*M_PI); for (SMC::Particle& p : particles) { p.state.pos = mesh->getLocation(pos); p.state.heading = dHead.draw(); p.weight = 1.0 / particles.size(); } } }; class MyPFTrans : public SMC::ParticleFilterTransition { //using MyNavMeshWalk = NM::NavMeshWalkSimple; //using MyNavMeshWalk = NM::NavMeshWalkWifiRegional; //using MyNavMeshWalk = NM::NavMeshWalkUnblockable; using MyNavMeshWalk = NM::NavMeshWalkKLD; MyNavMeshWalk walker; WiFiQualityAnalyzer analyzer; WiFiObserverFree wifiProbability; const double lambda = 0.0003; SMC::ParticleFilterEstimationBoxKDE estimator; public: MyPFTrans(MyNavMesh& mesh, WiFiModel& wifiModel) : walker(mesh), wifiProbability(Settings::WiFiModel::sigma, wifiModel){ // how to evaluate drawn points //walker.addEvaluator(new NM::WalkEvalHeadingStartEndNormal(0.04)); //walker.addEvaluator(new NM::WalkEvalDistance(0.1)); //walker.addEvaluator(new NM::WalkEvalApproachesTarget(0.9)); // 90% for particles moving towards the target estimator = SMC::ParticleFilterEstimationBoxKDE(&mesh, 0.2, Point2(1,1)); } void transition(std::vector>& particles, const MyControl* control) override { // walking and heading random Distribution::Normal dStepSizeFloor(0.70, 0.1); Distribution::Normal dStepSizeStair(0.35, 0.1); Distribution::Normal dHeading(0.0, 0.1); // wifi and quality of wifi const WiFiMeasurements wifiObs = Settings::WiFiModel::vg_eval.group(control->wifi); if(!wifiObs.entries.empty()){ analyzer.add(wifiObs); } float qualityWifi = analyzer.getQuality(); if(std::isnan(qualityWifi)){ qualityWifi = 1.0; } else if(qualityWifi == 0) { qualityWifi = 0.00000001; } // divergence between eval and transition std::vector> wifiParticles; NM::NavMeshRandom rnd = walker.getMesh().getRandom(); for(int i = 0; i < 10000; ++i){ NM::NavMeshLocation tmpLocation = rnd.draw(); double weight = wifiProbability.getProbability(tmpLocation.pos, control->currentTime, wifiObs); SMC::Particle tmpParticle(MyState(tmpLocation.pos), weight); wifiParticles.push_back(tmpParticle); } MyState wifiEstimate = estimator.estimate(wifiParticles); // fake kld const double kld = control->lastEstimate.getDistance(wifiEstimate.pos.pos); //const double kld = Divergence::KullbackLeibler::getMultivariateGauss(normParticle, normWifi);; //std::cout << "KLD: " << kld << std::endl; //std::cout << "Quality: " << qualityWifi << std::endl; //update wifi //walker.updateWiFi(wifiObs, control->currentTime, control->lastEstimate); #pragma omp parallel for num_threads(3) for (int i = 0; i < particles.size(); ++i) { SMC::Particle& p = particles[i]; // how to walk MyNavMeshWalkParams params; params.heading = p.state.heading + control->headingChangeSinceLastEval + dHeading.draw(); params.numSteps = control->numStepsSinceLastEval; params.start = p.state.pos; params.stepSizes.stepSizeFloor_m = dStepSizeFloor.draw(); params.stepSizes.stepSizeStair_m = dStepSizeStair.draw(); if(params.stepSizes.stepSizeFloor_m < 0.1 || params.stepSizes.stepSizeStair_m < 0.1){ params.stepSizes.stepSizeFloor_m = 0.1; params.stepSizes.stepSizeStair_m = 0.1; } double deltaUnblockable = 0.01; // walk //MyNavMeshWalk::ResultEntry res = walker.getOne(params); MyNavMeshWalk::ResultEntry res = walker.getOne(params, kld, lambda, qualityWifi); // assign back to particle's state p.weight *= res.probability; p.state.pos = res.location; p.state.heading = res.heading; } // reset the control (0 steps, 0 delta-heading) //control->afterEval(); } }; class MyPFEval : public SMC::ParticleFilterEvaluation { WiFiModel& wifiModel; WiFiObserverFree wifiProbability; //TODO: add this to transition probability double getStairProb(const SMC::Particle& p, const Activity act) { const float kappa = 0.75; switch (act) { case Activity::WALKING: if (p.state.pos.tria->getType() == (int) NM::NavMeshType::FLOOR_INDOOR) {return kappa;} if (p.state.pos.tria->getType() == (int) NM::NavMeshType::DOOR) {return kappa;} if (p.state.pos.tria->getType() == (int) NM::NavMeshType::STAIR_LEVELED) {return kappa;} {return 1-kappa;} case Activity::WALKING_UP: case Activity::WALKING_DOWN: if (p.state.pos.tria->getType() == (int) NM::NavMeshType::STAIR_SKEWED) {return kappa;} if (p.state.pos.tria->getType() == (int) NM::NavMeshType::STAIR_LEVELED) {return kappa;} if (p.state.pos.tria->getType() == (int) NM::NavMeshType::ELEVATOR) {return kappa;} {return 1-kappa;} } return 1.0; } public: MyPFEval(WiFiModel& wifiModel) : wifiModel(wifiModel), wifiProbability(Settings::WiFiModel::sigma, wifiModel){} virtual double evaluation(std::vector>& particles, const MyObservation& observation) override { double sum = 0; const WiFiMeasurements wifiObs = Settings::WiFiModel::vg_eval.group(observation.wifi); #pragma omp parallel for num_threads(3) for (int i = 0; i < particles.size(); ++i) { SMC::Particle& p = particles[i]; double pWifi = wifiProbability.getProbability(p.state.pos.pos, observation.currentTime, wifiObs); double pStair = getStairProb(p, observation.activity); //HACK HACK HACK HACK double prob = 1.0; prob = pWifi * pStair; p.weight *= prob; #pragma omp atomic sum += prob; } return sum; } }; using MyFilter = SMC::ParticleFilter; #endif