Pre loader

Tag: serial

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

1 vote
15k views

Hello,

I have been working with an application that plots real-time serial data using a FIFO buffer. I have started programming around the ECG-Monitor example as this is exactly what I am creating.

I have a device that broadcasts real-time ECG data via Bluetooth (HC-05), to be exact. I have paired the device and opened a SerialPort in my program to receive the data. My sampling rate is 256 Hz.

When I used a text file to simulate ECG data, it works perfectly well. However, when I use real-time data, there is a delay in charting that increases as the time increases. An easier way to understand this is, the chart continues plotting for a significant period of time even after I have switched off my hardware device.

I have then come to the conclusion that my data is being received at the rate that I want it to, but the plotting gets delayed at an increasing rate as the time increases.

I am currently using the Direct-X rendering type as this gives me a very smooth plot. I receive the data via SerialPort, write to an array and then to the FIFO buffer.

I’m attaching my code for the same.

namespace SciChart.Examples.Examples.SeeFeaturedApplication.ECGMonitor
{
    public class ECGMonitorViewModel : BaseViewModel
    {
    private Timer _timer;
    private IXyDataSeries<double, double> _series0;
    public static double[] _sourceData = new double[50000];
    private int _currentIndex = 0;
    private int _totalIndex = 0;
    private DoubleRange _yVisibleRange;
    private bool _isBeat;
    private int _heartRate;
    private bool _lastBeat;
    private DateTime _lastBeatTime;
    private ICommand _startCommand;
    private ICommand _stopCommand;
    private const double WindowSize = 5.0;
    private const int TimerInterval = 40;
    public static int counter = 0;
    public static SerialPort mySerialPort=new SerialPort("COM3",9600);

    public ECGMonitorViewModel()
    {
        mySerialPort.Open();
        ECGMonitorViewModel.mySerialPort.WriteLine("A");
        ECGMonitorViewModel.mySerialPort.WriteLine("F");

        _series0 = new XyDataSeries<double, double>() { FifoCapacity = 2460, AcceptsUnsortedData = true };

        YVisibleRange = new DoubleRange(-20, 500);
        _startCommand = new ActionCommand(OnExampleEnter);
        _stopCommand = new ActionCommand(OnExampleExit);
    }

    public ICommand StartCommand
    {
        get
        {
            return _startCommand;
        }
    }

    public ICommand StopCommand
    {
        get
        {
            return _stopCommand;
        }
    }

    public IXyDataSeries<double, double> EcgDataSeries
    {
        get
        {
            return _series0;
        }
        set
        {
            _series0 = value;
            OnPropertyChanged("EcgDataSeries");
        }
    }

    public DoubleRange YVisibleRange
    {
        get
        {
            return _yVisibleRange;
        }
        set
        {
            _yVisibleRange = value;
            OnPropertyChanged("YVisibleRange");
        }
    }

    public bool IsBeat
    {
        get
        {
            return _isBeat;
        }
        set
        {
            if (_isBeat != value)
            {
                _isBeat = value;
                OnPropertyChanged("IsBeat");
            }
        }
    }

    public int HeartRate
    {
        get { return _heartRate; }
        set
        {
            _heartRate = value;
            OnPropertyChanged("HeartRate");
        }
    }

    public void OnExampleExit()
    {
        if (_timer != null)
        {
            _timer.Stop();
            _timer.Elapsed -= TimerElapsed;
            _timer = null;
        }
    }

    public void OnExampleEnter()
    {
        _timer = new Timer(TimerInterval) { AutoReset = true };
        _timer.Elapsed += TimerElapsed;
        _timer.Start();
    }

    private void TimerElapsed(object sender, EventArgs e)
    {
        lock (this)
        {
            for (int i = 0; i < 10; i++)
            {
                AppendPoint(250);
            }

            if ((DateTime.Now - _lastBeatTime).TotalMilliseconds < 120) return;

            IsBeat = _series0.YValues[_series0.Count - 3] > 120 ||
                     _series0.YValues[_series0.Count - 5] > 120 ||
                     _series0.YValues[_series0.Count - 8] > 120;

            if (IsBeat && !_lastBeat)
            {
                HeartRate = (int)(60.0 / (DateTime.Now - _lastBeatTime).TotalSeconds);
                _lastBeatTime = DateTime.Now;
            }
        }
    }

    private void AppendPoint(double sampleRate)
    {
        if (_currentIndex >= _sourceData.Length)
        {
            _currentIndex = 0;
        }

        double voltage = _sourceData[_currentIndex];
        double time = _totalIndex / sampleRate %10;

        if(time==0.00)
        {
            voltage = double.NaN;
        }

        _series0.Append(time, voltage);

        _lastBeat = IsBeat;
        _currentIndex++;
        _totalIndex++;
    }

    public static void mySerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        while (mySerialPort.BytesToRead > 0)
        {
            int b;
            b = mySerialPort.ReadByte();
            _sourceData[counter] = b;
            counter++;
        }
    }
}
}

namespace SciChart.Examples.Examples.SeeFeaturedApplication.ECGMonitor
{
    public partial class ECGMonitorView : UserControl
    {
        public ECGMonitorView()
        {
            InitializeComponent();
            ECGMonitorViewModel.mySerialPort.DataReceived += new SerialDataReceivedEventHandler(ECGMonitorViewModel.mySerialPort_DataReceived);
        }
    }
}

The xaml code is as follows,

<UserControl
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:local="clr-namespace:SciChart.Examples.Examples.SeeFeaturedApplication.ECGMonitor"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:s="http://schemas.abtsoftware.co.uk/scichart"
         xmlns:s3D="http://schemas.abtsoftware.co.uk/scichart3D" xmlns:XamlRasterizer="clr-namespace:SciChart.Drawing.XamlRasterizer;assembly=SciChart.Drawing" x:Class="SciChart.Examples.Examples.SeeFeaturedApplication.ECGMonitor.ECGMonitorView"
         d:DesignHeight="400"
         d:DesignWidth="600"
         mc:Ignorable="d">

<UserControl.Resources>

    <Style TargetType="{x:Type s:RenderSurfaceBase}">
        <Setter Property="Effect">
            <Setter.Value>
                <DropShadowEffect BlurRadius="5"
                                  ShadowDepth="0"
                                  Color="#FFB3E8F6" />
            </Setter.Value>
        </Setter>
    </Style>

    <local:BeatToScaleConverter x:Key="BeatToScaleConverter" />
</UserControl.Resources>

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding StartCommand}" />
    </i:EventTrigger>
    <i:EventTrigger EventName="Unoaded">
        <i:InvokeCommandAction Command="{Binding StopCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

<Grid>

    <s:SciChartSurface RenderPriority="Low" MaxFrameRate="25" AutoRangeOnStartup="False">

        <s:SciChartSurface.RenderableSeries>
            <s:FastLineRenderableSeries DataSeries="{Binding EcgDataSeries}"
                Stroke="#FFB3E8F6"                                      
                StrokeThickness="2" />
        </s:SciChartSurface.RenderableSeries>

        <s:SciChartSurface.YAxis>
            <s:NumericAxis AxisTitle="Voltage (mV)"
                DrawMinorGridLines="True"
                MaxAutoTicks="5"
                VisibleRange="{Binding YVisibleRange, Mode=TwoWay}" />
        </s:SciChartSurface.YAxis>

        <s:SciChartSurface.XAxis>
            <s:NumericAxis AxisTitle="Seconds (s)" TextFormatting="0.000s" VisibleRange="0, 10" AutoRange="Never"/>
        </s:SciChartSurface.XAxis>

        <s:SciChartSurface.RenderSurface>
            <s3D:Direct3D10RenderSurface/>
        </s:SciChartSurface.RenderSurface>

    </s:SciChartSurface>

    <StackPanel Margin="30,30" Orientation="Horizontal">
        <StackPanel.Effect>
            <DropShadowEffect BlurRadius="5"
                ShadowDepth="0"
                Color="#FFB3E8F6" />
        </StackPanel.Effect>

        <Grid HorizontalAlignment="Left" VerticalAlignment="Top">
            <Canvas x:Name="layer1"
                Width="20"
                Height="20"
                Margin="12,34,10,0">
                <Canvas.RenderTransform>
                    <ScaleTransform CenterX="-6"
                        CenterY="-6"
                        ScaleX="{Binding IsBeat, Converter={StaticResource BeatToScaleConverter}}"
                        ScaleY="{Binding IsBeat, Converter={StaticResource BeatToScaleConverter}}" />
                </Canvas.RenderTransform>
                <Path Data="m 0 0 c -4 -4 -8.866933 -10.79431 -10 -15 0 0 0 -5 5 -5 5 0 5 5 5 5 0 0 0 -5 5 -5 5 0 5.242535 4.02986 5 5 -1 4 -6 11 -10 15 z" Fill="#FFB0E6F4" />
            </Canvas>
        </Grid>

        <TextBlock HorizontalAlignment="Left"
            VerticalAlignment="Top"
            FontFamily="ArialBlack"
            FontSize="36"
            FontWeight="Bold"
            Foreground="#FFB0E6F4"
            Text="{Binding HeartRate}" />
        <TextBlock HorizontalAlignment="Left"
            VerticalAlignment="Top"
            FontFamily="ArialBlack"
            FontSize="36"
            FontWeight="Bold"
            Foreground="#FFB0E6F4"
            Text="BPM" />

    </StackPanel>

    <TextBlock Margin="5"
        HorizontalAlignment="Left"
        VerticalAlignment="Bottom"
        FontSize="9"
        FontStyle="Italic"
        Foreground="#FFB0E6F4"/>

</Grid>

I’ve attached pictures of what my program currently does. I have also attached a file with sample data in case anybody wants to test the program. I have also tried building in release mode and that doesn’t help, either.

The only issue is the delay in plotting of real-time data. Otherwise, the graphing and rendering is really smooth. As I am a complete beginner to this, can somebody help with me with what I might have done wrong?

Thanks a ton,

Jaivignesh Jayakumar

Showing 1 result

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies