Mathématice, intégration des Tice dans l'enseignement des mathématiques  
Sommaire > N°56 - septembre 2017 > La géométrie de la tortue réaliste

La géométrie de la tortue réaliste
Danse de Saint Guy et tortue gaussienne
Moteur de recherche
Mis en ligne le 13 juin 2017, par Alain Busser, Patrice Debrabant

Lorsqu’on demande à un sphero de parcourir un carré en avançant d’1 mètre et tournant de 90°, ceci 4 fois de suite, la sphère n’est, à l’issue de cette tâche, pas de retour exactement à son point de départ, comme le révèle l’observation attentive de cette vidéo. Le parcours ressemble plutôt à ceci :

L’objet de cet article est de chercher la répartition statistique de la position finale de la tortue réaliste, et notamment celle des distances de "ratage de la cible".

Cet article est placé sous licence CC-by-SA : N’hésitez pas à y puiser des ressources !

On va explorer des modélisations de difficulté croissante :

  1. D’abord la tortue avancera tout droit mais par pas aléatoires : La distance totale suit une loi normale d’après le théorème central-limite.
  2. Puis la tortue effectuera des rotations de 90° pour parcourir un "carré gaussien" : C’est l’occasion d’introduire les vecteurs gaussiens et la matrice de covariance.
  3. Ensuite la tortue ne fera que des erreurs angulaires sans erreurs de distance ; on verra que la situation est plus complexe et dépendra de l’amplitude des erreurs angulaires.
  4. Ensuite les erreurs seront distribuées sur les petits pas de la tortue et elle n’ira donc plus tout-à-fait tout droit. La distribution des distances parcourues et des angles surprend un peu...
  5. Enfin on géénralisera au cas où les erreurs portent à la fois sur les distances et les angles ; on ira aussi un peu vers d’autres dimensions ou d’autres géométries...

C’est comment qu’on freine fait ?

D’où vient le hasard dont est victime un robot réel ? De micro-mouvements (aspérités du sol, glissements asymétriques des deux roues, imprécision des moteurs pas-à-pas, etc) statistiquement indépendants entre eux. Voici une expérience montrant cela : Les deux scripts suivants ont le même effet [1] :

Maintenant, on modifie légèrement la seconde version, en entachant

  • d’une erreur d’un pixel, chaque avancée de 10 pixels ;
  • d’une rotation aléatoire, d’un degré maximum, chaque avancée de 10 pixels.

Pour ce faire, on crée une variable aléatoire "e" uniforme entre -1 et 1 [2], et une instruction "avance" qui simule l’avancée de 100 pixels avec accumulation de petites erreurs de parcours :

Avec ces fonctions, le dessin du carré "réaliste" qui ouvre cet article a été fait avec ce script :

Remarque : On peut aller plus loin, par exemple cette version de "avance" (sous-entendu, de 100 pixels) :

donne aussi un carré très réaliste [3] :

Mise en place des outils

Dans cet article, on va s’attacher aux densités de probabilité, que l’on déterminera (ou confirmera) de façon statistique, en les approchant par des densités de fréquences.

En fait, à chaque pas de la tortue, il y a deux sortes d’erreurs possibles :

  1. les erreurs de distance (la tortue n’avance pas exactement de la distance voulue) ;
  2. les erreurs d’angle (la tortue n’avance pas tout droit, et ne tourne pas exactement de l’angle voulu).

On va voir que statistiquement, ces deux types d’erreur n’ont pas le même effet. On va donc commencer par regarder des cas où un seul type d’erreur est présent. Le cas le plus simple étant celui où il n’y a pas d’erreurs angulaires.

Covariance

Pour calculer la variance Vx des abscisses, on additionne les carrés des abscisses (une fois centrées) et on divise par le nombre de pas. De même, pour calculer la variance Vy des ordonnées, on élève celles-ci (après centrage) au carré. En effectuant le produit des abscisses centrées par les ordonnées centrées, la moyenne de ces produits est une sorte de variance qui n’est ni celle des x, ni celle des y, elle est un peu métissée des deux. On l’appelle covariance des abscisses et des ordonnées et on la note Cxy.

  • Les variances Vx et Vy ne sont pas nécessairement égales. Si elles le sont, le nuage de points a une forme arrondie. Sinon le nuage est une ellipse plus ou moins allongée selon que le rapport des variances est éloigné ou proche de 1 [4].
  • Si la covariance est nulle, l’ellipse a pour axes, les axes de coordonnées. Sinon l’ellipse est tournée.
  • Si l’ellipse est très allongée, on évoque la notion de droite de régression. Celle-ci est hors sujet parce qu’on verra que même lorsque le nuage de points est allongé, il ne l’est pas tant que ça.
  • Si la tortue est un drone évoluant dans l’espace de dimension 3, la matrice de covariance est 3×3 et le nuage de points est approché par un ellipsoïde (une sphère si les trois variances sont égales et les covariances nulles)

