Lissajous-Figuren Zeichnen

  • C#

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von Artentus.

    Lissajous-Figuren Zeichnen

    Hallo alle zusammen.

    Wir haben beute im Physik-Seminar unter anderem über sog. Lissajous-Figuren gesprochen und auch ein paar mit dem Oszilloskop und Frequenzgeneratoren erzeugt.
    Ich fand die Dinger interessant und hab mich gefragt, ob ich die nicht auch am Computer "erzeugen" kann. Der Plan ist, ich geb zwei Frequenzen an und mir wird die zugehörige Figur gezeichnet. Durch etwas Recherche hab ichs jetzt auch schon hinbekommen, dass die korrekten Figuren entstehen, allerdings bewegen sie sich nicht sondern sind starr. Ich hätte es aber gerne so, dass sie sich wie am Oszilloskop bewegen (siehe auch Bild auf Wikipedia). Scheinbar plotten alle Codes aus dem Internet nur die statischen Figuren, und da ich mich in dem Gebiet nicht wirklich auskenne, hab ich da keinen Ansatz.
    Mein Code sieht momentan so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. public class LissajousPlotter : Control
    2. {
    3. private struct PlottetPoint
    4. {
    5. public PointF Point;
    6. public double Time;
    7. }
    8. readonly List<PlottetPoint> plottedPoints;
    9. readonly object locker;
    10. Thread updateThread;
    11. bool loopRunning;
    12. public double Frequency1 { get; set; }
    13. public double Frequency2 { get; set; }
    14. public LissajousPlotter()
    15. {
    16. SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
    17. SetStyle(ControlStyles.ResizeRedraw, true);
    18. UpdateStyles();
    19. plottedPoints = new List<PlottetPoint>();
    20. loopRunning = false;
    21. locker = new object();
    22. }
    23. public void Start()
    24. {
    25. if (!loopRunning)
    26. {
    27. loopRunning = true;
    28. updateThread = new Thread(UpdateLoop);
    29. updateThread.IsBackground = true;
    30. updateThread.Start();
    31. }
    32. }
    33. public void Stop()
    34. {
    35. if (loopRunning)
    36. {
    37. loopRunning = false;
    38. updateThread.Join();
    39. plottedPoints.Clear();
    40. }
    41. }
    42. private static PlottetPoint Plot(double frequency1, double frequency2, double t)
    43. {
    44. float x = (float)Math.Sin(frequency1 * t);
    45. float y = (float)Math.Sin(frequency2 * t);
    46. return new PlottetPoint() { Point = new PointF(x, y), Time = t };
    47. }
    48. private void UpdateLoop()
    49. {
    50. var invalidateAction = new Action(Invalidate);
    51. var sw = new Stopwatch();
    52. sw.Start();
    53. while (loopRunning)
    54. {
    55. PlottetPoint p = Plot(Frequency1, Frequency2, sw.ElapsedMilliseconds / 1000.0);
    56. lock (locker)
    57. {
    58. plottedPoints.Add(p);
    59. for (int i = 0; i < plottedPoints.Count; i++)
    60. {
    61. if (plottedPoints[i].Time >= p.Time - 0.2)
    62. {
    63. plottedPoints.RemoveRange(0, i);
    64. break;
    65. }
    66. }
    67. }
    68. BeginInvoke(invalidateAction);
    69. Thread.Sleep(1);
    70. }
    71. sw.Stop();
    72. }
    73. protected override void OnPaint(PaintEventArgs e)
    74. {
    75. var g = e.Graphics;
    76. g.SmoothingMode = SmoothingMode.AntiAlias;
    77. g.PixelOffsetMode = PixelOffsetMode.HighQuality;
    78. PointF[] points;
    79. lock (locker) points = plottedPoints.Select(p => p.Point).ToArray();
    80. if (points.Length == 0)
    81. return;
    82. using (var matrix = new Matrix())
    83. {
    84. matrix.Translate(Width / 2.0f, Height / 2.0f);
    85. float scale = Math.Min(Width / 4.0f, Height / 4.0f);
    86. matrix.Scale(scale, -scale);
    87. g.Transform = matrix;
    88. using (var pen = new Pen(Color.Lime, 0.02f))
    89. g.DrawLines(pen, points);
    90. g.ResetTransform();
    91. }
    92. }
    93. }
    Was fehlt, damit sich die Figuren bewegen? Oder ist das ein ganz und gar falscher Ansatz?
    Außerdem bin ich mir nicht sicher, wie ich effektiv bestimmen kann, welche berechneten Punkte ich behalten kann/muss. Momentan nehme ich da einfach ne feste Zeit (Zeile 75), aber ich glaube das ist der falsche Weg. Wie geht es richtig?
    Also du meinst, ich soll Pro Update ne komplette Figur zeichnen und die dann immer verschieben. Ich hab mir auch schon gedacht, dass t vielleicht nicht wirklich die Echtzeit meint.
    Nur, wie viele Punkte muss ich dann zeichnen, damit die Figur gerade vollständig aber nicht doppelt gezeichnet wird?
    Ich hab den Code gerade mal laufen gelassen. Das funktioniert soo sogar schon.
    Wenn du dir das mal schneller vorstellst, dann wäre das eine Lissajou Figur.

    Du musst bedenken, dass dein Oszi nachleuchtet. Damit/durch wird die Figur erzeugt.
    Welche Frequenzen nimmst du? bei mir gehts mit 100 und 101 gut.

    EDIT: Probier mal 35/120, das gibt auch ne wunderschöne drehende Figur. Netter Code :)


    EDIT2: 61/102 gibt z.B. nen schönen Kreis wie im Wiki-Artikel unter Δφ 1:1 beschrieben.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Manawyrm“ ()

    100 und 101 funktioniert tatsächlich. Aber 100/150 z.B. funktioniert nicht, obwohl laut Wikipedia 2/3-Verhältnisse keine periodische Funktion ergeben sollten.
    Ich weiß, dass das Oszilloskop nachleuchtet, das ist vermutlich auch das Problem. Wie simuliere ich sowas per Code?
    Wahrscheinlich hab ichs nicht vollständig verstanden. :P
    Es ergeben sich ab und an tatsächlich relativ schöne Figuren, allerdings wirkt das ganze ziemlich abgehackt, überhaupt nicht flüssig, "größere" Figuren kann man nicht wirklich nachvollziehen.
    Ich hätte spontan gesagt, das Problem hängt damit zusammen, dass der Code relativ grob aufgelöst die Variable t ändert und dafür eine relativ niedrige Framerate hat.

    Zur Visualisierung hätte ich fast empfohlen, dass du dir 2 "virtuelle Oszis" einprogrammierst, also Y auf einer festen Zeitbasis und X als dein Wert der Sinus-Funktion, damit dürftest du dir wesentlich schöner anschauen können, wie die Phasenverschiebung in der Praxis funktioniert.
    Also, euch fehlt die Phasenverschiebung Phi zwichen den beiden Schwingungen. Die verursacht die scheinbare Bewegung bzw. Verformung bei gleichen Frequenzen.
    Das Nachleuchten ist bedeutungslos, wie man schon bei der Wikipedia-Demo sieht.
    Und die 1000 fps braucht ihr auch nicht:
    alle 1/25 sec für einen gesamten Bildaufbau/horizontalen Scan entspricht am ehesten den Oszillokop.
    Wenn ich irgendwas beliebiges dazuaddiere (spielt ja eigentlich keine Rolle, was, glaube ich), dann bewegt sich die Figur trotzdem nicht, sie wird nur schief.

    Edit: alles im Sinus muss eigentlich auch noch mit 2Pi multipliziert werden, fällt mir gerade auf.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Artentus“ ()

    jetzt die zweite Frequenz verdoppeln:
    Der Punkt läuft die doppel-schleifenfigur ab, wie auf dem Wiki-Bild

    dann die BEIDEN Frequenzen gleichzeitig solange verdoppeln bis aus dem Punkt eine Linie wird.
    und dan Phi leicht ändern und sehen was passiert

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Coldfire“ ()