usar number generate figuras examples como and java algorithm math random processing

java - number - ¿Camina aleatoriamente alrededor de una ubicación central en un área limitada?



random int processing (4)

No estoy seguro si puedo expresar esta pregunta correctamente, pero aquí va ...

Quiero codificar un ejemplo, donde los puntos pequeños tienen una velocidad según la cual se mueven, pero también hay un movimiento aleatorio superpuesto al movimiento "apropiado". Usando el código de Processing continuación, obtengo la siguiente animación:

Se supone que el punto correcto va hacia la esquina inferior derecha, y estoy de acuerdo con cómo se comporta. El problema es el punto izquierdo, que se supone que es "estático", por lo que solo mostraría el movimiento "aleatorio" "en su lugar"; sin embargo, como muestra el archivo .gif animado, tiende a desviarse una cierta distancia de su ubicación original. La velocidad aleatoria se calcula con:

this.randspeed.set(random(0,1)-0.5, random(0,1)-0.5);

Hubiera supuesto que al random(0,1)-0.5 , 5 no me da una "distribución normal" parecida a Gauss centrada en (o convergente) en cero; pero, de nuevo, incluso si fuera un Gaussiano "adecuado", aún podría tener esa "suerte", por lo que, digamos, los valores positivos [0: 0.5) se devuelven durante todo un día, y luego los valores negativos [-0.5: 0] se devuelven al día siguiente, y al final, todavía sería un gaussiano adecuado.

Entonces, supongo que estoy buscando una manera de convertir una (pseudo?) Secuencia aleatoria (como la generada por random(0,1)-0.5 ) a una pseudo aleatoria, pero en la que la suma promedio de N muestras (digamos, 10) es 0. No estoy seguro de cómo llamar a esto - una secuencia aleatoria convergiendo periódicamente a cero, supongo?

Tenga en cuenta que he estado intentando a continuación con ambos cambios de position directamente; y position guardado con cambio de finalpos en finalpos lugar: cambiar la posición parece más un movimiento suavizado "natural" (especialmente con la operación de cuadro modulo, por lo que una nueva velocidad aleatoria no se asigna a cada cuadro); pero luego, también permite que el ruido aleatorio se acumule y "empuje" el punto lejos de su ubicación central. Además, tenga en cuenta que me tomó algunas tomas hasta que pude reproducir esto en .gif, ejecutar el programa "en vivo" parece hacer que el punto diverja de la ubicación original más rápidamente (había leído algo sobre eventos de hardware como hard- las escrituras en disco se usan para cambiar la entropía para /dev/random en Linux, pero realmente no sé si está relacionado).

Además, pensé en establecer una especie de borde virtual alrededor de la posición de punto, y tener una detección de colisión para el movimiento aleatorio saliendo del borde, pero eso me parece demasiado trabajo (y ciclos de CPU para operaciones vectoriales) para este tipo de cosas; Hubiera esperado que la función aleatoria de alguna manera pudiera ser "atemperada" de una manera más fácil, en su lugar.

Entonces, ¿habría una manera recomendada de acercarse a este tipo de movimiento aleatorio alrededor de una ubicación central en un área limitada?

marbles.pde :

import java.util.*; // added for Iterator; ArrayList<Marble> marbles = new ArrayList<Marble>(); Iterator<Marble> imarb; color mclr = #0000FF; int RNDLIMIT = 2; int framecount = 0; void setup() { size(600,400,P2D); Marble m_moving = new Marble(width/2, height/2, 2, 2); marbles.add(m_moving); Marble m_stopped = new Marble(width/2-100, height/2, 0, 0); marbles.add(m_stopped); } void draw() { background(255); strokeWeight(1); stroke(mclr); fill(mclr); imarb = marbles.iterator(); while (imarb.hasNext()) { Marble m = imarb.next(); m.update(); ellipse(m.finalpos.x, m.finalpos.y, m.radius*2, m.radius*2); } framecount++; //~ saveFrame("marbles-######.png"); } class Marble { PVector position = new PVector(0,0); PVector finalpos = new PVector(0,0); PVector speed = new PVector(0,0); PVector randspeed = new PVector(0,0); float radius=4; public Marble() { } public Marble(float inx, float iny, float invx, float invy) { this.position.set(inx, iny); this.speed.set(invx, invy); } public void update() { this.position.add(this.speed); if (framecount % 4 == 0) { this.randspeed.set(random(0,1)-0.5, random(0,1)-0.5); this.randspeed.setMag(RNDLIMIT); } int algoTry = 1; // 0 switch(algoTry) { case 0: this.finalpos.set(PVector.add(this.position, this.randspeed)); break; case 1: this.position.set(PVector.add(this.position, this.randspeed)); this.finalpos.set(this.position); break; } } }


