粒子过滤器iOS实现失败

时间:2015-12-15 09:29:57

标签: ios particle-filter

这个问题让我发疯,我实际上需要一些帮助。

我必须在iOS中实现一个粒子过滤器,我从Java中的工作代码开始。

该算法非常接近于“运动员的人工智能”课程中的描述(https://www.udacity.com/course/artificial-intelligence-for-robotics--cs373

Java实现具有以下行为:我移动机器人,粒子越来越靠近机器人,然后它们以非常低的误差跟随它。我认为这是预期的行为。改变粒子的数量,标志的数量和噪音,我得到更好或更差的结果。

iOS实现行为完全不同:我移动机器人,粒子靠近机器人,但经过几次迭代,它们开始远离机器人。最初,平均值仍然接近机器人,但随后它跳得很远。 改变粒子数,标志数和噪音,我得到几乎相同的结果。

我仔细检查了iOS代码,显然它是正确的。

我怀疑这个问题与随机数生成和/或高斯随机生成有关。

我已经更改了我的代码,以使用Java库使用的代码(http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextGaussian())获得相同的结果。

我将高斯随机生成器移动到一个单例,以便在所有粒子上共享相同的生成器,但没有任何改变。

我尝试使用drand48()更改((double)arc4random() / (double)UINT32_MAX)获得相同的结果。

我没有其他想法。

我不是要求您调试我的代码,但是请给我任何建议来解决这个问题。

编辑1

也许这些照片可能会有所帮助

Initial particles distribution

Step 1

Step 2

从这一步开始,粒子远离机器人

Step 3

Step 7

Step 10

Step 13

Step 16

编辑2

这是我的粒子类:

@interface Particle ()

@property (nonatomic, strong)   MyPoint     *point;
@property                       double      orientation;
@property                       NSInteger   worldWidth;
@property                       NSInteger   worldHeight;
@property                       double      probability;

@property                       double      forwardNoise;
@property                       double      turnNoise;
@property                       double      senseNoise;

@property (nonatomic,strong)    Utils       *utils;

@end

@implementation Particle

-(instancetype)initWithWorldWidth:(float)worldWidth worldHeight:(float)worldHeight {

     self = [super init];

    if (self) {

        _worldWidth = worldWidth;
        _worldHeight = worldHeight;

        _point = [[MyPoint alloc] initWithX:drand48() * _worldWidth
                                      Y:drand48() * _worldHeight];

        _orientation = drand48() * 2. * M_PI;

        _forwardNoise = 0;
        _turnNoise = 0;
        _senseNoise = 0;

        _utils = [Utils sharedInstance];
    }

     return self;
}


-(void)setPosition:(MyPoint *)p orientation:(float)orientation probability:(double)probability {

    _point.x = p.x;
    _point.y = p.y;
    _orientation = orientation;
    _probability = probability;
}

-(void)setNoise:(double)forwardNoise turnNoise:(double)turnNoise senseNoise:(double)senseNoise {

    _forwardNoise = forwardNoise;
    _turnNoise = turnNoise;
    _senseNoise = senseNoise;
}

-(MyPoint *)getPosition {

     return _point;
}

-(double)getOrientation {

     return _orientation;
}

-(double)getProbability {

     return _probability;
}

-(double)getForwardNoise {

     return _forwardNoise;
}

-(double)getTurnNoise {

     return _turnNoise;
}

-(double)getSenseNoise {

     return _senseNoise;
}

-(NSArray<NSNumber *>*)sense:(NSArray<Landmark*>*)landmarks {

     NSMutableArray<NSNumber*> *measures = [[NSMutableArray alloc] init];

     for(int i=0; i<landmarks.count; i++) {

        Landmark *landmark = landmarks[i];

        double distance = [Utils distanceBetweenP1:_point andP2:landmark];

         double measure = distance + [_utils box_muller:0 :1.] * _senseNoise;

        [measures addObject:[NSNumber numberWithDouble:measure]];
    }

     return measures;
}

-(void)moveForward:(double)forward withTurn:(double)turn {

    //NSLog(@"---- Move ---- forward: %f ---- %f",forward,turn);

     double a1 = [_utils box_muller:0. :1.];

    //NSLog(@"\ta1=%.8f",a1);

    _orientation = _orientation + turn + a1 * _turnNoise;
    _orientation = [Utils circle:_orientation :2*M_PI];

     double a2 = [_utils box_muller:0. :1.];

    //NSLog(@"\ta2=%.8f",a2);

     double dist = forward + a2 * _forwardNoise;

    _point.x += cos(_orientation) * dist;
    _point.y += sin(_orientation) * dist;

    _point.x = [Utils circle:_point.x :_worldWidth];
    _point.y = [Utils circle:_point.y :_worldHeight];
}

-(double)measurementProb:(NSArray<NSNumber *> *)measurements landmarks:(NSArray<Landmark *>*)landmarks {

     double prob = 1.0;

     for(int i=0; i<measurements.count; i++) {

         Landmark *landmark = landmarks[i];
         double   measurement = [measurements[i] doubleValue];

         double dist = [Utils distanceBetweenP1:_point andP2:landmark];

         prob *= [Utils gaussian:dist :_senseNoise :measurement];
    }

    _probability = prob;
     return prob;
}

这是我的粒子滤镜:

#import "ParticleFilter.h"

@interface ParticleFilter ()

@property (nonatomic,strong) NSMutableArray<Particle *> *particles;
@property (nonatomic,strong) NSArray<Landmark *>        *landmarks;
@property                    NSInteger                  worldWidth;
@property                    NSInteger                  worldHeight;

@end

@implementation ParticleFilter

-(instancetype)initWithLandmarks:(NSArray<Landmark*>*)landmarks numberOfParticles:(NSInteger)numberOfParticles worldWidth:(float)worldWidth worldHeight:(float)worldHeight {

    self = [super init];

    if (self) {

        _worldWidth = worldWidth;
        _worldHeight = worldHeight;

        _particles = [[NSMutableArray alloc] init];

        for (int i = 0; i < numberOfParticles; i++) {

            [_particles addObject:[[Particle alloc] initWithWorldWidth:worldWidth worldHeight:worldHeight]];
        }

        _landmarks = [NSArray arrayWithArray:landmarks];
    }

    return self;
}

-(void)setNoise:(double)forwardNoise turnNoise:(double)turnNoise senseNoise:(double)senseNoise {

    for (Particle *p in _particles) {

    [p setNoise:forwardNoise turnNoise:turnNoise senseNoise:senseNoise];
    }
}

-(void)moveForward:(double)forward withTurn:(double)turn {

    for (Particle *p in _particles) {

        [p moveForward:forward withTurn:turn];
    }
}


-(void)resample:(NSArray<NSNumber *>*)measurements {

    NSMutableArray<Particle *> *newParticles = [[NSMutableArray alloc] init];

    for (Particle *p in _particles) {

        [p measurementProb:measurements landmarks:_landmarks];
    }

    double B = 0;
    Particle *bestParticle = [self getBestParticle];

    NSInteger index = drand48() * _particles.count;

    for (int i = 0; i < _particles.count; i++) {

        B += drand48() * 2. * [bestParticle getProbability];

        while (B > [_particles[index] getProbability]) {

            B -= [_particles[index] getProbability];

            index = [self circle:index+1 :_particles.count];
        }

        [newParticles addObject:_particles[index]];
    }

    [_particles removeAllObjects];
    [_particles addObjectsFromArray:newParticles];
}

-(NSInteger)circle:(NSInteger) num :(NSInteger)length {

    while(num > length - 1)
        num -= length;
    while(num < 0)
        num += length;

    return num;
}

-(Particle *)getAverageParticle {

    Particle *p = [[Particle alloc] initWithWorldWidth:_worldWidth worldHeight:_worldHeight];

    double x = 0;
    double y = 0;
    double orient = 0;
    double prob = 0;

    for(int i=0; i<_particles.count; i++) {

        x += [_particles[i] getPosition].x;
        y += [_particles[i] getPosition].y;

        orient += [_particles[i] getOrientation];
        prob += [_particles[i] getProbability];
    }

    x /= _particles.count;
    y /= _particles.count;
    orient /= _particles.count;
    prob /= _particles.count;

    [p setPosition:[[MyPoint alloc] initWithX:x Y:y]
   orientation:orient
   probability:prob];

    [p setNoise:[_particles[0] getForwardNoise]
  turnNoise:[_particles[0] getTurnNoise]
 senseNoise:[_particles[0] getSenseNoise]];

    return p;
}

每个动作都是:

    [_robot moveForward:2. withTurn:0];
    [_particleFilter moveForward:2. withTurn:0];

     NSLog(@"%@",_particleFilter);
     NSLog(@"Mean %@",[_particleFilter getAverageParticle]);

     NSArray<NSNumber*> *measurements = [_robot sense:_landmarks];
    [_particleFilter resample:measurements];

     NSLog(@"%@",_particleFilter);
     NSLog(@"Mean %@",[_particleFilter getAverageParticle]);

     NSLog(@"Robot %@",_robot);
     NSLog(@"Estimated Robot %@",[_particleFilter getAverageParticle]);
     NSLog(@"Best Robot %@",[_particleFilter getBestParticle]);

这里涉及随机数的代码

#import "Utils.h"

@interface Utils ()

@property BOOL haveNextNextGaussian;
@property double nextNextGaussian;

@end

@implementation Utils

 + (instancetype) sharedInstance {
     static id sharedInstance = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         sharedInstance = [[super alloc] initInstance];
    });
     return sharedInstance;
}

