Python
In diesem Abschnitt sollen einige für die Simulation und Datenverarbeitung relevante Konzepte angesprochen werden.
Hilfe zur allgemeinen Einführung in Python:
Echtzeit
Die Verarbeitung von Signalen setzt i.d.R. eine äquidistante Abgetastung (im Sinne der Signaltheorie bzw. der diskreten Regelungstechnik) voraus. Da die Übertragung von Datensätzen, die aus einer Abtastung stammen oftmal zeitlichen Schwankungen (Jitter) unterliegen, gibt man einem solchen Datensatz stets einen Zeitstempel (Timestamp) mit:
Zeitreihe:
\(kT\) | Wert \(x\) | Wert \(y\) |
---|---|---|
\(1 \cdot T\) | \(x_1\) | \(y_1\) |
\(2 \cdot T\) | \(x_2\) | \(y_2\) |
... | ... | ... |
\(n \cdot T\) | \(x_n\) | \(y_n\) |
Als json-Objekt:
[
{
ts : 1,
x : 0.1,
y : 10.1
},
{
ts : 2,
x : 0.2,
y : 10.2
},
]
time.sleep
Möchte man in Python eine zeitäquidistante Abarbeitung realisieren, dann kann mit den Standard-Bliotheken
time
datetime
mit Zeiten gerechnet werden. Folgende Beispiel-Skript gibt in einer Endlosschleife im Zeitraster \(T=1 s\) die aktuelle Zeit auf der Konsole aus.
time_loop.py
import time
from datetime import datetime
i = 0
while True:
i +=1
ts = datetime.now()
print(f'({i}) {ts.strftime("%H:%M:%S:%f")}')
time.sleep(1) # waiting
Konsolenausgabe:
Diese kleine Beispiel zeigt das Problem auf: Die Abstastzeit ist nicht konstant, sondern läuft (in Abhängigkeit der momentanen CPU-Last) langsam (in der Größenordnung 1 %) weg.
Abhilfe schafft der Einsatz spezieller Bibliotheken:
APScheduler
Eine sehr weit verbreitete und mächtige Bibliothek ist der
Advanced Process Scheduler Doku
Konsole: Installation
pip install APScheduler
Das Anwendungskonzept gliedert sich:
- function "Job": periodisch auszuführender Job (Funktion)
- Management der Jobs
aps.py
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
sched = BlockingScheduler()
i=0
def job():
global i
i +=1
ts = datetime.now()
print(f'({i}) {ts.strftime("%H:%M:%S:%f")}')
sched = BlockingScheduler({'apscheduler.timezone': 'UTC'})
sched.add_job(job,'interval',seconds=1,id='runJob1')
try:
sched.start()
except (KeyboardInterrupt, SystemExit):
pass
Konsolenausgabe:
Diese kleine Beispiel zeigt die Lösung: Die Abstastzeit ist annähernd konstant und jittert um eine sehr kleinen Betrag. der APScheduler lässt die Job als Thread laufen. Mit dem APS lassen sich noch eine Vielzahl weiterer zeitgesteuerter Aufgaben realisieren: Datum-getriggerte Aufgaben, sogenannte Cron-Jobs. Mehr in der Dokumentation
toml-Dateien
Um variable Kopnfigurationsdaten von dem eigentlichen Programmcode zu trennen, ist es praktisch, diese Daten als ASCII-Konfigurationsfile zur Verfügung zu stellen. In Frage kommen verschiedene standardisierte Formate zur Abbildung strukturierter Daten in Frage:
Da toml
ein sehr einfach zu handhabendes Format ist (und seit der Python-Version 3.12 standartmäßig verfügbar ist, soll es kurz vorgestellt werden.)
toml_1.py
import tomllib # py > 3.11
# import toml as tomllib # py <= 3.11 (pip install toml)
with open("cfg.toml", "rb") as f:
data = tomllib.load(f)
for d in data["dev"]:
print(d)
print(f'ip={data["web"]["ip"]} , Port={data["web"]["port"]} ')
python-benedict
Eine sehr mächtige Erweiterung stellt das Paket "python-benedict" zur Verfügung Link
Konsole: Installation
pip install python-benedict
"benedict" zielt mit seiner Klassen-Konzept auf eine Erweiterung der klassischen Python-Dictonaries. Elegant ist die Möglichkeit, eine toml-Datei einlesen und als benedict(dict)-Klasse nutzen zu können.
Zusätzlich lassen sich benedict-Daten auch schreiben (toml, yaml, csv, ...). Details sind in der Dokumentation beschrieben.
Beispiel
benedict_1.py
from benedict import benedict
# with open("cfg.toml", "rb") as f:
# data = tomllib.load(f)
data = benedict("cfg.toml", format="toml")
# for d in data["dev"]:
for d in data.dev:
print(d)
# print(f'ip={data["web"]["ip"]} , Port={data["web"]["port"]} ')
print(f'ip={data.web.ip} , Port={data.web.port} ')
Hinweis: Die Unterschiede zur tomllib sind durch Auskommentierung hervorgehoben.