# Heittoliikkeen simulointia, mukana ilmanvastus kv² # k riippuu ilman tiheydestä, joka riippuu korkeudesta ja lämpötilasta # lämpötila riippuu korkeudesta # joten k:n arvo muuttuu korkeuden mukaan # verlet second order method: x0,x1 alkuarvot, sitten loput x,y iteroimalla # iterointi: x(n+1) = 2x(n) - x(n-1) + a(n)*Dt^2 # Juhani Kaukoranta 17.10.2021 import pygame, math # pygame:ssa x kasvaa vasemmalta oikealle, y ylhäältä alas # laskut tehdään (x,y)-koordinaatistossa, tuloste pygame-koordinaatistossa pygame.font.init() font = pygame.font.Font('freesansbold.ttf', 24) # pallon ominaisuudet: (otettu baseballista, Cd=0.3) # ei ilmanvastusta Cd = 0, paraabelirata Cd = 0.3 # ilmanvastuskerroin, oletusarvo 0.3 roo = 1.225 # ilman tiheys kg/m³ (ICAO, 0m +15C) A = 0.0043 # pallon poikkipinta-ala m² m = 0.145 # pallon massa kg r = 5 # piirretyn pallon säde pikseleinä # ilman tiheys roo = 1.225*(288.15/(288.15-0.0065*h))**(-4.25578597) k1 = (Cd*A)/(2*m) # pallon vastuskertoimen osa # k = k1*roo # pallon vastuskerroin, mukana ilman tiheys roo v0 = 300 # lähtönopeus g = 9.80665 # putouskiihtyvyys alfadeg = 30 # heittokulma (suhteessa vaakatasoon) alfa = alfadeg*math.pi/180 # heittosuunta radiaaneina # pystykiihtyvyys y''(t) = -g - k*vy² = -(g+k*vy²) # vaakakiihtyvyys x''(t) = -k *vx² t0 = 0.0 # aloitusaika Dt = 1/100.0 # aika-askel T = 7000 # animaation maksimikesto 7000*1/100 = 70 s # piirtoalueen asetus (width,height) = (1280,720) # Pygamen piirtoala pikseleinä screen = pygame.display.set_mode((width, height)) black = (0,0,0) yellow =(255,255,0) red = (255,0,0) green = (0,255,0) blue =(0,0,255) magenta = (255,0,255) screen.fill(black) pygame.display.set_caption("pallon lento, ilmanvastus kv² ja tiheyden korkeusriippuvuus mukana: ") # pallon (0,0) vastaa Pygamen näytöllä (100,500) (x0,y0) =(0,0) # pallon koordinaattien aloitusarvot, (0 metriä, 0 metriä) (pygamex0,pygamey0) = (100,500) # Pygamen koordinaatiston origo h = 0 # korkeus lähtötasosta tasosta,lähtötaso on merenpinnan taso, Pygamen y=500=gamey0 roo = 1.225*(288.15/(288.15-0.0065*h))**(-4.25578597) # ilman tiheyden alkuarvo k = k1*roo # pallon ilmanvastuskertoimen aloitusarvo vx = v0*math.cos(alfa) # vaakasuoran nopeuskomponentin alkuarvo vy = v0*math.sin(alfa) # pystysuoran nopeuskomponentin alkuarvo x1 =x0 + vx*Dt - 0.5*(k*vx**2)*Dt**2 # eka x-askel, verlet y1 = y0 + vy*Dt - 0.5*(k*vy**2+g)*Dt**2 # eka y-askel, verlet vx = (x1 - x0)/Dt # vaakanopeus eka-askeleen jälkeen vy = (y1 - y0)/Dt # pystynopeus eka-askeleen jälkeen hmax = y1 # pitää kirjaa pallon maksimikorkeudesta h = y1 # pallon korkeus timer = 0 # ajastin, 0.5 s välein tulostetaan näytölle pallon dataa alku =90 # punainen lähtötasoviivan alku pikseleinä vähän ennen lähtöpaikkaa Pygamessa loppu = 1000 # punaisen lahtötasoviivan loppupistepikseleinä Pygamessa pygame.draw.line(screen,red,(pygamex0-20,pygamey0+r),(pygamex0+1000,pygamey0+r),2) # vaakaviiva # piirretty niin, että pallo on vaakaviivalla, keskipiste korkeudella r text = font.render("Lähtökulma = "+str(round(alfadeg))+" Lähtönopeus = "+str(round(v0)), True, yellow, black) screen.blit(text,(100,40)) pygame.draw.circle(screen, yellow,(pygamex0+x0,pygamey0-y0),r) # piirretään alkutilan (x0,y0) pallo pygame.display.flip() # päivitetään näyttö pygame.time.delay(2) pygame.draw.circle(screen,black,(pygamex0+x0,pygamey0-y0),r) # alkutilan (x0,y0) pallo pois pygame.draw.circle(screen,yellow,(pygamex0+x1,pygamey0-y1),r) # piirretään eka-askeen (x1,y1) pallo pygame.display.flip() pygame.time.delay(2) pygame.draw.circle(screen,black,(pygamex0+x1,pygamey0-y1),r) # eka-askeleen (x1,y1) pallo pois # simulointi jatkuu aikaan T asti iteroimalla x(n+1) = 2x(n) - x(n-1) + a(n)*Dt^2 # eka arvojen (x0,y0) ja (x1,y1) jälkeen lasketaan ja tulostetaan päivitettyjä (x,y) for j in range (0,T) : timer += 1 # puolen sekunnin paikkatietojen tulostusta varten roo = 1.225*(288.15/(288.15-0.0065*h))**(-4.25578597) # ilman tiheys k = k1*roo # ilmanvastuskerroin x = 2*x1 - x0 - (k*vx**2)*Dt**2 # pallon uusi x-koordinaatti, verlet y = 2*y1 - y0 - (g + k*vy**2)*Dt**2 # pallon uusi y -kordinaatti, verlet h = y # pallon korkeus if h > hmax: hmax = h pygame.draw.circle(screen,yellow,(pygamex0+x,pygamey0-y),r) # piirretään päivitetty pallo pygame.display.flip() pygame.time.delay(2) pygame.draw.circle(screen,black,(pygamex0+x,pygamey0-y),r) # edellinen pallon paikka pois (xpaikka,ypaikka) = (round(abs(x)),round(y)) # paikka muistiin timer-tulostusta varten vaakamatka = round(abs(x)) # muistiin timer-tulostusta varten korkeus = round(h) # muistiin timer-tulostusta varten vx = (x - x0)/(2*Dt) # päivitetty vaakanopeus, huom! tämä on tarkempi kuin (x1-x0)/Dt vy = (y - y0)/(2*Dt) # päivitetty pystynopeus, huom! tämä on tarkempi kuin (y1-y0)/Dt x0 = x1 # askeleen jälkeen päivitetään koordinaatit, iterointi alkaa x1 = x y0 = y1 y1 = y if y >= hmax : # pallo lakipisteessä korkeus = round(h) korkeustxt0 = font.render("xxxxxxxxxxxxxxxxxxx",True,black,black) korkeustxt = font.render("maxkorkeus = "+str(korkeus)+" m", True, yellow, black) screen.blit(korkeustxt0,(100,70)) # puhdistetaan korkeustietoja screen.blit(korkeustxt,(100,70)) hmax = y if y < 0 : # pallo putosi maahan break if timer == 50: #puolisekunti kulunut,näytetään paikkatietoja text0 = font.render("xxxxxxxxxxxxxxxx",True,black,black) screen.blit(text0,(100,100)) # puhdistetaan vaakamatkatiedot text = font.render("Vaakamatka = "+str(vaakamatka),True,yellow,black) screen.blit(text,(100,100)) screen.blit(text0,(100,120)) # puhdistetaan korkeustiedot txt = font.render("Lentoaika = "+str(round(100*j*Dt)/100),True,yellow,black) screen.blit(txt,(100,120)) timer = 0