-(instancetype)initInstance {

     self = [super init];

     if (self) {

    srand48(arc4random());
    }

     return self;
}


 +(double)distanceBetweenP1:(MyPoint *)p1 andP2:(MyPoint *)p2 {

     return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

 +(double)gaussian:(double)mu :(double)sigma :(double)x {

     return exp(-(pow(mu - x, 2.)) / pow(sigma, 2.) / 2.0) / sqrt(2.0 * M_PI * pow(sigma, 2.));
}


-(double)box_muller:(double)m :(double)s {

     if (_haveNextNextGaussian) {

        _haveNextNextGaussian = NO;

         return _nextNextGaussian;
    } else {
         double v1, v2, s;
         do {
             v1 = 2 * drand48() - 1;   // between -1.0 and 1.0
             v2 = 2 * drand48() - 1;   // between -1.0 and 1.0
             s = v1 * v1 + v2 * v2;
        }
         while (s >= 1 || s == 0);

         double multiplier = sqrt(-2 * log(s)/s);

        _nextNextGaussian = v2 * multiplier;
        _haveNextNextGaussian = YES;

         return v1 * multiplier;
    }
}


 +(double)circle:(double) num :(double)length {

     while(num > length - 1)
         num -= length;
     while(num < 0)
         num += length;

     return num;
}

@end

1 个答案:

答案 0 :(得分:1)

在OP发布任何代码之前,这个答案被发布为“如何找到x的问题”。

要查看代码,这可能不再相关,特别是因为OP断言已遵循下面列出的所有步骤。

这是一个模糊的答案,但这是一个模糊的问题......

我们不可能在此提供任何建议或指导,因为读者真正可以获得的唯一信息是您怀疑 问题在于随机数生成< / strong>即可。

这个你好吗?

作为读者回答这个问题,我们基本上比较了一个陌生人()在互联网上犯了错误 VS 的机会。一群ios开发人员犯了错误,并且没有注意到这个错误。不幸的是,我们必须对 你的错误 的错误下注。

编程人员的规则:在指责其他人的代码之前测试您的代码。如果你知道你要责备的人,那就再试一次。如果你要责怪的人每天都会看到你,那就试试第三次。如果你在与你应该责备的人的距离之内,再次测试它。

解决问题(AKA如何找到并修复你的小狗)

解决任何编码问题的第一步识别问题

不是一次又一次地随意查看代码中的错误( StackOverflow用户同意(c),你永远不会找到它):

  1. 创建一些单元测试以验证您的代码期望并确保您做得对。 如果你是,那么..
  2. 如果您测试过的代码单元都表现正常,请检查它们组合时的行为是否正确。创建检查操作链的测试。链越长,您将要测试的应用程序的端到端功能越多。 仍然无法正常工作?你可以考虑......
  3. 在应用程序运行时远程调试应用程序,以查看正在发生的情况。 无法进行远程调试工作?你这很难,但......
  4. 记录您应用中的一小组数据。创建测试以通过代码运行数据集。验证期望。 你仍然无法让它工作?然后尝试......
  5. 在StackOverflow上发布您的问题,并提供相关代码和数据集。
  6. 基本上 TEST,TEST,TEST

    如果您的应用正在积极开发中,那么每次测试都会为您节省时间(非常成熟且稳定的代码将受益更少)。