I made a C# WinForms application where I plot thousands of real time data points by using charts. I have noticed that during my application is running when I turn on lets say a web-browser the plot freezes. I tried to plot less points but it seems one never knows which program in parallel will be executed so I'm afraid the CPU usage of other programs depending on the PC will effect the performance.
edit:
private void button1_Click(object sender, EventArgs e)
{
///
_cts = new CancellationTokenSource();
_infiniteLoop = InfiniteLoop(_cts.Token);
}
private async Task InfiniteLoop(CancellationToken cancellationToken = default)
{
ushort[] ushortArray = null;
while (true)
{
Task loopMinimumDurationTask = Task.Delay(100, cancellationToken);
Task<ushort []> calculationTask = Task.Run(() => Calculate());
if (ushortArray != null) PlotData(ushortArray);
ushortArray = await calculationTask;
await loopMinimumDurationTask;
}
}
public ushort [] Calculate()
{
init();
daq.ALoadQueue(chArray, chRange, CHANCOUNT);
ScanOptions options = ScanOptions.Background | ScanOptions.Continuous | ScanOptions.ConvertData;
//setup the acquisiton
UL = daq.AInScan(FIRSTCHANNEL, SINGLE_KANAL_NUM, BUFFERSIZE, ref Rate, Range.Bip10Volts, buffer, options);
UL = daq.GetStatus(out daqStatus, out Count, out Index, FunctionType.AiFunction);
if ((Index >= HALFBUFFSIZE) & ReadLower) //check for 50% more data
{
//get lower half of buffer
UL = MccService.WinBufToArray(buffer, ushortArray, 0, HALFBUFFSIZE);
ReadLower = false; //flag that controls the next read
return ushortArray;
}
else if ((Index < HALFBUFFSIZE) & !ReadLower)
{
//get the upper half
UL = MccService.WinBufToArray(buffer, ushortArray, HALFBUFFSIZE, HALFBUFFSIZE);
ReadLower = true;//flag that controls the next read
return ushortArray;
}
return null;
}
public void PlotData(ushort[] datArray_Plot)
{
////////Thread.Sleep(10);
SerialList1.Clear();
for (int b = 0; b < HALFBUFFSIZE; b++)
{
UL = (daq.ToEngUnits(Range.Bip10Volts, datArray_Plot[b], out temp2));
SerialList1.Add(temp2);
SerialList2.Add(temp2);
ikb_p = ikb_p + 1;
}
int out_size = SerialList1.Count / h; //size of downsampled array
if (out_size <= 2)
out_size = 2;
array = SerialList1.ToArray(); //original array
if (h != 1)
array = Downsample(array, out_size); //downsampled array
if (ikb_p > BUFFERSIZE)
{
chart1.Series["Ch0"].Points.SuspendUpdates();
for (int b = 0; b < out_size; b++)
{
chart1.Series["Ch0"].Points.AddY(array[b]); //Plots each sample or use chart1.Series["Ch0"].Points.DataBindY(array);
if (chart1.Series["Ch0"].Points.Count > display_seconds * FREQ / h)
{
chart1.Series["Ch0"].Points.RemoveAt(0);
}
}
//chart1.Series["Ch0"].Points.ResumeUpdates();
chart1.Invalidate();
}
//FFT
if (SerialList2.Count > 4 * HALFBUFFSIZE / CHANCOUNT)
{
chart2.Series["Freq"].Points.Clear();
float sampling_freq = (float)FREQ;
float[] data = SerialList2.ToArray();
double[] dftIn = new double[data.Length];
double[] dftInIm = new double[data.Length];
double[] DftIn = new double[data.Length];
double[] FFTResult = new double[data.Length];
double[] f = new double[data.Length];
double[] power = new double[data.Length];
double[] window = MathNet.Numerics.Window.Hamming(data.Length);
for (int i = 0; i < data.Length; i++)
{
dftIn[i] = window[i] * (double)data[i];
}
for (int i = 0; i < data.Length; i++)
{
dftInIm[i] = 0.0;
}
FFT(dftIn, dftInIm, out reFFT, out imFFT, (int)Math.Log(data.Length, 2));
for (int i = 0; i < data.Length / 2; i++)
{
if (i > 0)
{
float a = sampling_freq / (float)data.Length;
float x = (float)i * a;
double y = Math.Sqrt(reFFT[i] * reFFT[i] + imFFT[i] * imFFT[i]);
f[i] = x;
FFTResult[i] = 2 * y / (data.Length / 2);
power[i] = 0.5 * FFTResult[i] * FFTResult[i];
}
}
double scale = data.Length / sampling_freq;
chart2.Series["Freq"].Points.DataBindXY(f, power);
float stdCh0 = 0;
float avg1 = SerialList2.Average();
float max1 = SerialList2.Max();
float min1 = SerialList2.Min();
float sum1 = (float)SerialList2.Sum(d => Math.Pow(d - avg1, 2));
stdCh0 = (float)Math.Sqrt((sum1) / (SerialList2.Count() - 1));
label5.Text = avg1.ToString("0.000000");
label22.Text = stdCh0.ToString("0.000000");
label70.Text = max1.ToString("0.000000");
label61.Text = min1.ToString("0.000000");
SerialList2.Clear();
label1.Text = count_sample.ToString();
}
///progressBar1
double ratio = (double)count_sample / (seconds * FREQ);
if (ratio > 1.000)
ratio = 1;
progressBar1.Value = (Convert.ToInt32(1000 * ratio));
progressBar1.Invalidate();
progressBar1.Update();
//Display event handlers
if (comboBox2_changed == true)
{
if (comboBox2.SelectedIndex == 0)
{
//chart1.ChartAreas[0].RecalculateAxesScale();
chart1.ChartAreas[0].AxisY.IsStartedFromZero = false;
}
if (comboBox2.SelectedIndex == 1)
{
//chart1.ChartAreas[0].RecalculateAxesScale();
chart1.ChartAreas[0].AxisY.IsStartedFromZero = true;
}
comboBox2_changed = false;
}
if (comboBox1_changed == true)
{
if (comboBox1.SelectedIndex == 0)
{
chart1.Series["Ch0"].ChartType = SeriesChartType.FastLine;
}
else
chart1.Series["Ch0"].ChartType = SeriesChartType.FastPoint;
}
if (num_updown1_changed)
{
display_seconds = (float)numericUpDown1.Value * 0.001f;
h = (int)numericUpDown2.Value;
chart1.Series["Ch0"].Points.Clear();
//chart1.ChartAreas[0].AxisX.Maximum = display_seconds * FREQ / h;
num_updown1_changed = false;
int avg = (int)((double)FREQ * (Decimal.ToDouble(numericUpDown1.Value) / 1000.0) / max_chart_points);
if (avg != 0)
numericUpDown2.Value = avg;
}
if (num_updown2_changed)
{
display_seconds = (float)numericUpDown1.Value * 0.001f;
h = (int)numericUpDown2.Value;
chart1.Series["Ch0"].Points.Clear();
//chart1.ChartAreas[0].AxisX.Maximum = display_seconds * FREQ / h;
num_updown2_changed = false;
}
}
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
_cts.Cancel();
// Wait the completion of the loop before closing the form
try { _infiniteLoop.GetAwaiter().GetResult(); }
catch (OperationCanceledException) { } // Ignore this error
}