Autor |
Beitrag |
Stefan99
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Mi 06.04.11 09:53
Hallo,
ich möchte Frequenzwerte eines Sensors darstellen.
Die Werte kann ich über eine dll vom Sensor auslesen (als float).
Ich habe mir das so vorgestellt, dass ich mir Wertepaare generiere (Frequenzwert, Zeitstempel) und diese dann wie
ein Oszibild in Echtzeit darstelle...
geht das?
wenn ja, wie?
ich weiß nicht, wie ich anfangen soll...
Dank Euch
|
|
Dr. Hallo
      
Beiträge: 110
Erhaltene Danke: 13
XP
C/C++/C#
|
Verfasst: Mi 06.04.11 12:12
im prinzip musst du dir 'nur' ein diagramm mit x und y achse zeichenen und darauf deine kurve auftragen oder du verwendest vorhanden komponenten, kuck mal hier:
www.codeproject.com/...aphics/zedgraph.aspx
hab spaß
|
|
Stefan99 
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Mi 06.04.11 13:13
dein 'nur' ist zutreffend 
|
|
Dr. Hallo
      
Beiträge: 110
Erhaltene Danke: 13
XP
C/C++/C#
|
Verfasst: Mi 06.04.11 15:00
na, zeig doch mal her was du bisher so codiert hast um die wertepaare auszulesen...
|
|
Stefan99 
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Do 07.04.11 07:12
so - bin schon ein schönes Stück weitergekommen.
Hab das jetzt so gemacht, dass ab 20 Werten beim Hinzufügen eines Neuen, der erste gelöscht wird - dann sieht das irgendwie etwas komisch aus, weil der Graph nicht "im Ursprung" anfängt, sonder eine Lücke entsteht (s. Screenshot).
Ein derzeitiges Problem ist, dass der Graph ziemlich doll flackert.
Wie kann ich die y-Achse "fest" machen? Damit immer 0..1000Hz angezeigt werden?
Hier mein Code:
Anmerkung: die Device_Dll stellt die serielle Kommunikation mit meinem Gerät dar...
mit der Funktion ReadCurrentAndFourDynamicVariables_C() erhalte ich Werte zurück, der erste Wert als float ist meine Frequenz. den Wert "time" ist bisher lediglich ein Zähler...
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.IO.Ports; using System.Threading; using ZedGraph;
namespace Heart_tool { public partial class Form1 : Form { public Form1() {
InitializeComponent();
button4.Enabled = false;
comboBox1.Items.Clear(); foreach (string s in System.IO.Ports.SerialPort.GetPortNames()) { comboBox1.Items.Add(s); if (s == "COM1") comboBox1.Text = s; else comboBox1.SelectedIndex = 0; } }
Device_Dll myDevice = new Device_Dll(); bool bRunRead = false;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { Device_Dll.ComPort = comboBox1.SelectedIndex; }
private void textBox11_TextChanged(object sender, EventArgs e) { Device_Dll.ShortAddress = Convert.ToByte(textBox11.Text); }
private void button1_Click(object sender, EventArgs e) {
int[] returnValues = new int[10]; myDevice.ReadVersion_C(Device_Dll.ComPort, Device_Dll.ShortAddress, returnValues);
textBox1.Text = returnValues.ToString<int>("\r\n"); }
private void button2_Click(object sender, EventArgs e) { float[] returnValues = new float[4]; myDevice.ReadCurrentAndFourDynamicVariables_C(Device_Dll.ComPort, Device_Dll.ShortAddress, returnValues); textBox1.Text = returnValues.ToString<float>("\r\n"); }
private void button3_Click(object sender, EventArgs e) { button4.Enabled = true; bRunRead = true; float[] returnValues = new float[4]; double newTime = 0; double newValue = 0; while (bRunRead) { myDevice.ReadCurrentAndFourDynamicVariables_C(Device_Dll.ComPort, Device_Dll.ShortAddress, returnValues); Thread.Sleep(250); newValue = (double)returnValues[0]; textBox2.Text = returnValues[0].ToString(); textBox2.Update(); CreateGraph(zedGraphControl1, newTime++, newValue); SetSize();
Application.DoEvents(); } }
private void button4_Click(object sender, EventArgs e) { bRunRead = false; button4.Enabled = false; }
private void Form1_Load(object sender, EventArgs e) { CreateGraph(zedGraphControl1,0,0); SetSize(); }
private void Form1_Resize(object sender, EventArgs e) { SetSize(); this.Invalidate(); }
private void SetSize() { zedGraphControl1.Location = new Point(10, 10); zedGraphControl1.Size = new Size(650, 250); }
static PointPairList list1 = new PointPairList();
private void CreateGraph(ZedGraphControl zgc, double time, double value) { GraphPane myPane = zgc.GraphPane; myPane.Title.Text = "Frequency"; myPane.XAxis.Title.Text = "time [ms]"; myPane.YAxis.Title.Text = "Frequency [Hz]"; list1.Add(time, value); if (list1.Count > 20) list1.RemoveAt(0);
LineItem myCurve = myPane.AddCurve("", list1, Color.Red, SymbolType.None); zgc.IsAntiAlias = true;
zgc.AxisChange(); zgc.Invalidate(); } } } |
Einloggen, um Attachments anzusehen!
|
|
norman2306
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: Do 07.04.11 08:48
Ich habe auch mal mit ZGraph gearbeitet. Persönlich ist das nicht meine erste Wahl. Ich empfehle das .NET eigene Chart. Das findest du unter System.Windows.Forms.DataVisualization.Charting.Chart in der System.Windows.Forms.DataVisualization-DLL. Alternativ empfehle ich WPF. Dort funktioniert das Data-Binding besser und das Ganze ist noch animiert.
Aber erstmal zur Forms Variante:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| public Form1() { . . .
chart1.AntiAliasing = AntiAliasingStyles.All; chart1.ChartAreas.Add("MyCurve"); chart1.ChartAreas["MyCurve"].AxisX.Title = "t [s]"; chart1.ChartAreas["MyCurve"].AxisY.Title = "[bps]"; } |
Danach musst du noch eine Datenquelle haben. Würde als Klassenvariable zwei Felder definieren:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| class MyClass { BindingList<double> x = new BindingList<double>(); BindingList<double> y = new BindingList<double>(); . . . } |
Diese weist du mittels Daten-Bindung deinem Chart zu:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| public Form1() { . . .
var serie = new Series(); serie.ChartType = SeriesChartType.Spline; serie.Color = Color.Blue; serie.Points.DataBindXY(x, y); chart1.Series.Add(serie);
. . . } |
Die Achsen-Steuerung kannst du über das über chart1.ChartAreas["MyCurve"].AxisX bzw. chart1.ChartAreas["MyCurve"].AxisY anstellen.
Bsp:
C#-Quelltext 1: 2: 3:
| chart1.ChartAreas["MyCurve"].AxisY.Maximum = 1000; chart1.ChartAreas["MyCurve"].AxisY.Interval = 100; chart1.ChartAreas["MyCurve"].AxisY.IsLogarithmic = true; |
in deiner Schleife machst du dann
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| while (bRunRead) { Thread.Sleep(250); myDevice.ReadCurrentAndFourDynamicVariables_C(Device_Dll.ComPort, Device_Dll.ShortAddress, returnValues); x.Add(0.25); y.Add((double)returnValues[0]); } |
Ich würde dir im übrigen empfehlen, statt einer while-Schleife einen Timer zu nehmen oder einen Thread aufzumachen.
Hier mal die Thread-Variante:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| private void button3_Click(object sender, EventArgs e) { Thread DoWork = new Thread(Worker); DoWork.Start(); }
void Worker() { DateTime Start = DateTime.Now; while (bRunRead) { myDevice.ReadCurrentAndFourDynamicVariables_C(Device_Dll.ComPort, Device_Dll.ShortAddress, returnValues); x.Add((DateTime.Now - Start).TotalSeconds); y.Add((double)returnValues[0]);
if(x.Count > 20) x.RemoveAt(0); if(y.Count > 20) y.RemoveAt(0);
Thread.Sleep(250); } } |
Für diesen Beitrag haben gedankt: Stefan99
|
|
Stefan99 
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Do 07.04.11 11:43
Danke dir!
Muss ich mir mal genauer anschauen... das mit dem Thread statt der while Schleife ist übrigens supi - jetzt flackert au nix mehr
Bezügl. WPF - muss ich dann eine WPF-Applikation erstellen?
oO wieder was anderes - jetzt hab ich erst mit C# angefangen 
|
|
norman2306
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: Do 07.04.11 12:12
Jop, da brauchst du eine WPF-Application. Aber wenn du gerade erst mit C#-Sharp angefangen hast, dann bleib lieber erstmal bei WinForms. Später lohnt sich aber der Einstieg in WPF auf jeden Fall.
|
|
Dr. Hallo
      
Beiträge: 110
Erhaltene Danke: 13
XP
C/C++/C#
|
Verfasst: Do 07.04.11 12:41
hier noch ein bsp einer echtzeitkurve mit einer völlig anderen componente...
Einloggen, um Attachments anzusehen!
Für diesen Beitrag haben gedankt: Stefan99
|
|
Dr. Hallo
      
Beiträge: 110
Erhaltene Danke: 13
XP
C/C++/C#
|
Verfasst: Do 07.04.11 12:44
aber ich die von norman beschriebene methode ist schon die beste und sicherste...
|
|
Stefan99 
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Do 07.04.11 12:49
Dr Hallo,
ich seh kein weiteres Beispiel 
|
|
Dr. Hallo
      
Beiträge: 110
Erhaltene Danke: 13
XP
C/C++/C#
|
Verfasst: Do 07.04.11 13:05
ich hab das als projekt hochgeladen, wenn du willst kannst dus dir runterladen und ansehen.
(müsste eigendlich gehen!!)  oder auch nicht  bin etwas wirr heute
vg
|
|
Stefan99 
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Mo 11.04.11 14:01
so jetzt läuft das Dingens mit der Chart-Funktion - sieht schonmal sehr viel besser aus
jetzt hab ich hier aber noch etwas störendes während der Darstellung und zwar:
jedesmal, wenn ein neuer X-Achsenabschnitt (derzeit alle 2sec) erzeugt wird, sprich ein vertikaler Einheitenstrich, bleibt das
Chart ganz kurz stehen macht dann Sprunghaft weiter - verloren gehen keine Daten, sieht nur etwas unschön aus.
weiß jemand, was ich da noch ändern/ hinzufügen könnte?
Danke
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| while(FillChart){ newTime = (DateTime.Now - Start).TotalSeconds; Random rdm = new Random(); newValue = Convert.ToDouble( rdm.Next(600) ); AddPoint( Math.Round(newTime,2), newValue); } . . private void AddPoint(double Time, double Value) { chart1.Series["Series1"].Points.AddXY(Time, Value); } |
|
|
norman2306
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: Mo 11.04.11 14:35
Läuft in einem Thrad oder? Füge mal ein Thread.Sleep(60) in deine while-Schleife ein.
|
|
Stefan99 
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Mo 11.04.11 14:44
nein das ging nicht mehr - sonst meckert der rum, dass er einen Aufruf in keinem externen Thread machen kann oder so...
ein Thread.Sleep bringt auch keine Besserung... Vielleicht liegts am Debuggen oder mein Rechner ist zu langsam *ggg*
hier (s. Anhang) nochmals kurz die Symptome erklärt
also das Chart bleibt kurz (wenn neuer vertikaler Strich gezeichnet wird) stehen, und das Chart baut sich dann nach-und-nach wieder zur "vollen Größe" auf...
Einloggen, um Attachments anzusehen!
|
|
norman2306
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: Mo 11.04.11 15:08
Das stimmt. Dann musst du mit Invoke arbeiten:
Thread:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| while(FillChart) { newTime = (DateTime.Now - Start).TotalSeconds; Random rdm = new Random(); newValue = Convert.ToDouble( rdm.Next(600) ); this.Invoke((Action<double, double>)AddPoint, new object[2] { Math.Round(newTime,2), newValue }); Thread.Sleep(60); } |
Für diesen Beitrag haben gedankt: Stefan99
|
|
Stefan99 
Hält's aus hier
Beiträge: 13
WIN XP
Ansi C, C# (VS2010 express)
|
Verfasst: Di 12.04.11 07:01
Wow - geil - DANKE!
Im Moment fällt mir nur noch eine Kleinigkeit auf:
ich habe einen <Beenden-Button>, dieser reagiert aber erst beim 2. Drücken.
Sieht so aus, als würde das Form erst beim ersten klick aktiviert und beim 2. dann erst
der Button bestätigt.
Sicher kannst du mir dabei auch helfen
Merci
|
|