Term aus einem String berechnen

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
MyAnno2070
User
Beiträge: 6
Registriert: Montag 20. April 2015, 22:25

Liebe Leser u. Leserinnen,
ich habe folgendes Problem (Teil eines größeren Problems #beliebiger Spalt #Interferenz #Wellengleichung): Das Programm erstellt einen Term dessen genaue Form vorher nicht festgelegt ist (Ein String aber das muss nicht sein wenn jemandem eine andere Idee kommt) - Dieser String hat ungefähr die Form a*sin(......)+...+f*sin(.......) d.h. eine Summe aus Lauter Sinus Termen (wieviele und mit welcher Phasenverschiebung ist erstmal vom Input Abhängig). Die Variablen sind nur zur Veranschaulichung! Im Orginal stehen dort Zahlen und es gibt keine! Variablen. Wie ihr euch sicher bereits denken könnt besteht nun das Problem darin den Term auszurechnen... Wie geht es? Am besten ohne einen Parser schreiben zu müssen... Ich bin nämlich Anfänger :D

Danke für eure Hilfe/Aufmerksamkeit,
Anno
BlackJack

@MyAnno2070: Was steht denn anstelle der Auslassungspunkte beim `sin()`-Aufruf? Ein vollständigeres Beispiel wäre nicht schlecht. Welche Eingangsdaten gibt es denn nun genau und wie soll das dazu passende (Zwischen)Ergebnis aussehen?
MyAnno2070
User
Beiträge: 6
Registriert: Montag 20. April 2015, 22:25

Lieber BlackJack du musst dir das ganze ungefähr so vorstellen:

Code: Alles auswählen

import math
#Settings/Input
l=float(input('Wellenlänge in m=')) 
T=l #Da c keine Rolle spielt wähle ich c=1 und somit l/c= T= l
d=float(input('Schirmabstand in m='))
list1=str(input('Alle Blendenöffnungen bitte in der Form a,...,f in Meter von 0 angeben: '))
list1=list1.split(',')
print ('Render Settings')
ug=float(input('Untere Grenze in m='))
og=float(input('Obere Grenze in m='))
sw=float(input('Schrittweite in m='))

#Berechnung
list4=[]
list2=[]
while ug<=og:
    list2.append(ug)
    a='0'
    
    for k in range (0,len(list1)): #Erstellung der Interferenz-Wellengleichung am Punkt ug
        v=float((d**2+(float(list1[k])-ug)**2)**(1/2)) #Strecke von Quelle k zum Punkte ug nach Pythagoras
        a=a+'+1/'+str(v)+'*math.sin(2*math.pi*(x/T-'+str(v)+'/l))'
    list3=[]
    x=0
    
    for f in range (1,26): #bestimmung des Maximums der Funktion über das Maximum einer Liste
        y=!!!!!!!!!!Wert vom Term a!!!!!!!!!!!
        y=(y**2)**(1/2) #Betrag y
        list3.append(y)
        x=x+l/50
        
    list4.append(max(list3)) 
    ug=ug+sw
print (list2)
print (list4)
In diesem Code habe ich nun auch Variablen Im Term ich weiß :D Aber das kann man ja ändern falls es bei der Lösung hilft. Am Ende wird Liste 4 nach Liste 2 für x geplottet (Graphischer Teil ist noch nicht fertig)
Zuletzt geändert von Anonymous am Dienstag 21. April 2015, 00:05, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@MyAnno2070: Du solltest sofort anfangen Aussagekräftige Bezeichner zu wählen, also keine kryptischen Kürzel und keine durchnummerierten `list*`-Namen die nichts über den Inhalt verraten.

`input()` liefert in Python 3 bereits eine Zeichenkette, es macht keinen Sinn darauf dann noch einmal `str()` aufzurufen. Die Elemente von `list1` würde ich auch gleich nach dem Aufteilen in Zahlen umwandeln und nicht später erst irgendo mitten in einer Rechnung.

Die äussere ``while``-Schleife ist eigentlich eine ``for``-Schleife über ein entsprechendes `range()`-Objekt.

Die ``for k …``-Schleife ist in Python ein „anti pattern”. Man kann in Python *direkt* über die Elemente einer Sequenz iterieren, ohne den Umweg über einen Index nehmen zu müssen.

Der `float()`-Aufruf mit der Rechnung für `v` ist überflüssig.

Statt eine Zeichenkette mit Quelltext einer Formel zu erstellen würde man sich hier einfach die `v`-Werte in einer Liste merken. Damit kann man diese Summe dann ja später für verschiedene `x`-Werte einfach ausrechnen.

Wenn man `f` von 0 bis 24 laufen lässt kann man `x` einfach berechnen statt das vorher mit einem Startwert zu belegen und am Ende jedes Schleifendurchlaufs zu erhöhen.

Der Code könnte ausserdem mal sinnvoll auf Funktionen aufgeteilt werden.
MyAnno2070
User
Beiträge: 6
Registriert: Montag 20. April 2015, 22:25

Danke für deine ausführliche Antwort. Wie du am Code sicher bemerkt hast ist es auch mein erstes Python programm überhaupt und daher nicht gerade ein Vorzeigestück ;D Die Variablen benenne ich aber Grundsätzlich erst am Ende um, da ich selbst mit den Kürzeln sehr gut zurechtkomme (schneller!). Außerdem habe ich heute morgen eine schönere Lösung gefunden als die von dir Vorgeschlagene - mit dem eval(String) Befehl kann man den String parsen lassen und bekommt direkt den Integer zurück, d.h. genau was ich gesucht hatte. Trotzdem Danke für deine Hilfe ich werde deine Vorschläge umsetzen,

Anno
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

@MyAnno2070: vergiss gleich wieder, dass es eval gibt. Warum willst Du ein Programm schreiben, das ein Programm schreibt, das etwas ausrechnet anstatt gleich ein Programm zu schreiben, das etwas ausrechnet? Die Summe kannst Du doch mit einer for-Schleife direkt berechnen. Wenn Du das in eine Funktion auslagerst, dann bleibt der Code auch an dieser Stelle übersichtlich. eval dagegen ist überhaupt nicht übersichtlich. An der Stelle wo eval steht muß man nämlich zuerst suchen, wie denn dieser String zustande kommt, was nicht möglich ist, ohne dass man den ganzen Programmabschnitt im Kopf durchgehen muß.

Das mit dem schneller kapiere ich nicht. "list2" zu schreiben ist schneller als ein sinnvoller Name der auch aus 5 Buchstaben besteht? Ich hatte jedenfalls große Probleme zu verstehen, was der Code eigentlich macht, daher keine Garantie, dass ich alle Formeln identisch umgesetzt habe, aber so könnte das Programm aussehen:

Code: Alles auswählen

import math

def calculate_interference(phases, delta):
    return sum(math.sin(2*math.pi*(delta - p)) / p for p in phases)

def find_max(phases):
    # Bestimmung des Maximums der Funktion über das Maximum von Schritten
    return max(abs(calculate_interference(phases, f / 50)) for f in range(25))

def main():
    #Settings/Input
    wavelength = float(input('Wellenlänge in m='))
    distance = float(input('Schirmabstand in m='))
    slit_positions = input('Alle Blendenöffnungen bitte in der Form a,...,f in Meter von 0 angeben: ')
    slit_positions = [float(p) for p in slit_positions.split(',')]

    print('Render Settings')
    lower_bound = float(input('Untere Grenze in m='))
    upper_bound = float(input('Obere Grenze in m='))
    step_size = float(input('Schrittweite in m='))
 
    #Berechnung
    points = []
    x = lower_bound
    while x <= upper_bound:
        #Phasendifferenz von Quelle k zum Punkte x nach Pythagoras
        phases = [math.sqrt(distance**2 + (p - x)**2) / wavelength for p in slit_positions]
        points.append((x, find_max(phases))) 
        x += step_size

    print(points)

if __name__ == '__main__':
    main()
Antworten