Stufe 1: Single Source of Truth (CSV + plot.py)

This commit is contained in:
Cedric Fritzsch 2026-05-03 17:22:03 +02:00
parent a9934f3033
commit 91d148c783
7 changed files with 123 additions and 75 deletions

View File

@ -1,29 +0,0 @@
# Stufe 0 Ausgangslage
Der Anti-Held. Hier ist alles falsch, was falsch sein kann.
Inhaltlich: Frequenzgangmessung einer Drehzahl-Regelstrecke
(thematisch angelehnt an Praktikum Regelungstechnik V4).
## Was im Ordner liegt
| Datei | Warum es das gibt |
|--------------------------------|--------------------------------------------------|
| `paper.tex` | Die "richtige" Datei (oder?) mit allen Sünden |
| `paper_v2.tex` | Filename-Chaos (Regel 6 wird das fixen) |
| `paper_FINAL_USE_THIS.tex` | Filename-Chaos |
| `paper_FINAL_FINAL_v3.tex` | Filename-Chaos |
| `aufbau.png` | Pixelig-rasterisierter Screenshot (Regel 7 ersetzt ihn) |
## Demo-Skript
```bash
ls -1 # Filename-Chaos zeigen
pdflatex paper.tex # kompiliert -- aber das Layout ist hand-gefriemelt
open paper.pdf # PNG ist sichtbar pixelig
```
## Welche Probleme sind eingebaut?
Schau dir den Anfangskommentar in `paper.tex` an — dort sind alle 7 Sünden
markiert, jeweils mit dem Hinweis, welche Regel sie behebt.

11
messwerte.csv Normal file
View File

@ -0,0 +1,11 @@
omega_rad_s,betrag_dB,phase_grad
0.3,-6.19,0.1
1,-6.05,-1.0
3,-5.83,-4.2
10,-6.02,-15.3
30,-6.41,-46.4
50,-8.00,-80.2
56,-8.99,-90.9
100,-16.54,-130.4
300,-35.29,-164.9
1000,-55.92,-176.5
1 omega_rad_s betrag_dB phase_grad
2 0.3 -6.19 0.1
3 1 -6.05 -1.0
4 3 -5.83 -4.2
5 10 -6.02 -15.3
6 30 -6.41 -46.4
7 50 -8.00 -80.2
8 56 -8.99 -90.9
9 100 -16.54 -130.4
10 300 -35.29 -164.9
11 1000 -55.92 -176.5

View File

@ -1,18 +1,18 @@
% =====================================================================
% STUFE 0 -- Ausgangslage (Anti-Held)
% STUFE 1 -- Single Source of Truth
% --------------------------------------------------------------------
% Diese Datei enth\"alt mit Absicht jeden der Fehler, die durch die
% Regeln 1--7 behoben werden. Beim Vortrag den Studierenden zum
% "Mitleiden" zeigen.
% Was sich gegenueber Stufe 0 geaendert hat:
% + messwerte.csv ist die EINE Quelle der Wahrheit
% + plot.py erzeugt plot.pdf, tabelle.tex und werte.tex
% + paper.tex enthaelt KEINE hand-getippte Messzahl mehr
%
% Probleme (in dieser Reihenfolge gefixt):
% * Werte mehrfach im Text wiederholt (56 rad/s, -6 dB, ...) -> Regel 1
% * Hand-formatierter Titel und Bold-Headings -> Regel 2
% * "TH N\"urnberg Georg Simon Ohm" 3x getippt; Einheiten falsch -> Regel 3
% * Zitate hand-getippt: [Lutz/Wendt, 2014] -> Regel 4
% * Verweise wie "siehe Abb. 1" hart codiert -> Regel 5
% * Filename-Chaos im Ordner (paper_FINAL_USE_THIS.tex etc.) -> Regel 6
% * aufbau.png als Pixelbild (BORIS-Screenshot) -> Regel 7
% Was noch unschoen ist (kommt in den naechsten Stufen):
% - Hand-formatierter Header (Regel 2)
% - "TH N\"urnberg Georg Simon Ohm" 2x getippt (Regel 3)
% - Zitat [Lutz/Wendt, 2014] hand-getippt (Regel 4)
% - "Abb.~1", "Tabelle~1" hart codiert (Regel 5)
% - kein Versionsverlauf (Regel 6)
% - aufbau.png noch pixelig (Regel 7)
% =====================================================================
\documentclass[a4paper, 11pt]{article}
@ -20,10 +20,12 @@
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage{graphicx}
\usepackage{booktabs}
\input{werte.tex} % \omegaKtheorie, \omegaKmess, \abweichung -- erzeugt von plot.py
\begin{document}
% --- Titel hand-formatiert (kein \title/\maketitle) ---
% --- Hand-formatierter Header (Regel 2 wird das fixen) ---
\begin{center}
{\Huge\bfseries Frequenzgangmessung einer Drehzahl-Regelstrecke}\\[6pt]
{\large Tom Ne\ss , Cedric Fritzsch, Lukas Klausen}\\[2pt]
@ -33,13 +35,12 @@ TH N\"urnberg Georg Simon Ohm\\
\vspace{1cm}
% --- Bold-Paragraphs als Pseudo-Headings ---
\noindent{\Large\bfseries 1. Einleitung}\\[6pt]
Diese Arbeit charakterisiert eine Drehzahl-Regelstrecke an der
TH N\"urnberg Georg Simon Ohm. Die theoretische Knickfrequenz
betr\"agt 56 rad/s [Lutz/Wendt, 2014]. Ziel ist die Validierung des
PT2-Modells durch eine Frequenzgangmessung, durchgef\"uhrt an der
TH N\"urnberg Georg Simon Ohm.
betr\"agt \omegaKtheorie\ rad/s [Lutz/Wendt, 2014]. Ziel ist die
Validierung des PT2-Modells durch eine Frequenzgangmessung,
durchgef\"uhrt an der TH N\"urnberg Georg Simon Ohm.
\bigskip
\noindent{\Large\bfseries 2. Aufbau}\\[6pt]
@ -48,29 +49,24 @@ BORIS-Modell mit Sinus-Generator, Drehzahlstrecke und Multiplot.
\begin{center}
\includegraphics[width=0.8\textwidth]{aufbau.png}\\[4pt]
{\bfseries Abb.~1:} Multiplot der Frequenzgangmessung
(BORIS-Screenshot, gerendert in Excel).
{\bfseries Abb.~1:} Multiplot der Frequenzgangmessung (BORIS-Screenshot).
\end{center}
\bigskip
\noindent{\Large\bfseries 3. Messergebnisse}\\[6pt]
Bei $\omega = 3$ rad/s wurde ein Betrag von $-6$ dB gemessen, bei
$\omega = 50$ rad/s nur noch $-8$ dB (siehe Tabelle~1). Die gemessene
Knickfrequenz liegt bei 56,2 rad/s und weicht um 0,4 \% vom
theoretischen Wert von 56 rad/s ab [Lutz/Wendt, 2014].
Das gemessene Bode-Diagramm ist in Abb.~2 dargestellt. Die ermittelte
Knickfrequenz liegt bei \omegaKmess\ rad/s und weicht um
\abweichung\ \% vom theoretischen Wert von \omegaKtheorie\ rad/s ab
[Lutz/Wendt, 2014]. Die Messpunkte zeigt Tabelle~1.
\begin{center}
{\bfseries Tabelle~1:} Frequenzgang.\\[4pt]
\begin{tabular}{|l|l|l|}
\hline
$\omega$ (rad/s) & Betrag (dB) & Phase (Grad) \\
\hline
3 & -6,02 & -4,3 \\
50 & -8,00 & -80,2 \\
56 & -8,99 & -90,9 \\
100 & -16,54 & -130,4 \\
\hline
\end{tabular}
\includegraphics[width=0.7\textwidth]{plot.pdf}\\[4pt]
{\bfseries Abb.~2:} Gemessenes Bode-Diagramm.
\end{center}
\begin{center}
{\bfseries Tabelle~1:} Frequenzgangmesspunkte.\\[4pt]
\input{tabelle.tex}
\end{center}
\bigskip

View File

@ -1,3 +0,0 @@
% Diese Datei existiert nur, damit das Filename-Chaos im Vortrag
% sichtbar wird (`ls 00_start/`).
\input{paper.tex}

View File

@ -1,4 +0,0 @@
% Diese Datei existiert nur, damit das Filename-Chaos im Vortrag
% sichtbar wird (`ls 00_start/`).
% Niemand wei\ss\ mehr, welche die richtige ist.
\input{paper.tex}

View File

@ -1,5 +0,0 @@
% Diese Datei existiert nur, damit das Filename-Chaos im Vortrag
% sichtbar wird (`ls 00_start/`).
% Inhaltlich ein Duplikat -- niemand weiss mehr, welche die richtige ist.
% Wird sp\"atestens in Stufe 6 (Versionsverwaltung) ger\"aumt.
\input{paper.tex}

82
plot.py Normal file
View File

@ -0,0 +1,82 @@
"""
plot.py -- erzeugt aus messwerte.csv:
* plot.pdf Bode-Diagramm (Betrag und Phase)
* tabelle.tex LaTeX-Tabelle der Messpunkte
* werte.tex LaTeX-Makros: \\omegaKtheorie, \\omegaKmess, \\abweichung
Idee: messwerte.csv ist die EINZIGE Quelle der Wahrheit. paper.tex
enthaelt keine Messzahlen mehr. CSV aendern, plot.py laufen lassen,
paper.tex neu kompilieren -- alles bleibt konsistent.
"""
import numpy as np
import matplotlib.pyplot as plt
# 1) CSV einlesen ------------------------------------------------------
# 3 Spalten: omega_rad_s, betrag_dB, phase_grad (erste Zeile = Ueberschrift)
daten = np.loadtxt("messwerte.csv", delimiter=",", skiprows=1)
omega = daten[:, 0] # Kreisfrequenz in rad/s
betrag = daten[:, 1] # Amplitudengang in dB
phase = daten[:, 2] # Phasengang in Grad
# 2) Theoretische Knickfrequenz (aus Identifikation der Strecke) -------
# PT2-Modell der Drehzahl-Strecke: omega_n = 56 rad/s
omega_K_theor = 56 # Knickfrequenz lt. Modell
K_s_dB = betrag[0] # DC-Verstaerkung (tiefste Frequenz)
# 3) Gemessene Knickfrequenz: dort wo der Betrag um 3 dB faellt --------
ziel_dB = K_s_dB - 3
# np.interp braucht aufsteigende x-Werte; betrag faellt mit omega -> umdrehen:
omega_K_mess = np.interp(ziel_dB, np.flip(betrag), np.flip(omega))
abweichung = abs(omega_K_mess - omega_K_theor) / omega_K_theor * 100
# 4) Bode-Diagramm zeichnen (zwei Subplots: Betrag + Phase) ------------
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(5, 4), sharex=True)
ax1.semilogx(omega, betrag, "o-")
ax1.axhline(ziel_dB, linestyle=":", color="gray",
label=f"$K_s - 3$ dB = {ziel_dB:.2f} dB")
ax1.axvline(omega_K_theor, linestyle="--", color="gray",
label=f"$\\omega_K$ theor. = {omega_K_theor} rad/s")
ax1.set_ylabel("Betrag in dB")
ax1.legend(loc="lower left", fontsize=8)
ax1.grid(True, which="both", alpha=0.3)
ax2.semilogx(omega, phase, "o-")
ax2.set_xlabel("Kreisfrequenz $\\omega$ in rad/s")
ax2.set_ylabel("Phase in Grad")
ax2.grid(True, which="both", alpha=0.3)
fig.tight_layout()
fig.savefig("plot.pdf")
# 5) Hilfsfunktion: Zahl mit deutschem Komma ---------------------------
def deutsch(zahl, nachkommastellen=2):
"""1.59 -> '1{,}59' (LaTeX-tauglich, deutsches Komma)."""
text = f"{zahl:.{nachkommastellen}f}"
return text.replace(".", "{,}")
# 6) Tabelle als LaTeX-Code schreiben ----------------------------------
zeilen = [
r"\begin{tabular}{rrr}",
r"\toprule",
r"$\omega$ (rad/s) & Betrag (dB) & Phase ($^\circ$) \\",
r"\midrule",
]
for i in range(len(omega)):
zeilen.append(f"{omega[i]:g} & {deutsch(betrag[i])} & {deutsch(phase[i], 1)} \\\\")
zeilen.append(r"\bottomrule")
zeilen.append(r"\end{tabular}")
with open("tabelle.tex", "w", encoding="utf-8") as datei:
datei.write("\n".join(zeilen) + "\n")
# 7) Werte als LaTeX-Makros schreiben ----------------------------------
with open("werte.tex", "w", encoding="utf-8") as datei:
datei.write(r"\newcommand{\omegaKtheorie}{" + deutsch(omega_K_theor, 0) + "}\n")
datei.write(r"\newcommand{\omegaKmess}{" + deutsch(omega_K_mess, 1) + "}\n")
datei.write(r"\newcommand{\abweichung}{" + deutsch(abweichung, 1) + "}\n")
print("Fertig: plot.pdf, tabelle.tex, werte.tex")
print(f" theoretisch: omega_K = {omega_K_theor} rad/s")
print(f" gemessen: omega_K = {omega_K_mess:.2f} rad/s")
print(f" Abweichung: {abweichung:.1f} %")