Tilbake
5.7
Styresystemer og regulering

5.7 Styresystemer og regulering

Åpen og lukket sløyfe, enkel PID-regulering og automatisering.

35 min
5 oppgaver
StyresystemTilbakekoblingPIDRegulering
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 5 oppgaver

Prosjektarbeid med programmering

Gjennom denne seksjonen har du lært variablar, kontrollstrukturar, funksjonar, lister, filhandtering og visualisering. No er det tid for å setje alt saman i eit prosjektarbeid.

Eit programmeringsprosjekt er meir enn berre koding – det handlar òg om å planleggje, teste, feilsøke og dokumentere arbeidet ditt. Desse ferdigheitene er sentrale i teknologi og forskingslære, og dei speglar korleis profesjonelle utviklarar og forskarar arbeider.

I dette kapittelet lærer du:
- Korleis du planlegg eit prosjekt med pseudokode og flytskjema
- Teknikkar for testing og debugging (feilsøking)
- Korleis du dokumenterer koden din med kommentarar og docstrings
- Korleis du strukturerer eit større program med funksjonar og modular

Etter dette kapittelet vil du ha verktøya du treng for å gjennomføre eit sjølvstendig programmeringsprosjekt frå start til slutt.

Planlegging med pseudokode og flytskjema
Pseudokode er ei uformell skildring av ein algoritme som brukar vanleg språk og enkel struktur. Det er eit mellomsteg mellom ideen i hovudet ditt og den ferdige Python-koden.

Døme – pseudokode for eit analyseprogram:

LES data fra fil
FOR hver måling i data:
    LEGG TIL måling i liste
BEREGN gjennomsnitt
BEREGN standardavvik
HVIS gjennomsnitt > grenseverdi:
    SKRIV advarsel
LAG graf av målingene
LAGRE rapport til fil

Eit flytskjema er ei visuell framstilling av programflyten med standardiserte symbol:
- Oval: Start/slutt
- Rektangel: Prosess (handling)
- Diamant (rombe): Avgjerd (if/else)
- Parallellogram: Inndata/utdata

Fordelar med planlegging:
- Du oppdagar logiske feil før du byrjar å kode
- Det er lettare å dele opp arbeidet i funksjonar
- Andre kan forstå planen din og gi tilbakemelding
- Du slepp å skrive om store delar av koden undervegs

Dei fire fasane i eit programmeringsprosjekt

Eit godt prosjekt følgjer desse fasane:

1. Planlegging (20 % av tida)
- Definer problemet tydeleg: Kva skal programmet gjere?
- Skisser løysinga med pseudokode eller flytskjema
- Identifiser kva for funksjonar du treng
- Bestem kva for bibliotek som er nyttige (csv, matplotlib, math)

2. Koding (40 % av tida)
- Skriv éin funksjon om gongen
- Test kvar funksjon for seg (einingstesting)
- Bruk skildrande variabelnamn og kommentarar
- Følg Python-konvensjonar (snake_case, innrykk med 4 mellomrom)

3. Testing (25 % av tida)
- Test med kjende data der du veit svaret
- Test grensetilfelle (tom liste, null, negative tal)
- Test med ugyldig inndata (tekst der det blir venta tal)
- Rett feil (debugging) og test på nytt

4. Dokumentasjon (15 % av tida)
- Skriv ei kort skildring av programmet
- Kommenter vanskelege delar av koden
- Lag ei brukarrettleiing dersom programmet har brukarinteraksjon
- Dokumenter kjelder (data, formlar, bibliotek)

✏️Frå pseudokode til ferdig program

Lat oss følgje prosessen for eit program som analyserer temperaturdata:

Steg 1 – Pseudokode:

LES temperaturer fra CSV-fil
BEREGN gjennomsnitt, min, maks
TELL dager med frost (under 0)
LAG linjediagram av temperaturene
LAGRE rapport til tekstfil

Steg 2 – Identifiser funksjonar:
- les_data(filnavn) – les CSV og returnerer lister
- beregn_statistikk(temperaturer) – returnerer gjennomsnitt, min, maks
- lag_graf(datoer, temperaturer) – lagar og viser grafen
- skriv_rapport(statistikk, filnavn) – skriv rapport til fil

Steg 3 – Kode:

import csv
import matplotlib.pyplot as plt

def les_data(filnavn):
    """Leser temperaturdata fra en CSV-fil."""
    datoer = []
    temperaturer = []
    with open(filnavn, "r") as fil:
        leser = csv.reader(fil)
        next(leser)  # Hopp over overskrift
        for rad in leser:
            datoer.append(rad[0])
            temperaturer.append(float(rad[1]))
    return datoer, temperaturer

def beregn_statistikk(temperaturer):
    """Beregner og returnerer statistikk som en dictionary."""
    return {
        "antall": len(temperaturer),
        "gjennomsnitt": sum(temperaturer) / len(temperaturer),
        "maks": max(temperaturer),
        "min": min(temperaturer),
        "frost": sum(1 for t in temperaturer if t < 0),
    }

def lag_graf(datoer, temperaturer):
    """Lager et linjediagram av temperaturene."""
    plt.figure(figsize=(12, 5))
    plt.plot(temperaturer, "b-", linewidth=1.5)
    plt.axhline(y=0, color="red", linestyle="--", alpha=0.5)
    plt.xlabel("Dag nr.")
    plt.ylabel("Temperatur (°C)")
    plt.title("Daglige temperaturer")
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.savefig("temperaturgraf.png", dpi=150)
    plt.show()

def skriv_rapport(statistikk, filnavn):
    """Skriver en rapport med statistikk til fil."""
    with open(filnavn, "w") as fil:
        print("TEMPERATURRAPPORT", file=fil)
        print("=" * 30, file=fil)
        for nokkel, verdi in statistikk.items():
            if isinstance(verdi, float):
                print(f"{nokkel:15s}: {verdi:8.1f}", file=fil)
            else:
                print(f"{nokkel:15s}: {verdi:8d}", file=fil)

# Hovedprogram
datoer, temperaturer = les_data("temperaturer.csv")
statistikk = beregn_statistikk(temperaturer)
lag_graf(datoer, temperaturer)
skriv_rapport(statistikk, "temperaturrapport.txt")

print("Analyse fullført!")

Legg merke til at hovudprogrammet på slutten er svært lesbart – kvar linje skildrar eitt steg i analysen.

📝Oppgave 1

Kva for fase av eit programmeringsprosjekt bør du bruke mest tid på?

Testing og debugging
Testing handlar om å sjekke at programmet fungerer korrekt. Debugging handlar om å finne og rette feil.

Tre typar testar:

1. Test med kjende data: Bruk inndata der du veit svaret.

# Test: gjennomsnitt av [2, 4, 6] skal gi 4.0
resultat = beregn_gjennomsnitt([2, 4, 6])
print(f"Forventet: 4.0, Fikk: {resultat}")

2. Test grensetilfelle: Sjekk at programmet handterer spesielle verdiar.

# Test med tom liste
# Test med ett element
# Test med negative tall
# Test med veldig store tall

3. Test med ugyldig inndata: Sjekk at programmet ikkje krasjar.

# Hva skjer hvis brukeren skriver "abc" i stedet for et tall?
try:
    tall = float(input("Tall: "))
except ValueError:
    print("Ugyldig inndata – skriv inn et tall.")

Debugging-teknikkar:
- Print-debugging: Legg til print() for å sjå verdiar undervegs
- Les feilmeldinga nøye: Python fortel deg type feil og linjenummer
- Kommenter ut kode: Isoler problemet ved å deaktivere delar av koden
- Gummiand-metoden: Forklar koden høgt for ei «gummiand» (eller ein medstudent)

Vanlege feil og korleis du fiksar dei

Her er dei vanlegaste feila nybegynnarar møter i Python:

1. SyntaxError – skrivefeil i koden

# Feil: mangler kolon
if x > 5
    print("Stor")

# Riktig:
if x > 5:
    print("Stor")

2. IndentationError – feil innrykk

# Feil: blander mellomrom og tab
def funksjon():
    print("a")
      print("b")    # For mye innrykk!

# Riktig: konsekvent innrykk med 4 mellomrom
def funksjon():
    print("a")
    print("b")

3. NameError – variabelen finst ikkje

# Feil: skrivefeil i variabelnavn
temperatur = 22.5
print(tempratur)    # NameError!

# Riktig:
print(temperatur)

4. TypeError – feil datatype

# Feil: kan ikke legge sammen streng og tall
alder = "17"
neste_ar = alder + 1    # TypeError!

# Riktig:
neste_ar = int(alder) + 1

5. IndexError – ugyldig indeks

# Feil: listen har bare 3 elementer (indeks 0–2)
tall = [10, 20, 30]
print(tall[3])    # IndexError!

# Riktig:
print(tall[2])    # Siste element

Tips: Les alltid heile feilmeldinga. Ho fortel deg type feil, linjenummer og ofte kva som gjekk gale.

✏️Systematisk testing av ein funksjon

Her testar vi ein funksjon som reknar ut karaktergjennomsnitt:

def beregn_snitt(karakterer):
    """Beregner gjennomsnittet av en liste med karakterer (1-6)."""
    if len(karakterer) == 0:
        return 0.0
    return sum(karakterer) / len(karakterer)

# === TESTER ===

# Test 1: Vanlig tilfelle
resultat = beregn_snitt([4, 5, 3, 6, 4])
forventet = 4.4
print(f"Test 1: {resultat} == {forventet}? {'OK' if abs(resultat - forventet) < 0.01 else 'FEIL'}")

# Test 2: Alle like
resultat = beregn_snitt([5, 5, 5])
forventet = 5.0
print(f"Test 2: {resultat} == {forventet}? {'OK' if abs(resultat - forventet) < 0.01 else 'FEIL'}")

# Test 3: Bare én karakter
resultat = beregn_snitt([6])
forventet = 6.0
print(f"Test 3: {resultat} == {forventet}? {'OK' if abs(resultat - forventet) < 0.01 else 'FEIL'}")

# Test 4: Tom liste (grensetilfelle)
resultat = beregn_snitt([])
forventet = 0.0
print(f"Test 4: {resultat} == {forventet}? {'OK' if abs(resultat - forventet) < 0.01 else 'FEIL'}")

Utskrift:

Test 1: 4.4 == 4.4? OK
Test 2: 5.0 == 5.0? OK
Test 3: 6.0 == 6.0? OK
Test 4: 0.0 == 0.0? OK

Legg merke til at vi brukar abs(resultat - forventet) < 0.01 for å samanlikne desimaltal – direkte samanlikning med == kan gi feil på grunn av avrunding.

📝Oppgave 2

Kva er ein docstring i Python?

Dokumentasjon av kode

God dokumentasjon gjer koden din forståeleg for andre – og for deg sjølv om nokre veker!

Kommentarar forklarar kvifor du gjer noko (ikkje kva – det ser ein av koden):

# Dårlig kommentar (sier hva koden gjør – det ser vi allerede):
x = x + 1  # Øker x med 1

# God kommentar (sier hvorfor):
x = x + 1  # Kompenser for 0-indeksering i utskriften

Docstrings dokumenterer funksjonar:

def beregn_bmi(vekt_kg, hoyde_m):
    """
    Beregner Body Mass Index (BMI).

    Parametre:
        vekt_kg (float): Vekt i kilogram
        hoyde_m (float): Høyde i meter

    Returnerer:
        float: BMI-verdien
    """
    return vekt_kg / (hoyde_m ** 2)

Filhovud – ein kommentar øvst i fila som skildrar programmet:

"""
Temperaturanalyse – Prosjektoppgave ToF 1

Programmet leser temperaturdata fra en CSV-fil,
beregner statistikk og lager visualiseringer.

Forfatter: Kari Nordmann
Dato: 2024-03-15
"""

Hugs: Kode blir lesen mykje oftare enn han blir skriven. God dokumentasjon er ei investering i framtidig leseforståing.

✏️Eit godt dokumentert miniprosjekt

Her er eit komplett miniprosjekt med god struktur og dokumentasjon:

"""
BMI-kalkulator med statistikk

Programmet lar brukeren registrere BMI for flere personer,
beregner statistikk og lager et stolpediagram.

Forfatter: Elev Elevesen
Dato: 2024-03-20
"""

import matplotlib.pyplot as plt

def beregn_bmi(vekt_kg, hoyde_m):
    """Beregner BMI basert på vekt (kg) og høyde (m)."""
    return vekt_kg / (hoyde_m ** 2)

def bmi_kategori(bmi):
    """Returnerer BMI-kategori som tekst."""
    if bmi < 18.5:
        return "Undervekt"
    elif bmi < 25:
        return "Normalvekt"
    elif bmi < 30:
        return "Overvekt"
    else:
        return "Fedme"

def les_inn_data():
    """Leser inn navn, vekt og høyde for flere personer."""
    navn_liste = []
    bmi_liste = []

    print("BMI-kalkulator (skriv 'ferdig' for å avslutte)")
    while True:
        navn = input("Navn: ")
        if navn.lower() == "ferdig":
            break
        try:
            vekt = float(input("Vekt (kg): "))
            hoyde = float(input("Høyde (m): "))
            bmi = beregn_bmi(vekt, hoyde)
            navn_liste.append(navn)
            bmi_liste.append(bmi)
            print(f"  BMI: {bmi:.1f} ({bmi_kategori(bmi)})")
        except ValueError:
            print("  Ugyldig input – prøv igjen.")

    return navn_liste, bmi_liste

def vis_statistikk(navn_liste, bmi_liste):
    """Skriver ut en oppsummering av BMI-dataene."""
    print("\nOPPSUMMERING")
    print("=" * 35)
    for navn, bmi in zip(navn_liste, bmi_liste):
        print(f"  {navn:15s} BMI: {bmi:5.1f} ({bmi_kategori(bmi)})")
    print("-" * 35)
    print(f"  Gjennomsnitt: {sum(bmi_liste) / len(bmi_liste):.1f}")

def lag_diagram(navn_liste, bmi_liste):
    """Lager et stolpediagram over BMI-verdiene."""
    farger = ["green" if 18.5 <= b < 25 else "orange" for b in bmi_liste]
    plt.figure(figsize=(8, 5))
    plt.bar(navn_liste, bmi_liste, color=farger)
    plt.axhline(y=18.5, color="gray", linestyle="--", alpha=0.5)
    plt.axhline(y=25, color="gray", linestyle="--", alpha=0.5)
    plt.ylabel("BMI")
    plt.title("BMI-oversikt")
    plt.tight_layout()
    plt.savefig("bmi_oversikt.png", dpi=150)
    plt.show()

# === HOVEDPROGRAM ===
navn, bmi = les_inn_data()
if len(navn) > 0:
    vis_statistikk(navn, bmi)
    lag_diagram(navn, bmi)
else:
    print("Ingen data registrert.")

Programmet viser alle elementa i eit godt prosjekt: filhovud, docstrings, feilhandtering, modulær oppbygging med funksjonar, og ein tydeleg hovudprogramdel.

Oppsummering

I dette kapittelet har du lært å:

- Planleggje eit programmeringsprosjekt med pseudokode og flytskjema
- Følgje dei fire fasane: planlegging, koding, testing og dokumentasjon
- Teste program systematisk med kjende data, grensetilfelle og ugyldig inndata
- Debugge vanlege Python-feil: SyntaxError, IndentationError, NameError, TypeError og IndexError
- Dokumentere kode med kommentarar, docstrings og filhovud
- Strukturere eit program med funksjonar som har tydeleg ansvar

Nøkkelprinsipp for gode prosjekt:
- Planlegg før du kodar – det sparar tid til slutt
- Skriv og test éin funksjon om gongen
- Les feilmeldingar nøye – dei fortel deg kva som er gale
- Dokumenter koden din – framtidas deg vil takke deg
- Hald funksjonar små og med eitt tydeleg formål

Med ferdigheitene frå heile seksjon 5 – variablar, kontrollstrukturar, funksjonar, lister, filhandtering, visualisering og prosjektarbeid – har du eit solid grunnlag for å bruke programmering som verktøy i teknologi og forskingslære.

📝Oppgave 3

Skriv pseudokode for eit program som les inn poengsummar frå ei prøve, reknar ut gjennomsnitt og median, og avgjer om snittet er greidd (over 50 %). Oversett deretter pseudokoden til Python-kode med minst to funksjonar.

📝Oppgave 4

Gjennomfør eit miniprosjekt: Lag eit Python-program som fungerer som ein «vêrstasjon». Programmet skal: a) Lese inn daglege målingar (temperatur, nedbør) i ei veke (7 dagar). b) Rekne ut og vise statistikk (gjennomsnitt, min, maks for begge). c) Lage to grafar med subplots: temperatur over veka og nedbør som stolpediagram. d) Lagre ein rapport til ei tekstfil. Kravliste: minst 3 funksjonar, docstrings på alle funksjonar, feilhandtering for ugyldig inndata, og eit filhovud.

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.