Gegenkopplung – VB.Net Beispiel

Gegen1

In diesem Programm wird eine Emitterschaltung mit Gegenkopplung simuliert. Die Änderung zu einem normalen Transistorverstärker ist, dass hier die Basis über einen Widerstand mit dem Kollektor verbunden ist. Damit wird einer Vergrößerung des Kollektorstroms entgegengewirkt. Das Resultat ist eine verkleinerte Verstärkung aber auch eine geringere Verzerrung.

In dem Programm treten viele Neuerungen auf einmal auf. Es wird hier zum ersten Mal mit einer gezeichneten Ausgabe auf einer Picturebox gearbeitet. Wenn Sie sich bereits mit älteren VB-Versionen auskennen, werden Sie hier einige Änderungen feststellen. Allerdings habe ich versucht, altbekannte Prozeduren nachzuprogrammieren. Das sollte die Umstellung erleichtern.

Zusätzlich zur der zeichnerischen Ausgabe wird hier auch noch mit Sinusfunktionen gearbeitet. Auch hier habe ich wieder eine allgemein gültige Funktion geschrieben, die ich in mehreren Programmen verwenden werde. Diese Funktionen erkläre ich wieder an diesem Beispiel ausführlich und konzentriere mich in späteren Beispielen nur noch auf die Besonderheiten.

Aber nun zum Wesentlichen.

Quelltextauszug 1: Zeichnen

Allgemein lässt sich sagen, dass eine Picturebox dafür da ist, ein Bild auf einem Formular anzuzeigen. Allerdings kann eine Picturebox noch mehr. Man kann nämlich auch auf ihr zeichnen. Das ging in VB 6 noch so, dass man mit Pset(x,y) einen Punkt in die Box gesetzt hat. Von diesem Punkt aus konnte man dann anschließend mit line(x,y) eine Linie irgendwo hinziehen. Das Ende der Linie war gleichzeitig der neue Startpunkt für weitere Zeichnungen. So konnte man sich ohne großen Aufwand zeichnerisch über die Picturebox bewegen.
In VB.Net ist die Sache nicht ganz so einfach. So ist es nicht mehr möglich einen einfachen Punkt in die Box zu zeichnen. Außerdem kann man nicht mehr so leicht bis zum nächsten Punkt zeichnen. Das Zeichnen in VB.Net funktioniert nun so:

PictureBox1.CreateGraphics.DrawLine(stift, P1, P2)

 
Mit dieser Prozedur wird eine Linie auf die PictureBox1 gemalt. P1 und P2 sind zwei vorher definierte Punkte, der Start- und der Endpunkt. Diese werden wie Folgt definiert:

Dim P1 As Point

    Dim P2 As Point
 
    P1.X = x
    P1.Y = y
    P2.X = x
    P2.Y = y
 
Für x und y setzen Sie einfache Koordinaten im Pixelformat. In dem Prozeduraufruf findet sich auch noch die Variable stift. Hierbei handelt es sich ebenfalls um eine vorher definierte Variable vom Typ Pen. Es handelt sich hierbei tatsächlich um eine Art Stift der über die Farbe und die Dicke (in Pixeln) definiert wird:

Dim
stiftl As New Pen(Color.LightGreen, 1)

Wir wissen also nun wie wir eine Linie zeichnen können, aber was ist mit einem Punkt? Ich habe keine adäquate Funktion für einen Punkt gefunden. Stattdessen habe ich ein Rechteck als Punkt benutzt. Der Nachteil: ein Rechteck hat eine Mindestgröße von zwei mal zwei Pixeln. Bei einer größeren Auflösung ist dies aber nicht zu sehen. Ein Rechteck definiert man so:

PictureBox1.CreateGraphics.DrawRectangle(Pens.LightGreen, rect)

Die Variable rect ist vom Typ rectangle. Ein Rectangle (Rechteck) wird wiederum über einen Startpunkt (p1) und seiner Größe (size) definiert:

Dim vsize As New Size(pz)
     Dim rect As New Rectangle(P1, vsize)
 
        P1.X = x
        P1.Y = y
        pz.X = 1
        pz.Y = 1

