Decomposing an EKG monitor into byte-sized components (part 1)
Starting with bad puns in the article title.. We’re off to a good start!
The same time every year, my wife, who is a nurse in the telemetry unit has to re-certify in her knowledge of cardiac arrhythmia. To be certified, every nurse in the telemetry unit must get a perfect score on an exam. Being able to identify ventricular fibrillation while juggling up to four other patients and making sure to chart everything is just one of the significant challenges that she has to conquer on a daily basis.
The first time my wife had to take this exam, she asked if I could help her study. “Sure,” I thought, “how hard could it be?” Well let’s just say I’ll stick with my current line of work as an engineer.
There are 20 arrhythmia, which if not treated can be problematic, and possibly fatal.
That’s 20 different patterns that you need to be able to accurately identify in a few seconds given only the information displayed on the patient’s heart rhythm monitor. If you mix them up, you might end up recommending a calcium channel blocker, which could cause your patients heart rate to grind to a halt! How stressful!
Before we began, I asked my wife what kinds of materials were made available to nurses in her unit to study for this exam. “They give us a bunch of printouts and we take modules every year to keep us sharp.” That’s pretty good, but I was hoping for more interactive tools to help with the studying. There’s only so much you can learn from staring at a static printout. I searched online to see if there were any additional resources we could use to study, but the best I found were YouTube videos and written articles. If you fail this test twice, you could literally be out of a job, so why aren’t there more simulated monitors that can be used to study?
I set out to create an interactive monitor which could be used to simulate all of the different arrhythmia in hopes to make studying for this certification process easier for my wife, and cardiac nurses everywhere. First I needed to do some research, asking questions like..
How does the monitor work?
The monitor itself invokes nostalgic memories of my TI-83 graphing calculator, as it’s main function is to plot a series of connected points onto a grid — the electrocardiogram. 10 electrodes placed on the patient measure differences in electrical potential between the locations where they are attached. The placement of these electrodes creates 12 measurable leads, one example being the lead formed from the those between the patient’s left and right arms. The measurements from these leads are represented in mV, plotted on the Y-axis of the monitor with the X-axis representing the passage of time. Vitals, including the heart rate, blood pressure, oxygen saturation, respiration, and temperature can also be displayed alongside the electrocardiogram. The monitor also contains a control panel, which allows you to set alarm conditions, mute the alarm, and create a read out of the monitor’s state for later review.
That’s a lot of useful functionality bundled in a fairly small package!
After watching the 15th YouTube video on heart rhythm monitoring, including one which explained the interesting etymology of the torsades arrhythmia, I was getting a little better at understanding some of the mathematics behind the practice. For example, the grid that is displayed on the EKG monitor is subdivided twice into squares of equal sizes. The small squares represent 40 ms of time on the X-axis and 0.1 mV of amplitude on the Y-axis. The larger squares are made up of 5x5 small squares, so they correspond to 0.2 seconds of time on the X-axis and 0.5 mV of amplitude on the Y-axis. While that may not sound very mind blowing, it turns out to be extremely useful in identifying various rhythms and AV blocks using the components of the rhythm. For example, you can just remember the number of squares wide that a QRS complex should be (2 to 3 small squares). You can also determine the approximate heart rate based on the number of squares (e.g. peaks 4 large squares apart is 75–100 BPM).
Now that I had a pretty good understanding of how to use an EKG monitor, it was time to write..
Requirements for a simulated EKG monitor
I put together a terse list of functional requirements:
- Accurately spaced small and large square grid background
- Real-time plotting of readings from leads that can be paused, resumed and restarted
- Overlaid text for additional vitals, including HR, BP, etc
- Ability to save current readings for later review
- Alarm which can be triggered when vitals are at configurable levels
Some of these requirements have some overlap, for example the grid background and the plotting of readings both are a kind of display. Being able to save readings and configure alarm levels both rely on some form of storage. After staring at a blank piece of paper for awhile, I started to formulate the building blocks that I would need to create which I could then assemble into an EKG monitor:
Designing a display component
When designing the display, I decided to break it down into several distinct layers. Each of these layers render different information including the text for the vitals, the rhythm, and the grid lines:
I wanted to leave the interface of my display component pretty basic so it wouldn’t be hard to create new implementations. I’m going to treat each layer (vitals, sensors, grid) as it’s own display, and by leaving this interface sparse it’s easy for me to implement it in these 3 separate cases:
draw method allows the owner request a new frame to be rendered however often they desire, and the
clear method allows for the display to be wiped clean, which will be useful when I want to load a reading from storage.
Notice this interface doesn’t contain any specifics on how these layers will be rendered, it only exposes how the display can be controlled, which is all that the owner of this component need concern itself with.
Of course, once I start implementing a
Display, I will need to render something, otherwise the display won’t be useful. But what should I target for the rendering device? Should it control an external device? Should it use an HTML canvas? Should it use a DirectX render target? There are many options, but I’m not going to worry about them just yet. I can figure that detail out later. Instead, I’ll just design an interface that can encapsulate all the functionality I desire for my use-cases:
From the layers I defined above, everything I need can be done with something that implements this interface. The vitals layer only uses
drawText to print out vitals, the leads layer only uses
drawLine, to render the plotted voltage readings, and the grid layer only uses
drawLine to create the large and small squares.
As you can see, I’ve also packed in some additional types to allow styling of lines and text, as well as some helpful aliases, like
Area, for making the parameters to these interface methods more compact.
Let’s see an example of how this interface can be implemented to create the grid layer:
GridDisplay was a fairly straightforward task. Everything it needs to do can be broken down into calls to
drawLine. At some point, it will need to render to some surface, so let’s look at a couple of examples on how we could implement a
I think this application will be most useful on a webpage, so that it can be accessed from a broad range of devices. An HTML Canvas would suit all of our needs quite well, but I didn’t understand how to use it at first, so I cheated a little and created an implementation that does nothing more than writes out what would have been drawn as text to the console:
This was vital in early debugging. It allowed me to ensure that all of my grid lines were being drawn straight, and at the right distances apart. After some more head scratching, I wrapped my head around how the HTML Canvas works and adapted it to my render context interface, but I’m going to save that fur part 2 of this write up, which will also include details on how I went about implementing the real-time measuring and drawing of lead voltages, how I implemented a feature to allow the playback of previously recorded data, and how I tested all of these features by taking advantage of the sparse interfaces that I had defined.
Thank you for reading.