Om fält, plottar i Python samt derivator

Introduktion till fält

I många sammanhang vill man analysera en större mängd av data. Det kan t.ex. vara mätdata från experiment eller resultat från olika typer av beräkningar. Det kan då vara praktiskt att spara sådan data i listor, eller fält. När man arbetar med fält i Python är det vanligt att importera modulen numpy för att få användbar funktionalitet.

Denna modul innehåller också de matematiska funktioner som kommer att behövas för att räkna med vektorer och mätdata, så du behöver inte importera math (det finns stora överlapp mellan modulerna).

Låt oss nu anta att vi mätt upp en bils hastighet i km/h vid olika tidpunkter och vill spara dessa i ett fält. Då kan vi skriva:

import numpy
hast = numpy.array([5,12,23,54,78,89,84,73,40,13,3,0])

Lägg in detta i rutan nedan och lägg själv till kommandot som behövs för att skriva ut hast, minns du vilket det var?

In [ ]:
 

OBS! För att separera värden i fältet används kommatecken ,.

Du behöver givtvis inte ha heltal i ett fält, det kan fyllas med vilka flyttal som helst:

v = numpy.array([numpy.pi, 1.34e-4, 2.3, 6])

är exempelvis giltigt. Prova det gärna i rutan ovan.

Eftersom vi kommer att använda numpy såpass mycket från och med nu hade det varit skönt att slippa skriva ordet numpy före varje funktion eller konstant från modulen. För att göra detta ändrar vi importkommandot till

import numpy as np

varefter det räcker att skriva

v = np.array([np.pi, 1.34e-4, 2.3, 6])

Notera att namnvalet np är godtyckligt, vi kan döpa numpy till vad vi vill.

Rader och kolonner

Vi kan även spara data i rader och kolonner (exempelvis ifall varje rad är en ny dag då vi mäter och varje kolonn är en tidpunkt vi mäter vid). Fältet är då tvådimensionellt, och kallas en matris. Du kan tänka på en matris lite som ett blad i Excel.

För att göra detta skapas ett fält som i sin tur innehåller fält. Testa följande i rutan nedan:

import numpy as np
A=np.array([[5,12,23],[54,78,89],[84,73,40],[13,3,0]])
print(A)
In [ ]:
 

Fältet hast ovan kan ses som en vektor med (12) element. Notera att ordet vektor (vector på engelska) här inte har samma betydelse som ni kanske tidigare använt begreppet i samband med geometriska vektorer. I matematiken används begreppet vektor lite mer generellt för objekt som har vissa specifika egenskaper. Geomtriska vektorer är bara ett av många exempel på objekt som har dessa egenskaper.

In [ ]:
 

Om man vill skapa en aritmetisk följd av tal (dvs. där avståndet mellan två efterföljande tal alltid är detsamma) kan man använda arange ifall man vill ange hur stort hoppet är i talföljden och linspace ifall man i stället vill ange hur många element talföljden ska innehålla (och körs linspace utan att man anger antalet punkter blir default 50 stycken). Prova följande:

import numpy as np
# talföljd från och med 1 till 10 med 0.5-hopp
A=np.arange(1,10,0.5) 
# talföljd från och med 1 till och med 10 med 5 element
B=np.linspace(1,10,5) 
print(A)
print(B)
In [ ]:
 

Som du ser ger arange intervallet $[start,stop)$, dvs. talföljden går till det största tal som är mindre än slutpunkten, så det gäller att vara försiktig.

Pröva dig själv: vad blir sista elementet i talföljden:

import numpy as np
A=np.arange(2,7,0.3) 
print(A)

Både arange och linspace kan stega från ett större tal till ett mindre. För arange anger du då en negativ steglängd.

import numpy as np
A=np.arange(10,1,-0.5) 
B=np.linspace(10,1,5)
print(A)
print(B)

Prova detta nedan:

In [ ]:
 

Det finns många andra funktioner som initierar fält i numpy. Du kan exempelvis skapa en vektor fylld av slumptal med hjälp av numpy.random.rand, dvs.

import numpy as np
R=np.random.rand(3,2) # matris med slumptal (3 rader 2 kolonner)
print(R)
In [ ]:
 

Glöm inte att du kan skriva help(np.random.rand) för att få information om rand kommandot, eller help(np.random) för att få information om de olika funktionerna som ligger under numpy.random eller help(np) för hjälp om numpy.

Importera data

Ofta sparas mätdata i filer som ska läsas in i Python innan de används. En användbar funktion är då numpy.genfromtxt som läser in filen och sparar den i ett fält. Eftersom dessa filer ser så väldigt olika ut har genfromtxt VÄLDIGT många inställningar som kan sättas så att det blir rätt (se efter själv genom att titta på hjälptexten för funktionen).

För att testa hur den fungerar så skapa en textfil med din favoriteditor och spara den i samma mapp som denna Jupyter notebook-fil. Fyll filen med några mätdata separerade med mellanslag, t.ex. 3 5 7 9 11 13 och döp filen till något lämpligt, t.ex. data_python_2.txt

För att nu läsa filen skriver du

import numpy as np
R=np.genfromtxt('data_python_2.txt') 
print(R)

OBS! Ifall du inte sparade filen i samma mapp som din Pythonkod så får du ange sökvägen dit också.

Prova detta i rutan nedan. Testa även att ändra i filen och se hur det påverkar din input.

In [ ]:
 

Hantera fält

Nu går vi vidare och pratar om hur vi kan arbeta med elementen i fälten.

Först ska vi lära oss att spara antalet element i en vektor eller matris i en variabel. Detta görs med kommandot size ifall du vill få ut det totala antalet, eller shape ifall du vill hålla rader och kolonner separerade. Provkör denna kod i rutan nedan:

import numpy as np
A=np.array([[5,12,23],[54,78,89],[84,73,40],[13,3,0]])
B=np.array([[5],[54],[84],[13]])
C = np.array([5,12,23,54,78,89,84,73,40,13,3,0])
print(np.size(A))
print(np.shape(A))
print(np.size(B))
print(np.shape(B))
print(np.size(C))
print(np.shape(C))
In [ ]:
 

Du kanske märker att fältet C får output (12,) och inte (12,1) eller (1,12). Detta är för att poängtera att det inte är ett tvådimensionellt fält (till skillnad från B där vi specifikt sagt att vi vill ha ett tvådimensionellt fält med endast ett element per rad).

För att plocka ut element ur ett fält så anges hakparenteser samt elementets index efter fältets variabelnamn, t.ex. C[2] för det tredje elementet i C. Ja, det tredje. Python (och många andra programmeringsspråk) börjar indexeringen från 0, så man måste ha detta i åtanke när man arbetar med fält.

För att plocka ut element från en matris så anges raden och sedan kolonnen för elementet, t.ex. A[1,2]. Anger man endast A[1] så får man ut fältet som ligger på andra positionen i det yttre fältet, dvs. man får ut hela rad 2.

Titta på koden nedan och gissa vad som kommer att skrivas ut. Kör sedan koden och se hur många rätt du fick:

import numpy as np
A=np.array([[5,12,23],[54,78,89],[84,73,40],[13,3,0]])
C = np.array([5,12,23,54,78,89,84,73,40,13,3,0])
print(C[0])
print(C[1])
print(A[1,2])
print(A[1])
In [ ]:
 

För att plocka ut en del av ett fält F kan man ange F[startkolonn:slutkolonn] för att få elementen från och med startkolonnen till (fast utan) slutkolonnen.

För matriser kan du på liknande sätt ange F[startrad:slutrad, startkolonn:slutkolonn].

Titta nu på koden nedan och gissa vad som kommer att skrivas ut. Kör sedan koden och se hur många rätt du fick:

import numpy as np
A=np.array([[5,12,23],[54,78,89],[84,73,40],[13,3,0]])
C = np.array([5,12,23,54,78,89,84,73,40,13,3,0])
print(C[0:3])
print(C[1:4])
print(C[1:1])
print(A[1:2,2])
print(A[0:2,1:2])
print(A[0:3,0:3])
In [ ]:
 

Index kan användas för att ändra på element i fält. Skriver du exempelvis C[1] = 356 så ändras andra elementet i C till 356. Detta går även att göra för hela rader, exempelvis A[0] = [1,1,1] sätter hela första raden till ettor (du måste se till att den vektor du vill skjuta in har exakt så många element som raden dock).

Titta nu på koden nedan och gissa vad som kommer att skrivas ut. Kör sedan koden och se hur många rätt du fick:

import numpy as np
A=np.array([[5,12,23],[54,78,89],[84,73,40],[13,3,0]])
C = np.array([5,12,23,54,78,89,84,73,40,13,3,0])

print(C)
C[2]=356
print(C)

print(A)
A[1]=[1,1,1]
A[1,2]=999
print(A)
In [ ]:
 

För att ange en kolonn från en matris kan du ange tecknet kolon : som radindex för att specificera att du vill ha alla rader (du behöver alltså inte skriva 0:antalrader där, även fast det också går). Så för att exempelvis ändra en hel kolonn kan du skriva:

import numpy as np
A=np.array([[5,12,23],[54,78,89],[84,73,40],[13,3,0]])
#Det nedan är samma som A[0:4,1] =  [-44,-44,-44,-44]
A[:,1] = [-44,-44,-44,-44] 
print(A)
In [ ]:
 

Andra viktiga funktioner:

  • np.sum(C) tar ut summan av elementen i C
  • np.sort(C) sorterar talen i C i storleksordning; hur tror du det blir för en matris?
  • np.random.permutation(C) kastar om talen i C slumpmässigt (permuterar elementen i C); hur tror du det blir för en matris?

Titta återigen på koden nedan och gissa vad som kommer att skrivas ut. Kör sedan koden och se hur många rätt du fick:

import numpy as np
A=np.array([[5,12,23],[54,78,89],[84,73,40],[13,3,0]])
C = np.array([5,12,23,54,78,89,84,73,40,13,3,0])
print(C)
print(np.sum(C))
print(np.sort(C))
print(np.random.permutation(C))

print(A)
print(np.sum(A))
print(np.sort(A))
print(np.random.permutation(A))
In [ ]:
 

Plotta linjer och punkter

Eftersom vi inte har oändligt många punkter sparade i våra fält så kan vi egentligen inte rita krökta kurvor. Det som händer när man ritar en graf i Python är som när man löser "prick till prick", man drar raka streck mellan alla prickar på pappret och får till slut en figur från sina linjer. Har man tillräckligt många prickar ser det till slut ut som en krökt kurva om man är på rätt avstånd. Det vi ritar kallas ett polygontåg.

Vi börjar med att rita ett linjestycke. För ett linjestycke behöver vi bara ange två punkter, sedan drar Python en linje mellan dem. Man anger dock x-koordinaterna i ena facket för plot-funktionen och y-koordinaterna i andra, vilket kanske känns förvirrande i början (detta är för att man endast ska ha två fack, inte ett fack per punkt).

För att rita måste vi importera funktioner från matplotlib.pyplot, det gör vi som vanligt högst upp.

För att rita en linje från $(0,2)$ till $(1,3)$ skriver vi alltså:

import matplotlib.pyplot as plt
plt.plot([0,1],[2,3])
plt.show()
In [ ]:
 

Vi behöver dock inte begränsa oss till linjer, vi kan exempelvis rita detta (gissa hur plotten kommer att se ut innan du kör koden):

import matplotlib.pyplot as plt
x = [0,1,2,3,4]
y = [2,3,2,3,2]
plt.plot(x,y)
plt.show()
In [ ]:
 

Om första och sista x-koordinaten resp. y-koordinaten är samma (dvs. första och sista talen i vektorn x resp. y är samma) så kommer polygontåget att bilda en (sluten) polygon.

Vad blir detta för figur?

import matplotlib.pyplot as plt
x = [0,1,2,0]
y = [2,3,2,2]
plt.plot(x,y)
plt.show()
In [ ]:
 

Du kan även välja färg på din figur genom att skriva in färgen efter y-koordinaterna i plot-kommandot, så här: plt.plot(x,y,'r') för att rita med röd färg.

Kör help(plt.plot) och rulla ner till **Colors** för att se vad du ska skriva för att rita med svart färg och rita sedan samma figur som ovan fast med svart färg:

In [ ]:
 

Vill du endast rita ut punkterna utan att dra streck mellan dem skriver du 'o' efter y-koordinaterna (strängen efteråt kan innehålla både färg och form samtidigt), t.ex.

import matplotlib.pyplot as plt
x = [0,1,2]
y = [2,3,2]
plt.plot(x,y,'ro')
plt.show()
In [ ]:
 

Genom att plotta fler saker i rad kan du kombinera plotter för att få fram mer avancerade figurer. Gissa vad detta blir och rita det sedan:

import matplotlib.pyplot as plt
x = [0,1,2,0]
y = [2,3,2,2]

plt.plot(x[0:3],y[0:3],'ro')
plt.plot(x,y)
plt.show()
In [ ]:
 

Med tillräckligt många punkter kan vi skapa en krökt kurva

import matplotlib.pyplot as plt

x=[0 ,0.08046657 ,0.16041128 ,0.23931566 ,0.31666799 ,0.39196661 ,0.46472317 ,0.53446583 ,0.60074226 ,0.66312266 ,0.72120245 ,0.77460496 ,0.82298387 ,0.8660254 ,0.90345043 ,0.93501624 ,0.96051811 ,0.97979065 ,0.99270887 ,0.999189 ,0.999189 ,0.99270887 ,0.97979065 ,0.96051811 ,0.93501624 ,0.90345043 ,0.8660254 ,0.82298387 ,0.77460496 ,0.72120245 ,0.66312266 ,0.60074226 ,0.53446583 ,0.46472317 ,0.39196661 ,0.31666799 ,0.23931566 ,0.16041128 ,0.08046657 , 0]

y=[0 ,0.00324269 ,0.01294974 ,0.02905818 ,0.05146356 ,0.08002056  ,0.11454397 ,0.15480991 ,0.20055724 ,0.25148925 ,0.30727565 ,0.36755462 ,0.43193525 ,0.5 ,0.57130744 ,0.64539511 ,0.72178254 ,0.79997431  ,0.87946332 ,0.95973406 ,1.04026594 ,1.12053668 ,1.20002569 ,1.27821746 ,1.35460489 ,1.42869256 ,1.5 ,1.56806475 ,1.63244538 ,1.69272435  ,1.74851075 ,1.79944276 ,1.84519009 ,1.88545603 ,1.91997944 ,1.94853644 ,1.97094182 ,1.98705026 ,1.99675731 ,2]

plt.plot(x,y)
plt.show()

Kör detta nedan för att se vad som händer. Det är dock lite opraktiskt att skriva in koordinater för hand, så vi ska se hur vi kan rita figurer utan att explicit ange koordinaterna.

In [ ]:
 

Elementvisa operationer

För att bland annat kunna skapa våra y-koordinater i plottar vill vi kunna utföra aritmetiska operationer på många tal i ett fält samtidigt, s.k. elementvisa operationer. När vi definierar våra fält med hjälp av np.array så kommer Python att förstå att vi vill utföra operationerna elementvis, så vi behöver oftast inte tänka på detta.

Om exempelvis x=np.array([0,1,2,3]) och y=np.array([2,3,4,5]) så kommer x+y ge [2,4,6,8] och y-x ge [2,2,2,2]

Titta på koden nedan och gissa vad som kommer att skrivas ut. Kör sedan koden och se hur många rätt du fick:

import numpy as np

x=np.array([0,1,2,3])
y=np.array([2,3,4,5])

print( 2 * x + y )
print( 3 + x - y )
print( x * y )
print( x / y )
print( y**x )
In [ ]:
 

Som du ser förstår även Python att ett tal multiplicerat med en vektor innebär att det talet ska multipliceras med varje element i vektorn.

Plotta med hjälp av elementvisa operationer

Vi kan nu kombinera det vi lärt oss om elementvisa operationer och plottar för att rita grafer till funktioner.

Säg att vi kör x = np.linspace(-5,5,100), då skapas en vektor med 100 x-värden mellan -5 och 5, dvs. x = [ -5, -4.8989899, -4.7979798, ... 4.7979798, 4.8989899, 5 ].

Ifall vi nu skriver y = x**2 - 3 så tas varje element i x och upphöjs med 2 och 3 dras sedan ifrån. Vi får alltså y = [22, 21.00010203, 20.02061014, ..., 20.02061014, 21.00010203, 22].

Vi har därför fått våra y-koordinater som parvis hör ihop med våra x-koordinater. När linjer dras mellan dessa koordinater får vi därför grafen till $y = x^2-3$

Kör detta nedan för att se att det fungerar:

import numpy as np
import matplotlib.pyplot as plt

# Skapa 100 punkter mellan -5 och 5
x = np.linspace(-5,5,100) 
# Beräkna "upphöjt med 2, minus 3" för varje element i x.
y = x**2 - 3; 
# Rita
plt.plot(x,y)
In [ ]:
 

Modulen numpy innehåller även funktionerna sin, cos, tan, log, ... vilka alla kan utföras elementvis på en vektor. Du kan därför exempelvis rita grafen för $x\cdot \sin(x) + 1$ genom att skriva:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-15,15,100) 
y = x*np.sin(x)+1
plt.plot(x,y)

Prova detta nedan

In [ ]:
 

Försök nu själv att rita följande figurer på intervallet $(1,7)$. Glöm inte att du behöver importera numpy och exempelvis skriva np.sin för sinus.

Uttryck                     Färg
$ \log_{10}(x) $ Röd
$ \ln(4x)+\sin(x)$ Blå
$ \frac {3\tan(\frac{x}{6})}{2} - \frac{x^2}{100} $ Svart

Resultatet ska se ut så här: plot av tre funktioner

In [ ]:
 

För att lättare kunna läsa av funktionsvärdena finns kommandot plt.grid() som lägger till ett rutnät över figuren. Testkör denna kod som ritar $\sin(x)$ på intervallet $[0,2\pi]$

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi)
y = np.sin(x)

plt.plot(x,y)
plt.grid()
In [ ]:
 

Diskontinuitet

Se upp för diskontinuiteter! Eftersom Python faktiskt bara stegar igenom punkterna "utan att tänka" så kommer du få en linje mellan punkterna där diskontinuiteten sker.

Kör exempelvis denna kod

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, np.pi)
y = np.tan(x)

plt.plot(x,y)
plt.grid()
In [ ]:
 

Den sista punkten till vänster om diskontinuiteten är strax över 30 och nästa punkt är under -30, så Python drar bara en linje mellan dessa punkter utan att ta hänsyn till vad som händer däremellan.

För att åtgärda detta får vi plotta på två intervall separat:

import numpy as np
import matplotlib.pyplot as plt

x1 = np.linspace(0, np.pi / 2 - 0.01) # Sluta lite innan pi/2
x2 = np.linspace(np.pi / 2 + 0.01, np.pi) # Börja lite efter pi/2

plt.plot(x1,np.tan(x1),'b')
plt.plot(x2,np.tan(x2),'b')

plt.grid()
In [ ]:
 

Det är inte bara funktionskurvor som kan plottas utan även andra kurvor som kan beskrivas med en parameter. Detta ligger lite utanför ramen för denna kurs, men som ett smakprov kan du pröva följande kommandon och försöka förstå vad som händer

import numpy as np
import matplotlib.pyplot as plt

v=np.linspace(0,2*np.pi)
x=np.cos(v)
y=np.sin(v)
plt.plot(x,y)
plt.axis('equal')
In [ ]:
 

Det sista kommandot plt.axis('equal') är ett mycket användbart kommando som ser till att sidförhållandet är 1:1 i figuren. Prova att köra koden ovan igen utan sista raden för att se skillnaden.

Definiera egna funktioner

Vi kan definiera våra egna funktioner i Python. Detta kan göra koden tydligare och enklare att arbeta med.

En funktion tar någon eller några inputparametrar, utför beräkningar och skickar vanligen ut någonting när beräkningarna är färdiga.

Vi definierar en funktion genom att använda def kommandot och det används så här:

def funktionens_namn(funktionens_input):
    funktionens_definition
    return funktionens_output

Här är det jätteviktigt att du hoppar in ett visst antal mellanslag (eller tab) på raderna som anger funktionens definition samt att du har lika många antal mellanslag (eller tab) på alla rader som är inskjutna.

En annan viktig regel är att du tydligt specificerar vad som spottas ut av funktionen. Detta görs med kommandot return.

Ett exempel på en enkel funktion är

def min_fun1(m):
    ut = 2 * m - m / 3
    return ut

När denna funktion är definierad kan den köras med hjälp av exempelvis min_fun1(5) för att beräkna $2\cdot 5 - \frac {5}{3}$

Prova själv att definiera följande funktioner och se ifall du får rätt värde när du kör print(fun(1))

f(x)                 f(1)
$ 3x+1 $ 4
$ x^2 - 5 $ -4
$ x^3-x+1 $ 1
In [ ]:
 

Det är mycket viktigt att komma ihåg att variabelnamnet som används för funktionens input är oberoende av ifall det finns en variabel med samma namn utanför funktionen. Raderna inom funktionen behandlar den angivna inputvariabeln som en "okänd" variabel fram tills man kallar på funktionen med en given input och det värdet som ges som input används då.

Se t.ex. denna kod:

x = 1

def fun(x):
   y = 100 * x
   return y

print(fun(4))

Här får vi output 400 och inte 100 även om vi har en variabel som heter x och har värde 1 i minnet.

Notera att man även kan definiera enklare funktioner på en enda rad genom att skriva

def fun(x): return funktionens_output

Exemplet ovan skulle i så fall bli:

def fun(x): return 100*x

Derivator och differenskvoter

Vi avslutar dagen med att prata om hur man kan arbeta med derivator i Python.

Vi kan studera gränsvärde av en funktion i en punkt genom att undersöka funktionsvärden nära punkten. Antag t.ex. att vi är intresserade av gränsvärdet av

$$ f(x) = \frac{\sin(x)}{x}$$

då $x\rightarrow 0$. Denna funktion är ju inte definierad då $x=0$ (varför?), men vi kan få en uppfattning om gränsvärdet genom att studera funktionsvärdet nära $x=0$

Detta kan antingen göras med en plot:

import numpy as np
import matplotlib.pyplot as plt

def sindivx(x):
   return np.sin(x)/x

h = 0.05
x1 = np.linspace(-1, 0 - h)
x2 = np.linspace(0 + h, 1)

y1=sindivx(x1)
y2=sindivx(x2)

plt.plot(x1,y1,'b')
plt.plot(x2,y2,'b')

Eller genom att titta på det faktiska funktionsvärdet:

import numpy as np

def sindivx(x):
   return np.sin(x)/x

h = 0.05
x1 = 0 - h
x2 = 0 + h

print(sindivx(x1))
print(sindivx(x1))

Notera att vi har return på samma rad som beräkningen för $\frac{\sin(x)}{x}$. Detta går jättebra så länge vi bara gör en beräkning som är på en rad. Notera även att vi kan kalla på funktioner från importerade moduler när vi definierar våra funktioner.

In [ ]:
 

Resultatet i föregående kommandoruta indikerar att gränsvärdet kanske är $1$, men vi får vara försiktiga! Vi har faktiskt inte bevisat det.

Det skulle ju kunna vara så att funktionen betedde sig väldigt märkligt inom intervallet $[-0.05,0.05]$. Därför krävs även ordentliga matematiska resonemang för att vara färdig.

En typ av gränsvärde, som ofta är av speciellt intresse, är ju derivata. Om man vet att derivatan av en funktion existerar i en viss punkt så kan man få en god approximation av dess värde med hjälp av derivatans differenskvot.

$$\frac{f(x+h)-f(x)}{h}$$

Vi kan beräkna differenskvoten i många punkter på ett intervall och då få en god bild av funktionens derivata.

Kör t.ex. koden i rutan nedan för att få grafen som approximerar derivatan till $x\sin(x)$ på intervallet $[0,4]$

import numpy as np
import matplotlib.pyplot as plt

def f(x):
 return x*np.sin(x)

x = np.linspace(0,4);
h = 0.0001

Df = (f(x+h)-f(x))/h

plt.plot(x,Df)
In [ ]:
 

Att kunna derivera är användbart när man studerar ideala modeller av "verkligheten". I praktiken är dock inte verkligheten så exakt och ofta har man inte heller tillräcklig kunskap om eventuella funktioner som beskriver det vi studerar. Ofta har man istället bara tillgång till mätdata från den process man studerar. För mätdata som ligger nära varandra i tid och rum kan man dock på olika sätt uppskatta derivatan.

Ett praktiskt exempel

Antag att vi vill studera sträckan $s$ ett föremål förflyttat sig efter en viss tid $t$, och att vi mätt upp att föremålet förflyttat sig sträckorna $s_1, s_2$ vid två närliggande tidpunkter $t_1, t_2$.

Vi kan då beräkna medelhastigheten på intervallet genom differenskvoten $\frac{s_2-s_1}{t_2-t_1}$. Eftersom avståndet mellan tidpunkterna är relativt litet så ger denna differenskvot också en god uppskattning av den momentana hastigheten i bl.a. $t_1$ dvs. derivatan $s'(t_1)$.

Om t.ex. $s_1=3.42m$, $s_2=3.49m$, $t_2=1.03s$ och $t_1=0.92s$, så får vi att hastigheten är

$$v=\frac{3.49-3.42}{1.03-0.92}\approx0.636 ~~(m/s)$$

Om vi har uppmätta sträckor vid många tidpunkter så kan vi hantera det effektivt med elementvisa beräkningar på vektorer.

Säg t.ex. att vi har sträckor och motsvarande tidpunkter i vektorer på följande sätt:

import numpy as np

s=np.array([3.42, 3.49, 3.52, 3.54, 3.55, 3.57, 3.62, 3.69]);
t=np.array([0.92, 1.03, 1.11, 1.19, 1.31, 1.42, 1.54, 1.61]);

För att elementvis beräkna alla differenser $s_2-s_1$, $s_3-s_2$, $s_4-s_3$, ... kan vi skriva

s[1:np.size(s)] - s[0:np.size(s)-1]

Så, varför fungerar detta?

Först skapar kommandot s[1:np.size(s)] en vektor med det andra elementet till och med sista elementet från s. Kommandot s[0:np.size(s)-1] skapar sedan en annan vektor med det första elementet till och med det näst sista från s. Tar vi sedan differensen mellan dessa två vektorer får vi ju $s_2-s_1$, $s_3-s_2$, $s_4-s_3$, ...

Läs inte vidare förrän du förstår vad det är som händer här. Det är viktigt för laborationen senare.

På samma sätt kan vi göra för t och vektorn med alla hastigheter blir därför

v = ( s[1:np.size(s)] - s[0:np.size(s)-1] ) / ( t[1:np.size(t)] - t[0:np.size(t)-1] )

Hastighetsvektorn innehåller ett element mindre än s och t eftersom det består av differenser, så ifall vi vill plotta hastighetsvektorn över tid måste vi välja ifall vi vill positionera hastigheterna vid de tidigare eller senare tidpunkterna vi använde när vi beräknade tidstifferensen. Vi kan alltså antingen rita grafen med

plt.plot(t[0:np.size(t)-1],v)

vänstra tider

eller med

plt.plot(t[1:np.size(t)],v)

högra tider

beroende på vad vi väljer. Det är alltså bara tidsaxeln som ändras. Med hjälp av detta kan vi exempelvis säga att den högsta hastigheten som sker då $t$ ligger på intervallet $[1.54, 1.61]$ eftersom det var dessa punkter vi använde när vi beräknade den högsta hastigheten.

Prova nu att skriva ihop koden som behövs för att generera plotterna som visas ovan.

OBS! Jupyter Notebook inaktiverar vissa funktioner för plotter, så ifall du exempelvis vill Zooma in i en plot kan du lägga till %matplotlib notebook någonstans i koden för att ta fram knappen för inzoomning.

Här är alltså koden vi ska köra för att göra allt som står ovan (och ha förstoringsglaset aktiverat):

# Denna rad aktiverar förstoringsglaset i Jupyter Notebook
%matplotlib notebook
import numpy as np

s=np.array([3.42, 3.49, 3.52, 3.54, 3.55, 3.57, 3.62, 3.69]);
t=np.array([0.92, 1.03, 1.11, 1.19, 1.31, 1.42, 1.54, 1.61]);

v = ( s[1:np.size(s)] - s[0:np.size(s)-1] ) / ( t[1:np.size(t)] - t[0:np.size(t)-1] )
plt.plot(t[0:np.size(t)-1],v)
In [ ]: