Wellenausbreitung

Wellen sind ja sich in den Raum ausbreitende Schwingungen. Doch von was hängt die Ausbreitungsgeschwindigkeit der Wellen ab? Elektromagnetische Wellen breiten sich im Vakuum mit der Lichtgeschwindigkeit c = 299 792 458 m/s aus. Doch wie sieht es mit Wellen in einem Festkörper aus? Um der Frage auf den Grund zu gehen, habe ich vor rund 20 Jahren eine Simulation zur Wellenausbreitung in Turbo Pascal erstellt. Das Modell besteht aus einzelnen Atomen mit der Masse m, welche miteinander über Federn mit der Federkonstante k verbunden sind. Zum Start lenke ich das erste Atom sinusförmig aus. Danach gehorchen die einzelnen Atome der Newtonschen Bewegungsgleichung F = m·a, wobei für die Kraft F das Hooksche Federgesetz F = k·Δl eingesetzt wird. Diese Differentialgleichungen habe ich mittels der Euler-Methode iterativ gelöst. Die Bewegung der Atome ist in y-Richtung eingeschränkt. Zu Beginn einzugeben ist die Anzahl der Atome, deren Masse m und die Federkonstante k. Zudem kann noch zwischen transversaler oder longitudinaler Auslenkung ausgewählt werden und ob man die Reflexion am freien oder festen Ende möchte.

Freies oder fixes Ende beeinflusst das Reflexionsverhalten der Welle. Bei einem freien Ende wird ein Wellenberg wieder als Wellenberg reflektiert. Bei einem fixen Ende kommt ein Wellenberg als Wellental zurück.

Zur Bestimmung der Ausbreitungsgeschwindigkeit wird einfach die Zeit t notiert, bei der sich das letzte Atom ganz rechts erstmalig zu bewegen beginnt. Die Geschwindigkeit v berechnet sich dann einfach aus Pixelanzahl/Zeit t. Diese wird dann in Abhängigkeit von m bzw. k bei jeweils konstantem k bzw. m erfasst.

Wie man sieht nimmt mit zunehmender Federkonstante k die Geschwindigkeit v zu. Bei härteren Federn breitet sich also die Welle schneller aus als bei weichen Federn. Der Graph v = v(k) sieht folgendermaßen aus:

Wie sieht es bei gleicher Federkonstante k aber unterschiedlichen Massen m aus?

Hier liegt genau eine verkehrte Proportionalität vor. Je größer die Masse m der Atome, desto langsamer breitet sich die Welle aus. Steigendes m liefert also ein sinkendes v. Für den Graph v = v(m) erhält man:

Um die genaue funktionale Abhängigkeit der Geschwindigkeit v von den Größen k und m herauszufinden, geht man wiefolgt vor:

Die Potenz von k in der Formel v = v(k,m) muss daher 0.5 sein. Wie sieht es für die Potenz von m aus?

Die Potenz von m muss demnach –0.5 sein. Daher ergibt sich folgender Zusammenhang zwischen v und den Größen k und m:

In der Literatur findet man folgende Formel für die Ausbreitungsgeschwindigkeit einer Welle in einem Festkörper:       

Anstelle der Federkonstante k tritt das Elastizitätsmodul E und anstelle der Masse m die Dichte ρ. Dies leuchtet aber auch ein. Denn das Elastizitätsmodul E ist gleich der notwendigen Kraft pro m², um einen Körper der Länge L auf seine doppelte Länge zu dehnen. Daran erkennt man die Ähnlichkeit zur Federkonstante k, welche ja der Kraft F entspricht, um die Feder um einen Meter zu dehnen. Die Zusammengehörigkeit der Masse m und der Dichte ρ ist ebenfalls offensichtlich, da ja die Dichte der Masse pro m³ entspricht.

Mit dieser einfachen Simulation haben wir also eine reale Formel zur Ausbreitungsgeschwindigkeit von Wellen hergeleitet, voila…

Das uralte Turbo-Pascal-Programm:

Program Welle;
{$N+,E+}

Uses Crt,Graph,Turbo3,Dos;

Type
    Feld_1 = Array[1..150] of Real;

Var                             { Variablendeklaration }

    vx_vorher,vy_vorher : Feld_1; { Geschwindigkeitskomponenten vorher }
    vx_nachher,vy_nachher : Feld_1; { Geschwindigkeitskomponenten nachher }
    sx_vorher,sy_vorher : Feld_1; { Ortskomponenten vorher }
    sx_nachher,sy_nachher : Feld_1; { Ortskomponenten nachher }

    m : Real; { Masse der Teilchen }
    k : Real; { Federkonstante }
    Force_x,Force_y: Real; { Auf die Atome wirkenden Kr„fte }
    delta_t,t : Real; { Zeit und Zeitintervall }
    Faktor : Real; { graphischer Darstellungsfaktor }

    Amplitude,Tau : Integer; { Anregungsschwingung }
    zaehler,i,j : LongInt; { Z„hlvariable }
    n : Integer; { Anzahl der Atome }
    l_0 : Integer; { L„nge der Federn }
    max : LongInt;
    GraphDriver,GraphMode : Integer;
    Xgraph,Ygraph : Integer;
    Maxx,Maxy : Integer;

    Ch,ant,Antwort_1,Antwort_2 : Char;

    Pfad: String;

    Weiter,Treffer,Loeschen : Boolean;

    Filename: Text;

Const

    NameHeader = 'Gitter , Version 1.1';
    WeiterHeader= '( weiter mit beliebiger Taste )';
    Pi = 3.14159265358979323846264338327950;
    g = 9.81;
    Esc = #27;
    Rad = (2.0 * Pi / 360.0);


Procedure WriteOut(S: String);
Begin
   OutTextXY(Xgraph,Ygraph,S);
   Inc(Ygraph,TextHeight('M')+4);
End;



     {ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»}
     {º               º}
     {º   STARTTEXT   º}
     {º               º}
     {ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ}


Procedure Starttext;         { Starttext }
   Begin
    ClearDevice;
    Setviewport(0,0,Maxx,Maxy,Clipon);
    SetTextStyle(TriplexFont,HorizDir,3);
    SetTextJustify(CenterText,TopText);
    SetColor(14);

    OutTextXY(Maxx div 2,30,'Programm zur Darstellung');
    OutTextXY(Maxx div 2,50,'von Wellen');
    SetTextStyle(TriplexFont,HorizDir,1);
    OutTextXY(Maxx div 2,85,'von');
    OutTextXY(Maxx div 2,105,'Dipl.Ing.Mag. Christoph Ernst');

    SetLineStyle(SolidLn,0,ThickWidth);
    Rectangle(30,20,595,145);

    SetColor(15);

    SetTextJustify(LeftText,TopText);
    SetTextStyle(DefaultFont,HorizDir,1);

    Ygraph := 210;
    Xgraph := 40;
    WriteOut('Anmerkung:');
    WriteOut(' ');
    WriteOut(' ');
    WriteOut('Dieses Programm simuliert Seilwellen.Als Modell dienen');
    WriteOut('mehrere Massen,welche mit den beiden Nachbarn ber Federn');
    WriteOut('verbunden sind. Bei den transversalen Schwingungen wurde');
    WriteOut('die Beweglichkeit der Massen eingeschr„nkt,sodaá sie sich nur');
    WriteOut('in y-Richtung bewegen k”nnen. Viel Spaá mit dem Programm !');

    SetColor(14);
    SetTextJustify(CenterText,TopText);
    OutTextXY((Maxx div 2), (Maxy-10),'<Esc> Programm beenden');
    SetColor(15);


    ant := Readkey;
    If ant = Esc Then
          Halt(1);
End;


     {ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»}
     {º               º}
     {º    ABFRAGE    º}
     {º               º}
     {ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ}


Procedure Abfrage;
   Begin
    ClearDevice;
    Setviewport(0,0,Maxx,Maxy,Clipon);
    SetTextStyle(TriplexFont,HorizDir,3);
    SetTextJustify(CenterText,TopText);
    SetColor(14);
    OutTextXY(Maxx div 2,30,'Parameter-Eingabe');

    SetColor(8);
    SetLineStyle(SolidLn,0,NormWidth);
    Rectangle(100,20,525,70);
    SetColor(7);
    SetLineStyle(SolidLn,0,NormWidth);
    Rectangle(102,22,523,68);
    SetColor(15);

    SetTextJustify(LeftText,TopText);
    SetTextStyle(DefaultFont,HorizDir,1);

    Ygraph := 120;
    Xgraph := 2;
    WriteOut(' ');
    WriteOut('Es mssen im folgenden von ihnen einige Parameter eingegeben werden:');

    GotoXY(1,12);
    Write('Wollen sie transversale (t) oder longitudinale (l) Schwingungen untersuchen? ');
    Readln(Antwort_1);
    Writeln(' ');

    Write('Soll die Reflexion am offenen (o) oder festen Ende (f) erfolgen? ');
    Readln(Antwort_2);
    Writeln(' ');

    Write('Anzahl der Atome [max. 125]: ');
    Repeat
       Readln(n);
    Until (n > 0) and (n <= 125);
    Writeln(' ');

    Write('Masse der Atome: ');
    Readln(m);
    Writeln(' ');

    Write('Federkonstante k in (N/m): ');
    Readln(k);
    Writeln(' ');
