Funksjonsmusikk

<div class="alert alert-block alert-danger">

Info til lærer

Tanken med dette opplegget er å representere funksjoner med lyd, og å la elevene utforske egenskaper til ulike funksjoner. Elevene skal se på kjennetegn ved ulike typer funksjoner, og får mulighet til å leke seg med lydbildene de gir.

Utformingen av opplegget legger ikke opp til at elevene skal bygge kode, men endre på parametere i ferdig kode for å generere ulike funksjoner. Dette kan læreren selvsagt endre etter nivået til klassen.

<div class="alert alert-block alert-warning">

Relevante kompetansemål i 1P

Mål for opplæringen er at eleven skal kunne

  • bruke digitale verktøy i utforsking og problemløsing knyttet til egenskaper ved funksjoner, og diskutere løsningene
</div>
<div class="alert alert-block alert-warning">

Relevante kompetansemål i 1T

Mål for opplæringen er at eleven skal kunne

  • utforske og beskrive egenskapene ved polynomfunksjoner, rasjonale funksjoner, eksponentialfunksjoner og potensfunksjoner
</div>
<img src="fx_x+1.png" style="float: right;" width="450"/>

En funksjon er en sammenheng mellom to forskjellige mengder, slik at hvert element i den ene mengden (definisjonsmengden) har nøyaktig ett tilhørende element i den andre mengden (verdimengden).

Et eksempel på en funksjon er f(x)=x+1f(x) = x + 1, som er slik at for hvert tall xx vi "sender inn" i funksjonen, vil vi få ut et tall som er nøyaktig én mer enn xx.

Det er også mange ulike måter man kan visualisere funksjoner, og de vanligste er ved som funksjonsuttrykk og grafisk. Til høyre er det en grafisk framstilling av f(x)=x+1f(x) = x + 1.

<div class="alert alert-block alert-success">

I dette programmet skal vi se på en tredje måte å utforske funksjoner, nemlig som lyd. Vi vil lage et program som kan ta inn en funksjon og gjøre høye tall om til lyse toner, og lave tall til mørke toner.

</div>

Aller først importerer vi bibliotekene vi trenger for å kjøre de ulike delene av programmet:

1 
2
3
4
import numpy as np                  # Diverse matematikkting vi trenger til programmet
import matplotlib.pyplot as plt     # Brukes til plotting
from scipy.io.mp3file import write  # Brukes til å lage lydfiler
from IPython.display import Audio   # Brukes til å spille av lydfiler
<div class="alert alert-block alert-info">

Oppgave 1

Hør på lydklippene under.

<br>

a) Hvordan tenker du grafene til funksjonene ser ut? Lag en skisse til hver lydfil.

<br>

b) Prøv å bestemme hva slags funksjon hver av de to lydklippene viser - lineær, polynom, eksponentiell, rasjonal, eller kanskje noe annet?

</div>
<div class="alert alert-block alert-danger">

Info til lærer

Dette passer også ypperlig å ta felles. Klassen hører en lydfil felles og alle jobber i 1 min med å diskutere og tegne grafen før det tas i felleskap.

[1]: 
1 
2
3
from IPython.display import Audio

Audio('funksjon1.mp3')      # Hvordan ser denne funksjonen ut?
[1]: 
[2]: 
1 
Audio('funksjon2.mp3')      # Hvordan ser denne funksjonen ut?
[2]: 
[3]: 
1 
Audio('funksjon3.mp3')      # Hvordan ser denne funksjonen ut?
[3]: 
[4]: 
1 
Audio('funksjon4.mp3')      # Hvordan ser denne funksjonen ut?
[4]: 

Nå skal vi bygge opp et program som kan lage slike lydfiler.

Vi lager en funksjon

For å i det hele tatt ha noe å høre på, må vi først lage en funksjon. Kodebiten under lager funksjonen f(x)=x2+x3f(x) = x^2 + x - 3 og plotter den på intervallet [5,5][-5, 5].

1 
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return x**2 - 2*x - 3

x = np.linspace(-5, 5, 1000)
y = f(x)

plt.plot(x, y, 'r')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.show()
<div class="alert alert-block alert-info">

Oppgave 2

Hvordan tenker du funksjonen vil høres ut når vi spiller den av?

</div>
<div class="alert alert-block alert-danger">

Info til lærer 1P

For å gjøre programmet mindre komplekst kan du gjerne vurdere å slette fram til overskriften "Fra funksjon til musikk".

</div>

Frekvens og toner

<img src="frekvens_b-lengde.png" style="float: right;" width="500"/>

I dette programmet vil vi la høye yy-verdier tilsvare lyse toner, og lave tilsvare mørke. Når vi spiller av figuren over vil vi derfor starte på en lys tone som blir mørkere og mørkere helt til den når bunnpunktet, og deretter lysere og lysere helt til den er ferdig. Men for at programmet skal få dette til, må vi først endre litt på yy-verdiene.

<div class="alert alert-block alert-success">

Toner er lydbølger og måles antall svingninger per sekund. De har enheten s1s^{-1}, som også kalles "hertz" (Hz). Antall hertz forteller oss frekvensen til en tone, og en høy frekvens vil gi en høy/lys tone, mens en med lavere frekvens er dypere.

</div>

denne siden kan du høre hvordan ulike frekvenser høres ut, og se hvilke toner de tilsvarer.

I funksjonen vi lagde over er den laveste yy-verdien vi får -4, og den høyeste er 32. Men vi kan ikke ha et negativt antall svingninger per sekund, og på lenken over vil du også se at en frekvens på 32 Hz ikke er hørbart for oss mennesker. Derfor er vi nødt til å skalere verdiene våre for at det skal gi mening. Det vil si at vi må endre alle verdiene slik at de har samme forhold til hverandre og ligger i et hørbart intervall.

Skalering

For å gjennomføre skaleringen, må vi først bestemme oss for hva som skal være den lyseste og den mørkeste tonen i funksjonsmelodien vår. Vi velger her å la den mørkeste tonen være A3 på 220 Hz, og den lyseste A7 på 3520 Hz, som gir oss en melodi som går over fire oktaver.

Vi kan bruke denne funksjonen til å skalere:

yny=yyminymaxymin(tmaxtmin)+tmin y_{ny} = \frac{y - y_{min}}{y_{max} - y_{min}} \cdot (t_{max} - t_{min}) + t_{min}

Her bruker vi øvre og nedre grense for våre yy-verdier, og øvre og nedre grense for verdiene vi vil at de skal ha i stedet.

  • yy er en yy-verdi vi får ut av funksjonen f(x)f(x). Dette tallet kan være hvilket som helst av yy-ene våre.
  • yminy_{min} og ymaxy_{max} er nedre og øvre grensene for yy-verdiene vi får fra funksjonen f(x)f(x). For vår funksjon er det -4 og 32.
  • tmint_{min} er den mørkeste tonen vi vil få ut, og tmaxt_{max} er den lyseste. Vi har valgt 220 og 3520.
  • ynyy_{ny} er den skalerte verdien til yy.
<div class="alert alert-block alert-info">

Oppgave 3

Hva blir omtrent frekvensen i nullpunktene til funksjonen f(x)=x2+x3f(x) = x^2 + x - 3 når vi bruker samme intervall som over, og bestemmer at alle tonene skal være mellom 220 og 3520 Hz?

</div> <div class="alert alert-block alert-danger">

Løsning (slett dette)

yny=0(4)32(4)(3520220)+220=4363300+220586.67 y_{ny} = \frac{0 - (-4)}{32 - (-4)} \cdot (3520 - 220) + 220 = \frac{4}{36} \cdot 3300 + 220 \approx 586.67

Tonen er omtrent en D5.

</div>

Vi definerer funksjonen skaler(y), som tar inn en yy-verdi og returnerer den skalerte verdien. Funksjonene max() og min() er innebygde funksjoner som finner den største verdien i ei liste/en array.

1 
2
3
4
5
6
7
8
9
def skaler(y):
    y_max = max(y)
    y_min = min(y)
    t_max = 3520
    t_min = 220
    
    y_skalert = (y - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    
    return y_skalert

Hvis plotter de skalerte yy-verdiene ser vi at grafen har samme form, men at verdiene er mellom ca. 250 og 1750 (i virkeligheten 220 og 1760), slik vi ønsker. Pass på å kjøre kodeboksen over før den under.

1 
2
3
4
5
6
7
8
9
10
11
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-5, 5, 1000)
y = f(x)
y = skaler(y)

plt.plot(x, y, 'r')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.show()

Fra funksjon til musikk

Siden lyd er bølger, må vi til slutt også lage en funksjon som gjør frekvensene vi har regnet ut om til en bølgebevegelse. Denne funksjonen kan se slik ut:

def lag_bolge(frekvens):
    samplerate = 44100
    amplitude = 4096

    bolge = amplitude * np.sin(2 * np.pi * np.cumsum(frekvens/samplerate))
    
    return bolge

samplerate, eller "samplingsrate", bestemmer hvor mange datapunkter vi skal ha per sekund. Samplingsraten må være minst det dobbelte av den høyeste frekvensen i lydklippet for å få en riktig gjengiving av lyden. Siden mennesker kan høre lyder opp til ca. 20'000 Hz, bør samplingsraten være minst 40'000 Hz, og det er vanlig å bruke 44'100 Hz. I vårt eksempel får vi bare lyder opp til 3520 Hz, så her hadde det holdt med en samlplingsrate på minst 7040 Hz - men hvis du reduserer raten til 7040 og øker t_max, vil du få uventede og hakkete melodier ut, så det er like greit å valge en høy samplerate.

Når vi definerer variabelen bolge lager vi selve bølgebevegelsen. Vi bruker en sinus-funksjon til å lage bølga, og ved å hente inn frekvensen til de skalerte yy-verdiene får vi en bølge som gjør alle frekvensene i input-funksjonen hørbare.

Nå skal vi sette alt dette sammen:

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
import numpy as np
import matplotlib.pyplot as plt
from scipy.io.mp3file import write
from IPython.display import Audio

samplerate = 44100

# Definerer funksjonen
def f(x):
    return x**2 - 2*x - 3

# Skalerer funksjonen til hørbare frekvenser
def skaler(y):
    y_max = max(y)
    y_min = min(y)
    t_max = 3520
    t_min = 220
    
    y_skalert = (y - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    
    return y_skalert

# Lager bølge av frekvensene
def lag_bolge(frekvens):
    samplerate = 44100
    amplitude = 4096

    bolge = amplitude * np.sin(2 * np.pi * np.cumsum(frekvens/samplerate))
    
    return bolge

start = -5      # Startverdi for x
slutt = 5       # Sluttverdi for x
tid = 5         # Antall sekunder melodien skal vare

x = np.linspace(start, slutt, int(samplerate * tid))
y = f(x)

# Tegner grafen til funksjonen
plt.plot(x, y, 'r')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.show()

# Bruker skaleringsfunksjonen på y-verdiene og bygger melodien
y = skaler(y)
melodi = lag_bolge(y)

write('funksjonsmelodi.mp3', samplerate, melodi.astype(np.int16))
Audio('funksjonsmelodi.mp3')
<div class="alert alert-block alert-info">

Oppgave 4

a) Hva skjer når du endrer amplituden? Hvordan påvirker det lyden?

<br>

b) Få programmet til å spille melodien til f(x)=x32xf(x) = x^3 - 2x på intervallet [2,2][-2, 2].

<br>

c) Få programmet til å spille melodien til f(x)=1xf(x) = \frac{1}{x} på intervallet [1,1][-1, 1]. Hva forventer du å høre? Hva hører du? Snakk med sidemannen din om hvorfor dere tror melodien blir som den blir.

<br>

d) Prøv å endre på funksjonen f(x) eller variablene start, slutt, t_min og t_max for å teste ut andre funksjoner, xx-intervaller og tonehøyder.

</div>
<div class="alert alert-block alert-success">

Tips

Numpy-biblioteket vi importerte i starten inneholder mange matematiske funksjoner og konstanter som kan være greie å kjenne til. Her er en oversikt over noen vanlige, i tilfelle du har lyst til å lage funksjoner med dem:

MatematiskProgrammering med NumpyBeskrivelse
π\pinp.piDen matematiske konstanten π3.14\pi \approx 3.14
eenp.exp(1)Den matematiske konstanten e2.72e \approx 2.72
exe^xnp.exp(x)ee opphøyd i xx
x\sqrt{x}np.sqrt(x)Kvadratroten til xx
ln(x)\ln(x)np.log(x)Den naturlige logaritmen til xx
sin(x)\sin(x)np.sin(x)Sinus til xx
cos(x)\cos(x)np.cos(x)Cosinus til xx
</div>

Nullpunkter

<img src="x2-2_original.png" style="float: right;" width="400"/>

Til høyre ser du grafen til funksjonen f(x)=x22f(x) = x^2 - 2, og som vi ser har den to nullpunkter.

Det er lett å se nullpunktene til en funksjon, men ikke like åpenbart hvordan man skal høre dem - men det skal vi prøve på nå.

<div class="alert alert-block alert-info">

Oppgave 5

Diskuter med makkeren din - hva skjer med funksjonsverdien f(x)f(x) i nullpunktene til funksjonen?

Hva er funksjonsverdien rett til venstre og høyre for nullpunktene?

</div>

I nullpunktene til f(x)=x22f(x) = x^2 - 2 skifter f(x)f(x) mellom å være positiv og negativ. Siden vi ikke kan ha "negativ lyd", må vi finne en alternativ måte å vise at lyden "skifter fortegn".

Absoluttverdi

Absoluttverdien av et tall er tallet med positivt fortegn. For eksempel er absoluttverdien til 5-5 lik 55, og absoluttverdien til 55 er også 55.

Vi skriver absoluttverdien til et tall aa som a|a|. Altså kan vi skrive 5=5|-5| = 5 og 5=5|5| = 5

I Python bruker vi funksjonen abs() for å regne absoluttverdien til tall:

[18]: 
1 
2
3
a = int(input("Skriv et tall: "))

print("Absoluttverdien til", a, "er", abs(a))
Skriv et tall: -5
Absoluttverdien til -5 er 5
<img src="x2-2_absolutt.png" style="float: right;" width="400"/>

Til høyre ser du grafen til absoluttverdien til f(x)f(x), altså f(x)=x22f(x) = |x^2 - 2|.

<div class="alert alert-block alert-info">

Oppgave 6

Hva er likt mellom grafen over og den til høyre? Hva er ulikt?

Hvordan tenker du funksjonen høres ut?

</div> <div class="alert alert-block alert-info">

Oppgave 7

Endre koden under slik at du får et program som kan spille av absoluttverdien til funksjoner ved å bytte ut spørsmålstegnene i linje 14, y = ???.

Du finner et forslag til kode lenger ned.

</div>
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
import numpy as np
from scipy.io.mp3file import write
from IPython.display import Audio

samplerate = 44100

def f(x):
    return x**2 - 2

def skaler(y):
    y_max, y_min = max(y), min(y)
    t_max, t_min = 3520, 220
    y_skalert = (y - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    return y_skalert

def lag_bolge(frekvens):
    samplerate = 44100
    amplitude = 4096
    bolge = amplitude * np.sin(2 * np.pi * np.cumsum(frekvens/samplerate))
    return bolge

start = -5      # Startverdi for x
slutt = 5       # Sluttverdi for x
tid = 5         # Antall sekunder melodien skal vare

x = np.linspace(start, slutt, int(samplerate * tid))

# ----------
# HER MÅ DU ENDRE PROGRAMMET:
y = ???         # Hva må stå her for at vi skal få absoluttverdien til funksjonen?
y = skaler(y)
melodi = lag_bolge(y)
# ----------

write('funksjonsmelodi.mp3', samplerate, melodi.astype(np.int16))
Audio('funksjonsmelodi.mp3')
<div class="alert alert-block alert-info">

Oppgave 8

Bruk programmet til å bestemme hvor mange nullpunkt disse funksjonene har i på intervallet [1,3][-1, 3]:

<br>

a)  f(x)=2x2+5x \ f(x) = -2x^2 + 5x

<br>

b)  f(x)=x1 \ f(x) = x - 1

<br>

c)  f(x)=x33x2+2 \ f(x) = x^3 - 3x^2 + 2

<br>

d)  f(x)=2x2 \ f(x) = 2^x - 2

</div>
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
import numpy as np
from scipy.io.mp3file import write
from IPython.display import Audio

samplerate = 44100

def f(x):
    return x**2 - 2

def skaler(y):
    y_max, y_min = max(y), min(y)
    t_max, t_min = 3520, 220
    y_skalert = (y - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    return y_skalert

def lag_bolge(frekvens):
    samplerate = 44100
    amplitude = 4096
    bolge = amplitude * np.sin(2 * np.pi * np.cumsum(frekvens/samplerate))
    return bolge

start = -1      # Startverdi for x
slutt = 3       # Sluttverdi for x
tid = 5         # Antall sekunder melodien skal vare

x = np.linspace(start, slutt, int(samplerate * tid))

y = abs(f(x))
y = skaler(y)
melodi = lag_bolge(y)

write('funksjonsmelodi.mp3', samplerate, melodi.astype(np.int16))
Audio('funksjonsmelodi.mp3')
<div class="alert alert-block alert-info">

Oppgave 9

Diskuter med makkeren din: Kan dere tenke dere noen situasjoner der det er problematisk å bruke dette programmet til å avgjøre om en funksjon har et eller flere nullpunkter i et intervall?

</div>
<div class="alert alert-block alert-danger">

Info til lærer:

Et nærliggende svar er selvsagt at det alltid vil by på vansker å bruke lyd framfor bilde/regning til å bestemme nullpunkter, men absoluttverdimetoden kan by på flere problemer i noen tilfeller, nemlig når funksjonen:

  • ikke har et nullpunkt
  • har nullpunkte(er) som også er ekstremalpunkt
  • har nullpunkt(er) i start- og/eller sluttverdien til intervallet

Da vil det være vanskelig å avgjøre om den laveste verdien er et nullpunkt eller bare en minimumsverdi.

</div>

Lyd i stereo - en funksjon i hvert øre

<img src="mono_stereo.png" style="float: right;" width="450"/>

Når du spiller av funksjonsmelodiene med headset/ørepropper hører du samme melodi i hvert øre. Vi kaller dette monofoni, som er at det kun går ut ett signal til alle høytalerne. Monofoni forkortes ofte til "mono".

Lyd kan også spilles av i "stereo" (stereofoni), som har to eller flere utgående signaler. Lyd med mer enn to utgående signaler kan også kalles "surrond".

Lydinnspilling i stereo ble populært på 70-tallet, og mange musikere eksperimenterte med den nye opptaksformen, ved å for eksempel ha ulike instrumenter i hver kanal. Prøv å høre på Here Comes The Sun av The Beatles med ørepropper mens du bytter på hvilken du har i øret - det høres ganske ulikt ut.

Nå skal vi utvide programmet vårt til å returnere stereolyd, slik at vi kan få en funksjon i hvert øre. Det er faktisk bare tre ting vi må endre på/tilføye for å få til dette:

  1. Først må vi lage en ekstra funksjon, som vi kan kalle g(x):
def g(x):
    return x**2 - 2
  1. Så må vi lage en ny skaleringsfunksjon. I funksjonen skaler(y) brukte vi max(y) og min(y) for å finne den største og minste yy-verdien til f(x)f(x). Når vi har to funksjoner, må vi passe på å skalere dem likt. Derfor lager vi funksjonen skaler_2(y1, y2), som henter inn yy-ene fra g(x)g(x) og f(x)f(x) og finner felles maksimum og minimum:
def skaler_2(y1, y2):
    y_max = np.max([y1, y2])    # Finner den største verdien fra begge y-ene
    y_min = np.min([y1, y2])    # Finner den minste verdien fra begge y-ene
    t_max = 3520
    t_min = 220
    
    y1_frekvens = (y1 - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    y2_frekvens = (y2 - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    
    return y1_frekvens, y2_frekvens
  1. Etter å ha regnet ut og skalert yy-verdiene står vi igjen med to lister av tall. Det siste vi må gjøre for å få lyden i stereo, er å gjøre disse to listene til hver sin kolonne i lydsignalet som skal ut. Det kan vi gjøre med numpy-funksjonen column_stack():
melodi = np.column_stack([mel_f, mel_g])

Til slutt settes dette sammen med programmet vi hadde fra før:

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
import numpy as np
import matplotlib.pyplot as plt
from scipy.io.mp3file import write
from IPython.display import Audio

samplerate = 44100

# Definerer de to matematiske funksjonene:
def f(x):
    return -x

def g(x):
    return x**2-2

# Lager en ny skaleringsfunksjon som finner felles maksimum og minimum fra to funksjoner
def skaler_2(y1, y2):
    y_max = np.max([y1, y2])
    y_min = np.min([y1, y2])
    t_max = 3520
    t_min = 220
    
    y1_frekvens = (y1 - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    y2_frekvens = (y2 - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    
    return y1_frekvens, y2_frekvens

# Bølgelagingsfunksjonen er den samme som før
def lag_bolge(frekvens):
    samplerate = 44100
    amplitude = 4096
    
    bolge = amplitude * np.sin(2 * np.pi * np.cumsum(frekvens/samplerate))
    
    return bolge

start = -2
slutt = 3
tid = 10

x = np.linspace(start, slutt, int(samplerate * tid))
y_f = f(x)
y_g = g(x)

# Her plottes de to funksjonene i samme koordinatsystem
plt.plot(x, y_f, 'r')
plt.plot(x, y_g, 'b')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.show()

# Bruker skaleringsfunksjonen på y-verdiene fra f og g, og bygger melodien
y_f, y_g = skaler_2(y_f, y_g)

mel_f = lag_bolge(y_f)
mel_g = lag_bolge(y_g)
melodi = np.column_stack([mel_f, mel_g])

write('funksjon_stereo.mp3', samplerate, melodi.astype(np.int16))
Audio('funksjon_stereo.mp3')
<div class="alert alert-block alert-info">

Oppgave 4

Bruk kodeboksen under for å undersøke hvor mange skjæringspunkt disse funksjene har på intervallet [2,2][-2, 2]:

<br>

a)  f(x)=2x,  g(x)=x+0.5\ f(x) = 2x, \ \ g(x) = x + 0.5

<br>

b)  f(x)=0.5x,  g(x)=x21\ f(x) = 0.5x, \ \ g(x) = x^2 - 1

<br>

c)  f(x)=x+1,  g(x)=ex\ f(x) = -x+1, \ \ g(x) = e^x

<br>

d) Velg dine egne funksjoner f(x)f(x) og g(x)g(x) og prøv å høre etter skjæringspunkter

</div>
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
import numpy as np
from scipy.io.mp3file import write
from IPython.display import Audio

samplerate = 44100

def f(x):
    return -x+1

def g(x):
    return np.exp(x)

def skaler_2(y1, y2):
    y_max = np.max([y1, y2])
    y_min = np.min([y1, y2])
    t_max, t_min = 3520, 220 
    y1_frekvens = (y1 - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    y2_frekvens = (y2 - y_min)/(y_max - y_min) * (t_max - t_min) + t_min
    return y1_frekvens, y2_frekvens

def lag_bolge(frekvens):
    samplerate = 44100
    amplitude = 4096
    bolge = amplitude * np.sin(2 * np.pi * np.cumsum(frekvens/samplerate))
    return bolge

start = -2
slutt = 2
tid = 10

x = np.linspace(start, slutt, int(samplerate * tid))
y_f = f(x)
y_g = g(x)

y_f, y_g = skaler_2(y_f, y_g)

mel_f = lag_bolge(y_f)
mel_g = lag_bolge(y_g)
melodi = np.column_stack([mel_f, mel_g])

write('funksjon_stereo.mp3', samplerate, melodi.astype(np.int16))
Audio('funksjon_stereo.mp3')
<div class="alert alert-block alert-danger">

Info til lærer:

Her går det også mulig å diskutere hvordan man kan bruke dette programmet til å bestemme hvor mange nullpunkt en funksjon har i et gitt intervall (nemlig ved å la den ene funksjonen være g(x)=0g(x) = 0).

</div>