Bueno, creo que llegué a algún lado; Gracias al comentario de @Teepeemm , aprendí sobre el proceso Ornstein - Uhlenbeck, y también sobre la moción browniana : " se describe en el proceso de Wiener ... uno de los procesos más conocidos de Lévy ". Releyendo Ornstein - Proceso de Uhlenbeck (" Con el tiempo, el proceso tiende a derivar hacia su significado a largo plazo ... es un prototipo de un proceso de relajación ruidoso ... la longitud x (t) de la primavera fluctuará estocásticamente alrededor de la primavera longitud de descanso x0; "), me di cuenta de que no era lo que quería, habría hecho que mi punto finalmente se asentara en la posición central, y entonces habría tenido que" hacer ping "de vez en cuando.

Justo cuando me di cuenta de que me llevaría mucho tiempo entender primero, y luego codificar, esos procesos, encontré esto:

Generación de ruido con PSD dado - Newsreader - MATLAB Central

Quiero generar datos de ruido con características de frecuencia específicas: Es decir, la densidad espectral de potencia (PSD) debe ser proporcional a f ^ 0, f, f ^ 2, etc.

f ^ 0 - use randn
f ^ (- 2) - filtro de paso bajo la serie temporal f ^ 0, o integrar con cumsum
f ^ 2 - diferenciar, como con diff

... así que pensé, tal vez de alguna manera puedo procesar los números aleatorios crudos, para obtener una "distribución" como quiera. Así que se me ocurrió un parche Processing, que encontrarás a continuación como rndquest2.pde . El procesamiento facilita el uso de colores alfa para los puntos, y si el fondo no se borra, se acumulan, por lo que es más fácil ver cuál es la distribución real de una salida aleatoria ajustada. Tengo esta imagen:

La "elección 0" parece indicar que random() genera una secuencia con distribución uniforme (ruido blanco). Por ejemplo, "elección 1" haría que el punto tienda a pegarse en los bordes; La "opción 2" obviamente muestra plegables; y yo preferiría un círculo, también. Al final, obtuve algo más parecido a un Gauss (más frecuente en el centro, y disminuyendo lentamente hasta los bordes) en la "opción 9", por algo así como un plegado radial, supongo. Todavía hay un límite de umbral visible en "opción 9", pero si se implementa en el código anterior en OP, entonces obtengo algo como esto:

... que es, en realidad, como yo lo quería! (no estoy seguro de por qué salió el inicio como lo hizo, sin embargo) El truco es que el vector aleatorio, una vez limitado / procesado, debe interpretarse como una posición (o más bien, se debe agregar a la posición, para obtener una nueva posición, usado para calcular una nueva velocidad para los finalpos ); ¡no se debe agregar directamente a la velocidad / velocidad!

Entonces, solo se deben agregar estos cambios en el código 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)); } ...

... para que funcione como se muestra en el gif en esta publicación.

Bueno, espero que esto ayude a alguien,
¡Aclamaciones!

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); // #0000FF web colors only 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"); // these help trigger the draw(), apparently.. 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 = abs(rv.x)-radius/2; //~ pr2 = abs(rv.y)-radius/2; pr1 = rv.mag()-radius/2; //~ pr3 = int(radius-abs(rv.x)); //~ pr4 = int(radius-abs(rv.y)); pr3 = int(radius-pr1); pr3 = (pr3 == 0) ? 1 : pr3; //~ pr4 = (pr4 == 0) ? 1 : pr4; if (pr1>0) r1 = rv.x - random(1)*2*signum(rv.x)*pr1; //framecount ; b2i(int(random(radius)) % pr3 == 0)* if (pr1>0) //(pr2>0) r2 = rv.y - random(1)*2*signum(rv.y)*pr1;//pr2; 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()); //pr1); pr3 = (pr3 == 0) ? 1 : pr3; if (pr1>0) { r1 = rv.x - random(1)*2*signum(rv.x)*pr3; //framecount ; b2i(int(random(radius)) % pr3 == 0)* r2 = rv.y - random(1)*2*signum(rv.y)*pr3;//pr2; //~ r1 = rv.x - 2*signum(rv.x)*pr3; //like an X for pr3 = int(radius-pr1); //~ r2 = rv.y - 2*signum(rv.y)*pr3; } rv.set(r1,r2); x1 = mainpos.x + rv.x; y1 = mainpos.y + rv.y; println("9"); break; } // note: patch does not draw point(mainpos.x + getRandom(), ..) point(x1, y1); fill(255); stroke(255); //~ stroke(255,0,0); 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; }


Estás simulando una caminata aleatoria. Generalmente, una caminata aleatoria después de n pasos estará en el orden de sqrt(n) desde donde comenzó (más específicamente, obedecerá la Ley del Logaritmo Iterado , de modo que su magnitud después de n pasos es O(sqrt(n log log n)) ). Lo cual es una manera larga de decir que la caminata se alejará con el tiempo (pero debido a que es bidimensional, eventualmente regresará al origen).

Para resolver esto, debes tener una deriva hacia el origen. Un proceso aleatorio que tiene esta propiedad es el proceso Ornstein - Uhlenbeck , que tiene una deriva hacia el origen que es proporcional a su distancia desde el origen. (Y la parte aleatoria de la caminata aleatoria todavía causaría que se mueva alrededor de su origen).

Esto podría lograrse en su código original por algo similar a

double driftScale = .01; double wiggleScale = 1; Point origin = new Point(0,0); ... this.randspeed.set(driftScale*(origin.x-this.position.x)+wiggleScale*(random(0,1)-.5), driftScale*(origin.y-this.position.y)+wiggleScale*(random(0,1)-.5));

Sería mejor reemplazar al random(0,1)-.5 con un Gauss estándar normal, pero no sé cuán notable sería ese efecto. La mayor diferencia es que con el código actual, hay una distancia máxima que el punto puede obtener desde su inicio. Con un gaussiano, teóricamente podría llegar arbitrariamente lejos (pero aún así regresaría al origen).

Tampoco estoy muy seguro de lo mucho que esto coincide con su solución final. Tengo problemas para seguir tu lógica (el uso de PVector y 10 casos no me ayudaron).


Si desea un movimiento aleatorio dentro de una cierta distancia de un punto "real", podría tratar de tener una distancia fija, máxima desde la ubicación "real", y no permitir que la pelota quede fuera de ese radio.

Si no desea un límite estricto, puede agregar algún tipo de fuerza que atraiga al objeto hacia su ubicación "real" y hacerlo aumentar linealmente, cuadráticamente o mediante alguna otra función de su elección con la distancia desde ese punto. . Entonces el objeto sería libre de moverse alrededor de su ubicación "real", pero se mantendría relativamente cerca.


Una típica "caminata aleatoria" siempre se desviará, porque las estadísticas no "equilibran". Muévete mucho hacia la izquierda no se corregirá con movimiento hacia la derecha. Entonces la calidad de la aleatoriedad no es el problema.

Si desea que el punto permanezca en una ubicación específica, debe almacenar esa ubicación y realizar el movimiento "adecuado" (como lo llamó) siempre moverse hacia esa ubicación. Algunas restas de la ubicación actual de la ubicación del objetivo deben obtener el movimiento correcto "correcto". Con esta solución, el punto siempre estará inclinado a volver al lugar donde se inició.