End;



      {ÉÍÍÍÍÍÍÍÍÍÍÍÍÍ»}
      {º             º}
      {º    Kraft    º}
      {º             º}
      {ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ}

Procedure Force(j_F,l_F: Integer;m_F,k_F: Real;x_F,y_F: Feld_1);
Var distance_links,distance_rechts : Extended;

   Begin
      { Wechselwirkung zw. den Nachbaratomen }
      { ==================================== }

      distance_links := SQRT((sx_vorher[j_F] - sx_vorher[j_F - 1]) *
                                   (sx_vorher[j_F] - sx_vorher[j_F - 1]) +
                                   (sy_vorher[j_F] - sy_vorher[j_F - 1]) *
                                   (sy_vorher[j_F] - sy_vorher[j_F - 1]));

      If (j_F < n) Then
         Begin
            distance_rechts := SQRT((sx_vorher[j_F] - sx_vorher[j_F + 1]) *
                                    (sx_vorher[j_F] - sx_vorher[j_F + 1]) +
                                    (sy_vorher[j_F] - sy_vorher[j_F + 1]) *
                                    (sy_vorher[j_F] - sy_vorher[j_F + 1]));
         End
      Else
         Begin
            { letztes Atom hat keinen rechten Nachbarn }

            distance_rechts := l_F;
         End;


      If (Antwort_1 = 't') Then
         Begin
            { Bei transversaler Schwingung bleiben Atome in x-Richtung fixiert! }
            { ================================================================= }

            Force_x := 0.0;
         End
      Else
         Begin
            Force_x := -(distance_links - l_F) * k_F *
                        ((sx_vorher[j_F] - sx_vorher[j_F - 1]) / distance_links) +
                        (distance_rechts - l_F) * k_F *
                        ((sx_vorher[j_F + 1] - sx_vorher[j_F]) / distance_rechts);
         End;

      Force_y := -(distance_links - l_F) * k_F *
                  ((sy_vorher[j_F] - sy_vorher[j_F - 1]) / distance_links) +
                  (distance_rechts - l_F) * k_F *
                  ((sy_vorher[j_F + 1] - sy_vorher[j_F]) / distance_rechts);

   End;


      {ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»}
      {º                             º}
      {º    Differenzen-Verfahren    º}
      {º                             º}
      {ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ}

Procedure Newton(n_sub,l_sub: Integer;delta_t_sub,m_sub,k_sub : Real;VAR x0,x1,y0,y1,vx0,vx1,vy0,vy1 : Feld_1);
Var
   delta_sx,delta_sy : Extended;
   j_sub : LongInt;

   Begin
      { Ort- und Geschwindigkeitsindizes: 0...vorher,1...nachher }

      For j_sub := 2 To n_sub Do
         Begin
            Force(j_sub,l_sub,m_sub,k_sub,x0,y0); { Berechnung der Kraft auf das j-te Atom}

            vx1[j_sub] := vx0[j_sub] + delta_t_sub * (1.0 / m_sub) * Force_x;
            vy1[j_sub] := vy0[j_sub] + delta_t_sub * (1.0 / m_sub) * Force_y;

            delta_sx := (vx1[j_sub] + vx0[j_sub]) * 0.5 * delta_t_sub; { gemittelte šbergabe ! }
            delta_sy := (vy1[j_sub] + vy0[j_sub]) * 0.5 * delta_t_sub; { gemittelte šbergabe ! }

            x1[j_sub] := x0[j_sub] + delta_sx;
            y1[j_sub] := y0[j_sub] + delta_sy;
         End;
   End;


      {ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»}
      {º               º}
      {º    Graphik    º}
      {º               º}
      {ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ}

Procedure Graphik(Loeschen_sub : Boolean);
   Begin
      If (Loeschen_sub) Then
         Begin
            { Graphik loeschen }
            { ================ }

            SetColor(0);
            Circle(Trunc(sx_vorher[1]),Trunc(((maxy - 70) / 2) - sy_vorher[1]),8);

            For j := 2 To n Do
               Begin
                  Circle(Trunc(sx_vorher[j]),Trunc(((maxy - 70) / 2) - sy_vorher[j]),8);
                  Line(Trunc(sx_vorher[j - 1]),Trunc(((maxy - 70) / 2) - sy_vorher[j - 1]),
                       Trunc(sx_vorher[j]),Trunc(((maxy - 70) / 2) - sy_vorher[j]));
               End;
         End
      Else
         Begin
            { Graphik zeichnen }
            { ================ }
            {
            If (vx_vorher[1] >= 0) Then
               Begin
                  SetColor(1);
                  Circle(Trunc(sx_vorher[1]),Trunc(((maxy - 70) / 2) - sy_vorher[1]),8);
               End
            Else
               Begin
                  SetColor(2);
                  Circle(Trunc(sx_vorher[1]),Trunc(((maxy - 70) / 2) - sy_vorher[1]),8);
               End;
            }
            For j := 1 To n Do
               Begin
                  If (vx_vorher[j] = 0) Then
                     Begin
                        SetColor(3);
                        Circle(Trunc(sx_vorher[j]),Trunc(((maxy - 70) / 2) - sy_vorher[j]),8);
                     End
                  else If (vx_vorher[j] > 0) Then
                     Begin
                        SetColor(1);
                        Circle(Trunc(sx_vorher[j]),Trunc(((maxy - 70) / 2) - sy_vorher[j]),8);
                     End
                  Else
                     Begin
                        SetColor(2);
                        Circle(Trunc(sx_vorher[j]),Trunc(((maxy - 70) / 2) - sy_vorher[j]),8);
                     End;
               End;

            For j := 2 To n Do
               Begin
                  SetColor(15);
                  Line(Trunc(sx_vorher[j - 1]),Trunc(((maxy - 70) / 2) - sy_vorher[j - 1]),
                       Trunc(sx_vorher[j]),Trunc(((maxy - 70) / 2) - sy_vorher[j]));
               End;

         End;

   End;


      {ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»}
      {º                   º}
      {º  INITIALISIERUNG  º}
      {º                   º}
      {ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ}

