Hilfe beim Verständnis von (Micro)Python-Code gesucht

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
IchnixPython
User
Beiträge: 1
Registriert: Donnerstag 21. Mai 2020, 11:16

Hallo ihr Lieben,

es geht um folgendes: Ich habe an der Uni ein Modul namens "Präsentationstechnik". Wie der Name bereits erahnen lässt, werden meine Mitstudenten und ich, im besagten Modul, dazu genötigt Vorträge zu halten :roll: .
Nun ist es zu allem Übel so, dass die Themen dieser Vorträge ausgelost wurden. Ich habe das Thema Micropython. Ich bei meinen Recherchen auf den IC MAX86150 gestoßen, welcher es einem unter anderem ermöglicht ein EKG zu schreiben. Wenig später habe ich sogar ein Codebeispiel für besagtes EKG gefunden (glaube ich).

Jetzt stehe ich vor dem Problem, dass ich als Student des Studienganges Elektrotechnik, Schwerpunkt Fahrzeugtechnik, keinerlei Berührungspunkte mit Python bzw. Micropython habe. Rudimentäre C/C++ - Kenntnisse sind vorhanden.

Wäre jemand von euch so nett und würde mir erklären wie die untenstehenden Codes funktionieren ?

Code: Alles auswählen

# vim: set ts=4 sw=4 tw=0 et pm=:
import numpy
import wave
import sys
import struct


def read(file_name):
    signal = numpy.fromfile(file_name, dtype=numpy.int16)
    return signal


signal = read(sys.argv[1])


sampleRate = 128.0  # hertz
duration = len(signal) / sampleRate  # seconds

wavef = wave.open("out.wav", "w")
wavef.setnchannels(1)  # mono
wavef.setsampwidth(2)
wavef.setframerate(sampleRate)

for i in range(int(duration * sampleRate)):
    value = int(signal[i])
    data = struct.pack("<h", value)
    wavef.writeframesraw(data)


wavef.close()

Code: Alles auswählen

# vim: set ts=4 sw=4 tw=0 et pm=:
import numpy
import sys
import matplotlib.pyplot as plt


def read(file_name):
    signal = numpy.fromfile(file_name, dtype=numpy.int16)
    return signal


signal = read(sys.argv[1])
factor = -1
count = 5
offset = 0

signal = signal[offset * 128 :]

count = min(min(len(signal) / 1280 + 1, 10), count)

font = {"family": "serif", "color": "darkred", "weight": "normal", "size": 16}

title = False

for i in range(count):
    plt.subplot(count, 1, i + 1)
    sub_signal = signal[i * 1280 : (i + 1) * 1280] * factor

    # pad with 0 as needed.
    # TODO: find a better solution to visialize this
    sub_signal = numpy.pad(sub_signal, (0, 1280 - len(sub_signal)), "constant")

    time_scale = (
        numpy.array(range(i * 1280, i * 1280 + len(sub_signal))) / 128.0 + offset
    )

    plt.plot(time_scale, sub_signal, "-")
    if not title:
        plt.title("File: %s" % sys.argv[1].split("/")[-1], fontdict=font)
        title = True

plt.xlabel("time (s)", fontdict=font)
plt.show()

Herzlichen Dank

und

Viele Grüße
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nichts davon ist micropython-Code, oder hat auch nur im entferntesten mit dem MAX86150 zu tun. Da wirst du nochmal suchen muessen.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@IchnixPython: Wo liegt denn das konkrete Problem beim Verständnis der beiden Code-Beispiele?

MicroPython ist ja grundsätzlich erst einmal Python, also bietet es sich an mal das Tutorial in der Python-Dokumentation durchzuarbeiten um sich einen Überblick über Python zu verschaffen. Dann gibt es in der MicroPython-Dokumentation eine Beschreibung der Unterschiede zwischen ”normalem” Python, also die Implementierung die man von python.org bekommt, und MicroPython.

Das erste Beispiel ist kein gutes Beispiel für Python-Code, unter anderem weil es ein grosses „anti pattern“ enthält mit der ``for``-Schleife über Indexwerte die dann nur für den Zugriff in das Numpy-Array verwendet werden, statt *direkt* über die Werte zu iterieren.

Die Berechnung für das `range()` sind unsinnig. Erst wird `duration` ausgerechnet in dem die Anzahl der Werte durch die Frequenz geteilt wird, und dann wird die Anzahl der Schleifendurchläufe berechnet in dem `duration` wieder mit der Frequenz multipliziert wird. Das ist wieder die Anzahl der Werte — dazu braucht man nicht so unsinnig rumrechnen, die hat(te) man ja bereits. Also anstatt ``for i in range(int(duration * sampleRate)):`` einfach ``for i in range(len(signal)):``. Da `i` dann aber nur als Index in `signal` verwendet wird, bleibt in idiomatischem Python ``for value in singal:`` übrig.

Das Umwandeln von einem Wert aus dem Numpy-Array in ein `int()` ist auch nicht nötig. Das `struct`-Modul kommt prima mit `numpy.int16`-Werten klar.

Wobei `struct` hier fehlerhaft verwendet wird mit der expliziten Angabe, dass der Wert „little endian“ gepackt werden soll. Denn das `wave`-Modul geht von nativer ”endieness” aus und korrigiert die falls nötig!

Der Schritt jeden einzelnen Wert so zu kodieren ist aber auch überhaupt gar nicht nötig, weil man direkt das Numpy-Array schreiben lassen kann.

Das würde also besser so aussehen (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
# vim: set ts=4 sw=4 tw=0 et pm=:
import sys
import wave

import numpy


def read(file_name):
    return numpy.fromfile(file_name, dtype=numpy.int16)


def main():
    sample_rate = 128  # hertz
    signal = read(sys.argv[1])
    with wave.open("out.wav", "wb") as wave_file:
        wave_file.setnchannels(1)  # mono
        wave_file.setsampwidth(2)
        wave_file.setframerate(sample_rate)
        wave_file.writeframes(signal)


if __name__ == "__main__":
    main()
Wobei hier immer noch ein „endieness“-Problem besteht, denn das geht davon aus, dass die Daten im nativen Format des Systems vorliegen auf dem das ausgeführt wird. Um den Fehler beheben zu können müsste man wissen in welchem Format die Daten tatsächlich vorliegen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Wenn die Themen des Moduls "Präsentationstechnik" fachspezifisch bezogen sein sollen, dann würde ich Micropython als Möglichkeit zum embedded Programming mittels Python vorstellen: irgendwas schalten anhand von einem Signal. Das muss gar nicht großartig ins Detail gehen, denn vermutlich sollt ihr primär lernen, Vorträge zu halten. Das kann auch nicht jeder aus dem Stegreif. Insofern ein Modul von hohem Praxiswert. Ansonsten gilt, was __deets__ schon anmerkte.
Antworten