The personal website of Scott W Harden
August 24th, 2016

TENMA Multimeter Serial Hack

I just spent the afternoon reverse-engineering the 72 series TENMA multimeter serial interface, and can now access all of its readings from a standalone Python script. This lets me send all measurements made with the multimeter to my computer in real time (using an optically isolated connection), and eliminates the need for the TENMA PC interface software. In addition to allowing the development of custom software to use measurements from TENMA multimeters in real time, this project also lets allows TENMA multimeters to interface with Linux computers (such as the raspberry pi).

I have owned a TENMA 72-7750 multimeter for several years, and over all I've been happy with it! To be honest, 90% of my multimeter needs are just using a continuity tester or checking to see if there is voltage on a line. For checking electrical signals, I love my no-name (actually it's branded "KOMEC") $15 eBay special multimeter. The screen updates about 4 times a second, and I don't care if it's off by 10%, it's cheap and light and fast and easy for simple tasks. However, when I'm going to use a multimeter to actually measure something, I reach for a higher quality meter like my TENMA 72-7750. Although similar TENMA models may be more popular, I went with this particular one because it could measure frequency which is convenient when building RF circuits. While big fancy frequency counters are nice to have on your workbench, I liked the idea of having that functionality built into my multimeter. I believe my particular model is discontinued, but it looks like the 72-7745 is a similar product, and there are many TENMA multimeters on Amazon. Back in April of 2013 I mentioned on my website that I'd consider writing interface software in Python. Now that I'm [finally] out of school and have a little more free time, I decided to pick up the project again. I ran into a few tangles along the way, but I'm happy to report this project is now working beautifully! The pyTENMA project is open-sourced on my GitHub. I'm excited to see what kind of data I can get out of this thing!

This is my multimeter taking a measurement (resistance) and sending the data to my computer using the optically-isolated serial connector (which ships with the multimeter). In this picture, it's interacting with the official TENMA software. To try to figure out what was going on, I probed pins of the serial port while data was being exchanged. The yellow trace is the data signal.

There was a problem, and this problem took me hours to figure it out, but now that I realize what's going on it seems so obvious. The problem was that I could never get the multimeter to send my Python script data, despite the fact that the exact same configuration would send the commercial program data. I used serial port sniffing software to view the data too! I matched the baud rate (19200 / 19230), data bits (7), and parity (odd), and I just couldn't figure out why the heck this thing wouldn't work. I resorted to using an oscilloscope to probe the pins of the serial cable directly. I made a small man-in-the-middle test jig to give me headers I could easily probe or solder wires to. After poking around, I learned two things. (1) I really need a logic analyzer. They're so cheap now, I went ahead and ordered one. (2) The RTS line goes low and the DSR line goes high when data is being sent. I realized that the Python software was disregarding these pins. You wouldn't think you needed them if you're just going to be receiving data with software control... but I immediately realized that those pins may be important for powering the optoelectronics (likely a phototransistor and some passive components) underlying the data exchange. After all, it's not like the multimeter is able to source or sink appreciable current through an optical connection! I'll note that some sketchy schematics are floating around Hackaday (pun intended), but the web page they link to doesn't look very complete so I'm not sure how far that author got toward the same endeavor I'm chasing.

Here you can see some of the adjacent (non-data) pins change their voltage state during transmissions. Once I realized replicating these states was also necessary, everything quickly fell into place. After manually commanding the RTS pin to lie low (1 line of code), the data starting coming in! I finished writing a basic pyTENMA class (which does a lot of hardware detection, string parsing, etc. to generate simple no-nonsense value/unit pairs to return to the user as well as log values to disk automatically) and tried to make it as simple as possible. Without going into too much detail (see the note in the top of my source code for more information), the multimeter just sends a 9-character ASCII string every second. I refer to this string as ABBBBCDEF. Byte 1 is a multiplier and bytes 2-5 are the value displayed on the screen. The actual value of a read is BBBB*10^A. The units depend on the mode (resistance, capacitance, etc), which is indicated by byte 6. It's a little funny in that "4" means temperature and ";" means voltage, but once I figured out (through trial and error) which symbols match with which mode it was pretty easy to make it work for me. D is the sign (negative, zero, or positive), and I still haven't really figured what E and F are. I thought they might be things like backlight or perhaps indicators of the range setting. I didn't care to figure it out, because I already had access to the data I wanted!

To use the pyTENMA script, just drop it alongside a Python script you want to work on. Import it, tell it a COM port to use (if not, it'll try to guess one) and a log file (optional). This is all the code you need:

import pyTENMA # make sure pyTENMA.py is in the same folder
PT=pyTENMA.pyTenma("COM4","log.txt")
PT.readUntilBroken()

The output is very simple. Here it is compared to the commercial TENMA software. PyroElectro has a good demonstration of the PC interface software that ships with this unit. While the TENMA software is functional, it has some serious limitations that motivate me to improve upon it. (1) It's Windows only. (2) It doesn't automatically log data (you have to manually click save to write it to disk). (3) It seems to be limited to COM1-COM4. My USB serial adapter was on COM7 and inaccessible to this program. I had to go in the device manager and change the advanced settings to allow the commercial software to read my device. (4) The graphs are poor, non-interactive, and often broken. (5) Data output format is only an Excel spreadsheet (.xls), and I don't have control to save in other formats like CSV. If I'm going to use this on a raspberry pi, I don't want to fumble around with Microsoft Office! Yeah I know I can get modules (even for Python) to access data in excel spreadsheets, but it seems like an unnecessary complexity just to retrieve some voltage readings. Over all it seems a little unfortunate that a relatively great product is pulled down when its weakest link is its software. It's okay, we are on our way to can fixing this with pyTENMA!

Measuring Capacitor Leakage

I set up an experiment to demonstrate how logging data works. I charged a 22uF capacitor on a breadboard and let it sit there disconnected, slowly draining through leakage (and perhaps micro current draw from the multimeter). After a while I slowly charged it (using my body as a resistor, touching the +5V line and touching the capacitor lead with my fingers) and watched it discharge again. You can set pyTENMA software to save as little or often as you want. It defaults to every 10 reads, but I adjust it to every 100 reads for longer experiments. Also note that if you break it (with CTRL+C) it gently disconnects the serial device, logs remaining data to disk, then exits gracefully.

In this demonstration, voltage across the capacitor on the breadboard is being measured by the multimeter, and reported (and logged) in real time by pyTENMA seen on the screen. Here is what that data looks like after about a half hour of run time. The code to read the log file and make graphs from it (using numpy and matplotlib) is in the logPlot source code.

Measuring OCXO Warm-Up

Now that I know everything is up and running, I can use this device to make some measurements I'm actually interested in! In reality, this usage case is the reason I went through all the trouble to write custom data logging software for this multimeter is specifically for this case. I'm working on a large project involving a GPS-disciplined oven controlled crystal oscillator (OCXO) for a 1pps frequency reference, and spoiler alert it involves a raspberry pi to plot and upload live graphs of real-time frequency and accuracy statistics to my website. I don't want to discuss it yet (it's not complete), but I can't avoid mentioning it since I'm showing photos of it. I'll surely make a follow-up post when that project is complete and well documented. For now, the only relevant thing is that the device is an oven which takes a lot of current to heat from room temperature to a high temperature, and a smaller amount of current to maintain it at that temperature. I wanted to know how long it takes the current to stabilize over time (on a scale of hours), determine if its current draw oscillates, and also assess what the voltage at the oscillator reads during warm-up (high current draw) vs. stable conditions.

My test setup uses the TENMA multimeter in current measuring configuration. Note the configuration of the multimeter test leads as being in series with the power supply. This meter has two current measurement settings, one for <600 mA and one for up to 10 A. I know that the oscillator draws about 2 A during warm-up (this is because I'm intentionally limiting it to 2A), and stabilizes to somewhere near 200 mA after several minutes. To maximize my sample resolution, I started the recording using the 10 A setting, then after it dropped well below 600 mA I switched to the lower current setting. The data is colored red and blue, respectively:

current stabilizes within 10 minutes:

Current is maxed-out for a few minutes, oscillates then stabilizes. 10 A / 600 mA measuring settings are in red and blue (respectively):

once stable, current draw is stable for hours

I concluded that this thing stabilizes to within 10% of its final current draw well within 10 minutes. From there, it seems really stable, but slowly oscillates on a time scale of tens of minutes. I suspect this correlates with the AC unit of my house turning on and off. A similar recording of temperature of the oscillator (which the TENMA 72-7750 can also do with the thermocouple it was shipped with) may provide more insight as to whether or not the oscillator itself is actually changing temperature during these current oscillations. Now I'm curious what the voltage does during the warm-up period while the current is maxed out. I guess I need to reveal that my current limit is provided by two parallel LM7809 voltage regulators each in series with a 2 Ohm current limiting resistor before connecting to a common +9V rail which is running the oscillator. Since each regulator is current limited to about 1A, it's no surprise my maximum current is about 2A, but I'd be interested to learn what the voltage is doing during that period.

I measured voltage just downstream of the voltage regulators:

During current max-out, the voltage is <<9V

Voltage stabilizes after about 10 minutes

I am interested in seeing what of these measurements (with more such as temperature and OCXO frequency) look like when they are all measured simultaneously. The TENMA multimeter I'm using can't measure voltage and current at the same time (which would require a third lead, if you think about it), so this solution will require alternative equipment. Stay tuned, because I have a cool solution for that in the works! For now, I couldn't be happier with my TENMA multimeter's ability to log data to text files using pyTENMA and the ease in which numpy/matplotlib can read and graph them. A data logging multimeter is a great tool to have in any engineer's toolbox, and I'm glad I now have one that plays nicely with Python.

Resources

Markdown source code last modified on January 18th, 2021
---
title: TENMA Multimeter Serial Hack
date: 2016-08-24 03:08:28
tags: python, old
---

# TENMA Multimeter Serial Hack

__I just spent the afternoon reverse-engineering the 72 series TENMA multimeter serial interface,__ and can now access all of its readings from a standalone Python script. This lets me send all measurements made with the multimeter to my computer in real time (using an optically isolated connection), and eliminates the need for the TENMA PC interface software. In addition to allowing the development of custom software to use measurements from TENMA multimeters in real time, this project also lets allows TENMA multimeters to interface with Linux computers (such as the raspberry pi). 

**I have owned a [TENMA 72-7750](http://www.farnell.com/datasheets/1955368.pdf?_ga=1.217276502.1323514874.1471841353) multimeter for several years, and over all I've been happy with it!** To be honest, 90% of my multimeter needs are just using a continuity tester or checking to see if there is voltage on a line. For _checking_ electrical signals, I love my no-name (actually it's branded "KOMEC") $15 eBay special multimeter. The screen updates about 4 times a second, and I don't care if it's off by 10%, it's cheap and light and fast and easy for simple tasks. However, when I'm going to use a multimeter to actually _measure_ something, I reach for a higher quality meter like my TENMA 72-7750. Although [similar TENMA models may be more popular](http://www.newark.com/MarketingProductList?storeId=10194&catalogId=15003&langId=-1&orderCode=02J5540,02J5541,02J5542,02J5543,02J5546), I went with this particular one because it could measure frequency which is convenient when building RF circuits. While big fancy frequency counters are nice to have on your workbench, I liked the idea of having that functionality built into my multimeter. I believe my particular model is discontinued, but it looks like the 72-7745 is a similar product, and there are [many TENMA multimeters on Amazon](https://www.amazon.com/s/field-keywords=tenma+multimeter). Back in April of 2013 I mentioned on my website that I'd consider writing interface software in Python. Now that I'm [finally] out of school and have a little more free time, I decided to pick up the project again. I ran into a few tangles along the way, but I'm happy to report this project is now working beautifully! The [pyTENMA project](https://github.com/swharden/pyTENMA) is open-sourced on my GitHub. I'm excited to see what kind of data I can get out of this thing!

<div class="text-center img-border">

[![](IMG_7956_thumb.jpg)](IMG_7956.jpg)

</div>

**This is my multimeter taking a measurement (resistance) and sending the data to my computer using the optically-isolated serial connector (which ships with the multimeter).** In this picture, it's interacting with the official TENMA software. To try to figure out what was going on, I probed pins of the serial port while data was being exchanged. The yellow trace is the data signal. 

__There was a problem, and this problem took me hours to figure it out,__ but now that I realize what's going on it seems so obvious. The problem was that I could never get the multimeter to send my Python script data, despite the fact that the exact same configuration would send the commercial program data. I used serial port sniffing software to view the data too! I matched the baud rate (19200 / 19230), data bits (7), and parity (odd), and I just couldn't figure out why the heck this thing wouldn't work. I resorted to using an oscilloscope to probe the pins of the serial cable directly. I made a small man-in-the-middle test jig to give me headers I could easily probe or solder wires to. After poking around, I learned two things. (1) I really need a logic analyzer. They're so cheap now, I went ahead and ordered one. (2) The RTS line goes low and the DSR line goes high when data is being sent. I realized that the Python software was disregarding these pins. You wouldn't _think_ you needed them if you're just going to be receiving data with software control... but I immediately realized that those pins may be important for powering the optoelectronics (likely a phototransistor and some passive components) underlying the data exchange. After all, it's not like the multimeter is able to source or sink appreciable current through an optical connection! I'll note that some [sketchy schematics](http://hackaday.com/2014/12/05/fixing-a-multimeters-serial-interface/) are floating around Hackaday (pun intended), but the [web page they link to](http://www.wattnotions.com/tenma-72-7735-serial-interface/) doesn't look very complete so I'm not sure how far that author got toward the same endeavor I'm chasing.

<div class="text-center img-border">

[![](IMG_7961_thumb.jpg)](IMG_7961.jpg)

</div>

__Here you can see some of the adjacent (non-data) pins change their voltage state during transmissions. Once I realized replicating these states was also necessary, everything quickly fell into place.__ After manually commanding the RTS pin to lie low (1 line of code), the data starting coming in! I finished writing a basic pyTENMA class (which does a lot of hardware detection, string parsing, etc. to generate simple no-nonsense value/unit pairs to return to the user as well as log values to disk automatically) and tried to make it as simple as possible. Without going into too much detail ([see the note in the top of my source code for more information](https://github.com/swharden/pyTENMA/blob/master/pyTENMA.py)), the multimeter just sends a 9-character ASCII string every second. I refer to this string as ABBBBCDEF. Byte 1 is a multiplier and bytes 2-5 are the value displayed on the screen. The actual value of a read is BBBB*10^A. The units depend on the mode (resistance, capacitance, etc), which is indicated by byte 6. It's a little funny in that "4" means temperature and ";" means voltage, but once I figured out (through trial and error) which symbols match with which mode it was pretty easy to make it work for me. D is the sign (negative, zero, or positive), and I still haven't really figured what E and F are. I thought they might be things like backlight or perhaps indicators of the range setting. I didn't care to figure it out, because I already had access to the data I wanted!

__To use the pyTENMA script, just drop it alongside a Python script you want to work on.__ Import it, tell it a COM port to use (if not, it'll try to guess one) and a log file (optional). This is all the code you need:

```python
import pyTENMA # make sure pyTENMA.py is in the same folder
PT=pyTENMA.pyTenma("COM4","log.txt")
PT.readUntilBroken()
```

__The output is very simple.__ Here it is compared to the commercial TENMA software. [PyroElectro has a good demonstration](http://www.pyroelectro.com/tutorials/tenma_digital_multimeter/software.html) of the PC interface software that ships with this unit. While the TENMA software is functional, it has some serious limitations that motivate me to improve upon it. (1) It's Windows only. (2) It doesn't automatically log data (you have to manually click save to write it to disk). (3) It seems to be limited to COM1-COM4. My USB serial adapter was on COM7 and inaccessible to this program. I had to go in the device manager and change the advanced settings to allow the commercial software to read my device. (4) The graphs are poor, non-interactive, and often broken. (5) Data output format is only an Excel spreadsheet (.xls), and I don't have control to save in other formats like CSV. If I'm going to use this on a raspberry pi, I don't want to fumble around with Microsoft Office! Yeah I know I can get modules (even for Python) to access data in excel spreadsheets, but it seems like an unnecessary complexity just to retrieve some voltage readings. Over all it seems a little unfortunate that a relatively great product is pulled down when its weakest link is its software. It's okay, we are on our way to can fixing this with [pyTENMA](https://github.com/swharden/pyTENMA)!

<div class="text-center img-border img-small">

[![](screenshot_thumb.jpg)](screenshot.jpg)
![](commercialSoftware.jpg)

</div>

## Measuring Capacitor Leakage

__I set up an experiment to demonstrate how logging data works.__ I charged a 22uF capacitor on a breadboard and let it sit there disconnected, slowly draining through leakage (and perhaps micro current draw from the multimeter). After a while I slowly charged it (using my body as a resistor, touching the +5V line and touching the capacitor lead with my fingers) and watched it discharge again. You can set pyTENMA software to save as little or often as you want. It defaults to every 10 reads, but I adjust it to every 100 reads for longer experiments. Also note that if you break it (with CTRL+C) it gently disconnects the serial device, logs remaining data to disk, then exits gracefully.

<div class="text-center img-border">

[![](IMG_7981_thumb.jpg)](IMG_7981.jpg)

</div>

__In this demonstration,__ voltage across the capacitor on the breadboard is being measured by the multimeter, and reported (and logged) in real time by pyTENMA seen on the screen. Here is what that data looks like after about a half hour of run time. The code to read the log file and make graphs from it (using numpy and matplotlib) is in the [logPlot source code](https://github.com/swharden/pyTENMA/blob/master/extras/logPlot.py).

<div class="text-center img-medium">

[![](logDemo_thumb.jpg)](logDemo.png)

</div>

## Measuring OCXO Warm-Up

__Now that I know everything is up and running, I can use this device to make some measurements I'm actually interested in!__ In reality, this usage case is the _reason_ I went through all the trouble to write custom data logging software for this multimeter is specifically for this case. I'm working on a large project involving a GPS-disciplined oven controlled crystal oscillator (OCXO) for a 1pps frequency reference, and spoiler alert it involves a raspberry pi to plot and upload live graphs of real-time frequency and accuracy statistics to my website. I don't want to discuss it yet (it's not complete), but I can't avoid mentioning it since I'm showing photos of it. I'll surely make a follow-up post when that project is complete and well documented. For now, the only relevant thing is that the device is an oven which takes a lot of current to heat from room temperature to a high temperature, and a smaller amount of current to maintain it at that temperature. I wanted to know how long it takes the current to stabilize over time (on a scale of hours), determine if its current draw oscillates, and also assess what the voltage at the oscillator reads during warm-up (high current draw) vs. stable conditions.

<div class="text-center img-border">

[![](FullSizeRender-2_thumb.jpg)](FullSizeRender-2.jpg)

</div>

__My test setup uses the TENMA multimeter in current measuring configuration.__ Note the configuration of the multimeter test leads as being in series with the power supply.  This meter has two current measurement settings, one for <600 mA and one for up to 10 A. I know that the oscillator draws about 2 A during warm-up (this is because I'm intentionally limiting it to 2A), and stabilizes to somewhere near 200 mA after several minutes. To maximize my sample resolution, I started the recording using the 10 A setting, then after it dropped well below 600 mA I switched to the lower current setting. The data is colored red and blue, respectively:

current stabilizes within 10 minutes:

<div class="text-center">

[![](ocxo-1_thumb.jpg)](ocxo-1.png)

</div>

Current is maxed-out for a few minutes, oscillates then stabilizes. 10 A / 600 mA measuring settings are in red and blue (respectively):

<div class="text-center">

[![](ocxo-2_thumb.jpg)](ocxo-2.png)

</div>

once stable, current draw is stable for hours

<div class="text-center">

[![](ocxo-3_thumb.jpg)](ocxo-3.png)

</div>

__I concluded that this thing stabilizes to within 10% of its final current draw well within 10 minutes.__ From there, it seems really stable, but slowly oscillates on a time scale of tens of minutes. I suspect this correlates with the AC unit of my house turning on and off. A similar recording of temperature of the oscillator (which the TENMA 72-7750 can also do with the thermocouple it was shipped with) may provide more insight as to whether or not the oscillator itself is actually changing temperature during these current oscillations. Now I'm curious what the voltage does during the warm-up period while the current is maxed out. I guess I need to reveal that my current limit is provided by two parallel LM7809 voltage regulators each in series with a 2 Ohm current limiting resistor before connecting to a common +9V rail which is running the oscillator. Since each regulator is current limited to about 1A, it's no surprise my maximum current is about 2A, but I'd be interested to learn what the voltage is doing during that period.

<div class="text-center img-border">

[![](FullSizeRender-3_thumb.jpg)](FullSizeRender-3.jpg)

</div>

I measured voltage just downstream of the voltage regulators:
<div class="text-center">

[![](mV1_thumb.jpg)](mV1.png)

</div>

During current max-out, the voltage is <<9V
<div class="text-center">

[![](mV2_thumb.jpg)](mV2.png)

</div>

Voltage stabilizes after about 10 minutes
<div class="text-center">

[![](mV3_thumb.jpg)](mV3.png)

</div>

__I am interested in seeing what of these measurements (with more such as temperature and OCXO frequency) look like when they are all measured simultaneously.__ The TENMA multimeter I'm using can't measure voltage and current at the same time (which would require a third lead, if you think about it), so this solution will require alternative equipment. Stay tuned, because I have a cool solution for that in the works! For now, I couldn't be happier with my TENMA multimeter's ability to log data to text files using [pyTENMA](https://github.com/swharden/pyTENMA) and the ease in which numpy/matplotlib can read and graph them. A data logging multimeter is a great tool to have in any engineer's toolbox, and I'm glad I now have one that plays nicely with Python.

## Resources

* pyTENMA on GitHub: [github.com/swharden/pyTENMA](https://github.com/swharden/pyTENMA)
August 20th, 2016

Breadboard Line Driver Module

Sometimes I rapidly want to amplify a signal, but building amplifiers, buffers, and line drivers can be a hassle, especially on a breadboard! It's important to know how to carefully design build tuned and untuned amplifier circuits, but sometimes you just want to analyze or work with a signal without modifying it by sinking too much current, so being able to rapidly drop in a buffer stage would be a great help. Sometimes I want to buffer a signal so I can analyze it (with an oscilloscope or frequency counter) or use use it (perhaps to drive or gate something), but the signal source is across the room, so I need a beefy amplifier to drive it into coax as I run it across my ceiling while I'm experimenting. A MOSFET voltage follower or a Darlington transistor may do the job, but I have to worry about input conditioning, biasing, output voltage limiting, class A, B, C, D, etc., RF vs DC, copying this circuit multiple times for multiple signals, and before you know it I'm sinking more time into my task than I need to.

Line driver chips are one of my go-tos for quickly amplifying digital signals because they're so fast to drop in a breadboard and they provide a strong output with very high impedance inputs and need no external components. Individual buffer of the integrated chip can be paralleled to multiply their current handling capabilities too. One of the common variants is the 74HC240. I don't know why it's so popular (I still find its pinout odd), but because it is popular it is cheap. They're $0.50 on Mouser.com (perhaps cheaper on ebay) and according to their datasheet they can be run up to 7V to deliver or sink 20mA/pin with a maximum dissipation of 500mW. With propagation, enable, and disable times of tens of nanoseconds, they're not awful for lower-range radio frequencies (HF RF). This specific chip (somewhat comically at the exclusion of almost all others) has been latched onto by amateur radio operators who use it as an amplifier stage of low power (QRP) Morse code radio transmitters often pushing it to achieve ~1 watt of power output. A quick google reveals thousands of web pages discussing this! This Portuguese site is one of the most thorough. Even if not used as the final amplifier, they're a convenient intermediate stage along an amplifier chain as they can directly drive FET final stages very well (probably best for class C operation). If you're interested, definitely check out The Handiman's Guide to MOSFET "Switched Mode" Amplifiers guide by Paul Harden (no relation). Also his part 2.

This is the circuit I commonly build. I have one variant on hand for RF (extremely fast oscillations which are continuously fed into the device and often decoupled through a series capacitor), and one for TTL signals (extremely fast). I find myself paralleling line driver outputs all the time. On a breadboard, this means tons of wires! It becomes repetitive and a pain. I've started pre-packaging highly parallel line drivers into little modules which I find really convenient. I have a half dozen of these soldered and ready to go, and I can use them by simply dropping them into a breadboard and applying ground, power (+5V), and input signal, and it amplifies it and returns an output signal. Note that in the "Case 2: RF input" example, the inverted output of the first stage is continuously fed back into the input. This will result in continuous oscillation and undesired output if no input is supplied. In case 2, RF must be continuously applied. The advantage is that the feedback network holds the input near the threshold voltage, so very little voltage swing through the decoupling capacitor is required to generate strong output.

Although I have made this entirely floating, I prefer using copper-clad board. Not only does it aid heat dissipation and provide better mechanical structure, but it also serves as a partial RF shield to minimize noise in the input and output signals. A Dremel with a diamond wheel does a good job at cutting out notches in the copper-clad board.

The best way to replicate this is to look at the picture. It's surprisingly difficult to get it right just by looking at the datasheet, because when it's upside down it's mirror-imaged and very easy to make mistakes. I just connect all inputs and all outputs in parallel, for 7 of 8 gates. For one gate, I connect its output to the parallel inputs. I added some passives (including a ferrite bead and decoupling capacitor on the VCC pin) and it's good to go. With only 4 pins (GND, +5V, IN, and OUT) this amplifier is easy to drop in a breadboard:

Although I often use it in a breadboard, it's easy to stick in a project. Since the back side is unpopulated, you can use a dot of super glue and stick it anywhere you want. In this example, I had a GPS receiver module which blinked a LED at exactly one pulse per second (1PPS) [check out why] and I wanted to do some measurements on its output. I couldn't send this line signal out a coax line because it was so low current (in reality, I didn't know what it could deliver). This is a perfect use for a buffer / line driver.

I glued this board inside my temporary project enclosure (which admittedly looks nicer and more permanent than it's actually intended to be) and set the output to deliver through 50 Ohm coax. It works beautifully!

Markdown source code last modified on January 18th, 2021
---
title: Breadboard Line Driver Module
date: 2016-08-20 19:16:27
tags: circuit, old
---

# Breadboard Line Driver Module

__Sometimes I rapidly want to amplify a signal, but building amplifiers, buffers, and line drivers can be a hassle, especially on a breadboard!__ It's important to know how to carefully design build [tuned and untuned amplifier circuits](https://en.wikibooks.org/wiki/Practical_Electronics/Amplifiers#Type_of_load), but sometimes you just want to analyze or work with a signal without modifying it by sinking too much current, so being able to rapidly drop in a buffer stage would be a great help. Sometimes I want to buffer a signal so I can analyze it (with an oscilloscope or frequency counter) or use use it (perhaps to drive or gate something), but the signal source is across the room, so I need a beefy amplifier to drive it into coax as I run it across my ceiling while I'm experimenting. A [MOSFET voltage follower](https://en.wikipedia.org/wiki/Buffer_amplifier#Impedance_transformation_using_the_MOSFET_voltage_follower) or a [Darlington transistor](https://en.wikipedia.org/wiki/Darlington_transistor) may do the job, but I have to worry about input conditioning, biasing, output voltage limiting, class A, B, C, D, etc., RF vs DC, copying this circuit multiple times for multiple signals, and before you know it I'm sinking more time into my task than I need to. 

__Line driver chips are one of my go-tos for quickly amplifying digital signals because they're so fast to drop in a breadboard and they provide a strong output with very high impedance inputs and need no external components.__ Individual buffer of the integrated chip can be paralleled to multiply their current handling capabilities too. One of the common variants is the 74HC240. I don't know why it's so popular (I still find its pinout odd), but because it is popular it is cheap. They're [$0.50 on Mouser.com](http://www.mouser.com/Semiconductors/Integrated-Circuits-ICs/Logic-ICs/Buffers-Line-Drivers/_/N-6j78c?P=1z0z63x&Keyword=74hc240&FS=True) (perhaps cheaper on ebay) and [according to their datasheet](http://www.nxp.com/documents/data_sheet/74HC_HCT240.pdf) they can be run up to 7V to deliver or sink 20mA/pin with a maximum dissipation of 500mW. With propagation, enable, and disable times of tens of nanoseconds, they're not awful for lower-range radio frequencies (HF RF). This specific chip (somewhat comically at the exclusion of almost all others) has been latched onto by amateur radio operators who use it as an amplifier stage of low power (QRP) Morse code radio transmitters often pushing it to achieve ~1 watt of power output. A quick google [reveals](https://www.google.com/search?q=74hc240+transmitter) thousands of web pages discussing this! This [Portuguese site](http://py2ohh.w2c.com.br/trx/digital/rfdigital.htm) is one of the most thorough. Even if not used as the final amplifier, they're a convenient intermediate stage along an amplifier chain as they can directly drive FET final stages very well (probably best for class C operation). If you're interested, definitely check out [The Handiman's Guide to MOSFET "Switched Mode" Amplifiers guide by Paul Harden](http://www.aoc.nrao.edu/~pharden/hobby/_ClassDEF1.pdf) (no relation). Also his [part 2](http://www.aoc.nrao.edu/~pharden/hobby/_ClassDEF2.pdf).

<div class="text-center img-medium">

[![](schematic_thumb.jpg)](schematic.jpg)

</div>

This is the circuit I commonly build. I have one variant on hand for RF (extremely fast oscillations which are continuously fed into the device and often decoupled through a series capacitor), and one for TTL signals (extremely fast). __I find myself paralleling line driver outputs all the time. On a breadboard, this means tons of wires!__ __It becomes repetitive and a pain. I've started pre-packaging highly parallel line drivers into little modules which I find really convenient.__ I have a half dozen of these soldered and ready to go, and I can use them by simply dropping them into a breadboard and applying ground, power (+5V), and input signal, and it amplifies it and returns an output signal. Note that in the "Case 2: RF input" example, the inverted output of the first stage is continuously fed back into the input. This will result in continuous oscillation and undesired output if no input is supplied. In case 2, RF must be continuously applied. The advantage is that the feedback network holds the input near the threshold voltage, so very little voltage swing through the decoupling capacitor is required to generate strong output.

<div class="text-center img-border img-small">

[![](IMG_7890_thumb.jpg)](IMG_7890.jpg)
[![](IMG_7894_thumb.jpg)](IMG_7894.jpg)
[![](IMG_7897_thumb.jpg)](IMG_7897.jpg)

</div>

__Although I have made this entirely floating, I prefer using copper-clad board.__ Not only does it aid heat dissipation and provide better mechanical structure, but it also serves as a partial RF shield to minimize noise in the input and output signals. A Dremel with a diamond wheel does a good job at cutting out notches in the copper-clad board.

<div class="text-center img-border img-small">

[![](IMG_7898_thumb.jpg)](IMG_7898.jpg)
[![](IMG_7900_thumb.jpg)](IMG_7900.jpg)
[![](IMG_7909_thumb.jpg)](IMG_7909.jpg)

</div>

__The best way to replicate this is to look at the picture.__ It's surprisingly difficult to get it right just by looking at the datasheet, because when it's upside down it's mirror-imaged and very easy to make mistakes. I just connect all inputs and all outputs in parallel, for 7 of 8 gates. For one gate, I connect its output to the parallel inputs. I added some passives (including a [ferrite bead](https://en.wikipedia.org/wiki/Ferrite_bead) and decoupling capacitor on the VCC pin) and it's good to go. With only 4 pins (GND, +5V, IN, and OUT) this amplifier is easy to drop in a breadboard:

<div class="text-center img-border">

[![](IMG_7904_thumb.jpg)](IMG_7904.jpg)

</div>

__Although I often use it in a breadboard, it's easy to stick in a project.__ Since the back side is unpopulated, you can use a dot of super glue and stick it anywhere you want. In this example, I had a GPS receiver module which blinked a LED at exactly one pulse per second (1PPS) [[check out why](http://electronics.stackexchange.com/questions/30750/why-do-gps-receivers-have-a-1-pps-output)] and I wanted to do some measurements on its output. I couldn't send this line signal out a coax line because it was so low current (in reality, I didn't know what it could deliver). This is a perfect use for a buffer / line driver. 

<div class="text-center img-border">

[![](IMG_7912_thumb.jpg)](IMG_7912.jpg)

</div>

I glued this board inside my temporary project enclosure (which admittedly looks nicer and more permanent than it's actually intended to be) and set the output to deliver through 50 Ohm coax. It works beautifully!

<div class="text-center img-border img-small">

[![](IMG_7943_thumb.jpg)](IMG_7943.jpg)
[![](IMG_7948_thumb.jpg)](IMG_7948.jpg)

</div>
August 8th, 2016

DIY ECG with 1 op-amp

⚠️ Check out my newer ECG design:

I made surprisingly good ECG from a single op-amp and 5 resistors! An ECG (electrocardiograph, sometimes called EKG) is a graph of the electrical potential your heart produces as it beats. Seven years ago I posted DIY ECG Machine on the Cheap which showed a discernible ECG I obtained using an op-amp, two resistors, and a capacitor outputting to a PC sound card's microphone input. It didn't work well, but the fact that it worked at all was impressive! It has been one of the most popular posts of my website ever since, and I get 1-2 emails a month from people trying to recreate these results (some of them are during the last week of a college design course and sound pretty desperate). Sometimes people get good results with that old circuit, but more often than not the output isn't what people expected. I decided to revisit this project (with more patience and experience under my belt) and see if I could improve it. My goal was not to create the highest quality ECG machine I could, but rather to create the simplest one I could with emphasis on predictable and reproducible results. The finished project is a blend of improved hardware and custom cross-platform open-source software (which runs on Windows, Linux, and MacOS), and an impressively good ECG considering the circuit is so simple and runs on a breadboard! Furthermore, the schematics and custom software are all open-sourced on my github!

Here's a video demonstrating how the output is shown in real time with custom Python software. The video is quite long, but you can see the device in action immediately, so even if you only watch the first few seconds you will see this circuit in action with the custom software. In short, the amplifier circuit (described in detail below) outputs to the computer's microphone and a Python script I wrote analyzes the audio data, performs low-pass filtering, and graphs the output in real time. The result is a live electrocardiograph!

ECG Circuit

The circuit is simple, but a lot of time and thought and experimentation went into it. I settled on this design because it produced the best and most reliable results, and it has a few nuances which might not be obvious at first. Although I discuss it in detail in the video, here are the highlights:

  • The output goes to the microphone jack of your computer.

  • There's nothing special about the op-amp I used (LM741). A single unit of an LM324 (or any general purpose op-amp) should work just as well.

  • Resistor values were chosen because I had them on hand. You can probably change them a lot as long as they're in the same ballpark of the values shown here. Just make sure R1 and R2 are matched, and R3 should be at least 10MOhm.

  • Do not use a bench power supply! "BAT+" and "BAT-" are the leads of a single 9V battery.

  • Note that the leg electrode is ground (same ground as the computer's microphone ground)

  • R5 and R4 form a traditional voltage divider like you'd expect for an op-amp with a gain of about 50.

    • You'd expect R4 to connect to ground, but since your body is grounded, chest 2 is essentially the same

    • R3 must be extremely high value, but it pulls your body potential near the optimal input voltage for amplification by the op-amp.

    • R1 and R2 split the 9V battery's voltage in half and center it at ground, creating -4.5V and +4.5V.

  • altogether, your body stays grounded, and the op-amp becomes powered by -4.5V and +4.5V, and your body is conveniently near the middle and ready to have small signals from CHEST1 amplified. Amplification is with respect to CHEST2 (roughly ground), rather than actual ground, so that a lot of noise (with respect to ground) is eliminated.

For those of you who would rather see a picture than a schematic, here's a diagram of how to assemble it graphically. This should be very easy to reproduce. Although breadboards are typically not recommended for small signal amplification projects, there is so much noise already in these signals that it doesn't really matter much either way. Check out how good the signals look in my video, and consider that I use a breadboard the entire time.

The most comfortable electrodes I used were made for muscle simulators. A friend of mine showed me some muscle stimulator pads he got for a back pain relief device he uses. As soon as I saw those pads, I immediately thought they would be perfect for building an ECG! They're a little bit expensive, but very comfortable, reusable, last a long time, and produce brilliant results. They also have 3.5 mm (headphone jack) connectors which is perfect for DIY projects. On Amazon.com you can get 16 pads for $11 with free shipping. I decided not to include links, because sometimes the pads and cords are sold separately, and sometimes they have barrel connectors and sometimes they have snap connectors. Just get any adhesive reusable electrodes intended for transcutaneous electrical nerve stimulation (TENS) that you can find! They should all work fine.

Pennies as Electrodes

You can make your own electrodes for $0.03! Okay that's a terrible joke, but it's true. I made not-awful electrodes by soldering wires to copper pennies, adding strength by super-gluing the wire to the penny, and using electrical tape to attach them to my chest. Unless you want a tattoo of an old guy's face on your torso, wait until they cool sufficiently after soldering before proceeding to the adhesion step. I suspect that super gluing the penny to your chest would also work, but please do not do this. Ironically, because the adhesive pads of the TENS electrodes wear away over time, the penny solution is probably "more reusable" than the commercial electrode option.

This ECG was recorded using pennies as electrodes:

Notes on filtering: Why didn't I just use a hardware low-pass filter?

  1. It would have required extra components, which goes against the theme of this project
  2. It would require specific value components, which is also undesirable for a junkbox project
  3. I'm partial to the Chebyshev filter, but getting an extremely sharp roll-off a few Hz shy of 50Hz would take multiple poles (of closely matched passive components) and not be as trivial as it sounds.

Notes on software: This a really cool use of Python! I lean on some of my favorite packages numpy, scipy, matplotlib, pyqrgraph, and PyQt4. I've recently made posts describing how to perform real-time data graphing in Python using these libraries, so I won't go into that here. If you're interested, check out my real-time audio monitor, notes on using PlotWidget, and notes on using MatPlotLib widget. I tried using PyInstaller to package this project into a single .EXE for all my windows readers who might want to recreate this project, but the resulting EXE was over 160MB! That's crazy! It makes sense considering packagers like PyInstaller and Py2EXE work by building your entire python interpreter and all imported libraries. With all those fun libraries I listed above, it's no wonder it came out so huge. It may be convenient for local quick-fixes, but not a good way to distribute code over the internet. To use this software, just run it in Python. It was tested to work with out-of-the-box WinPython-64bit-3.5.2.1 (not the Qt5 version), so if you want to run it yourself start there.

Notes on safety. How safe is this project? I'm conflicted on this subject. I want to be as conservative as I can (leaning on the side of caution), but I also want to be as realistic as possible. I'm going to play it safe and say "this may not be safe, so don't build or use it". As an exercise, let's consider the pros and cons:

  • PROS:

    • It's powered from a 9V battery which is safer than a bench power supply (but see the matching con).

    • The only connections to your body are:

      • leg - ground. you ground yourself all the time. using a wrist grounding strap is the same thing.
      • chest 1 - extremely high impedance. You're attaching your chest to the high impedance input of an op-amp (which I feel fine with), and also to a floating battery through a 10MOhm resistor (which also I feel fine with)
      • chest 2 - raises an eyebrow. In addition to a high impedance input, you're connected to an op-amp through a 100k resistor. Even if the op-amp were putting out a full 4.5V, that's 0.045mA (which doesn't concern me a whole lot).
    • I don't know where to stick this, but I wonder what type of voltages / currents TENS actually provide.

  • CONS / WARNINGS:

    • It's powered from a 9V battery. So are many stun guns.
    • If the op-amp oscillates, oscillations may enter your body. Personally I feel this may be the most concerning issue.
    • Small currents can kill. I found a curiously colored website that describes this. It seems like the most dangerous potential effect is induction of cardiac fibrillation, which can occur around 100mA.

Improving safety through optical isolation: The safety of this device may be improved (albeit with increased complexity) through the implementation of opto-isolators. I may consider a follow-up post demonstrating how I do this. Unlike digital signals which I've optically isolated before, I've never personally isolated analog signals. Although I'm sure there are fully analog means to do this, I suspect I'd accomplish it by turning it into a digital signal (with a voltage-to-frequency converter), pulsing the output across the optoisolator, and turning it back into voltage with a frequency-to-voltage converter or perhaps even a passive low-pass filter. Analog Devices has a good write-up about optical isolation techniques.

Do you have comments regarding the safety of this device? Write your thoughts concisely and send them to me in an email! I'd be happy to share your knowledge with everyone by posting it here.

Did you build this or a device similar to it? Send me some pictures! I'll post them here.

Source code and project files: https://github.com/swharden/diyECG-1opAmp/

LEGAL: This website is for educational purposes only. Do not build or use any electrical devices shown. Attaching non-compliant electronic devices to your body may be dangerous. Consult a physician regarding proper usage of medical equipment.

Markdown source code last modified on January 18th, 2021
---
title: DIY ECG with 1 op-amp
date: 2016-08-08 01:49:24
tags: diyECG, python, circuit
---

# DIY ECG with 1 op-amp

> **⚠️ Check out my newer ECG design:** 
* [**Sound Card ECG with AD8232**](https://swharden.com/blog/2019-03-15-sound-card-ecg-with-ad8232/)

__I made surprisingly good ECG from a single op-amp and 5 resistors! __An ECG (electrocardiograph, sometimes called EKG) is a graph of the electrical potential your heart produces as it beats. Seven years ago I posted _[DIY ECG Machine on the Cheap](https://www.swharden.com/wp/2009-08-14-diy-ecg-machine-on-the-cheap/)_ which showed a discernible ECG I obtained using an op-amp, two resistors, and a capacitor outputting to a PC sound card's microphone input. It didn't work well, but the fact that it worked at all was impressive! It has been one of the most popular posts of my website ever since, and I get 1-2 emails a month from people trying to recreate these results (some of them are during the last week of a college design course and sound pretty desperate). Sometimes people get good results with that old circuit, but more often than not the output isn't what people expected. I decided to revisit this project (with more patience and experience under my belt) and see if I could improve it. My goal was not to create the highest quality ECG machine I could, but rather to create the _simplest_ one I could with emphasis on predictable and reproducible results. The finished project is a blend of improved hardware and custom cross-platform open-source software (which runs on Windows, Linux, and MacOS), and an impressively good ECG considering the circuit is so simple and runs on a breadboard! Furthermore, the schematics and custom software are all [open-sourced on my github](https://github.com/swharden/diyECG-1opAmp/)!

![](https://www.youtube.com/embed/AfirWls9Sys)

__Here's a video demonstrating how the output is shown in real time with custom Python software.__ The video is quite long, but you can see the device in action immediately, so even if you only watch the first few seconds you will see this circuit in action with the custom software. In short, the amplifier circuit (described in detail below) outputs to the computer's microphone and a Python script I wrote analyzes the audio data, performs low-pass filtering, and graphs the output in real time. The result is a live electrocardiograph!

<div class="text-center">

[![](ECG_1470609065_thumb.jpg)](ECG_1470609065.png)

</div>

### ECG Circuit

<div class="text-center">

[![](circuit_thumb.jpg)](circuit.jpg)

</div>

__The circuit is simple, but a lot of time and thought and experimentation went into it.__ I settled on this design because it produced the best and most reliable results, and it has a few nuances which might not be obvious at first. Although I discuss it in detail in the video, here are the highlights:

*   The output goes to the microphone jack of your computer.
*   There's nothing special about the op-amp I used ([LM741](http://www.ti.com/lit/ds/symlink/lm741.pdf)). A single unit of an [LM324](http://www.ti.com.cn/cn/lit/ds/symlink/lm2902-n.pdf) (or any general purpose op-amp) should work just as well.
*   Resistor values were chosen because I had them on hand. You can probably change them a lot as long as they're in the same ballpark of the values shown here. Just make sure R1 and R2 are matched, and R3 should be at least 10MOhm.
*   <span style="color: #ff0000;">Do not use a bench power supply!</span> "BAT+" and "BAT-" are the leads of a single 9V battery.
*   Note that the leg electrode is ground (same ground as the computer's microphone ground)
*   R5 and R4 form a traditional voltage divider like you'd expect for an op-amp with a gain of about 50.

    *   You'd expect R4 to connect to ground, but since your body is grounded, chest 2 is essentially the same

    *   R3 must be extremely high value, but it pulls your body potential near the optimal input voltage for amplification by the op-amp.

    *   R1 and R2 split the 9V battery's voltage in half and center it at ground, creating -4.5V and +4.5V.

*   altogether, your body stays grounded, and the op-amp becomes powered by -4.5V and +4.5V, and your body is conveniently near the middle and ready to have small signals from CHEST1 amplified. Amplification is with respect to CHEST2 (roughly ground), rather than actual ground, so that a lot of noise (with respect to ground) is eliminated.

<div class="text-center img-border">

[![](IMG_7574_thumb.jpg)](IMG_7574.jpg)

</div>

__For those of you who would rather see a picture than a schematic__, here's a diagram of how to assemble it graphically. This should be very easy to reproduce. Although breadboards are typically not recommended for small signal amplification projects, there is so much noise already in these signals that it doesn't really matter much either way. Check out how good the signals look in my video, and consider that I use a breadboard the entire time.

<div class="text-center">

[![](design_thumb.jpg)](design.jpg)

</div>

__The most comfortable electrodes I used were made for muscle simulators.__ A friend of mine showed me some muscle stimulator pads he got for a back pain relief device he uses. As soon as I saw those pads, I immediately thought they would be perfect for building an ECG! They're a little bit expensive, but very comfortable, reusable, last a long time, and produce brilliant results. They also have 3.5 mm (headphone jack) connectors which is perfect for DIY projects. On Amazon.com you can get 16 pads for $11 with free shipping. I decided not to include links, because sometimes the pads and cords are sold separately, and sometimes they have barrel connectors and sometimes they have snap connectors. Just get any adhesive reusable electrodes intended for [transcutaneous electrical nerve stimulation (TENS)](https://en.wikipedia.org/wiki/Transcutaneous_electrical_nerve_stimulation) that you can find! They should all work fine.

<div class="text-center img-border">

[![](IMG_7576_thumb.jpg)](IMG_7576.jpg)

</div>

### Pennies as Electrodes

__You can make your own electrodes for $0.03!__ Okay that's a terrible joke, but it's true. I made not-awful electrodes by soldering wires to copper pennies, adding strength by super-gluing the wire to the penny, and using electrical tape to attach them to my chest. Unless you want a tattoo of an old guy's face on your torso, wait until they cool sufficiently after soldering before proceeding to the adhesion step. I suspect that super gluing the penny to your chest would also work, but please do not do this. Ironically, because the adhesive pads of the TENS electrodes wear away over time, the penny solution is probably "more reusable" than the commercial electrode option.

<div class="text-center img-border img-small">

[![](IMG_7527_thumb.jpg)](IMG_7527.jpg)
[![](IMG_7570-1_thumb.jpg)](IMG_7570-1.jpg)

</div>

This ECG was recorded using pennies as electrodes:

<div class="text-center">

[![](ECG_1470611901_thumb.jpg)](ECG_1470611901.png)

</div>

__Notes on filtering:__ Why didn't I just use a [hardware low-pass filter](https://en.wikipedia.org/wiki/Low-pass_filter)?

1.   It would have required extra components, which goes against the theme of this project
2.   It would require _specific value_ components, which is also undesirable for a junkbox project
3.   I'm partial to the [Chebyshev filter](https://en.wikipedia.org/wiki/Chebyshev_filter), but getting an extremely sharp roll-off a few Hz shy of 50Hz would take multiple poles (of closely matched passive components) and [not be as trivial as it sounds](http://www.analog.com/library/analogDialogue/archives/43-09/EDCh%208%20filter.pdf?doc=ADA4661-2.pdf).

__Notes on software:__ This a really cool use of Python! I lean on some of my favorite packages [numpy](http://www.numpy.org/), [scipy](https://www.scipy.org/), [matplotlib](http://matplotlib.org/), [pyqrgraph](http://www.pyqtgraph.org/), and [PyQt4](https://wiki.python.org/moin/PyQt4). I've recently made posts describing how to perform real-time data graphing in Python using these libraries, so I won't go into that here. If you're interested, check out my [real-time audio monitor](https://www.swharden.com/wp/2016-07-31-real-time-audio-monitor-with-pyqt/), notes on using [PlotWidget](https://www.swharden.com/wp/2016-07-31-live-data-in-pyqt4-with-plotwidget/), and notes on using [MatPlotLib widget](https://www.swharden.com/wp/2016-07-30-live-data-in-pyqt4-with-matplotlibwidget/). I tried using [PyInstaller](http://www.pyinstaller.org/) to package this project into a single .EXE for all my windows readers who might want to recreate this project, but the resulting EXE was over 160MB! That's crazy! It makes sense considering packagers like PyInstaller and Py2EXE work by building your entire python interpreter and all imported libraries. With all those fun libraries I listed above, it's no wonder it came out so huge. It may be convenient for local quick-fixes, but not a good way to distribute code over the internet. To use this software, just run it in Python. It was tested to work with out-of-the-box [WinPython-64bit-3.5.2.1](https://sourceforge.net/projects/winpython/files/) (not the Qt5 version), so if you want to run it yourself start there.

__Notes on safety.__ How safe is this project? I'm conflicted on this subject. I want to be as conservative as I can (leaning on the side of caution), but I also want to be as realistic as possible. I'm going to play it safe and say "this may not be safe, so don't build or use it". As an exercise, let's consider the pros and cons:

*   __PROS:__

    *   It's powered from a 9V battery which is safer than a bench power supply (but see the matching con).
    *   The only connections to your body are:

        *   leg - ground. you ground yourself all the time. using a wrist grounding strap is the same thing.
        *   chest 1 - extremely high impedance. You're attaching your chest to the high impedance input of an op-amp (which I feel fine with), and also to a floating battery through a 10MOhm resistor (which also I feel fine with)
        *   chest 2 - raises an eyebrow. In addition to a high impedance input, you're connected to an op-amp through a 100k resistor. Even if the op-amp were putting out a full 4.5V, that's 0.045mA (which doesn't concern me a whole lot).

    *   I don't know where to stick this, but I wonder what type of voltages / currents [TENS](https://en.wikipedia.org/wiki/Transcutaneous_electrical_nerve_stimulation) actually provide.

*   __CONS / WARNINGS:__

    *   It's powered from a 9V battery. So are many stun guns.
    *   If the op-amp oscillates, oscillations may enter your body. Personally I feel this may be the most concerning issue.
    *   Small currents can kill. I found a [curiously colored website](https://www.physics.ohio-state.edu/~p616/safety/fatal_current.html) that describes this. It seems like the most dangerous potential effect is induction of cardiac fibrillation, which can occur around 100mA.

__Improving safety through optical isolation:__ The safety of this device may be improved (albeit with increased complexity) through the implementation of [opto-isolators](https://en.wikipedia.org/wiki/Opto-isolator). I may consider a follow-up post demonstrating how I do this. Unlike digital signals which I've [optically isolated before](https://www.swharden.com/wp/2016-07-28-opto-isolated-laser-controller-build/), I've never personally isolated analog signals. Although I'm sure there are fully analog means to do this, I suspect I'd accomplish it by turning it into a digital signal (with a voltage-to-frequency converter), pulsing the output across the optoisolator, and turning it back into voltage with a frequency-to-voltage converter or perhaps even a passive low-pass filter. Analog Devices has a good write-up about [optical isolation techniques](http://www.analog.com/media/en/training-seminars/tutorials/MT-071.pdf).

__Do you have comments regarding the safety of this device?__ Write your thoughts concisely and send them to me in an email! I'd be happy to share your knowledge with everyone by posting it here.

__Did you build this or a device similar to it?__ Send me some pictures! I'll post them here.

__Source code and project files:__ <https://github.com/swharden/diyECG-1opAmp/>

___LEGAL__: This website is for educational purposes only. Do not build or use any electrical devices shown. Attaching non-compliant electronic devices to your body may be dangerous. Consult a physician regarding proper usage of medical equipment._
July 31st, 2016

Python Real-time Audio Frequency Monitor

A new project I'm working on requires real-time analysis of soundcard input data, and I made a minimal case example of how to do this in a cross-platform way using python 3, numpy, and PyQt. Previous posts compared performance of the matplotlib widget vs PyQtGraph plotwidget and I've been working with PyQtGraph ever since. For static figures matplotlib is wonderful, but for fast responsive applications I'm leaning toward PyQtGraph. The full source for this project is on a github page, but here's a summary of the project.

I made the UI with QT Designer. The graphs are QGraphicsView widgets promoted to a pyqtgraph PlotWidget. I describe how to do this in my previous post. Here's the content of the primary program:

from PyQt4 import QtGui,QtCore
import sys
import ui_main
import numpy as np
import pyqtgraph
import SWHear

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
    def __init__(self, parent=None):
        pyqtgraph.setConfigOption('background', 'w') #before loading widget
        super(ExampleApp, self).__init__(parent)
        self.setupUi(self)
        self.grFFT.plotItem.showGrid(True, True, 0.7)
        self.grPCM.plotItem.showGrid(True, True, 0.7)
        self.maxFFT=0
        self.maxPCM=0
        self.ear = SWHear.SWHear()
        self.ear.stream_start()

    def update(self):
        if not self.ear.data is None and not self.ear.fft is None:
            pcmMax=np.max(np.abs(self.ear.data))
            if pcmMax>self.maxPCM:
                self.maxPCM=pcmMax
                self.grPCM.plotItem.setRange(yRange=[-pcmMax,pcmMax])
            if np.max(self.ear.fft)>self.maxFFT:
                self.maxFFT=np.max(np.abs(self.ear.fft))
                self.grFFT.plotItem.setRange(yRange=[0,self.maxFFT])
            self.pbLevel.setValue(1000*pcmMax/self.maxPCM)
            pen=pyqtgraph.mkPen(color='b')
            self.grPCM.plot(self.ear.datax,self.ear.data,
                            pen=pen,clear=True)
            pen=pyqtgraph.mkPen(color='r')
            self.grFFT.plot(self.ear.fftx[:500],self.ear.fft[:500],
                            pen=pen,clear=True)
        QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    form = ExampleApp()
    form.show()
    form.update() #start with something
    app.exec_()
    print("DONE")

This project uses a gutted version of the SWHEar class which I still haven't released on githib yet. It will likely have its own project folder. For now, take this project with a grain of salt. The primary advantage of this class is that it makes it easy to use PyAudio to automatically detect input sound cards, channels, and sample rates which are likely to succeed without requiring the user to enter any information.

All files used for this project are in a GitHub folder

Audio Visualizer Screenlet

2016-09-05: Okko adapted this project into a screenlet (cross platform) which also includes an installer for Windows: https://github.com/ninlith/audio-visualizer-screenlet

Markdown source code last modified on January 18th, 2021
---
title: Python Real-time Audio Frequency Monitor
date: 2016-07-31 15:21:11
tags: python, old
---

# Python Real-time Audio Frequency Monitor

__A new project I'm working on requires real-time analysis of soundcard input data, and I made a minimal case example of how to do this in a cross-platform way using python 3, numpy, and PyQt.__ Previous posts compared performance of the [matplotlib widget](https://www.swharden.com/wp/2016-07-30-live-data-in-pyqt4-with-matplotlibwidget/) vs [PyQtGraph plotwidget](https://www.swharden.com/wp/2016-07-31-live-data-in-pyqt4-with-plotwidget/) and I've been working with [PyQtGraph](http://www.pyqtgraph.org/) ever since. For static figures matplotlib is wonderful, but for fast responsive applications I'm leaning toward PyQtGraph. The [full source for this project is on a github page](https://github.com/swharden/Python-GUI-examples/tree/master/2016-07-37_qt_audio_monitor), but here's a summary of the project.

<div class="text-center img-border img-small">

![](demo-1.gif)

</div>

![](https://www.youtube.com/embed/lDS9rI0o6mM)

__I made the UI with QT Designer.__ The graphs are _QGraphicsView_ widgets promoted to a pyqtgraph_ PlotWidget_. I describe how to do this [in my previous post](https://www.swharden.com/wp/2016-07-31-live-data-in-pyqt4-with-plotwidget/). Here's the content of the primary program:

```python
from PyQt4 import QtGui,QtCore
import sys
import ui_main
import numpy as np
import pyqtgraph
import SWHear

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
    def __init__(self, parent=None):
        pyqtgraph.setConfigOption('background', 'w') #before loading widget
        super(ExampleApp, self).__init__(parent)
        self.setupUi(self)
        self.grFFT.plotItem.showGrid(True, True, 0.7)
        self.grPCM.plotItem.showGrid(True, True, 0.7)
        self.maxFFT=0
        self.maxPCM=0
        self.ear = SWHear.SWHear()
        self.ear.stream_start()

    def update(self):
        if not self.ear.data is None and not self.ear.fft is None:
            pcmMax=np.max(np.abs(self.ear.data))
            if pcmMax>self.maxPCM:
                self.maxPCM=pcmMax
                self.grPCM.plotItem.setRange(yRange=[-pcmMax,pcmMax])
            if np.max(self.ear.fft)>self.maxFFT:
                self.maxFFT=np.max(np.abs(self.ear.fft))
                self.grFFT.plotItem.setRange(yRange=[0,self.maxFFT])
            self.pbLevel.setValue(1000*pcmMax/self.maxPCM)
            pen=pyqtgraph.mkPen(color='b')
            self.grPCM.plot(self.ear.datax,self.ear.data,
                            pen=pen,clear=True)
            pen=pyqtgraph.mkPen(color='r')
            self.grFFT.plot(self.ear.fftx[:500],self.ear.fft[:500],
                            pen=pen,clear=True)
        QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    form = ExampleApp()
    form.show()
    form.update() #start with something
    app.exec_()
    print("DONE")

```

This project uses a gutted version of the SWHEar class which I still haven't released on githib yet. It will likely have its own project folder. For now, take this project with a grain of salt. The primary advantage of this class is that it makes it easy to use PyAudio to automatically detect input sound cards, channels, and sample rates which are likely to succeed without requiring the user to enter any information.

All files used for this project are [in a GitHub folder](https://github.com/swharden/Python-GUI-examples/tree/master/2016-07-37_qt_audio_monitor)

### Audio Visualizer Screenlet

2016-09-05: Okko adapted this project into a screenlet (cross platform) which also includes an installer for Windows: https://github.com/ninlith/audio-visualizer-screenlet

<div class="text-center img-border">

[![](widget_thumb.jpg)](widget.png)

</div>
July 31st, 2016

Live Data in PyQt4 with PlotWidget

After spending a day comparing performance of MatplotlibWidget with PlotWidget, when it comes to speed PlotWidget wins by a mile! Glance over my last post where I describe how to set up the window with QT Designer and convert the .ui file to a .py file. With only a few changes to the code, I swapped the matplotlib _MatplotlibWidget _with the pyqtgraph PlotWidget. I easily got a 20x increase in speed (frame rate), and I'm likely to favor PyQtGraph over matpltolib for python applications involving realtime display of data. Just like the previous example using matplotlib, this one uses the system time to control the phase and color of a sine wave in real time. You can grab the full code from my github folder.

When designing the GUI with QT Designer, add a QGraphicsView widget then assign it to become a PyQtGraph object. To do this, follow the steps found on the pyqtgraph docs page:

  • In Designer, create a QGraphicsView widget
  • Right-click on the QGraphicsView and select “Promote To...”
  • Set “Promoted class name” to “PlotWidget”
  • Under “Header file”, enter “pyqtgraph”
  • Click “Add”, then click “Promote”
  • apparently this only needs to be done once per project

In addition to faster frame rate, the PyQtGraph method is easy to interact with. Clicking and dragging scrolls the data, and right-clicking and dragging zooms on each axis. Here's the program code:

from PyQt4 import QtGui,QtCore
import sys
import ui_main
import numpy as np
import pylab
import time
import pyqtgraph

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
    def __init__(self, parent=None):
        pyqtgraph.setConfigOption('background', 'w') #before loading widget
        super(ExampleApp, self).__init__(parent)
        self.setupUi(self)
        self.btnAdd.clicked.connect(self.update)
        self.grPlot.plotItem.showGrid(True, True, 0.7)

    def update(self):
        t1=time.clock()
        points=100 #number of data points
        X=np.arange(points)
        Y=np.sin(np.arange(points)/points*3*np.pi+time.time())
        C=pyqtgraph.hsvColor(time.time()/5%1,alpha=.5)
        pen=pyqtgraph.mkPen(color=C,width=10)
        self.grPlot.plot(X,Y,pen=pen,clear=True)
        print("update took %.02f ms"%((time.clock()-t1)*1000))
        if self.chkMore.isChecked():
            QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    form = ExampleApp()
    form.show()
    form.update() #start with something
    app.exec_()
    print("DONE")

This project is available on GitHub: https://github.com/swharden/Python-GUI-examples/tree/master/2016-07-31_qt_PyQtGraph_sine_scroll

Markdown source code last modified on January 18th, 2021
---
title: Live Data in PyQt4 with PlotWidget
date: 2016-07-31 07:28:28
tags: python, old
---

# Live Data in PyQt4 with PlotWidget

__After spending a day comparing performance of MatplotlibWidget with PlotWidget, when it comes to speed PlotWidget wins by a mile!__ Glance over my [last post](https://www.swharden.com/wp/2016-07-30-live-data-in-pyqt4-with-matplotlibwidget/) where I describe how to set up the window with QT Designer and convert the .ui file to a .py file. With only a few changes to the code, I swapped the matplotlib _MatplotlibWidget _with the pyqtgraph _PlotWidget_. I easily got a 20x increase in speed (frame rate), and I'm likely to favor [PyQtGraph](http://www.pyqtgraph.org/) over matpltolib for python applications involving realtime display of data. Just like the [previous example using matplotlib](https://www.swharden.com/wp/2016-07-30-live-data-in-pyqt4-with-matplotlibwidget/), this one uses the system time to control the phase and color of a sine wave in real time. You can grab the full code from [my github folder](https://github.com/swharden/Python-GUI-examples/tree/master/2016-07-31_qt_PyQtGraph_sine_scroll).

<div class="text-center img-border img-small">

![](demo2.gif)
[![](demo2cmd_thumb.jpg)](demo2cmd.png)

</div>

__When designing the GUI with QT Designer, add a QGraphicsView widget then assign it to become a PyQtGraph object.__ To do this, follow the steps found on the [pyqtgraph docs page](http://www.pyqtgraph.org/documentation/how_to_use.html#embedding-widgets-inside-pyqt-applications):

* In Designer, create a QGraphicsView widget
* Right-click on the QGraphicsView and select “Promote To...”
* Set “Promoted class name” to “PlotWidget”
* Under “Header file”, enter “pyqtgraph”
* Click “Add”, then click “Promote”
* _apparently this only needs to be done once per project_

<div class="text-center img-border">

[![](promoted_thumb.jpg)](promoted.png)

</div>

__In addition to faster frame rate, the PyQtGraph method is easy to interact with.__ Clicking and dragging scrolls the data, and right-clicking and dragging zooms on each axis. Here's the program code:

```python
from PyQt4 import QtGui,QtCore
import sys
import ui_main
import numpy as np
import pylab
import time
import pyqtgraph

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
    def __init__(self, parent=None):
        pyqtgraph.setConfigOption('background', 'w') #before loading widget
        super(ExampleApp, self).__init__(parent)
        self.setupUi(self)
        self.btnAdd.clicked.connect(self.update)
        self.grPlot.plotItem.showGrid(True, True, 0.7)

    def update(self):
        t1=time.clock()
        points=100 #number of data points
        X=np.arange(points)
        Y=np.sin(np.arange(points)/points*3*np.pi+time.time())
        C=pyqtgraph.hsvColor(time.time()/5%1,alpha=.5)
        pen=pyqtgraph.mkPen(color=C,width=10)
        self.grPlot.plot(X,Y,pen=pen,clear=True)
        print("update took %.02f ms"%((time.clock()-t1)*1000))
        if self.chkMore.isChecked():
            QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    form = ExampleApp()
    form.show()
    form.update() #start with something
    app.exec_()
    print("DONE")
```

This project is available on GitHub: https://github.com/swharden/Python-GUI-examples/tree/master/2016-07-31_qt_PyQtGraph_sine_scroll
Pages