In questo articolo impareremo il concetto di modello matematico e simulazione, applicati ad un semplice programma per Seeeduino Wio Terminal e Arduino.
Immaginiamo di lanciare in aria una moneta nove volte, e di ottenere per nove volte di seguito “testa”. Qual è la probabilità che al decimo lancio esca “croce”?
Se avete risposto “il 90%”, allora andate pure avanti con la lettura, un piccolo ripasso di statistica sarà certamente il benvenuto.
Se invece siete tra quegli eletti che rispondono (correttamente) “il 50%”, allora già conoscete la differenza tra eventi dipendenti ed indipendenti. Come si è soliti ripetere in ambito statistico, una moneta non ha memoria del proprio passato, e ad ogni lancio le probabilità che esca testa sono pari alle probabilità che esca croce. Anche se la serie precedente ha visto l’uscita di 99 “croce” di seguito, ogni volta che gettiamo in aria la moneta, i numeri legati alle probabilità si resettano, e si riparte da zero.
E’ evidente che un simile comportamento appaia quantomeno controintuitivo a chi, come l’essere umano medio, sia abituato a ricercare pattern in ogni sua percezione sensoriale. Ci troviamo di fronte alla solita, antichissima storia che ci vede attori nella ricerca di un miglioramento del nostro stato attraverso il tentativo di riconoscere le cause prime dietro ad ogni manifestazione della Realtà.
Dalle monete ai dadi
Se abbiamo esattamente il 50% delle probabilità di vedere cadere una moneta su testa o su croce (trascurando quelle rare eccezioni in cui la moneta rimane in piedi sul bordo), quante sono invece le probabilità di uscita per ciascuna faccia di un dado? Semplice: ad ogni tiro ciascuna faccia ha esattamente una possibilità su sei di apparire. Quindi, circa il 16,67%.
In altri termini, ciascun valore da 1 a 6 ha esattamente le stesse probabilità di uscita (a meno di avere dadi piombati…).
Le cose diventano più interessanti quando aumentiamo il numero dei dadi da lanciare: in nessun modo, infatti sarà possibile ottenere il valore 1 con due dadi (ovviamente…). Nella tabella seguente vediamo in quanti modi diversi potremo ottenere ciascun valore come risultato.
Uscita | Numero possibilità | Combinazioni possibili | Probabilità di uscita |
---|---|---|---|
2 | 1 | 1+1 | 1/36 --> 2,78% |
3 | 2 | 1+2, 2+1 | 2/36 --> 5,55% |
4 | 3 | 1+3, 2+2, 3+1 | 3/36 --> 8.33% |
5 | 4 | 1+4, 2+3, 3+2, 4+1 | 4/36 --> 11,11% |
6 | 5 | 1+5, 2+4, 3+3,4+2, 5+1 | 5/36 --> 13,89% |
7 | 6 | 1+6, 2+5, 3+4, 4+3, 5+2, 6+1 | 6/36 --> 1/6 --> 16,67% |
8 | 5 | 2+6, 3+5, 4+4, 5+3, 6+2 | 5/36 --> 13,89% |
9 | 4 | 3+6, 4+5, 5+4, 6+3 | 4/36 --> 11,11% |
10 | 3 | 4+6, 5+5, 6+4 | 3/36 --> 8.33% |
11 | 2 | 1+5, 5+1 | 2/36 --> 5,55% |
12 | 1 | 6+6 | 1/36 --> 2,78% |
Con un po’ di matematica combinatoria (ma anche solo buonsenso) è facile riconoscere che le possibilità di uscita per ciascun numero non sono più le stesse, in quanto alcuni valori possono essere combinati in più modi differenti. Se osserviamo la tabella, ci rendiamo conto di avere ad ogni lancio 36 possibili combinazioni differenti. Il valore 2 ed il valore 12 avranno ciascuno 1 probabilità su 36 di uscire ad ogni lancio, il valore 3 ed il valore 11 avranno 2 probabilità ciascuno di uscire ad ogni lancio, e così via. In altri termini, la probabilità di uscita di ciascun numero non è più la stessa rispetto al dado singolo, e in particolare, la probabilità di uscita di un 2 o di un 12 con due dadi risulta pari all’uscita di un numero secco alla roulette (1/36 o 2,78%, se per il momento non consideriamo lo zero).
Aumentiamo la complessità.
Cosa accade se anziché due soli dadi ne utilizzassimo di più? Quali sarebbero le probabilità per ciascuna uscita? Conserverebbero l’apparente linearità di crescita o creerebbero curve più strane? Potremmo calcolare i valori a mano, ma rischieremmo di sbagliare al crescere dei calcoli da effettuare. Un computer, invece, sarebbe perfettamente a proprio agio…
Abbiamo per l’appunto una piccola scheda dotata di capacità di calcolo particolari, il Seeeduino Wio Terminal. Si tratta di un Arduino su steroidi, dotato di un sistema SAMD51 con processore ARM Cortex M4. Abbiamo già visto questo sistema al lavoro nel calcolo dei frattali di Lyapunov. Si tratta solo di scrivere un semplice programma che si occupi di simulare il lancio di 6 dadi utilizzando la funzione random(), accumulare i valori di uscita per ciascuna combinazione e calcolarne la percentuale rispetto al totale delle uscite.
Per rendere il programma più simpatico da visualizzare, aggiungeremo la visualizzazione del numero delle uscite per ciascuna combinazione su di una tabella.
Al termine del programma, basterà cliccare sul tasto azzurro per avere una tabulazione dei valori probabilistici calcolati per ciascuna combinazione.
Di seguito il programma relativo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
#include"TFT_eSPI.h" #include <SPI.h> #include"Histogram.h" //include histogram library TFT_Histogram histogram=TFT_Histogram(); //Initializing tft and histogram TFT_eSPI tft; #define MAX_TIRI 65000 int valori[36]; int dado[6]; int somma = 0; int max_value = 0; void setup() { randomSeed(analogRead(0)); pinMode(WIO_5S_PRESS, INPUT_PULLUP); tft.begin(); tft.setRotation(3); } void loop() { calcolo(); grafico(); stampa(); while(true){} } void calcolo() { for (int i = 0; i < MAX_TIRI; i++) { somma = 0; for (int j = 0; j < 6; j++) { dado[j] = random(1, 7); somma = somma + dado[j]; } valori[somma-1]++; } // Find the max value to scale on the 320x240 screen for (int i = 0; i < 36; i++) { if (valori[i] > max_value) { max_value = valori[i]; } } } void grafico() { // Set backgroundcolor tft.fillScreen(TFT_BLUE); //Draw the histogram for (int i = 5; i < 36; i++) { tft.fillRect((i-3)*9,210 - (valori[i]*180/max_value),8,210,TFT_WHITE); } // Wait ultil the paddle is pressed while(!keypressed()); } void stampa() { tft.fillScreen(TFT_GREEN); tft.setTextColor(TFT_BLACK); tft.setTextSize(2); tft.drawString("Statistiche", 80, 20); tft.setTextSize(1); for (int i = 0; i < 18; i++) { static char tabella[50] = {'\0'}; snprintf(tabella, sizeof(tabella), "%02i - %04i %02i - %04i", i+1, valori[i], i+18+1, valori[i+18]); tft.drawString(tabella, 50, 50+10*i); } } bool keypressed() { do { delay(100); } while(digitalRead(WIO_5S_PRESS) != LOW); return true; } |
Come sempre, il programma è disponibile anche su GitHub.
Se vi interessa approfondire l’argomento simulazioni al computer, scriveteci!
Link utili: