这个问题让我发疯,我实际上需要一些帮助。
我必须在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
也许这些照片可能会有所帮助
从这一步开始,粒子远离机器人
编辑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
答案 0 :(得分:1)
要查看代码,这可能不再相关,特别是因为OP断言已遵循下面列出的所有步骤。
我们不可能在此提供任何建议或指导,因为读者真正可以获得的唯一信息是您怀疑 问题在于随机数生成< / strong>即可。
作为读者回答这个问题,我们基本上比较了一个陌生人(你)在互联网上犯了错误 VS 的机会。一群ios开发人员犯了错误,并且没有注意到这个错误。不幸的是,我们必须对 你的错误 的错误下注。
编程人员的规则:在指责其他人的代码之前测试您的代码。如果你知道你要责备的人,那就再试一次。如果你要责怪的人每天都会看到你,那就试试第三次。如果你在与你应该责备的人的距离之内,再次测试它。
解决任何编码问题的第一步是识别问题。
不是一次又一次地随意查看代码中的错误( StackOverflow用户同意(c),你永远不会找到它):
基本上 TEST,TEST,TEST
如果您的应用正在积极开发中,那么每次测试都会为您节省时间(非常成熟且稳定的代码将受益更少)。