Imports System.Drawing Imports System.Drawing.Drawing2D Imports System.Windows.Forms Imports System.Collections.Generic Public Class Form1 ' Animációs változók Private WithEvents animationTimer As New Timer() Private currentAngle As Single = 0.0F Private rotationSpeed As Single = 1.0F ' Mechanikai sebesség (Fok / tick) Private fieldRelativeAngle As Single = 0.0F ' Frekvenciaváltó változói (-50 Hz és +50 Hz között) Private rotorFrequencyHz As Single = 5.0F Private rotorPhaseAngleRad As Double = 0.0 ' Grafikon adatok Private maxGraphPoints As Integer = 300 Private uHistory As New Queue(Of Single)() Private vHistory As New Queue(Of Single)() Private wHistory As New Queue(Of Single)() ' Vezérlők Private WithEvents speedTrackBar As TrackBar Private speedLabel As Label Private WithEvents freqTrackBar As TrackBar Private freqLabel As Label Protected Overrides Sub OnLoad(e As EventArgs) MyBase.OnLoad(e) Me.Text = "DFIG Szimuláció - Kétirányú mezőgerjesztéssel" Me.Size = New Size(1000, 700) Me.DoubleBuffered = True ' 1. TrackBar: Mechanikai sebesség (0 - 20) speedTrackBar = New TrackBar() With { .Minimum = 0, .Maximum = 20, .Value = 2, .Location = New Point(20, 520), .Size = New Size(400, 45) } Me.Controls.Add(speedTrackBar) speedLabel = New Label() With { .Text = "Mech. sebesség (fok): " & (speedTrackBar.Value / 2.0F).ToString("0.0"), .Location = New Point(430, 525), .Size = New Size(150, 20) } Me.Controls.Add(speedLabel) ' 2. TrackBar: Frekvenciaváltó (-50 Hz és +50 Hz között, 0 van középen) freqTrackBar = New TrackBar() With { .Minimum = -50, .Maximum = 50, .Value = 5, .Location = New Point(20, 580), .Size = New Size(400, 45) } Me.Controls.Add(freqTrackBar) freqLabel = New Label() With { .Text = "Rotor frekvencia: " & freqTrackBar.Value & " Hz", .Location = New Point(430, 585), .Size = New Size(150, 20) } Me.Controls.Add(freqLabel) rotationSpeed = speedTrackBar.Value / 2.0F rotorFrequencyHz = freqTrackBar.Value ' Timer (~60 FPS) animationTimer.Interval = 16 animationTimer.Start() End Sub Private Sub speedTrackBar_Scroll(sender As Object, e As EventArgs) Handles speedTrackBar.Scroll rotationSpeed = speedTrackBar.Value / 2.0F speedLabel.Text = "Mech. sebesség (fok): " & rotationSpeed.ToString("0.0") End Sub Private Sub freqTrackBar_Scroll(sender As Object, e As EventArgs) Handles freqTrackBar.Scroll rotorFrequencyHz = freqTrackBar.Value freqLabel.Text = "Rotor frekvencia: " & rotorFrequencyHz & " Hz" End Sub Private Sub animationTimer_Tick(sender As Object, e As EventArgs) Handles animationTimer.Tick fieldRelativeAngle += CSng(rotorFrequencyHz * 0.05 * 2.0) ' A pozitív frekvencia jobbra (pozitív irányba), a negatív balra forgat If fieldRelativeAngle >= 360.0F Then fieldRelativeAngle -= 360.0F If fieldRelativeAngle < 0.0F Then fieldRelativeAngle += 360.0F ' Mechanikai szög léptetése currentAngle += rotationSpeed If currentAngle >= 360.0F Then currentAngle -= 360.0F Dim timeScale As Double = 0.05 Dim dt As Double = 0.016 * timeScale ' 16ms szorozva a lassítással rotorPhaseAngleRad += 2.0 * Math.PI * rotorFrequencyHz * dt ' Szög normalizálása 0 és 2*PI között If rotorPhaseAngleRad >= 2.0 * Math.PI Then rotorPhaseAngleRad -= 2.0 * Math.PI ElseIf rotorPhaseAngleRad < 0.0 Then rotorPhaseAngleRad += 2.0 * Math.PI End If ' --- Feszültség számítás DFIG fizikával --- Dim mechElectricalRad As Double = (currentAngle * 3) * Math.PI / 180.0 ' Eredő fázisszög = Mechanikai szög + Gerjesztési szög (ami lehet negatív is) Dim totalAngleRad As Double = mechElectricalRad + rotorPhaseAngleRad Dim amplitude As Single = 60.0F Dim uVolt As Single = amplitude * CSng(Math.Sin(totalAngleRad)) Dim vVolt As Single = amplitude * CSng(Math.Sin(totalAngleRad - (2.0 * Math.PI / 3.0))) Dim wVolt As Single = amplitude * CSng(Math.Sin(totalAngleRad - (4.0 * Math.PI / 3.0))) uHistory.Enqueue(uVolt) vHistory.Enqueue(vVolt) wHistory.Enqueue(wVolt) If uHistory.Count > maxGraphPoints Then uHistory.Dequeue() vHistory.Dequeue() wHistory.Dequeue() End If Me.Invalidate() End Sub Protected Overrides Sub OnPaint(e As PaintEventArgs) MyBase.OnPaint(e) Dim g As Graphics = e.Graphics g.SmoothingMode = SmoothingMode.AntiAlias Dim centerX As Integer = 250 Dim centerY As Integer = 450 \ 2 DrawStator(g, centerX, centerY, 180) ' FORGÓRÉSZ (Rotor) kirajzolása a relatív mező-szöggel együtt DrawRotor(g, centerX, centerY, 90, currentAngle, rotorPhaseAngleRad, fieldRelativeAngle) DrawGraph(g, 550, 70, maxGraphPoints, 200) End Sub Private Sub DrawStator(g As Graphics, cx As Integer, cy As Integer, radius As Integer) Using p As New Pen(Color.DarkSlateGray, 8) Dim rOut As Integer = radius + 20 g.DrawEllipse(p, cx - rOut, cy - rOut, rOut * 2, rOut * 2) End Using Using p As New Pen(Color.Gray, 4) g.DrawEllipse(p, cx - radius, cy - radius, radius * 2, radius * 2) End Using Dim phases() As String = {"U1", "V1", "W1", "U2", "V2", "W2"} For i As Integer = 0 To 5 Dim angleStep As Single = i * 60.0F Dim state As GraphicsState = g.Save() g.TranslateTransform(cx, cy) g.RotateTransform(angleStep) Dim poleHeight As Integer = 40 Dim poleWidth As Integer = 30 g.FillRectangle(Brushes.LightGray, -poleWidth \ 2, -radius, poleWidth, poleHeight) g.DrawRectangle(Pens.Black, -poleWidth \ 2, -radius, poleWidth, poleHeight) g.FillRectangle(Brushes.SaddleBrown, -(poleWidth + 8) \ 2, -radius + 5, poleWidth + 8, poleHeight - 15) g.DrawRectangle(Pens.Brown, -(poleWidth + 8) \ 2, -radius + 5, poleWidth + 8, poleHeight - 15) Using font As New Font("Arial", 10, FontStyle.Bold) Dim textState As GraphicsState = g.Save() g.TranslateTransform(0, -radius - 35) g.RotateTransform(-angleStep) Dim textSize As SizeF = g.MeasureString(phases(i), font) g.DrawString(phases(i), font, Brushes.DarkBlue, -textSize.Width / 2, -textSize.Height / 2) g.Restore(textState) End Using g.Restore(state) Next End Sub Private Sub DrawRotor(g As Graphics, cx As Integer, cy As Integer, baseRadius As Integer, mechAngle As Single, acFieldAngleRad As Double, relativeFieldAngle As Single) Dim state As GraphicsState = g.Save() g.TranslateTransform(cx, cy) g.RotateTransform(mechAngle) ' 1. Mechanikai forgás (a teljes rotor forog) ' Forgórész test és tengely g.FillEllipse(Brushes.SlateGray, -baseRadius, -baseRadius, baseRadius * 2, baseRadius * 2) g.DrawEllipse(Pens.Black, -baseRadius, -baseRadius, baseRadius * 2, baseRadius * 2) ' --- DINAMIKUSAN SZÍNEZETT MÁGNESES MEZŐ GYŰRŰ --- Dim fieldState As GraphicsState = g.Save() g.RotateTransform(relativeFieldAngle) ' Relatív forgás a rotorhoz képest Dim fieldRingRadius As Integer = baseRadius - 25 ' Kiszámoljuk, hány fokot kell átszíneznünk a frekvencia nagyságától függően. ' Mivel a max frekvencia 50 Hz, ha megszorozzuk 3.6-tal, akkor 50 Hz-nél pontosan ' 180 fokot (fél kört) fog lefedni a színes csík. Dim fillAngleRange As Single = CSng(Math.Abs(rotorFrequencyHz) * 3.6) ' A kört 5 fokos lépésekben rajzoljuk meg egyedi kis vonalanként (összesen 72 körcikk) For a As Integer = 0 To 355 Step 5 Dim currentLineAngle As Single = a ' Alapértelmezett szín a cián Dim linePen As New Pen(Color.Cyan, 4) ' Kivonunk 270-et, és gondoskodunk róla, hogy 0 és 360 közé essen. Dim relativeToYellow As Single = (currentLineAngle - 270.0F + 360.0F) Mod 360.0F ' Megnézzük, hogy az aktuális vonal beleesik-e a színezési tartományba If rotorFrequencyHz > 0 Then ' Pozitív frekvencia: a sárga ponttól JOBBRA (azaz 0-tól fillAngleRange-ig) piros If relativeToYellow > 0 AndAlso relativeToYellow <= fillAngleRange Then linePen = New Pen(Color.Crimson, 4) End If ElseIf rotorFrequencyHz < 0 Then ' Negatív frekvencia: a sárga ponttól BALRA (azaz 360-fillAngleRange és 360 között) sötétkék If relativeToYellow >= (360.0F - fillAngleRange) AndAlso relativeToYellow < 360 Then linePen = New Pen(Color.DarkBlue, 4) End If End If ' Kis vonal kirajzolása (3 fok hosszú, 2 fok szünet) g.DrawArc(linePen, -fieldRingRadius, -fieldRingRadius, fieldRingRadius * 2, fieldRingRadius * 2, currentLineAngle, 3) linePen.Dispose() Next ' Egy határozott jelölő nyíl/vonal a gyűrű tetején (ez a 0 fok / sárga pont) Using pArrow As New Pen(Color.Gold, 4) g.DrawLine(pArrow, 0, -fieldRingRadius + 8, 0, -fieldRingRadius - 8) g.FillEllipse(Brushes.Gold, -4, -fieldRingRadius - 12, 8, 8) End Using g.Restore(fieldState) ' Visszaállítjuk a rotor alap koordináta-rendszerét ' Tengely középen g.FillEllipse(Brushes.DarkGray, -15, -15, 30, 30) g.DrawEllipse(Pens.Black, -15, -15, 30, 30) ' 6 darab elektromágneses pólus rajzolása For i As Integer = 0 To 5 Dim poleAngle As Single = i * 60.0F Dim poleState As GraphicsState = g.Save() g.RotateTransform(poleAngle) Dim poleHeight As Integer = 45 Dim poleWidth As Integer = 24 g.FillRectangle(Brushes.LightGray, -poleWidth \ 2, -baseRadius - poleHeight, poleWidth, poleHeight) g.DrawRectangle(Pens.Black, -poleWidth \ 2, -baseRadius - poleHeight, poleWidth, poleHeight) Dim currentField As Double = Math.Sin(acFieldAngleRad + (i * Math.PI)) Dim poleColor As Color Dim poleText As String = "" Dim intensity As Integer = CInt(Math.Abs(currentField) * 200) + 55 If currentField > 0.05 Then poleColor = Color.FromArgb(intensity, 0, 0) poleText = "N" ElseIf currentField < -0.05 Then poleColor = Color.FromArgb(0, 0, intensity) poleText = "S" Else poleColor = Color.DimGray poleText = "0" End If Using b As New SolidBrush(poleColor), p As New Pen(Color.FromArgb(120, poleColor), 1) g.FillRectangle(b, -(poleWidth + 6) \ 2, -baseRadius - poleHeight + 5, poleWidth + 6, poleHeight - 10) g.DrawRectangle(p, -(poleWidth + 6) \ 2, -baseRadius - poleHeight + 5, poleWidth + 6, poleHeight - 10) End Using Using font As New Font("Arial", 9, FontStyle.Bold) Dim textSize As SizeF = g.MeasureString(poleText, font) g.DrawString(poleText, font, Brushes.White, -textSize.Width / 2, -baseRadius - poleHeight + 15) End Using g.Restore(poleState) Next g.Restore(state) End Sub Private Sub DrawGraph(g As Graphics, x As Integer, y As Integer, width As Integer, height As Integer) ' Háttér rács (Oszcilloszkóp fekete doboz) g.FillRectangle(Brushes.Black, x, y, width, height) g.DrawRectangle(Pens.DarkGreen, x, y, width, height) Dim midY As Integer = y + (height \ 2) Using p As New Pen(Color.FromArgb(50, Color.Green), 1) p.DashStyle = DashStyle.Dash g.DrawLine(p, x, midY, x + width, midY) For i As Integer = x + 50 To x + width Step 50 g.DrawLine(p, i, y, i, y + height) Next End Using ' --- LEEGYSZERŰSÍTETT SZEMLÉLTETŐ SZAMÍTÁS --- ' rotationSpeed a csúszka értéke felezve (tehát ha a csúszka 10, a rotationSpeed = 5) ' Ha a rotationSpeed = 5, akkor 5 * 10 = 50 Hz a mechanikai alapfrekvencia. Dim mechHz As Double = rotationSpeed * 10.0 ' A frekvenciaváltó értékét (rotorFrequencyHz) közvetlenül hozzáadjuk vagy kivonjuk Dim outputFrequency As Double = mechHz + rotorFrequencyHz Using font As New Font("Arial", 10, FontStyle.Bold) g.DrawString("Indukált feszültség fázishelyzete", font, Brushes.Black, x, y - 25) ' Fázisjelölések színei g.DrawString("U", font, Brushes.Red, x + 10, y + height + 10) g.DrawString("V", font, Brushes.LimeGreen, x + 40, y + height + 10) g.DrawString("W", font, Brushes.DodgerBlue, x + 70, y + height + 10) ' Kimeneti frekvencia kijelzése (Kerekítve 1 tizedesjegyre) Dim freqText As String = "Kimeneti frekvencia: " & outputFrequency.ToString("0.0") & " Hz" g.DrawString(freqText, font, Brushes.DarkSlateGray, x + 120, y + height + 10) End Using If uHistory.Count < 2 Then Return Dim uPoints As New List(Of PointF)() Dim vPoints As New List(Of PointF)() Dim wPoints As New List(Of PointF)() Dim uArr() As Single = uHistory.ToArray() Dim vArr() As Single = vHistory.ToArray() Dim wArr() As Single = wHistory.ToArray() For i As Integer = 0 To uArr.Length - 1 Dim ptX As Single = x + i uPoints.Add(New PointF(ptX, midY - uArr(i))) vPoints.Add(New PointF(ptX, midY - vArr(i))) wPoints.Add(New PointF(ptX, midY - wArr(i))) Next Using pU As New Pen(Color.Red, 2.5F), pV As New Pen(Color.LimeGreen, 2.5F), pW As New Pen(Color.DodgerBlue, 2.5F) g.DrawLines(pU, uPoints.ToArray()) g.DrawLines(pV, vPoints.ToArray()) g.DrawLines(pW, wPoints.ToArray()) End Using End Sub End Class