2012-04-13 3 views
2

Wie der Titel sagte:Zeichnen Arten von Signalen mit wechselnder Amplitude und Frequenz im laufenden Betrieb

Ich habe Form mit 2 Trackbars. Ein für Frequenz und einem für Amplitude. Ich richte den Timer ein, um mich im laufenden Betrieb zu ändern.

private void timer1_Tick(object sender, EventArgs e) 
    { 
     float amplitude, frequency; 

     amplitude = Convert.ToSingle(trackBar1.Value)/100; 
     label1.Text = amplitude.ToString() + " V"; 

     frequency = trackBar2.Value; 
     label2.Text = frequency.ToString() + " Hz"; 
    } 

I haben auch 4 Radioknöpfe, um zu entscheiden, welche Signaltyp wird angezeigt (Sinus, Rechteck, Dreieck, sawthoot)

Jetzt habe ich dies umgesetzt mit Abbildungsliste (ändern Bild von Signal).

Wie kann ich Art von Signal zu ziehen und regulieren sie mit mit trackbars? So wird es wie im Oszilloskop sein.

Vielen Dank für Ihre Antworten und Code.

+0

Suchen Sie die Formel bitten, eine Linie zu zeichnen oder wie man tatsächlich die Zeile auf dem Formular setzen? – carny666

+1

Was ist das Timer-Ding? Warum hörst du nicht auf das TrackBar.ValueChanged-Ereignis? –

+1

@Nicolas: Timer ist für anderen Teil des Codes. Ich gebe die genauen Werte (Amplitude, Frequenz) an die Hardware-Ausgabe, so dass es Werte zur Ausgabe on-the-fly senden wird. Versucht, das reale Hardware-Ausgangssignal zu visualisieren. –

Antwort

1

Beginnen wir durch die unterschiedlichen Signalarten zu schaffen, ist dies ein Funktion, die eine Wellenlänge der Amplitude 1 erzeugt:

private PointF[] CreateBaseSignal(SignalType signalType) 
{ 
    switch (signalType) 
    { 
    case SignalType.Sine: 
     const int oversampling = 32; 
     PointF[] signal = new PointF[oversampling]; 
     for (int i = 0; i < signal.Length; i++) 
     { 
     signal[i].X = (float) i/oversampling; 
     signal[i].Y = Convert.ToSingle(Math.Sin((double) i/oversampling * 2 * Math.PI)); 
     } 
     return signal; 

    case SignalType.Square: 
     return new PointF[] 
     { 
     new PointF(0.0f, -1.0f), 
     new PointF(0.5f, -1.0f), 
     new PointF(0.5f, 1.0f), 
     new PointF(1.0f, 1.0f), 
     }; 

    case SignalType.Triangle: 
     return new PointF[] 
     { 
     new PointF(0.0f, -1.0f), 
     new PointF(0.5f, 1.0f), 
     }; 

    case SignalType.Sawtooth: 
     return new PointF[] 
     { 
     new PointF(0.0f, -1.0f), 
     new PointF(1.0f, 1.0f), 
     }; 

    default: 
     throw new ArgumentException("Invalid signal type", "signalType"); 
    } 
} 

Dann erstellen wir das tatsächliche Signal mit der gewählten Amplitude und Frequenz:

private PointF[] CreateSignal(PointF[] baseSignal, float frequency, float amplitude) 
{ 
    PointF[] signal = new PointF[Convert.ToInt32(Math.Ceiling(baseSignal.Length * frequency))]; 
    for(int i = 0; i < signal.Length; i++) 
    { 
    signal[i].X = baseSignal[i % baseSignal.Length].X/frequency + (i/baseSignal.Length)/frequency; 
    signal[i].Y = baseSignal[i % baseSignal.Length].Y * amplitude; 
    } 
    return signal; 
} 

Bevor Sie versuchen, dieses Signal zu einem PictureBox plotten, skalieren wir das Signal, welches die Breite und Höhe passen:

private PointF[] ScaleSignal(PointF[] signal, int width, int height) 
{ 
    const float maximumAmplitude = 10.0f; 
    PointF[] scaledSignal = new PointF[signal.Length]; 
    for(int i = 0; i < signal.Length; i++) 
    { 
    scaledSignal[i].X = signal[i].X * width; 
    scaledSignal[i].Y = signal[i].Y * height/2/maximumAmplitude; 
    } 
    return scaledSignal; 
} 

Graphics.DrawLine Unter Verwendung des Signals zu zeichnen ist viel besser als Bitmap.SetPixel, da die Daten Punkte werden auch bei hohen Frequenzen verbunden sein. Bitmap.SetPixel ist auch sehr langsam, Sie müssen wirklich Bitmap.LockBits und unsicheren Code für die Manipulation einzelner Pixel verwenden, um eine anständige Leistung zu erzielen. Mit Graphics.DrawLine, können Sie auch die Kontrolle über die Linienbreite haben, Anti-Aliasing usw.

Da wir das Signal in einem PointF Array gespeichert haben, können wir die einfachen Grafiken verwenden.DrawLines Verfahren das Signal statt Iteration über die Datenpunkte zeichnen:

private void PlotSignal(PointF[] signal, PictureBox pictureBox) 
{ 
    Bitmap bmp = new Bitmap(pictureBox.ClientSize.Width, pictureBox.ClientSize.Height); 
    signal = ScaleSignal(signal, bmp.Width, bmp.Height); // Scale signal to fit image 

    using(Graphics gfx = Graphics.FromImage(bmp)) 
    { 
    gfx.SmoothingMode = SmoothingMode.HighQuality; 
    gfx.TranslateTransform(0, bmp.Height/2); // Move Y=0 to center of image 
    gfx.ScaleTransform(1, -1); // Make positive Y axis point upward 
    gfx.DrawLine(Pens.Black, 0, 0, bmp.Width, 0); // Draw zero axis 
    gfx.DrawLines(Pens.Blue, signal); // Draw signal 
    } 

    // Make sure the bitmap is disposed the next time around 
    Image old = pictureBox.Image; 
    pictureBox.Image = bmp; 
    if(old != null) 
    old.Dispose(); 
} 

Wenn Sie das Signal oft neu zu zeichnen, haben Sie wahrscheinlich die die Bitmap und Grafikobjekten statt neue zu schaffen jedes Mal wieder verwenden wollen. Denken Sie daran, Graphics.Clear zwischen jedem Neuzeichnen aufzurufen.

Putting alles zusammen in einer großen Aussage:

PlotSignal(
    CreateSignal(
    CreateBaseSignal(signalType), 
    frequency, 
    amplitude), 
    thePictureBox); 
0

Wenn Sie nach einer schnellen Plotten Bibliothek sind, ich wirklich wie Dynamic Data Display

Dynamic Data Display

Dies ist eine WPF-Komponente, sondern auch für schnelle, reibungslose Ziehanwendungen wirklich ich denke, es lohnt sich, in den Hafen zu WPF früher rathar als später. Es fühlt sich an, als ob du im Moment sowieso nicht zu weit in deinem Projekt bist.

Entwicklung für WPF scheint für diese Komponente stehen geblieben zu sein (obwohl es für Silverlight zu bearbeitenden weiter). Die Dokumentation ist schrecklich, aber der Quellcode ist über den obigen Link verfügbar, so dass Sie ihn nach Bedarf erweitern können (er ist ziemlich gut geschrieben und sehr erweiterbar) und die Quelle ist von unschätzbarem Wert als Ersatz für das fast vollständige Fehlen jeglicher Dokumentation.

0

Angenommen, Sie eine Sinuswelle auf einem Bildfeld-Steuerelement zeichnen möchten, ein Bildfeld-Steuerelement auf dem Formular erstellen führen Sie dann die folgenden Schritte aus:

int width = pictureBox1.Width; 
    int height = pictureBox1.Height; 
    Bitmap b = new Bitmap(width, height); 

    for (int i = 0; i < width; i++) 
    { 
     int y = (int)((Math.Sin((double)i * 2.0 * Math.PI/width) + 1.0) * (height - 1)/2.0); 
     b.SetPixel(i, y, System.Drawing.Color.Red); 
    } 
    pictureBox1.Image = b; 
+0

Diese zeichnen Sinuslinie, und wie kann ich Amplitude und Frequenz regulieren? Ich nehme an, dass kühne Werte Amplitude und Frequenz ändern. Was sind Verhältnisse? Wie berechnet man sie? int y = (int) ((Math.Sin ((Doppel) i * ** 2.0 ** * Math.PI/Breite) + 1.0) * (Höhe - 1)/** 2.0 **); –

Verwandte Themen