I am trying plot real-time signal, signal vs time, with WPF and C# (Dynamic Data Display); Once a signal is generated, it should be showed up on a plot chart instantly; The signal can be generated very fast (on the order of mili-second (0.001 second)); What would be the best way to do it? Any suggestion is appreciated.Thanks.
EDIT: An example code will be highly appreciated.
Here is what I have tried:
Plot initiation:
#region Constructor
public SignalStatsDisplay()
{
InitializeComponent();
plotter.Legend.Remove();
_initialChildrenCount = plotter.Children.Count;
int count = plotter.Children.Count;
//do not remove the initial children
if (count > _initialChildrenCount)
{
for (int i = count - 1; i >= _initialChildrenCount; i--)
{
plotter.Children.RemoveAt(i);
}
}
_nColorChannels = 4;
_lineprofileColor = new Color[4];
_lineprofileColor[0] = Colors.Transparent;
_lineprofileColor[1] = Colors.Red;
_lineprofileColor[2] = Colors.Black;
_lineprofileColor[3] = Colors.Blue;
//LineGraph lg = new LineGraph();
LineAndMarker<MarkerPointsGraph> lg = new LineAndMarker<MarkerPointsGraph>();
CirclePointMarker pm = new CirclePointMarker { Size = 10, Fill = Brushes.Green };
// MarkerPointsGraph mpg = new MarkerPointsGraph();
if (_nColorChannels > 0) // plotter init
{
_dataX = new List<int[]>();
_dataY = new List<int[]>();
int[] dataXOneCh = new int[1];
int[] dataYOneCh = new int[1];
dataXOneCh[0] = 0;
dataYOneCh[0] = 0;
/*CirclePointMarker marker = new CirclePointMarker();
marker.Fill = new SolidColorBrush(_lineprofileColor[0]);
marker.Pen = new Pen(marker.Fill, 0);
marker.Size = 2;
int lineWidth = 1;*/
for (int i = 0; i < 4; i++)
{
_dataX.Add(dataXOneCh); // data x-y mapping init
_dataY.Add(dataYOneCh);
EnumerableDataSource<int> xOneCh = new EnumerableDataSource<int>(dataXOneCh);
EnumerableDataSource<int> yOneCh = new EnumerableDataSource<int>(dataYOneCh);
xOneCh.SetXMapping(xVal => xVal);
yOneCh.SetXMapping(yVal => yVal);
CompositeDataSource dsOneCh = new CompositeDataSource(xOneCh, yOneCh);
// LineProfileColorSetup();
lg = plotter.AddLineGraph(dsOneCh,
(new Pen(Brushes.Green, 2)),
pm,
(new PenDescription("Data")));
// lg = plotter.AddLineGraph(dsOneCh,
// Colors.Transparent,
// 2,
// "Data");
// pm.FilteringEnabled = false;
}
plotter.FitToView();
}
else
{
return;
}
}
Data update:
for (int i = 0; i < 1; i++)
{
if (_dataX[i].Length == _dataY[i].Length)
{
EnumerableDataSource<int> xOneCh = new EnumerableDataSource<int>(_dataX[i]);
xOneCh.SetXMapping(xVal => xVal);
EnumerableDataSource<int> yOneCh = new EnumerableDataSource<int>(_dataY[i]);
yOneCh.SetYMapping(yVal => yVal);
CompositeDataSource ds = new CompositeDataSource(xOneCh, yOneCh);
Action UpdateData = delegate()
{
// ((LineGraph)plotter.Children.ElementAt(startIndex + i)).DataSource = ds;
// ((LineGraph)plotter.Children.ElementAt(startIndex + i)).LinePen = new Pen(new SolidColorBrush(Colors.Green), 1);
// ((PointsGraphBase)plotter.Children.ElementAt(startIndex + i)).DataSource = ds;
((PointsGraphBase)plotter.Children.ElementAt(startIndex + i + 1)).DataSource = ds;
// }
// (plotter.Children.ElementAt(startIndex + i)).DataSource = ds;
};
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, UpdateData);
}
}
The problem I have is when signal comes in very fats, say a new signal is generated every mili-second, it seems the graph only generate a new marker every 1 second, which I don't understand.
The basic idea is to generate a plotter.AddLineGraph, then only update the DataSource. But it seems not working. So I thought maybe I am on the wrong direction.
I am not a C# or WPF expert. When LineAndMarker does not work as expected, I started doubting. So I am wondering what would be the general way for people to display real-time signal (rapidly changing, time span between samples could be on mili-second) using WPF and C#.
I found where I did wrong. Here is the part where problem happens:
_pxlValAllChan[0, signalIndex] = pxlValue;
DateTime currentTime = DateTime.Now; //has to come from real file: Tiff
TimeSpan timeSpan = currentTime - _startTime;
_timeStampAllChan[0, signalIndex] = Convert.ToInt16(timeSpan.TotalSeconds);
_pxlValOneChan = new int[_signalLength]; // no need to new it every time
_timeStampOneChan = new int[_signalLength];
for (int i = 0; i <= signalIndex; i++)
{
_pxlValOneChan[i] = _pxlValAllChan[0, i];
//_timeStampOneChan[i] = _timeStampAllChan[0, i];
_timeStampOneChan[i] = i;
}
_signalDisplay.SetData(_timeStampOneChan, _pxlValOneChan, 0, true);
My x data was based on time. I basically consider the initiation of program as starting point, then I keep track of time elapse by subtracting starting time with current time. Then the time elapse is saved as x-axis data (see the line that is commented out). And this actually causes problem. When I simple change x-axis data as index, the problem is gone. The graph update pretty fast. Although I have not figure out how I should change the logic to still use time elapse as my x-axis data, but that is the culprit of slow updating on the graph.