Il est d’usage de représenter un nuage de points (ou de vecteurs) gaussien par la matrice de covariance, égale à $\begin{pmatrix}V_x & C_{xy} \\ C_{xy} & V_y\end{pmatrix}$. Cette matrice est utile parce que si les déplacements de la tortue sont indépendants entre eux, la matrice de covariance de la position finale est la somme des matrices de covariance des pas de la tortue. Si le nuage de points ne correspond pas à la matrice de covariance calculée, il y a conflit entre le modèle probabiliste et le modèle statistique et ce conflit est indicateur d’une dépendance entre les pas de la tortue. En particulier, on va voir (sur le nuage de points) que les erreurs de rotation introduisent ce genre de dépendance. Pour en savoir plus, voir cet article compagnon.

I/ La tortue va tout droit mais d’une distance aléatoire

Cet algorithme permet de facilement simuler une variable aléatoire normale d’espérance 6 et de variance 1 :

Ce fichier d’exemple fourni avec Sofus, permet de dessiner l’histogramme, qui montre l’allure de la courbe en cloche obtenue. Comme alea est uniforme entre 0 et 1, chaque pas de la tortue a pour espérance 1/2 et pour variance 1/12. Donc la somme (approximativement gaussienne) a pour espérance 12/2=6 et pour variance 12/12=1.

Un peu plus de dynamisme

L’histogramme tend vers une courbe (de densité de probabilité), que l’on peut tracer.
On peut utiliser DGPad pour construire une courbe dynamique par rapport à différents paramètres :

  • nombre de variables aléatoires uniformes que l’on ajoute (= nombre de fois)
  • écart
  • nombre d’essais (paramètre statistique)

La courbe verte représente la densité de fréquence, la courbe rouge la densité de probabilité attendue.

Ouvrir la figure dynamique dans une autre fenêtre

Remarque : on peut remarquer que l’ultra-dynamisme de DGPad (il recalcule et reconstruit tout à chaque variation) rend, paradoxalement, la figure peu réactive (c’est rarissime avec DGPad, le contexte est très particulier). Avec d’autres logiciels, les problèmes seraient d’un autre ordre (voir plus loin une version CaRMetal).

La courbe rouge représente la loi normale d’espérance 0 et de variance $p.e^2/12$
p est le nombre de variables aléatoires
e est l’écart
n est le nombre d’essais

Chaque courbe a été tracée à l’aide d’une liste de points.

Voici le code de la liste pour la gaussienne (en rouge) :

  1. S=[];
  2. for (j=0;j<100;j++){
  3. u=j/100*e*p-e*p/2;
  4. theV=e*e/12*p;
  5. S.push([u,Math.exp(-u*u/(2*theV))/Math.sqrt(2*Math.PI*theV)]);
  6. };
  7. S

Télécharger

et celui pour la courbe en vert (obtenue statistiquement) :

  1. function pas(){
  2. return ((Math.random()*2-1)*GetExpressionValue("e")/2);
  3. }
  4. function initA(){
  5. for (i=0;i<101;i++) {
  6. A[i]=0;
  7. }
  8. }
  9. A=[];
  10. S=[];
  11. initA();
  12. for (k=0;k<n;k++) {
  13. resI=0;
  14. for (j=0;j<p;j++){
  15. resI += pas();
  16. }
  17. indiceX=Math.round(100*resI/(e*p))+50;
  18. A[indiceX]+=1/n;
  19. }
  20. for (j=0;j<100;j++){
  21. S.push([j/100*e*p-e*p/2,A[j]/p/e*100]);
  22. };
  23. S

Télécharger

Si on avait tracé un histogramme, il y aurait 100 rectangles.
On notera le recours à GetExpressionValue dans la fonction pas() car le nommage DGPad direct des expressions ne fonctionne pas dans une fonction javascript.


II/Distances aléatoires et angles droits

Maintenant qu’on a vu pourquoi, si les pas sont aléatoires, la distance parcourue est normale, on va voir à quoi ressemble un carré dont les angles sont parfaitement droits mais les côtés ont de telles longueurs gaussiennes :

Présentation de la situation

La figure dynamique suivante va permettre de tester les variations de position finale de la tortue faisant un carré de côté 10 dans le cas simple où les angles sont parfaits et où le déplacement (Avancer de 10) suit une loi uniforme d’écart e.