Die Größe wird wiederum über einen Punkt definiert, hier mit den Koordinaten (1,1), der kleinstmöglichen Größe. Die Größe ist später als relativ zum Startpunkt anzusehen.
Damit ich das Programm leichter von VB3.0 in VB.Net transferieren konnte, habe ich mir die beiden alten Prozeduren zum Zeichnen nachprogrammiert. Ich habe sie pset und line genannt. Hier der Quelltext:

Private Sub pSet(ByVal x As Integer, ByVal y As Integer)
        P1.X = x
        P1.Y = y
        pz.X = 1
        pz.Y = 1
 
        Dim vsize As New Size(pz)
        Dim rect As New Rectangle(P1, vsize)
        PictureBox1.CreateGraphics.DrawRectangle(Pens.LightGreen, rect)    End Sub
 
    Private Sub Line(ByVal x As Integer, ByVal y As Integer)
        P2.X = x
        P2.Y = y
 
        PictureBox1.CreateGraphics.DrawLine(stiftl, P1, P2)
        P1.X = x
        P1.Y = y
    End Sub

Punkt P1 ist global definiert. Das bedeutete, dass alle Prozeduren darauf zugreifen können. P1 ist auch immer mein Startpunkt und wird immer neu gesetzt. Dadurch kann ich, wie im alten VB3.0, immer eine Linie relativ vom letzten Punkt ziehen. Wie man sieht muss ich der Prozedur Line nur die Endkoordinaten übergeben. Das bedeutet aber auch, dass wir bei Programmstart zuerst einen Startpunkt setzen müssen.

Quelltextauszug 2: Zeichnen II und Sinusfunktion

Die Prozedur ZeichnenSin ist relativ komplex. Hier wird die komplette Ausgabe behandelt. Zu Beginn wird das Gitter auf die Picturebox gezeichnet:

If pixelx = 0 Then

           For i = 0 To 14
                For j = 0 To 11
                    pSet(5 + (i * 10), (j * 10) + 5)
                Next j
            Next i
            pSet(0, pixely)
        End If

Die beiden For-Schleifen laufen alle möglichen X und Y-Punkte Werte durch. Die Punkte werden dann jeweils mit 10 Pixeln Abstand gezeichnet. Am Ende wird wieder ein Startpunkt gesetzt. Dieser ganze Teil des Programm wird immer nur ausgeführt, wenn pixelx = 0 ist. Dies kommt vor, wenn das Programm zum ersten Mal startet oder das Ende der PB erreicht wurde und ein Reset ausgelöst wurde, wie wir im folgenden Teil sehen:

pixelx = pixelx + 1
        If pixelx >= 150 Then
            PictureBox1.Image = Nothing
            pixelx = 0
        End If

Der pixelx-Wert ist ein allgemeiner Positionspointer. Er wird bei jedem Aufruf um einen Pixel erhöht. Wenn er den Wert 150 annimmt, ist das Ende der Box erreicht. Der Inhalt der Picturebox wird komplett gelöscht und der Pointer wieder auf 0 gesetzt. Das bedeutet auch, dass im nächsten Funktionsaufruf das komplette Raster neu gezeichnet wird.
Wir beschäftigen uns nun mit der Sinusfunktion. In der Elektrotechnik ist folgende Sinusfunktion geläufig:

U(t) = u0 + û * sin(wt)

Hier ist u0 die Grundspannung. Û der Scheitelwert also die maximale Aussteuerung. W (eigentlich Omega) steht hier für die Kreisfrequenz (Berechnung: 2+pi+frequenz). Und t ist die Zeitkonstante. Wenn man t jetzt permanent erhöht, wird sin(…) permanent Werte zwischen 0 und 1 annehmen. Durch die Multiplikation mit dem Scheitelwert entstehen dadurch Werte zwischen 0 und dem Scheitelwert. Wenn u0 größer als null ist, verschiebt sich das Ganze auf der Y-Achse um diesen U0-Wert.
Genau dies erreiche ich im Programm mit diesen Zeilen:

        vt = vt + (7.2 * f)
        If vt >= 361 Then vt = 0
        xvt = Math.PI * vt / 180.0
        ut = u0 + (Math.Sin(xvt)) * ui

Ut entspricht also meiner Eingangsspannung in Abhängigkeit von der Zeit. Jetzt müssen nur noch die anderen Spannungen und die Ströme berechnet werden.
Uce ist die Spannung Kollektor-Emitter. Uce0 der entsprechende Startwert. Ib ist der Basisstrom, ic der Kollektorstrom, v die Verstärkung, rb der Basiswiderstand. Ich benutze hier wieder eine For-Schleif, um den komplexen Einschwingvorgang zu simulieren (vgl. NPN). Nach etwa 10 Berechnungen gleicht der Wert näherungsweise dem tatsächlich messbaren Wert. Vereinfacht wurde hier Ube als konstant 0.6 V angenommen.

uce = 2.5
        uce0 = 2.5
        For i = 1 To 10
            uce0 = (uce0 + uce) / 2
            ib = (uce0 – 0.6) / rb + ut / 1000
            ic = ib * v
            uce = 5 – ic * 1000
            If uce > 5 Then uce = 5
            If uce < 0.1 Then uce = 0.1
        Next i

Was nun nur noch fehlt ist die Ausgabe:

        pixely = 115 – uce * (10 / dime)  ‚*20 denn 1v = 2 kästchen
        If pixely > 115 Then pixely = 115
        If pixely < 5 Then pixely = 5
        Line(pixelx, pixely)

Der y-Wert entspricht der Aussteuerung, der x-Wert der Zeit, die konstant durchläuft. Die Amplitude ist auf die Größe der Picturebox begrenzt. Wird ein bestimmter Wert überschritten oder unterschritten wird einfach ein maximal/minmal Wert gezeichnet. Line zeichnet dann schließlich bis zu den berechneten Koordinaten eine Linie.

Quelltextauszug 3: Der Rest

Die ganze Sinus-Prozedur wird nun alle 2o ms von einem Timer aufgerufen. Dadurch gibt es weniger Ruckler während der Zeichnung. Die Parameter bestimmen Zeichenfrequenz, u0, Û und die Rastergröße.

  Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        ZeichnenSin(1, 0, 1, 0.5)
  End Sub

Ansonsten besteht der Quelltext hauptsächlich aus der Erfassung der aktuellen Werte. Wie man sieht wurde der Scrollbar UI auch hier wieder umgedreht. Außerdem ist die Ausgabe des eingestellten Wertes an eine Textbox in der Prozedur zum Scroll-Event behandelt.

Private Sub VScrollBarUi_Scroll(ByVal sender As System.Object, ByVal e AsSystem.Windows.Forms.ScrollEventArgs) Handles VScrollBarUi.Scroll
        ui = (VScrollBarUi.Maximum – VScrollBarUi.Value + VScrollBarUi.Minimum) / 1000
        lbUi.Text = „Ui = “ + Str(ui * 1000) + „mV“
    End Sub
 
    Private Sub HScrollBarV_Scroll(ByVal sender As System.Object, ByVal e AsSystem.Windows.Forms.ScrollEventArgs) Handles HScrollBarV.Scroll
        v = HScrollBarV.Value
        lbV.Text = „V = “ + Str(v)
    End Sub

Zu Programmstart werden ein paar Startwerde definiert und aktuelle Einstellungen eingelesen.

    Private Sub frmGegenkopplung_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) HandlesMyBase.Load
        uss = 0.01
        v = 100
 
        ui = (VScrollBarUi.Maximum – VScrollBarUi.Value + VScrollBarUi.Minimum) / 1000
        lbUi.Text = „Ui = “ + Str(ui * 1000) + „mV“
        v = HScrollBarV.Value
        lbV.Text = „V = “ + Str(v)
    End Sub

Kompletter Quelltext

Public Class frmGegenkopplung
    Dim pixelx, pixely
    Dim vt, ut
 
    Dim uss, v, ui
    Dim ugrund, uv
 
    Dim P1 As Point
    Dim pz As Point
    Dim P2 As Point
    Dim stiftl As New Pen(Color.LightGreen, 1)
 
    Private Sub pSet(ByVal x As Integer, ByVal y As Integer)
        P1.X = x
        P1.Y = y
        pz.X = 1
        pz.Y = 1
 
        Dim vsize As New Size(pz)
        Dim rect As New Rectangle(P1, vsize)
        PictureBox1.CreateGraphics.DrawRectangle(Pens.LightGreen, rect) ‚, P1) ‚, P1)
    End Sub
 
    Private Sub Line(ByVal x As Integer, ByVal y As Integer)
        P2.X = x
        P2.Y = y
 
        PictureBox1.CreateGraphics.DrawLine(stiftl, P1, P2)
        P1.X = x
        P1.Y = y
    End Sub
 
    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        ZeichnenSin(1, 0, 1, 0.5)
    End Sub
 
    Private Sub VScrollBarUi_Scroll(ByVal sender As System.Object, ByVal e AsSystem.Windows.Forms.ScrollEventArgs) Handles VScrollBarUi.Scroll
        ui = (VScrollBarUi.Maximum – VScrollBarUi.Value + VScrollBarUi.Minimum) / 1000
        lbUi.Text = „Ui = “ + Str(ui * 1000) + „mV“
    End Sub
 
    Private Sub HScrollBarV_Scroll(ByVal sender As System.Object, ByVal e AsSystem.Windows.Forms.ScrollEventArgs) Handles HScrollBarV.Scroll
        v = HScrollBarV.Value
        lbV.Text = „V = “ + Str(v)
    End Sub
 
    Private Sub frmGegenkopplung_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) HandlesMyBase.Load
        uss = 0.01
        v = 100
 
        ui = (VScrollBarUi.Maximum – VScrollBarUi.Value + VScrollBarUi.Minimum) / 1000
        lbUi.Text = „Ui = “ + Str(ui * 1000) + „mV“
        v = HScrollBarV.Value
        lbV.Text = „V = “ + Str(v)
    End Sub
 
    Private Sub ZeichnenSin(ByVal f As Integer, ByVal u0 As Integer, ByVal umax As Integer, ByVal dime As Double)
        Dim xvt, i, ut
        Dim ib, ic, uce, uce0
        ‚Grundspannung
        Dim rb = 270000
        ‚ v = 500
        If pixelx = 0 Then
 
            For i = 0 To 14
                For j = 0 To 11
                    pSet(5 + (i * 10), (j * 10) + 5)
                Next j
            Next i
            pSet(0, pixely)
        End If
        ‚X Koordinaten +1 mit Reset
        pixelx = pixelx + 1
        If pixelx >= 150 Then
            PictureBox1.Image = Nothing
            pixelx = 0
        End If
        ‚Zeit des Sinus
        ‚Herzangabe Frequenz bei Timer = 20ms
        vt = vt + (7.2 * f)
        If vt >= 361 Then vt = 0
        xvt = Math.PI * vt / 180.0
        ‚Ut kurz vor Ausgabe. UV muss berechnet werden
        ut = u0 + (Math.Sin(xvt)) * ui
 
        uce = 2.5
        uce0 = 2.5
        For i = 1 To 10
            uce0 = (uce0 + uce) / 2
            ib = (uce0 – 0.6) / rb + ut / 1000
            ic = ib * v
            uce = 5 – ic * 1000
            If uce > 5 Then uce = 5
            If uce < 0.1 Then uce = 0.1
        Next i
 
        pixely = 115 – uce * (10 / dime)  ‚*20 denn 1v = 2 kästchen
        If pixely > 115 Then pixely = 115
        If pixely < 5 Then pixely = 5
        Line(pixelx, pixely)
    End Sub
End Class

[collapse]

Download Projektdatei

Wenn Sie nur an der Exe-Datei interessiert sind, befindet sich diese in dem Unterordner \bin\Debug.