Procedure Initialisierung;     { Initialisierung s„mtlicher Parameter }
Var ErrorCode: Integer;
Begin
   GraphDriver := Detect;
   DirectVideo := False;

   { =============================================================== }
   { ACHTUNG : Graphik-Programme *.BGI und Schriften *.CHR mssen im }
   {           Verzeichnis des auszufhrenden Programms sein !!! }
   { =============================================================== }

   InitGraph (GraphDriver,GraphMode,'');

   ErrorCode := GraphResult;


   If ErrorCode <> grOk Then Begin
      Writeln(#7,'Sorry, but I''ve a Graphics Error:');
      Writeln(GraphErrorMsg(ErrorCode));
      Writeln('Program intermediately stopped.');
      Halt(1);
   End;
   SetLineStyle(SolidLn,0,Normwidth);
   SetTextJustify(LeftText,TopText);
   SetTextStyle(DefaultFont,HorizDir,1);
   Setviewport(0,0,Maxx,Maxy,Clipon);

   Maxx := Getmaxx;
   Maxy := Getmaxy;

   Weiter := FALSE;
End;


      {ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»}
      {º °°°°°°°°°°°°°°°°°°°°° º}
      {º °°° HAUPTPROGRAMM °°° º}
      {º °°°°°°°°°°°°°°°°°°°°° º}
      {ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ}

Begin

   Initialisierung;
   Starttext;
   ClearDevice;
   Abfrage;

   { ====================================== }
   { ========Initialisierung-Anfang======== }
   { ====================================== }

   l_0 := Trunc((Maxx - 100) / n);  { L„nge der Federn }

   { Parameter der Erregerschwingung }
   { =============================== }

   If (Antwort_1 = 'l') Then
      Begin
         Tau := 5;
         Amplitude := 10;
      End
   Else
      Begin
         Tau := 10;
         Amplitude := 50;
      End;

   { Startwerte der Atome }
   { ==================== }

   For zaehler := 1 To n Do
      Begin
         sx_vorher[zaehler] := zaehler * l_0;
         sy_vorher[zaehler] := 0.0;
         vx_vorher[zaehler] := 0.0;
         vy_vorher[zaehler] := 0.0;
      End;


   Weiter := False;
   t := 0.0;
   delta_t := 0.005;

   { ==================================== }
   { ========Initialisierung-Ende======== }
   { ==================================== }

   ClearDevice;
   SetViewport(0,0,Maxx,Maxy,Clipon);
   SetLineStyle(SolidLn,0,NormWidth);
   SetColor(14);
   SetTextStyle(DefaultFont,HorizDir,1);
   SetTextJustify(CenterText,TopText);
   OutTextXY((Maxx div 2),470,'< Abbruch mit Esc-Taste >');
   SetTextStyle(7,HorizDir,4);
   OutTextXY((Maxx div 2),9,'Wellen');
   SetTextJustify(LeftText,TopText);
   SetTextStyle(2,HorizDir,4);
   OutTextXY(455,15,'Version 1.1');

   SetColor(8);
   Rectangle(0,48,Maxx - 86,Maxy - 18);
   SetColor(7);
   Rectangle(1,49,Maxx - 87,Maxy - 19);
   SetLineStyle(SolidLn,0,NormWidth);
   SetViewport(2,50,Maxx - 88,Maxy - 20,Clipon);
   SetColor(7);
   GotoXY(71,5);
   Write('<->: slow');
   GotoXY(71,6);
   Write('<+>: fast');
   GotoXY(71,8);
   Write('t:');

   { erstmalige graph. Darstellung fr Start t = 0: }
   Loeschen := False;
   Graphik(Loeschen);

   t := t + delta_t; { Zeit-Inkrementierung }


   { =================================== }
   { ========== Zeit-Schleife ========== }
   { =================================== }

   Repeat
      If Keypressed Then
         Begin
            ant := readkey;

            Case ant of
               Esc : Weiter := True;
               '+' : Begin
                        delta_t := delta_t * 2.0;
                     End;
               '-' : Begin
                        delta_t := delta_t * 0.5;
                     End;
            End; {End Case of }
         End;

      { =========================================================== }
      { Ermittlung der ver„nderten Positionen und Geschwindigkeiten }
      {               durch das Unterprogramm Newton                }
      { =========================================================== }

      Newton(n,l_0,delta_t,m,k,
             sx_vorher,sx_nachher,sy_vorher,sy_nachher,
             vx_vorher,vx_nachher,vy_vorher,vy_nachher);

      { ==================================== }
      { erstes Atom folgt eine halbe Periode }
      {       lang einer Sinusschwingung     }
      { ==================================== }

      If (Antwort_1 = 't') Then
         Begin
            { transversale Erregerschwingung }
            { ============================== }

            sx_nachher[1] := sx_vorher[1];
            vx_nachher[1] := vx_vorher[1];
            vy_nachher[1] := vy_vorher[1];

            If (t <= 0.5 * Tau) Then
               Begin
                  sy_nachher[1] := Amplitude * sin(2 * Pi * t / Tau);
               End
            Else
               Begin
                  sy_nachher[1] := 0.0;
               End;
         End
      Else
         Begin
            { longitudinale Erregerschwingung }
            { =============================== }

            sy_nachher[1] := sy_vorher[1];
            vx_nachher[1] := vx_vorher[1];
            vy_nachher[1] := vy_vorher[1];

            If (t <= 0.5 * Tau) Then
               Begin
                  sx_nachher[1] := l_0 + Amplitude * sin(2 * Pi * t / Tau);
               End
            Else
               Begin
                  sx_nachher[1] := l_0 + 0.0;
               End;
         End;


      { letztes Atom bleibt fest oder offen }
      { =================================== }

      If (Antwort_2 = 'f') Then
         Begin
            { festes Ende,daher unver„nderte Koordinaten }

            sx_nachher[n] := sx_vorher[n];
            sy_nachher[n] := sy_vorher[n];
            vx_nachher[n] := vx_vorher[n];
            vy_nachher[n] := vy_vorher[n];
         End;


      { Bildpunkte loeschen }
      { =================== }

      Loeschen := True;
      Graphik(Loeschen);

      { Wertebergabe und graphische Darstellung }
      { ======================================== }

      For i := 1 To n Do
         Begin
            sx_vorher[i] := sx_nachher[i];
            sy_vorher[i] := sy_nachher[i];
            vx_vorher[i] := vx_nachher[i];
            vy_vorher[i] := vy_nachher[i];
         End;

      Loeschen := False;
      Graphik(Loeschen);

      GotoXY(73,8);
      Write('       ');
      GotoXY(73,8);
      Write(t:4:2);

      t := t + delta_t;

   Until Weiter;

   ant := readkey;
End.

 

Zum Abschluss noch das Youtube-Video: