EDN Admin
Well-known member
What Im doing: Building a real time voltage meter. Im graphing an analog input of my Arduino over time in a picture box in a Windows Forms application. My arduino sends measurements through a Serial Port Connection to the Forms Application.
But to simplify things as I got the graphics working, I just built a dummy method, int GetReading(), which just spits out the next number in a simple triangle waveform.
My Problem: I have code to graph this simple function working, but the performance is slower than I would like. The time it takes to graph a new point is 3 ms, limiting my sampling frequency to about 330 Hz at best (this is without the Serial
Communication).
My Question: Can I graph faster? Can I reduce the time it takes to plot a new point?
Or is 3 ms pretty much as good as it gets? If I only update part of the picture box rather than the whole control, will that speed things up at all. I began to try that, but couldnt get it working. Is there another faster graphing technique? Is there a
way I could optimize my code below? Would graphing points instead of graphing lines speed things up much? Should I use use OpenGL instead of the System:rawing namespaces?
Ideally Id like to be sampling as fast as in the kHz, but I realize now that thats probably impossible. Even if I could get my time down to 1 or 2 ms per new point, that would be excellent. I know that I could take an array of samples quickly and then
graph them after the fact, but Id much prefer a real time display. If anyone has any advice, I would really REALLY appreciate it. Im pretty lost here.
All the best,
clydeFrog
PS. Ive included excerpts from my code below... This is a VC++ Forms Application...
My Code:
<pre class="prettyprint using namespace System;<br/>using namespace System:iagnostics;<br/>using namespace System::ComponentModel;<br/>using namespace System::Collections;<br/>using namespace System::Windows::Forms;<br/>using namespace System:ata;<br/>using namespace System:rawing; private: <br/> Stopwatch ^ timeElapsed;
int ticks;
int lastY;
Bitmap ^ bm;
Graphics ^ bmg;
static bool picBoxInitialized = false;
//...
void InitializeComponent(void)
{
//...
this->pictureBox1->Paint += gcnew PaintEventHandler(this, &Form1:ictureBox1_Paint);
//...
}
//...
private: System::Void StartBtn_Click(System::Object^ sender, System::EventArgs^ e) {
this->StartBtn->Enabled = false;
this->DrawAxes(); //Draws two lines for the x and y axes
timeElapsed = Stopwatch::StartNew();
for(ticks = 1; ticks < 489; ticks++){
this->pictureBox1->Invalidate();
this->Update();
}
timeElapsed->Stop();
Int64 numTicks = timeElapsed->ElapsedTicks;
long freq = timeElapsed->Frequency;
double timePerSample = span/489; //489 points plotted
this->StartBtn->Enabled = true;
}
private: void pictureBox1_Paint(System::Object^ sender, System::Windows::Forms:aintEventArgs ^ e){
if(!this->picBoxInitialized)
{
bm = gcnew Bitmap(this->pictureBox1->Width, this->pictureBox1->Height);
bmg = System:rawing::Graphics::FromImage(bm);
bmg->SmoothingMode = System:rawing:rawing2D::SmoothingMode::AntiAlias;
bmg->CompositingQuality = System:rawing:rawing2D::CompositingQuality::GammaCorrected;
bmg->Clear(Color::White);
picBoxInitialized = true;
DrawAxes();
lastY = 0;
}
else
{
int newY = getReading(); //Returns next value of a simple triangle waveform I setup for testing
//GetY and GetX just convert an x y coordinate
//to a location in pictureBox1
bmg->DrawLine(Pens::Black, GetX(ticks-1), GetY(lastY), GetX(ticks), GetY(newY));
lastY = newY;
}
e->Graphics->DrawImage(bm, 0, 0);
}
//... [/code]
<br/>
View the full article
But to simplify things as I got the graphics working, I just built a dummy method, int GetReading(), which just spits out the next number in a simple triangle waveform.
My Problem: I have code to graph this simple function working, but the performance is slower than I would like. The time it takes to graph a new point is 3 ms, limiting my sampling frequency to about 330 Hz at best (this is without the Serial
Communication).
My Question: Can I graph faster? Can I reduce the time it takes to plot a new point?
Or is 3 ms pretty much as good as it gets? If I only update part of the picture box rather than the whole control, will that speed things up at all. I began to try that, but couldnt get it working. Is there another faster graphing technique? Is there a
way I could optimize my code below? Would graphing points instead of graphing lines speed things up much? Should I use use OpenGL instead of the System:rawing namespaces?
Ideally Id like to be sampling as fast as in the kHz, but I realize now that thats probably impossible. Even if I could get my time down to 1 or 2 ms per new point, that would be excellent. I know that I could take an array of samples quickly and then
graph them after the fact, but Id much prefer a real time display. If anyone has any advice, I would really REALLY appreciate it. Im pretty lost here.
All the best,
clydeFrog
PS. Ive included excerpts from my code below... This is a VC++ Forms Application...
My Code:
<pre class="prettyprint using namespace System;<br/>using namespace System:iagnostics;<br/>using namespace System::ComponentModel;<br/>using namespace System::Collections;<br/>using namespace System::Windows::Forms;<br/>using namespace System:ata;<br/>using namespace System:rawing; private: <br/> Stopwatch ^ timeElapsed;
int ticks;
int lastY;
Bitmap ^ bm;
Graphics ^ bmg;
static bool picBoxInitialized = false;
//...
void InitializeComponent(void)
{
//...
this->pictureBox1->Paint += gcnew PaintEventHandler(this, &Form1:ictureBox1_Paint);
//...
}
//...
private: System::Void StartBtn_Click(System::Object^ sender, System::EventArgs^ e) {
this->StartBtn->Enabled = false;
this->DrawAxes(); //Draws two lines for the x and y axes
timeElapsed = Stopwatch::StartNew();
for(ticks = 1; ticks < 489; ticks++){
this->pictureBox1->Invalidate();
this->Update();
}
timeElapsed->Stop();
Int64 numTicks = timeElapsed->ElapsedTicks;
long freq = timeElapsed->Frequency;
double timePerSample = span/489; //489 points plotted
this->StartBtn->Enabled = true;
}
private: void pictureBox1_Paint(System::Object^ sender, System::Windows::Forms:aintEventArgs ^ e){
if(!this->picBoxInitialized)
{
bm = gcnew Bitmap(this->pictureBox1->Width, this->pictureBox1->Height);
bmg = System:rawing::Graphics::FromImage(bm);
bmg->SmoothingMode = System:rawing:rawing2D::SmoothingMode::AntiAlias;
bmg->CompositingQuality = System:rawing:rawing2D::CompositingQuality::GammaCorrected;
bmg->Clear(Color::White);
picBoxInitialized = true;
DrawAxes();
lastY = 0;
}
else
{
int newY = getReading(); //Returns next value of a simple triangle waveform I setup for testing
//GetY and GetX just convert an x y coordinate
//to a location in pictureBox1
bmg->DrawLine(Pens::Black, GetX(ticks-1), GetY(lastY), GetX(ticks), GetY(newY));
lastY = newY;
}
e->Graphics->DrawImage(bm, 0, 0);
}
//... [/code]
<br/>
View the full article