Ouvrir la figure dynamique dans une autre fenêtre

La surface en vert représente la surface de probabilité obtenue statistiquement. La surface en rouge représente la surface de probabilité d’une loi gaussienne de variance dont la matrice de covariance est $\begin{pmatrix} theV & 0 \\ 0 & theV \end{pmatrix}$ où theV, variance commune des abscisses et des ordonnées, est un paramètre dynamique.
p représente le nombre de tours.
n représente le nombre d’essais.

On doit clairement obtenir une coïncidence des deux surfaces quand $theV = p.e^2/12*2=p.e^2/6$

Un outil important est le théorème central limite vectoriel : La somme de vecteurs aléatoires indépendants entre eux tend vers un vecteur gaussien. Or si les rotations de la tortue sont infiniment précises, son trajet est une succession de translations entachées d’alea, et sa position est la somme des vecteurs de ces translations. Si les vecteurs sont aléatoires et indépendants entre eux, la position est gaussienne !

Preuve de la valeur de la variance

En effet, comme le premier côté a été tracé parallèlement à l’axe des abscisses, la variance des ordonnées est nulle après le tracé de ce côté. La matrice de covariance est alors égale à $\begin{pmatrix} p\frac{e^2}{12} & 0 \\ 0 & 0\end{pmatrix}$. Pour le tracé du second côté, la matrice de covariance n’est plus la même, mais celle qu’on obtient par rotation de 90°, c’est-à-dire par conjugaison de cette matrice, par celle d’une rotation de 90°. En fait c’est la variance des x qui est nulle puisque la tortue avance parallèlement à l’axe des ordonnées, et la matrice de covariance du second côté est $\begin{pmatrix} 0 & 0 \\ 0 & p\frac{e^2}{12} \end{pmatrix}$. Si les tracés des deux côtés sont indépendants l’un de l’autre, les matrices de covariance s’additionnent simplement et la matrice de covariance de la position de la tortue après le tracé des deux premiers côtés est donc $\begin{pmatrix} p\frac{e^2}{12} & 0 \\ 0 & 0\end{pmatrix} + \begin{pmatrix} 0 & 0 \\ 0 & p\frac{e^2}{12} \end{pmatrix} = \begin{pmatrix} p\frac{e^2}{12} & 0 \\ 0 & p\frac{e^2}{12} \end{pmatrix}$ : À ce stade, l’abscisse et l’ordonnée de la position de la tortue ont même variance, ce qui n’est pas surprenant. Mais si le tracé de la seconde moitié du carré est indépendant du tracé de la première moitié, la matrice de covariance du tracé des 3e et 4e côté étant évidemment la même que celle du tracé des deux premiers côtés, la matrice de covariance finale est donc $\begin{pmatrix} p\frac{e^2}{12} & 0 \\ 0 & p\frac{e^2}{12} \end{pmatrix} + \begin{pmatrix} p\frac{e^2}{12} & 0 \\ 0 & p\frac{e^2}{12} \end{pmatrix} = \begin{pmatrix} p\frac{e^2}{6} & 0 \\ 0 & p\frac{e^2}{6} \end{pmatrix}$ c.q.f.d.

Comme les variances de x et de y sont égales entre elles (on a un beau nuage gaussien bien rond), la loi de la distance de ratage de la cible est une loi de Rayleigh de paramètre $e\sqrt{\frac{p}{6}}$. La distance la plus souvent atteinte est le mode de cette loi, soit son paramètre $e\sqrt{\frac{p}{6}}$. Et la distance de ratage moyenne est l’espérance de cette loi, soit $e\sqrt{\frac{p\pi}{12}}$. Qui l’eût cru ?

Code de la liste donnant la surface verte

  1. function pas(){
  2. return ((Math.random()*2-1)*GetExpressionValue("e")/2);
  3. }
  4. function initA(){
  5. for (i=0;i<201;i++) {
  6. A[i]=[];
  7. for (j=0;j<201;j++) {
  8. A[i][j]=0;
  9. }
  10. }
  11. }
  12. A=[];
  13. S=[];
  14. teta=0;
  15. de=10;
  16. initA();
  17. for (l=0;l<n;l++) {
  18. arriveeX=0;
  19. arriveeY=0;
  20. de=10+pas();
  21. for (j=0;j<p;j++){
  22. arriveeY+=de*Math.cos(teta);
  23. arriveeX+=de*Math.sin(teta);
  24. de=10+pas();
  25. arriveeY+=-de*Math.sin(teta);
  26. arriveeX+=de*Math.cos(teta);
  27. de=10+pas();
  28. arriveeY+=-de*Math.cos(teta);
  29. arriveeX+=-de*Math.sin(teta);
  30. de=10+pas();
  31. arriveeY+=de*Math.sin(teta);
  32. arriveeX+=-de*Math.cos(teta);
  33. de=10+pas();
  34. }
  35. indiceX=Math.round(arriveeX*10/(p*e)+10);
  36. indiceY=Math.round(arriveeY*10/(p*e)+10);
  37. if (indiceX<21&&indiceY<21&&indiceX>-1&&indiceY>-1) {
  38. A[indiceX][indiceY]+=1/n;
  39. }
  40. }
  41. for (i=0;i<20;i++){
  42. for (j=0;j<20;j++){
  43. if (100/(p*p*e*e)*A[i][j]>0.01) {
  44. S.push([(i-10)*p*e/10,(j-10)*p*e/10,100/(p*p*e*e)*A[i][j]]);
  45. }
  46. }
  47. S.push([NaN,NaN,NaN]);
  48. };
  49. S

Télécharger

Code de la liste donnant la surface gaussienne

  1. S=[];
  2. for (i=0;i<20;i++){
  3. for (j=0;j<20;j++){
  4. q=(i-10)*p*e/10;
  5. r=(j-10)*p*e/10;
  6. if (Math.exp(-(q*q+r*r)/(2*theV))/(2*Math.PI*theV)>0.01) {
  7. S.push([q,r,Math.exp(-(q*q+r*r)/(2*theV))/(2*Math.PI*theV)]);
  8. }
  9. }
  10. S.push([NaN,NaN,NaN]);
  11. };
  12. S

Télécharger

Le déplacement de 10 n’a pas d’influence ici. On pourrait prendre 200, voire 0, on obtiendrait le même résultat.

Programmation avec CaRMetal

On construit la surface de probabilité sur [-10,10] × [-10,10] avec un pas de 0,1.

La surface en noir est obtenue statistiquement.
La surface en rouge correspond à la gaussienne théorique.
Le tracé est plus long, mais la précision du quadrillage est plus grande.
d est un paramètre d’agrandissement pour l’affichage sur l’axe des z.


La coïncidence est parfaite. Ce premier sombrero est la densité d'un vecteur gaussien

CaRScript

fonction pas(){
        return ((Math.random()*2-1)/2);
}

fonction affinerU(){
        var arriveeX=0;
        var arriveeY=0;
        var indiceX;
        var indiceY;
        teta=0;
        teta+=pas()*b;
        d=10+pas()*a;
        pour var k allant de 1 à nbTours {
                arriveeY+=d*Math.cos(teta);
                arriveeX+=d*Math.sin(teta);
                teta+=pas()*b;
                d=10+pas()*a;
               
                arriveeY+=-d*Math.sin(teta);
                arriveeX+=d*Math.cos(teta);
                teta+=pas()*b;
                d=10+pas()*a;       
                arriveeY+=-d*Math.cos(teta);
                arriveeX+=-d*Math.sin(teta);
                teta+=pas()*b;
                d=10+pas()*a;
               
                arriveeY+=d*Math.sin(teta);
                arriveeX+=-d*Math.cos(teta);
                teta+=pas()*b;
                d=10+pas()*a;
        }
       
        indiceX=Math.round(arriveeX*10+100);
        indiceY=Math.round(arriveeY*10+100);
        si (indiceX<201&&indiceY<201&&indiceX>-1&&indiceY>-1) {
                U[indiceX][indiceY]=U[indiceX][indiceY]+1/nPoints;
        }
}
fonction afficherU(){
        pour i allant de 1 à 200 {
                pour j allant de 1 à 200 {
                        si (U[i][j]>0.000001) {
                                Point3D((i-100)/10,(j-100)/10,"d*"+U[i][j]);
                        }
                        //Afficherligne(V[i][j]);
                        si (Math.exp(-(((i-100)/10)*((i-100)/10)+((j-100)/10)*((j-100)/10)))>0.000000001) {
                                SetColor(Point3D((i-100)/10,(j-100)/10,V[i][j]),"red");
                        }
                }
        }
}

// --------------------------

nPoints=10000000;
a=GetExpressionValue("deltaD");
b=GetExpressionValue("deltaA");  //deltaAngle
nbTours=GetExpressionValue("nbT");
U=[];
V=[];
SetExpressionValue("c",nbTours/6*(a*a+100*b*b));

pour i allant de 0 à 200 {
        U[i]=[];V[i]=[];
        pour j allant de 0 à 200 {
                U[i][j]=0;
                V[i][j]="exp(-(("+((i-100)/10)+")^2+("+((j-100)/10)+")^2)/(2*c))/(2*pi*c)*d*0.01";
        }
}

