我觉得我有所进展,多亏了@Teepeemm的评论,我学到了奥恩斯坦-乌伦贝克过程,以及布朗运动:““由维纳过程描述……是最著名的Lévy过程之一”。
重新阅读奥恩斯坦-乌伦贝克过程(“随着时间的推移,该过程趋向于漂移到其长期平均值……是嘈杂松弛过程的原型……弹簧的长度x(t)将随机地在弹簧静止长度x0周围波动”),我意识到这不是我想要的——它最终会导致我的点定居在中心位置,然后我不得不每隔一段时间就“ping”它。
正如我意识到要理解并编写这些过程需要很长时间一样,我发现了这个:
Generation of noise with given PSD - Newsreader - MATLAB Central
我想生成具有特定频率特性的噪声数据:即功率谱密度(PSD)必须与f ^ 0、f、f ^ 2等成比例。
f ^ 0--使用randn
f ^(-2)--低通滤波f ^ 0时间序列,或与cumsum集成
f ^ 2--差分,如diff
……所以我想,也许我可以以某种方式处理原始随机数字,以获得我想要的“分布”。于是我想出了一个Processing补丁程序,您将在下面找到它作为rndquest2.pde
。 Processing使使用alpha颜色对点易如反掌,如果不擦除背景,它们会累积-因此更容易看到随机输出被调整的实际分布。 我得到了这张图片:
![rndquest2.pde.png](https://istack.dev59.com/HDH44.webp)
“选择0”似乎表明
random()
生成具有均匀分布(白噪声)的序列。例如,“选择1”会导致点倾向于停留在边缘;“选择2”明显显示折叠;我也更喜欢圆形。最后,通过类似于径向折叠的方式,在“选择9”上得到了最接近高斯分布(在中心最频繁,逐渐减少到边缘)的东西。在“选择9”上仍然有一个可见的阈值边界,但如果在OP上面的代码中实现它,那么我会得到像这样的东西:
![marbles2.gif](https://istack.dev59.com/T2maE.gif)
...这正是我想要的!(虽然不确定为什么起始状态会出现这样的情况)。关键在于,一旦限制/处理随机向量,它应该被解释为一个
位置(或者说,应该添加到位置上,以获得一个新位置,用于计算
finalpos
的新速度);它不应该直接添加到速度/方向上!
因此,只需要在OP代码中添加这些更改:
...
float r1 =0, r2 = 0;
PVector rv = new PVector(r1, r2);
float radius = 10;
float pr1 =0; int pr3 =0;
...
int signum(float f) {
if (f > 0) return 1;
if (f < 0) return -1;
return 0;
}
float getRandom() {
float ret;
ret = random(-radius,radius);
return ret;
}
void getRandomVect() {
r1 = getRandom();
r2 = getRandom();
rv.set(r1,r2);
while(rv.mag() > radius) {
r1 = getRandom();
r2 = getRandom();
rv.set(r1,r2);
}
pr1 = rv.mag()-radius/2;
pr3 = int(radius-rv.mag());
pr3 = (pr3 == 0) ? 1 : pr3;
if (pr1>0) {
r1 = rv.x - random(1)*2*signum(rv.x)*pr3;
r2 = rv.y - random(1)*2*signum(rv.y)*pr3;
}
rv.set(r1,r2);
}
...
public void update() {
this.position.add(this.speed);
if (framecount % 4 == 0) {
getRandomVect();
this.randspeed.set(PVector.div(PVector.sub(PVector.add(this.position, rv), this.finalpos), 4));
}
this.finalpos.set(PVector.add(this.finalpos, this.randspeed));
}
...
...以便像这篇帖子中的gif所示那样使其正常工作。
希望这可以帮助到某些人,
干杯!
rndquest2.pde
PVector mainpos = new PVector(200.0, 200.0);
float radius = 50;
float x1 =0, y1 = 0;
float r1 =0, r2 = 0;
float pr1 =0, pr2 = 0;
int pr3 =0, pr4 = 0;
PVector rv = new PVector(r1, r2);
color clr = color(0,0,255,30);
int choice = 0;
int framecount = 0;
void setup() {
size(600,400,P2D);
background(255);
textSize(14);
textAlign(LEFT, TOP);
}
void draw() {
try {
strokeWeight(2);
stroke(clr);
fill(clr);
point(mainpos.x, mainpos.y);
r1 = getRandom();
r2 = getRandom();
switch(choice) {
case 0:
x1 = mainpos.x + r1;
y1 = mainpos.y + r2;
println("0");
break;
case 1:
rv.set(r1,r2);
if(rv.mag() > radius) {
rv.setMag(radius);
}
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("1");
break;
case 2:
rv.set(r1,r2);
if(rv.mag() > radius) {
rv.sub(PVector.mult(rv,0.1*(rv.mag()-radius)));
}
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("2");
break;
case 3:
rv.set(r1,r2);
while(rv.mag() > radius) {
r1 = getRandom();
r2 = getRandom();
rv.set(r1,r2);
}
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("3");
break;
case 4:
pr1 = rv.x;
pr2 = rv.y;
rv.set(r1-pr1,r2-pr2);
while(rv.mag() > radius) {
r1 = getRandom();
r2 = getRandom();
rv.set(r1-pr1,r2-pr2);
}
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("4");
break;
case 5:
pr1 = rv.x;
pr2 = rv.y;
rv.set(r1-pr1,r2-pr2);
if(rv.mag() > radius) {
rv.mult(1.0/(rv.mag()-radius));
}
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("5");
break;
case 6:
pr1 = (pr1 + r1)/2.0;
pr2 = (pr2 + r2)/2.0;
rv.set(pr1,pr2);
if(rv.mag() > radius) {
rv.mult(1.0/(rv.mag()-radius));
}
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("6");
break;
case 7:
r1 = (pr1 + r1)/2.0;
r2 = (pr2 + r2)/2.0;
rv.set(r1,r2);
while(rv.mag() > radius) {
r1 = getRandom();
r2 = getRandom();
r1 = (pr1 + r1)/2.0;
r2 = (pr2 + r2)/2.0;
rv.set(r1,r2);
}
pr1 = rv.x;
pr2 = rv.y;
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("7");
break;
case 8:
rv.set(r1,r2);
while(rv.mag() > radius) {
r1 = getRandom();
r2 = getRandom();
rv.set(r1,r2);
}
pr1 = rv.mag()-radius/2;
pr3 = int(radius-pr1);
pr3 = (pr3 == 0) ? 1 : pr3;
if (pr1>0)
r1 = rv.x - random(1)*2*signum(rv.x)*pr1;
if (pr1>0)
r2 = rv.y - random(1)*2*signum(rv.y)*pr1;
rv.set(r1,r2);
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("8");
break;
case 9:
rv.set(r1,r2);
while(rv.mag() > radius) {
r1 = getRandom();
r2 = getRandom();
rv.set(r1,r2);
}
pr1 = rv.mag()-radius/2;
pr3 = int(radius-rv.mag());
pr3 = (pr3 == 0) ? 1 : pr3;
if (pr1>0) {
r1 = rv.x - random(1)*2*signum(rv.x)*pr3;
r2 = rv.y - random(1)*2*signum(rv.y)*pr3;
}
rv.set(r1,r2);
x1 = mainpos.x + rv.x;
y1 = mainpos.y + rv.y;
println("9");
break;
}
point(x1, y1);
fill(255);
stroke(255);
rect(mainpos.x-radius,100,mainpos.x-radius+100,20);
fill(0,0,255);
stroke(clr);
text(String.format("choice %d (f:%d)", choice, framecount), mainpos.x-radius, 100);
framecount++;
if (framecount % 5000 == 0) {
saveFrame(String.format("rndquest2-%d-%d-######.png", choice, framecount));
}
} catch(Exception e) {
e.printStackTrace();
}
}
int signum(float f) {
if (f > 0) return 1;
if (f < 0) return -1;
return 0;
}
int b2i(boolean inb) {
if (inb) return 1;
else return 0;
}
float getRandom() {
float ret;
ret = random(-radius,radius);
return ret;
}
void mousePressed() {
choice = (choice + 1) % 10;
background(255);
framecount = 0;
}
RNDLIMIT
的大小。这种缩放会破坏任何纯粹基于随机数生成本身(而不是实际位置)的东西:即使4个随机步骤的总和为0,结果(总和)位置也取决于步骤是否为-0.1,-0.1,-0.1,+0.3或-0.2,+0.2,-0.2,+0.2。 - Marco13RNDLIMIT
现在已经消失了...并且修改随机序列分布似乎也起作用了(虽然没有进行广泛测试)。干杯! - sdaau