Estymacja liczby PI metodą monte carlo

Typ_projektu
microPython
Zdjecie główne
Estymacja liczby pi na podstawie losowo wybranych punktów na kole i kwadracie
Krótki opis projektu

Liczbę PI możemy wyznaczyć na bardzo wiele różnych sposobów. Jednym z nich jest zaprzęgnięcie do pracy prostej probabilistyki. Estymacja polega na wybraniu losowo punktów na kwadracie i kole. Świetny przykład jak można użyć prawdopodobieństwa i podstawowej geometrii do robienia niesamowitych rzeczy!

Niezbędne elementy

1. Płytka esp8266

2. Wyświetlacz oled

3. Kilka kabli

4. Guzik

Sprzęt

1. Komputer z programem Thonny

Opis projektu

Na czym polega projekt?
Projekt polega na estymacji liczby pi korzystając z losowo wybranych punktów na kwadracie. Wszystko wyświetlimy na ekranie i dodatkowo będziemy mogli "dodawać" kolejne punkty na rysunku ręcznie (klikając guzik).

Jak to działa?
Wyobraźmy sobie kwadrat o boku 1. Teraz rysujemy wycinek koła w taki sposób, aby połączyć dwa wierzchołki kwadratu, a środek okręgu był w wierzchołku między nimi (patrz obrazek). Jakie jest pole kwadratu? Proste! bok*bok=1*1=1. A jakie jest pole koła? Też proste: PI*R^2. Promień R też jest równy 1, czyli nasze pole to równe PI. Korzystamy z wycinka koła na kwadracie w taki sposób, że mamy narysowaną 1/4 koła, czyli pole naszego wycinka to PI*R^2*(1/4) = PI*1/4. 
Robiąc stosunek pola koła do pola kwadratu uzyskamy nasze PI/4 (patrz rysunek).

Teraz wylosujmy położenie np.15000 punktów. Wykorzystamy to czy są wewnątrz okręgu czy na zewnątrz. Stosunek ilości punktów wewnątrz do zewnątrz proporcjonalny do stosunku naszych pól. Czyli PI/4.

W kodzie ten wynik pomnożymy razy 4 uzyskując czyste PI. 

Podaję dwa kody:
-kod dzięki któremu możemy dodawać pojedynczo nasze punkty(klikając guzikiem, bardzo wolny)
-kod który automatycznie narysuje wszystkie zadane punkty (na początku kodu można zmieniać ich ilość)

Co zobaczymy na ekranie?
Na ekranie wyświetli się na liczba pi, rysunek wraz z punktami, ilość punktów znajdujących się na rysunku oraz błąd od liczby (czyli jak stosunek naszego PI do poprawnego PI, im dalej od wartości 1 tym bardziej niepoprawny mamy wynik)

 

Zdjęcia
kod programu
#######
#PONIŻEJ ZNAJDUJĄ SIE DWA KODY (AUTOMATYCZNY I RECZNY) DO LOSOWANIA
#######

#KOD PIERWSZY
from machine import Pin,I2C
import ssd1306
import time
from math import sqrt
import random

ilosc=1000 #ile punktów chcemy wybrac,  JEDYNIE W TEJ LINIJCE ZMIENIAMY WARTOSC, PRZY OGROMNYCH WARTOSCIACH (>2000) MOGA POJAWIAC SIE BLEDY Z PAMIECIA
i2c=I2C(scl=Pin(5),sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128,64,i2c)
x=64
y=2
x_p=[]
y_p=[]
pin=machine.Pin(12,machine.Pin.IN, machine.Pin.PULL_UP)
def circle(x,y,r):
    for i in range(128):
        for j in range (64):
            if sqrt((x-i-1)*(x-i-1)+(y-j-1)*(y-j-1)) >r-1 and sqrt((x-i-1)*(x-i-1)+(y-j-1)*(y-j-1)) <r+1:
                if i>x and j>y:
                    oled.pixel(i,j,1)
def wkole(x,y,x_l,y_l):
    if sqrt((x-x_l-1)*(x-x_l-1)+(y-y_l-1)*(y-y_l-1)) >60:
        return 1
    if sqrt((x-x_l-1)*(x-x_l-1)+(y-y_l-1)*(y-y_l-1)) <=60:
        return 0
        
oled.rect(x, y, 60, 60, 1)
circle(64,2,60)
w=0
p=0
pi=0
dokladnosc=0
punkty=0
pi_s=str(pi)
dokladnosc_s=str(dokladnosc)
punkty_s=str(punkty)
oled.show()