pour r allant de 0 à nPoints {
        affinerU();
}
afficherU();
CarMetal - 5.1 ko

III/Carré à angles presque droits

Lorsque les erreurs aléatoires ne s’accumulent que sur les longueurs, on voit à la fin du tracé du carré, un nuage gaussien. C’est le moment d’explorer la situation inverse, où les distances parcourures ne sont entachées d’aucune erreur mais où les angles ne sont pas tout-à-fait droits.

Présentation de la situation

Cette fois-ci, c’est l’angle qui suit une loi uniforme d’écart e.
d est la distance de dépassement à chaque étape (fixe).

Ouvrir la figure dynamique dans une autre fenêtre

Le problème est nettement plus compliqué. L’angle d’orientation est une troisième composante de la matrice de covariance et les variations d’angle se cumulent.
Pour le premier tour, la variance $V_x$ est égale à :

$V_x=\dfrac{1}{e^4}.\iiiint_{-e/2}^{e/2} d^2(cos(x)-sin(x+y)-cos(x+y+z)+sin(x+y+z+t))^2 dx.dy.dz.dt$

Pour une petite variation d’angle

Quand e est petit, on a :

$V_x\approx\dfrac{1}{e^2}.\iint_{-e/2}^{e/2} d^2(-(x+y)+(x+y+z+t))^2 dz.dt \approx \dfrac{1}{e^2}.\iint_{-e/2}^{e/2} d^2.(z+t)^2 dz.dt\approx\dfrac{d^2.e^2}{6}$

Et si on imagine que les tours sont des variables aléatoires indépendantes (ce qui n’est pas le cas !) alors :

$V_x\approx p.(d.e)^2/6$

Et on obtient le même résultat pour $V_y$

Dans la suite, on va regarder déjà dans quel domaine il convient d’intégrer : Il s’agit d’un espace de configuration, qu’une tortue munie de poinçons peut dessiner si on lui fait répéter souvent le même parcours, les erreurs étant indépendantes d’une répétition à la suivante.

Code de la liste pour la surface verte

  1. function pas(){
  2. return ((Math.random()*2-1)*GetExpressionValue("e")/2);
  3. }
  4. function initA(){
  5. for (i=0;i<201;i++) {
  6. A[i]=[];
  7. for (j=0;j<201;j++) {
  8. A[i][j]=0;
  9. }
  10. }
  11. }
  12. A=[];
  13. S=[];
  14. teta=0;
  15. initA();
  16. SetExpressionValue("theV",p*d*d*e*e/6);
  17. for (l=0;l<n;l++) {
  18. arriveeX=0;
  19. arriveeY=0;
  20. teta=0;
  21. teta+=pas();
  22. for (j=0;j<p;j++){
  23. arriveeY+=d*Math.cos(teta);
  24. arriveeX+=d*Math.sin(teta);
  25. teta+=pas();
  26. arriveeY+=-d*Math.sin(teta);
  27. arriveeX+=d*Math.cos(teta);
  28. teta+=pas();
  29. arriveeY+=-d*Math.cos(teta);
  30. arriveeX+=-d*Math.sin(teta);
  31. teta+=pas();
  32. arriveeY+=d*Math.sin(teta);
  33. arriveeX+=-d*Math.cos(teta);
  34. teta+=pas();
  35. }
  36. indiceX=Math.round(arriveeX*10/(p*e*d)+10);
  37. indiceY=Math.round(arriveeY*10/(p*e*d)+10);
  38. if (indiceX<21&&indiceY<21&&indiceX>-1&&indiceY>-1) {
  39. A[indiceX][indiceY]+=1/n;
  40. }
  41. }
  42. for (i=0;i<20;i++){
  43. for (j=0;j<20;j++){
  44. if (100/(p*p*e*e*d*d)*A[i][j]>0.01) {
  45. S.push([(i-10)*p*e*d/10,(j-10)*p*e*d/10,100/(p*p*e*e*d*d)*A[i][j]]);
  46. }
  47. }
  48. S.push([NaN,NaN,NaN]);
  49. };
  50. S

Télécharger

Code de la liste pour la surface rouge (inchangé)

  1. S=[];
  2. for (i=0;i<20;i++){
  3. for (j=0;j<20;j++){
  4. q=(i-10)*p*e*d/10;
  5. r=(j-10)*p*e*d/10;
  6. if (Math.exp(-(q*q+r*r)/(2*theV))/(2*Math.PI*theV)>0.01) {
  7. S.push([q,r,Math.exp(-(q*q+r*r)/(2*theV))/(2*Math.PI*theV)]);
  8. }
  9. }
  10. S.push([NaN,NaN,NaN]);
  11. };
  12. S

Télécharger

pour une variation d’angle importante

Programmation avec CaRMetal


Ce second sombrero est-il encore gaussien ?

Tout ce qui brille n’est pas or. Voici une vue de dessus :

Ce n’est pas un sombrero, c’est le bicorne qu’aurait porté Napoléon. S’il était mexicain. Caramba !

Bonaparte franchissant le Grand-Saint-Bernard par David (détail)

Statistiquement, la distribution ne semble plus tout à fait normale, et elle est plus dispersée que la distribution théorique (écarts-types plus grands). Cela semble logique car les variables aléatoires ne sont pas indépendantes, ce qui a tendance à augmenter la variance (les premières variations d’angles se répercutent sur tous les tours).


On va donc tenter une généralisation bidimensionelle de l’arithmétique d’intervalles sur le cas angulaire.

Lieux de points

Dans le cas d’un carré à côtés tous égaux mais à angles pas exactement droits, la première rotation de 90° se faisant uniformément entre 90-h et 90+h, et la distance parcourue ensuite étant supposée précise, le nuage de points après ce parcours est un arc de cercle :

Au bout d’une nouvelle rotation d’un angle compris entre 90-h et 90+h, suivie d’un parcours de longueur constante, la position de la tortue sera dans la transformée de l’arc de cercle par la transformation qui donne un arc de cercle (!) ; il est clair que ce domaine est un quadrilatère à bords circulaires :

Version DGPad du bras articulé :

Et au bout de la troisième étape (rotation uniforme et déplacement) le nuage de points a une forme hexagonale :