for i in range(ilosc):
    punkty+=1
    losowy_x=random.getrandbits(8)%60+64
    losowy_y=random.getrandbits(8)%60+2
    x_p.append(losowy_x)
    y_p.append(losowy_y)
    if wkole(x,y,losowy_x,losowy_y)==1:
        w+=1
    if wkole(x,y,losowy_x,losowy_y)==0:
         p+=1
    if w>0 and p>0:
        pi=(w/p)*4*3
        dokladnosc=pi/3.14159
     
pi_s=str(pi)
dokladnosc_s=str(dokladnosc)
punkty_s=str(punkty)
oled.text(punkty_s,0,30,1)
oled.text(dokladnosc_s,0,50,1)
oled.text(pi_s,0,10,1)
oled.pixel(losowy_x,losowy_y,1)
oled.text('Blad:',0,40,1)
oled.text('Punkty',0,20,1)
oled.text("Pi:",0,0,1)
for i in range(punkty):
    oled.pixel(x_p[i],y_p[i],1)   
oled.show()

############################
#PONIŻEJ ZACZYNA SIE KOD SŁUŻĄCY LOSOWANIA PUNKTÓW GUZIKIEM PO KOLEJI
############################
#KOD DRUGI RECZNY
from machine import Pin,I2C
import ssd1306
import time
from math import sqrt
import random

i2c=I2C(scl=Pin(5),sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128,64,i2c)
x=64
y=2
x_p=[]
y_p=[]
pin=machine.Pin(12,machine.Pin.IN, machine.Pin.PULL_UP)
def circlefull(x,y,r):
    for i in range(128):
        for j in range (64):
            if sqrt((x-i-1)*(x-i-1)+(y-j-1)*(y-j-1)) >r-1 and sqrt((x-i-1)*(x-i-1)+(y-j-1)*(y-j-1)) <r+1:
                    oled.pixel(i,j,1)
def circle(x,y,r):
    for i in range(128):
        for j in range (64):
            if sqrt((x-i-1)*(x-i-1)+(y-j-1)*(y-j-1)) >r-1 and sqrt((x-i-1)*(x-i-1)+(y-j-1)*(y-j-1)) <r+1:
                if i>x and j>y:
                    oled.pixel(i,j,1)
def wkole(x,y,x_l,y_l):
    if sqrt((x-x_l-1)*(x-x_l-1)+(y-y_l-1)*(y-y_l-1)) >60:
        return 1
    if sqrt((x-x_l-1)*(x-x_l-1)+(y-y_l-1)*(y-y_l-1)) <=60:
        return 0
        
oled.rect(x, y, 60, 60, 1)
circle(64,2,60)
w=0
p=0
pi=0
dokladnosc=0
punkty=0
pi_s=str(pi)
dokladnosc_s=str(dokladnosc)
punkty_s=str(punkty)
oled.text("Pi:",0,0,1)
oled.text(pi_s,0,10,1)
oled.text('Points:',0,20,1)
oled.text(punkty_s,0,30,1)
oled.text('Blad:',0,40,1)
oled.text(dokladnosc_s,0,50,1)
oled.show()

while True:
    print(pin.value())
    if pin.value()==0:
        punkty+=1
        oled.fill(0)
        losowy_x=random.getrandbits(8)%60+64
        losowy_y=random.getrandbits(8)%60+2
        x_p.append(losowy_x)
        y_p.append(losowy_y)
        if wkole(x,y,losowy_x,losowy_y)==1:
            w+=1
            print(w)
        if wkole(x,y,losowy_x,losowy_y)==0:
            p+=1
            print(p)
        for i in range(punkty):
            circlefull(x_p[i],y_p[i],1)
        oled.text('Blad:',0,40,1)
        oled.text('Punkty',0,20,1)
        oled.text("Pi:",0,0,1)
        if w>0 and p>0:
            pi=(w/p)*4*3
            dokladnosc=pi/3.14159
        oled.rect(x, y, 60, 60, 1)
        circle(64,2,60)
    pi_s=str(pi)
    dokladnosc_s=str(dokladnosc)
    punkty_s=str(punkty)
    oled.text(punkty_s,0,30,1)
    oled.text(dokladnosc_s,0,50,1)
    oled.text(pi_s,0,10,1)
    oled.show()
Pliki_projektu
Schemat
Tagi
#PI #OLED #BUTTON #MONTE_CARLO #MICRO