On retrouve expérimentalement la constatation faite sur le cas mixte (erreurs de distance et d’angle, cumulées) : Nuage de points allongé (variances de x et y différentes entre elles) et tourné (covariance non nulle entre x et y). En fait, on n’étudie plus le même problème, en effet on peut considérer chaque trajet possible de la tortue comme une position possible d’un bras de robot [5], articulé aux sommets du carré. Dans les copies d’écran ci-dessus, l’épaule est à (100,0), le coude à (100,100) (en position de repos, le poignet à (0,100) et le nuage de points final est l’ensemble des positions que peut atteindre la main du robot. Le segment de longueur fixe de CaRMetal est un bon outil pour modéliser ce genre d’articulation (on peut attacher un segment de longueur fixe au bout d’un autre segment de longueur f

Pour étudier plus précisément les distributions statistiques lors des mouvements étudiés précédemment, on peut adapter le script CaRMetal que l’on a utilisé pour tracer les sombreros :
L’unité correspond à une centaine de pixels.
La variation d’angle (en radians) est 0,6.
On passe à un modèle statistique : on ne représente que la partie "significative" du nuage.

En fait, regarder la position de la tortue comme un point de coordonnées (x,y) est une modélisation insuffisante puisque la position suivante dépend non seulement de la position actuelle, mais aussi de l’orientation actuelle : L’espace où évolue la tortue est donc de dimension 3. Les nuages de points vus ci-dessus sont donc les projetés de surfaces de l’espace, sur le plan de la tortue. On va commencer par une vue de dessus du nuage et observer sa forme. Celle-ci tend-elle vers un disque correctement centré ? Cliquer sur l’image pour se faire une idée.

GIF

Et si l’on s’intéresse aux tours complets, il semble que l’on tend vers une loi gaullienne, comme on le distingue sur les vues de dessus. Mais cette loi semble centrée au centre du carré plutôt qu’à la position initiale de la tortue, ce qui paraît très étonnant !

GIF


Pour représenter la distribution en 3D, on prend la même variation d’angle (0,6 rad) et une variation de distance (dans avancer de ...) suffisamment faible pour être négligeable.

Après la première rotation, la transformée est un arc de cercle et la distribution est uniforme. Petite fantaisie, le nuage a la forme d’un prie-dieu curule.

Après la deuxième rotation (on tourne à droite ici...), on obtient le quadrilatère à bords circulaires et une distribution qui reste quasi-uniforme. On peut remarquer que la surface est légèrement concave.

Voici la vue de dessus :

Après la troisième rotation, la distribution n’est plus uniforme, on obtient une espèce de coque de bateau inversée :

Voici la vue de dessus :

Enfin, après la quatrième rotation, on obtient une coiffe intermédiaire entre le bonnet phrygien et le sombrero, représentée ici en coupe (tracé incomplet) :

dont voici la vue dessus :

CaRScript

  1. fonction pas(){
  2. return ((Math.random()*2-1)/2);
  3. }
  4.  
  5. fonction affinerU(){
  6. var arriveeX=0;
  7. var arriveeY=0;
  8. var indiceX;
  9. var indiceY;
  10. teta=0;
  11. teta+=pas()*b;
  12. d=1+pas()*a;
  13. if (nbE>0) {
  14. arriveeY+=d*Math.cos(teta);
  15. arriveeX+=d*Math.sin(teta);
  16. teta+=pas()*b;
  17. d=1+pas()*a;
  18. YT=1;
  19. XT=0;
  20. }
  21. if (nbE>1) {
  22. arriveeY+=-d*Math.sin(teta);
  23. arriveeX+=d*Math.cos(teta);
  24. teta+=pas()*b;
  25. d=1+pas()*a;
  26. YT=1;
  27. XT=1;
  28. }
  29. if (nbE>2){
  30. arriveeY+=-d*Math.cos(teta);
  31. arriveeX+=-d*Math.sin(teta);
  32. teta+=pas()*b;
  33. d=1+pas()*a;
  34. YT=0;
  35. XT=1;
  36. }
  37. if (nbE>3){
  38. arriveeY+=d*Math.sin(teta);
  39. arriveeX+=-d*Math.cos(teta);
  40. teta+=pas()*b;
  41. d=1+pas()*a;
  42. YT=0;
  43. XT=0;
  44. }
  45.  
  46. indiceX=Math.round((arriveeX-XT)*100+100);
  47. indiceY=Math.round((arriveeY-YT)*100+100);
  48. si (indiceX<201&&indiceY<201&&indiceX>-1&&indiceY>-1) {
  49. U[indiceX][indiceY]=U[indiceX][indiceY]+1/nPoints;
  50. }
  51. }
  52. fonction afficherU(){
  53. pour i allant de 1 à 200 {
  54. pour j allant de 1 à 200 {
  55. si (U[i][j]>0.000001) {
  56. Point3D((i-100)/100+XT,(j-100)/100+YT,"d*"+U[i][j]);
  57. }
  58. }
  59. }
  60. }
  61.  
  62. // --------------------------
  63.  
  64. nPoints=10000000;
  65. a=GetExpressionValue("deltaD");
  66. b=GetExpressionValue("deltaA"); //deltaAngle
  67. nbE=GetExpressionValue("nbE");
  68. U=[];
  69.  
  70. pour i allant de 0 à 200 {
  71. U[i]=[];
  72. pour j allant de 0 à 200 {
  73. U[i][j]=0;
  74. }
  75. }
  76.  
  77. pour r allant de 0 à nPoints {
  78. affinerU();
  79. }
  80. afficherU();

Télécharger

Et le fichier CaRMetal :

CarMetal - 5 ko

Ainsi, il semble que si, après beaucoup de petits parcours partiellement aléatoires, la position de la tortue devient de plus en plus gaussienne, au bout de peu d’itérations, le nuage de points est allongé, tourné, et pas très elliptique. La partie suivante suivante montre l’importance des rotations de 90° dans cette non-normalité.


IV/Quand la tortue titubante essaye d’aller tout droit

Expériences

On reprend le tracé aléatoire avec erreurs uniquement angulaires, mais cette fois-ci seulement sur un côté, et on marque un point au bout du trajet :


Remarque : Avec Sofus on peut utiliser plusieurs tortues, mais là on a choisi de remettre au départ la même tortue. On obtient alors ce genre de tracé :

La distribution a l’allure d’une chaise percée... (ou d’un diadème si l’on veut rester dans le chapeau)

dont voici la vue de dessus (pour les coeurs bien accrochés) :

CarMetal - 4.9 ko

Typiquement, l’effet obtenu est une légère diminution de la distance parcourue (par rapport au cas sans rotation), parce que les cas non typiques sont ceux où les erreurs angulaires se sont accumulées, ce qui est rare d’après l’inégalité de Bienaymé-Tchebychev.

histogramme

Voici, à fins statistiques, un script Python simulant ce phénomène :

  1. from random import *
  2. from turtle import *
  3. import matplotlib.pyplot as plt
  4. speed(0)
  5. penup()
  6. hideturtle()
  7. tracer(0,0)
  8. ds = []
  9. def e():
  10. return 2*random()-1
  11.  
  12. def avance(d):
  13. for n in range(d//10):
  14. left(e())
  15. forward(10)
  16. for n in range(10000):
  17. home()
  18. avance(200)
  19. ds.append(distance(0,0))
  20.  
  21. plt.hist(ds,50)
  22. plt.show()

Télécharger

Sur un million de répétitions, l’histogramme ressemble à ceci :

Ainsi, les distances suivent une loi ayant la même allure qu’une loi bêta de paramètres 18 et 2 (distribution conditionnelle du pourcentage de boules rouges dans une urne sachant qu’un tirage avec remise a donné 18 boules rouges et 2 boules bleues) : Elle est toujours proche du maximum même si ce maximum n’est pas 1 (comme c’est le cas avec la loi bêta). On peut donc dire que dans ce cas les distances sont presque toutes les mêmes et que la tortue est proche d’un arc de cercle. Quand à la distribution des angles sur cet arc de cercle, elle semble suivre une loi de von Mises. Quel sont ses paramètres ?

Distribution statistique des distances

La tortue va confier les mesures de distances à l’origine à un serpent : Le célèbre Python2 [6]. Voici le script :

  1. from random import *
  2. from turtle import *
  3. import matplotlib.pyplot as plt
  4. speed(0)
  5. penup()
  6. hideturtle()
  7. tracer(0,0)
  8. ds = []
  9. def e():
  10. return 2*random()-1
  11.  
  12. def avance(d):
  13. for n in range(d//10):
  14. left(e())
  15. forward(10+e())
  16. def carre():
  17. home()
  18. for n in range(4):
  19. avance(200)
  20. left(90)
  21. for n in range(10000):
  22. carre()
  23. ds.append(distance(0,0))
  24.  
  25. plt.hist(ds,50)
  26. plt.show()

Télécharger

Et voici l’histogramme des distances obtenu sur 10000 tracés de carrés :

On constate une distance modale d’environ 10 pixels, ce qui suggère (sous hypothèse gaussiene !) une loi de Rayleigh de paramètre environ 10, et dans ce cas la distance moyenne de ratage est d’environ 15 pixels.

Pour aller plus loin

On peut aller dans la troisième dimension, en ajoutant des petits pivots aléatoires en plus des rotations aléatoires (vers la gauche et la droite) de la tortue : En bref, modéliser non plus le robot de sol qui ne va pas tout droit, mais le drone dont tout enfant sait à quel point il est incontrôlable : On trouve un nuage de points tridimensionnel.

Dans le cas d’un carré, on obtient cette figure DGPad à ouvrir dans une autre fenêtre.

Dans le cas du parcours hamiltonien d’un cube, si les angles sont de 90°, on a une sphère gaussienne comme l’illustre cette autre figure DGPad.

Sinon le nuage de points est plutôt polyhédral, comme le montre (un peu) ce nuage anaglyptique produit par Géotortue (à regarder avec des lunettes rouge/cyan) :

Géotortue parmet aussi d’aller vers la quatrième dimension, et là encore pas de grosse surprise, le nuage de points semble polychoral. Mais, plus facile à interpréter, le disque de Poincaré (plan hyperbolique) dans lequel la tortue peut dessiner un pentagone régulier à angles droits ; avec erreurs de parcours, le nuage de points est assez allongé :

En résumé :

  • distances aléatoires et angles certains : La position finale est gaussienne ;
  • ditances certaines et angles aléatoires : La distance totale est presque certaine, la distribution des angles est presque gaussienne, mais si l’espérance des angles est grande, le nuage a une forme complexe et la distribution statistique aussi.
  • Pour un mix des deux (distances et rotations aléatoires) le nuage peut bénéficier d’une approximation gaussienne, comme on le voit ici

notes

[1C’est par ce principe que sont animées les tortues de Sofus en mode lent, sauf que "avancer de 100" revient à "avancer 100 fois d’un pixel" et non "avancer 10 fois de 10 pixels", et que ce ne sont pas des petites erreurs qui sont introduites à chaque étape, mais un petit temps d’attente

[2donc centrée, cela garantit que l’espérance du vecteur aléatoire obtenu est (100 ;0)

[3N’aurait-on pas réussi à modéliser aussi l’effet de la caféine sur un dessinateur ? La tortue sous caféine, il fallait oser !

[4Cette ellipse est une généralisation à la dimension 2, de la notion d’intervalle de fluctuation : On peut tracer une ellipse contenant un pourcentage donné, par exemple 95%, des points du nuage.

[5on passe de R2D2 (la tortue) à C3PO (le bras)...

[6On peut le faire aussi avec Python3, mais ce langage est plus éloigné de Logo que ne l’était Python2

Réagir à cet article
Vous souhaitez compléter cet article pour un numéro futur, réagir à son contenu, demander des précisions à l'auteur ou au comité de rédaction...
À lire aussi ici
MathémaTICE est un projet
en collaboration avec
Suivre la vie du site Flux RSS 2.0  |  Espace de rédaction  |  Nous contacter  |  Site réalisé avec: SPIP  |  N° ISSN 2109-9197