VHF Frequency Counter with PC Interface

Projects I build often involve frequency synthesis, and one of the most useful tools to have around is a good frequency counter. Being a budding programmer and data analysis guru, I love the idea of being able to access / log / analyze frequency readings on my computer too. Commercial frequency counters can be large, expensive, and their calibration is a chicken-and-egg problem (you need a calibrated frequency counter to calibrate a frequency reference you use to calibrate a frequency counter!). For about the cost of a latte I made a surprisingly good frequency frequency counter (which directly counts >100 MHz without dividing-down the input signal) by blending a SN74LV8154 dual 16-bit counter (which can double as a 32-bit counter, \$1.04 on mouser) and an ATMega328 microcontroller (\$3.37 on Mouser). Although these two chips are all you need to count something, the accuracy of your counts depend on your gate. If you can generate a signal of 1 pulse per second (1PPS), you can count anything, but your accuracy depends on the accuracy of your 1PPS signal. To eliminate the need for calibration (and to provide the 1PPS signal with the accuracy of an atomic clock) I’m utilizing the 1PPS signal originating from a GPS unit which I already had distributed throughout my shack (using a 74HC240 IC as a line driver). If you don’t have a GPS unit, consider getting one! I’m using a NEO-6M module (\$17.66 on Amazon) to generate the 1PPS gate, and if you include its cost we’re up to \$22.07. Also, all of the code for this project (schematics, C that runs on the microcontroller, and a Python to interact with the serial port) is shared on GitHub! You may be wondering, “why do GPS units have incredibly accurate 1PPS signals?” It’s a good question, but a subject for another day. For now, trust me when I say they’re fantastically accurate (but slightly less precise due to jitter) if you’re interested in learning more read up on GPS timing.

This is the general idea behind how this frequency counter works. It’s so simple! It’s entirely digital, and needs very few passive components. sn74lv8154 is configured in 32-bit mode (by chaining together its two 16-bit counters, see the datasheet for details) and acts as the front-end directly taking in the measured frequency. This chip is “rare” in the sense I find very few internet projects using it, and they’re not available on ebay. However they’re cheap and plentiful on mouser, so I highly encourage others to look into using it! The datasheet isn’t very clear about its maximum frequency, but in my own tests I was able to measure in excess of 100 MHz from a breadboarded circuit! This utilized two cascaded ICS501 PLL frequency multiplier ICs to multiply a signal I had available (the 11.0592 MHz crystal the MCU was running from) by ten, yielding 110 MHz, which it was able to measure (screenshot is down on the page).

The 1PPS gate signal is generated from an inexpensive GPS module available on AmazonI’ve hinted at the construction of this device before and made a post about how to send output signals like the 1PPS signal generated here throughout your shack via coax using a line driver, so I won’t re-hash all of those details here. I will say that this module has only VCC, GND, and TX/RX pins, so to get access to the 1PPS signal you have to desolder the SMT LED and solder a wire to its pad. It requires a bit of finesse. If you look closely, you can see it in this picture (purple wire).

I first built this device on a breadboard, and despite the rats nest of wires it worked great! Look closely and you can see the ICS501 frequency multiplier ICs I wrote about before. In this case it’s measuring the 10x multiplied crystal frequency clocking the MCU (11 MHz -> 110 MHz) and reporting these readings every 1 second to the computer via a serial interface.

Frequency measurements of the VHF signal are reported once per second. Measurements are transmitted through a USB serial adapter, and captured by a Python script. Note that I’m calling this signal VHF because it’s >30 MHz. I am unsure if this device will work up to 300 MHz (the border between VHF and UHF), but I look forward to testing that out! Each line contains two numbers: the actual count of the counter (which is configured to simply count continuously and overflow at 2^32=4,294,967,296), and the gated count (calculated by the microcontroller) which is the actual frequency in Hz.

This screenshot shows that my ~11.05 MHz crystal is actually running at 11,061,669.4 Hz. See how I capture the 0.4 Hz unit at the end? That level of precision is the advantage of using this VHF-capable counter in conjunction with a 10x frequency multiplier!

Once I confirmed everything was working, I built this device in a nice enclosure. I definitely splurge every few months and buy extruded split body aluminum enclosures in bulk (ebay), but they’re great to have on hand because they make projects look so nice. I added some rubber feet (cabinet bumpers from Walmart), drilled holes for all the connectors with a continuous step drill bit, made a square hole for the serial port using a nibbler, and the rest is pretty self-evident. Labels are made with a DYMO LetraTag (Target) and clear labels (Target, Amazon) using a style inspired by PA2OHH. I tend to build one-off projects like this dead-bug / Manhattan style.

I super-glued a female header to the aluminum frame to make in-circuit serial programming (ICSP) easy. I can’t believe I never thought to do this before! Programming (and reprogramming) was so convenient. I’m going to start doing this with every enclosed project I build from now on. FYI I’m using a USBTiny ISP (\$10.99, Amazon) to do the programming (no longer the BusPirate, it’s too slow) like I describe here for 64-bit Windows 7 (although I’m now using Windows 10 and it works the same).

The front of the device has LEDs indicating power, serial transmission, and gating. Without a 1PPS gate, the device is set to send a count (of 0) every 5 seconds. In this case, the TX light will illuminate. If a gate is detected, the TX and GATE LEDs will illuminate simultaneously. In reality I just drilled 3 holes when I really needed two, so I had to make-up a function for the third LED (d’oh!)

The back of the device has serial output, frequency input, gate input, and power. Inside is a LM7805 voltage regulator, and careful attention was paid to decoupling and keeping ripple out of the power supply (mostly so our gate input wouldn’t be affected). I’m starting to get in the habit of labeling all serial output ports with the level (TTL vs CMOS, which makes a HUGE difference as MAX232 level converter may be needed, or a USB serial adapter which is capable of reading TTL voltages), as well as the baud rate (119200), byte size (8), parity (N), and stop bit (1). I just realized there’s a typo! The label should read 8N1. I don’t feel like fixing it, so I’ll use a marker to turn the 2 into an 8. I guess I’m only human after all.

I should have tried connecting all these things before I drilled the holes. I got so lucky that everything fit, with about 2mm to spare between those BNC jacks. Phew!

This is an easy test frequency source. I have a dozen canned oscillators of various frequencies. This is actually actually a voltage controlled oscillator (VCO) with adjustment pin (not connected), and it won’t be exactly 50 MHz without adjustment. It’s close enough to test with though! As this is >30 MHz, we can call the signal VHF.

You can see on the screen it’s having no trouble reading the ~50 MHz frequency. You’ll notice I’m using RealTerm (with a good write-up on sparkfun) which is my go-to terminal program instead of HyperTerminal (which really needs to go away forever). In reviewing this photo, I’m appreciating how much unpopulated room I have on the main board. I’m half tempted to build-in a frequency multiplier circuit, and place it under control of the microcontroller such that if an input frequency from 1-20MHz is received, it will engage the 10x multiplier. That’s a mod for another day though! Actually, since those chips are SMT, if I really wanted to do this I would make this whole thing a really small SMT PCB and greatly simplify construction. That sounds like a project for another day though…

Before closing it up I added some extra ripple protection on the primary counter chip. There’s a 560 uH series inductor with the power supply, followed by a 100 nF capacitor parallel with ground. I also added ferrite beads to the MCU power line and gate input line. I appreciate how the beads are unsecured and that this is a potential weakness in the construction of this device (they’re heavy, so consider what would happen if you shook this enclosure). However, anything that would yank-away cables in the event of shaking the device would probably also break half the other stuff in this thing, so I think it’s on par with the less-than-rugged construction used for all the other components in this device. It will live a peaceful life on my shelf. I am not concerned.

This is the final device counting frequency and continuously outputting the result to my computer. In the background you can see the 12V power supply (yellow) indicating it is drawing only 20 mA, and also the GPS unit is in a separate enclosure on the bottom right. Click here to peek inside the GPS 1PPS enclosure.

I’m already loving this new frequency counter! It’s small, light, and nicely enclosed (meaning it’s safe from me screwing with it too much!). I think this will prove to be a valuable piece of test equipment in my shack for years to come. I hope this build log encourages other people to consider building their own equipment. I learned a lot from this build, saved a lot of money not buying something commercial, had a great time making this device, and I have a beautiful piece of custom test equipment that does exactly what I want.

Microcontroller code (AVR-GCC), schematics, and a Python script to interface with the serial port are all available on this project’s GitHub page

Afterthought: Using without GPS

One of the great advantages of this project is that it uses GPS for an extremely accurate 1 PPS signal, but what options exist to adapt this project to not rely on GPS? The GPS unit is expensive (though still <\$20) and GPS lock is not always feasible (underground, in a Faraday cage, etc). Barring fancy things like dividing-down rubidium frequency standards or oven controlled oscillators, consider having your microcontroller handle the gating using either interrupts and timers precisely configured to count seconds. Since this project uses a serial port with a 11.0592 MHz crystal, your 1PPS stability will depend on the stability of your oscillator (which is pretty good!). Perhaps more elegantly you could use a 32.768 kHz crystal oscillator to create a 1 PPS signal. This frequency can be divided by 2 over and over to yield 1 Hz perfectly. This is what most modern wristwatches do. Many AVRs have a separate oscillator which can accomodate a 32 kHz crystal and throw interrupts every 1 second without messing with the system clock. Alternatively, the 74GC4060 (a 14 stage ripple counter) can divide 32k into 1 Hz and even can be arranged as an oscillator (check the datasheet). It would be possible to have both options enabled (local clock and GPS) and only engage the local clock if the GPS signal is absent. If anyone likes the idea of this simple VHF frequency counter with PC interface but doesn’t want to bother with the GPS, there are plenty of options to have something almost as accurate. That really would cut the cost of the final device down too, keeping it under the \$5 mark.

Update: Integrating Counter Serial Output with GPS Serial Output

The NEO-M8 GPS module is capable of outputting serial data at 9600 baud and continuously dumps NEMA formatted GPS data. While this isn’t really useful for location information (whose frequency counter requires knowing latitude and longitude?) it’s great for tracking things like signal strength, fix quality, and number of satellites. After using this system to automatically log frequency of my frequency reference, I realized that sometimes I’d get 1-2 hours of really odd data (off by kHz, not just a few Hz). Power cycling the GPS receiver fixes the problem, so my guess it that it’s a satellite issue. If I combine the GPS RX and counter in 1 box, I could detect this automatically and have the microcontroller power cycle the GPS receiver (or at the least illuminate a red error LED). I don’t feel like running 2 USB serial adapters continuously. I don’t feel like programming my AVR to listen to the output from the GPS device (although that’s probably the correct way to do things).  Instead I had a simpler idea that worked really well, allowing me to simultaneously log serial data from my GPS unit and microcontroller (frequency counter) using 1 USB serial adapter.

The first thing I did was open up the frequency counter and reconnect my microcontroller programmer. This is exactly what I promised myself I wouldn’t do, and why I have a nice enclosure in the first place! Scott, stop fidgeting with things! The last time I screwed this enclosure together I considered adding super glue to the screw threads to make sure I didn’t open it again. I’ll keep my modifications brief! For now, this is a test of a concept. When it’s done, I’ll revert the circuitry to how it was and close it up again. I’ll take what I learn and build it into future projects.

I peeked at the serial signals of both the frequency counter (yellow) and the GPS unit output (blue). To my delight, there was enough dead space that I thought I could stick both in the same signal. After a code modification, I was able to tighten it up a lot, so the frequency counter never conflicts with the GPS unit by sending data at the same time.

I had to slow the baud rate to 9600, but I programmed it to send fewer characters. This leaves an easy ~50ms padding between my frequency counter signal and the GPS signal. Time to mix the two! This takes a little thought, as I can’t just connect the two wires together. Serial protocol means the lines are usually high, and only pulled down when data is being sent. I had to implement an active circuit.

Using a few components, I built an AND gate to combine signals from the two serial lines. For some reason it took some thought before I realized an AND gate was what I needed here, but it makes sense. The output is high (meaning no serial signal) only when both inputs are high (no serial signals on the input). When either signal drops low, the output drops low. This is perfect. My first thought was that I’d need a NOR gate, but an inverted AND gate is a NOR gate.

Here’s my quick and dirty implementation. A reminder again is that this will be removed after this test. For now, it’s good enough.

After connecting the GPS serial output and frequency counter serial output to the AND gate (which outputs to the computer), I instantly got the result I wanted!

RealTerm shows that both inputs are being received. It’s a mess though. If you want to know what everything is, read up on NEMA formatted GPS data.

I whipped-up a python program to parse, display, and log key information. This display updates every 1 second. The bottom line is what is appended to the log file on ever read. It’s clunky, but again this is just for testing and debugging. I am eager to let this run for as long as I can (days?) so I can track how changes in satellite signal / number / fix quality influence measured frequency.

ICS501 Simple Frequency Multiplier

Today I made a high frequency multiplier using a single component: the ICS501 PLL clock multiplier IC. This chip provides 2x, 5x, 8x (and more) clock multiplication using an internal phased-lock loop (PLL). At less than a dollar on eBay\$1.55 on mouser, and \$0.67 on Digikey, they don’t break the bank and I’m glad I have a few in my junk box! I have a 10MHz frequency standard which I want to use to measure some 1Hz (1pps) pulses with higher precision, so my general idea is to use a frequency multiplier circuit to increase the frequency (to 80 MHz) and use this to run a counter IC to measure the number of clock pulses between the PPS pulses. I spent a lot of time working with the CD4046 micro-power phased lock loop IC which has a phase comparator and a voltage controlled oscillator built in. It seemed this chip was the go-to for many years, but it requires external circuitry (ICs in my case) to divide by N and is intended to adjust a VCO output voltage based on the phase difference of two different inputs. Although I made some great progress using this chip, I found a few SMT ICS501 ICs in my junk box and decided to give them a try. I was impressed how easy it was to use! I just fed it 5V and my clock signal, and it output 8x my clock signal! Since I don’t have my 10MHz reference frequency running at the moment, I tested it with a 1MHz canned oscillator. It worked great, and was so easy! I’ll definitely be using this chip to multiply-up crystal oscillator frequencies to improve the precision of frequency counting.

The pin connections are straightforward: +5V and GND to pins 2 and 3, no connection for pins 7 and 8, clock goes in 1 and comes out on 5. Pins 4 and 6 are both set to +5V to yield a x8 multiplier, according to the chart. All of this is in the datasheet for the chip.

The IC I had on hand was SOIC. I don’t think they make this IC in DIP. Luckily, I have breadboardable breakout boards on hand. These breakout boards are identical to those sold on dipmicro but I got mine from ebay and they’re all over ebay!

I didn’t feel like changing my soldering iron tip so I gave it a go with a huge wedge, and it worked pretty well! I first melted a little bit of solder on all the rails, waited until it cooled, pressed the IC into the solder, then re-melted it with the iron. It was relatively easy and I had no shorts. I do have a hot air gun (which I also didn’t feel like setting up and waiting for to get warm) but this worked fine…

Here’s the test circuit. I added a 100nF power decoupling capacitor and a SMT LED (with a 1 kOhm current limiting resistor) so I could tell when it was powered. I am using a 1MHz can oscillator at the input of the ICS501, and capturing both outputs through a 0.1uF capacitors terminating in a 50 ohm loads (at the oscilloscope, seen better in the next photo).

It worked immediately with no trouble! The top trace is the original 1MHz clock signal, and the bottom is the 8MHz trace.

The frequency isn’t exactly 1MHz because the adjustment pin of the can oscillator has been left floating. Also, I recognize the power supply is noisy which is also getting noise in the signals. None of that matters, I’m just testing the concept here. The bottom line is that the ICS501 is an extremely easy way to multiply a clock frequency to beyond 100 MHz and it requires no external components! I will definitely be using this IC in some of my future designs. I’m glad I have it! I had to search my email to see when I ordered it because I had no memory of doing so. It looks like I got them in August 2013 (3 years ago!) and never used them. Regardless, I’m happy to have found them in my junk box, and will definitely be using them from now on.

Update: Cascading Two ICS501s for 10x Frequency Multiplication

My ultimate goal is to build a frequency counter using a 10 MHz frequency source, multiplied to a higher value for greater precision. Although I could achieve 8x frequency multiplication with a single ICS501, I didn’t like the idea of frequency steps not being decimal. I decided to try to cascade two ICS501 chips configured to multiply by 2 then by 5 to yield 10. Supposedly this could work on a range of frequencies up through 64x multiplication, but for me generating 100 MHz from a 10 MHz reference is exactly what I need.

Here’s my design. It’s simple. I configure S0 or S1 as floating, grounded, or high to set the multiplication factor (see the chart above).

Here’s my implementation. I didn’t have enough space on the breakout board to fit the whole chip (I was missing a single row!). Luckily the SMT perf board is spaced perfectly for SOIC. I was surprised how easy this thing was to solder on the SMT perf board. I’m going to have to buy some more and try prototyping with it. It would be cool to get good at it. That’s another story for another day though…

The breadboard design got way easier! This thing now just needs power (+5V and GND), an input signal (1 MHz in this demo), and the output signal is 10x the input (10 MHz).

This is what the output looks like. Signals terminate into a 10 ohm load at the level of the oscilloscope.

I had the USB drive in the thing so I went ahead and pushed the print button. Here’s the actual screen capture.

Here it is converting 10 MHz into 100 MHz. The signals are a bit noisy, likely because both ICs are being powered together (behind the same inductor/capacitor). In a production device, each IC should have its own inductor/capacitor to isolate it from ripple on the power rail. Regardless, this works great in cascading arrangement to multiply HF frequencies to VHF frequencies. The 10MHz source is my oven controlled crystal oscillator (OCXO) which I haven’t written about yet.

All in all, the ICS501 was an easy cheap single-component solution to frequency multiplication, and cascading two in series easily allows me to multiply the frequency of an incoming signal. I look forward to posting details of my frequency counter build soon!

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’ve had 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")
```

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!

Simple Example: 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.

Real World Example: Measuring voltage and current during warm-up of an oven controlled crystal oscillator (OCXO)

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:

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 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.

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.

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!

DIY ECG with 1 op-amp

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!

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.

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.

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.

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):
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()
app.exec_()
print("DONE")
```

note: 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

2016-09-05: Okko adapted this project into a screenlet (cross platform) which also includes an installer for Windows. That Githib page is here: https://github.com/ninlith/audio-visualizer-screenlet Below is a screenshot of me running it on my Windows 10 machine

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:

1. In Designer, create a QGraphicsView widget.
2. Right-click on the QGraphicsView and select “Promote To…”.
3. Set “Promoted class name” to “PlotWidget”.
4. Under “Header file”, enter “pyqtgraph”.
5. Click “Add”, then click “Promote”.
6. 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):
super(ExampleApp, self).__init__(parent)
self.setupUi(self)
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()
app.exec_()
print("DONE")
```

All files used in project can be downloaded from the GitHub page.

Live Data in PyQt4 with MatplotlibWidget

I keep getting involved in projects which require live data to be graphed in real time. Since most of my back-end is written in Python, it makes sense to have a Pythonic front-end. Cross-platform GUI programming in Python is frustratingly non-trivial, as there multiple window frameworks available (TK, GTK, and QT) and their respective graphical designers (torture, Glade, and QT Designer) and each has its own way of doing things. Add different ways to plot data in the mix (gnuplot, matplotlib, and custom widgets) and it can become a complicated mess. Different framework combinations favor different features (with unique speed / simplicity / elegance), so my goal is to slowly test out a few combinations most likely to work for my needs, and add my findings to a growing github repository. The first stab is using PyQt4 and matplotlib’s widget (MatplotlibWidget). Rather than capture data from the sound card (my ultimate goal), I’m going to generate a sine wave whose phase and color is related to the system time. Matplotlib plotting is a bit slow, but the output is beautiful, and their framework is so robust. Here’s the output of my first test showing the sine wave generated as well as the console output (showing that each call to the plotting function takes about 40 ms. At this rate, I can expect a maximum update rate of ~25 Hz.

Designing this project was easy, but it was surprisingly hard to figure out how to do this based on examples I found on the internet. This is part of why I wanted to place this example here. The downside of many internet examples is that they did not use Qt Designer to make the window, so their code to create a window and insert the MatplotlibWidget wasn’t copy/paste compatible with my goals, and often more complex than I needed. Some internet examples did use Qt Designer to make the window, but left a frame empty which they later manually filled with a widget and attached to a matplotlib canvas. This is fine, but more complex than I need to get started.

First, I designed a GUI with Qt Designer. I dropped a MatplotlibWidget somewhere, and used its default name. I saved this file as ui_main.ui (which is an XML file, ready to be used for multiple programming languages).

Next, I converted the UI file into a .py file with a standalone python script that’s an alternative to using pyuic from the command line. The script to do this is ui_convert.py and it calls PyQt4.uic.compileUi():

```from PyQt4 import uic
fin = open('ui_main.ui','r')
fout = open('ui_main.py','w')
uic.compileUi(fin,fout,execute=False)
fin.close()
fout.close()
```

I then created my main program file which populates the matplotlib widget with data. I called it go.py and running it will launch the app. The code explains it all, and there’s not much more to say! It produces the output at the top of this post.

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

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
def __init__(self, parent=None):
super(ExampleApp, self).__init__(parent)
self.setupUi(self)
self.matplotlibwidget.axes.hold(False) #clear on plot()

def update(self):
t1=time.time()
points=100 #number of data points
X=np.arange(points)
Y=np.sin(np.arange(points)/points*3*np.pi+time.time())
C=pylab.cm.jet(time.time()%10/10) # random color
self.matplotlibwidget.axes.plot(X,Y,ms=100,color=C,lw=10,alpha=.8)
self.matplotlibwidget.axes.grid()
self.matplotlibwidget.axes.get_figure().tight_layout() # fill space
self.matplotlibwidget.draw() # required to update the window
print("update took %.02f ms"%((time.time()-t1)*1000))
if self.chkMore.isChecked():
QtCore.QTimer.singleShot(10, self.update) # QUICKLY repeat

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

All files used in project are available on GitHub

Opto-Isolated Laser Controller Build

I just finished building a device to interface a modern fiber-coupled DPSS laser used for optogenetic experiments with 15 year old scientific hardware. I finished this project in one afternoon, and I’m very happy with how it came out! This project has a blend of analog and digital circuitry, microcontrollers, and lasers (all the fun stuff!) and turned out to be a pretty cool build, so I’m sharing the design and construction with the hope that it will be inspiring to someone else. I don’t intend anyone to replicate this project (it’s designed to fill a very small niche), but I’ve learned a lot over the years by reading other peoples’ project build web pages and I’m happy every time I get the opportunity to make one of my own. The hardware I needed to interface is made by Coulbourn Instruments and is essentially just a large multi-channel computer-controlled DAC/ADC and it does its job well (turning lights on and off, recording button presses, etc.), but this new task requires millisecond resolution and modulation patterns which [most likely] lie outside the specs of this system and software. My goal was to utilize a free hardware output line to signal to a device that I build to modulate the laser in a special way. This way there would be no modification to any existing equipment, and no software to install. Further, since this hardware isn’t mine, I don’t like the idea of permanently modifying it (or even risking breaking it by designing something which could damage it by connecting to it). The specific goal is to allow the existing software to cause the laser to fire 20 ms pulses at 15 Hz for a few dozen cycles of 5s on, 5s off. It’s also important to have some flexibility to reprogram this firing protocol in the future if a change is desired. What’s more is that experiments are already underway and I needed this device to be complete within a couple of days! As much as I’d love to go to the internet and order the perfect, cheap components from China and have a beautiful build completed after the 6-8 weeks of shipping time, I had to build this only using parts I already had at my home.

• The input should be able to accomodate any signal (TTL, CMOS, 28V, etc)
• The input is totally isolated electrically, so this should be very safe on the hardware
• The microcontroller is a socketed ATTiny85 which I programmed with a Bus Pirate.
• I decided to rely on a crystal rather than the internal RC clock to improve temporal precision of the output signal. A 11.0592 MHz crystal was chosen because I have a bucket of them (they’re perfect for serial communication at all common baud rates). Any crystal could be used, as long as it’s frequency is defined in software.
• Capacitors were added more to ensure oscillation initiates than to bring down the oscillation frequency. (I’m told that omitting them may cause a case where the crystal doesn’t resonate as well, but I’ve never found this in my personal experience.) A good note on microcontroller clocks is in a Microchip PIC application note.
• I included a “test” button (momentary switch) to simulate having an input signal.
• Note that R1 must be able to handle the current applied to it. It was mistakenly designed as 1k, and later replaced with 10k. See the bodge note at the bottom of this post for details.

This design could still benefit from:

• Forward protection diodes on the input could protect accidental reverse polarity
• Adding an ICSP header would prevent de-socketing of the MCU if reprogramming is desired
• The BNC output is directly from a MCU pin. It should be at least transistor-buffered to deliver higher current.

Because there is a possibility that a different output (laser control) pattern may be desired in the future, I considered whether or not I should make the output pattern user-configurable. Adding buttons, a display, and designing a menu system in software would be a lot of work and no one’s really strongly asking for it, so I concluded that I’m going to build this device to the specific task at hand. If the end user eventually wants the ability to modulate the pattern on their own, the device they ask for would be a very different one than the one I was tasked to create. Since the current pattern is burned into a microchip, a compromise is that I could have new patterns burned into new microchips, and the end-user could change the chip (as long as it’s an infrequent occurrence).

Wait a minute, turning 20 ms pulses at 15 Hz sounds like an easy task for a 555 timer without the need for digital circuitry. Also, it would be easy for the end user to adjust both of these features by turning a knob! Is a microcontroller overkill? I struggled with this question for a while, but concluded that the advantage of the MCU (crystal-disciplined time precision of the output pulses) outweighed the convenience of  a purely analog circuit. A 555 timer in astable / multi-vibrator configuration would mostly get the job done, but you would either (1) only allow one output pattern and rely on precision passive components (which I don’t have on hand), or (2) allow the end-user to adjust duty/frequency with potentiometers (which would require the output to be quantitatively monitored on an oscilloscope). I considered a blend of analog and digital circuitry by using analog components (with knobs) to adjust the duty/frequency, and microcontroller to measure the pulse width and period and display this on a screen (essentially building the oscilloscope into the device). Again, this is more work, and without being asked by the end-user to have an adjustable product (they just indicated interest when I proposed it), I decided I’d continue with the simplest-case, high-resolution design. Also I’ll note that I’m relying on an external crystal (rather than the internal RC clock) to maximize precision from day to day use. Since this device will be used for scientific experimentation, I want to minimize the influence of temperature on the temporal precision of the output signal.

Luckily I had an enclosure ready to go. I always buy enclosures in bulk, and even though nice ones tend to be expensive, having them on hand encourages me to build devices as I think of them, rather than making flaky hardware which I have a history of doing which sometimes borders on ridiculousness. I usually stock unfinished Hammond diecast aluminum enclosures (which I write on with sharpie) for making quick RF projects, and generic fancier boxes with feet and side vents, but for this task I decided to (mostly) seal everything inside a typical (but a little more costly) aluminum enclosure (most likely an eBay special from China, but I can’t remember where I got it). I love using low current LEDs, and I started going with frosted instead of clear LEDs because they’re easier on the eyes. Also, I switched to mostly 3mm LEDs instead of 5MM because I think they look cooler. I have black bezels but they don’t snap in as well as I’d hope, so I find myself having to add a dot of super glue to retain the LED and the bezel in position.

I used nicer perfboard with platted-through holes to build this circuit. Normally I use cheap ubiquitous perfboard with little copper rings glued to one side.  It’s easy to solder to because the copper is so thin it heats quickly, but it’s not always a good long-term solution because the copper pads have a tendency to un-stick. I rarely use this nicer perfboard (it is more expensive, I order from China on ebay), but again I value having things like this stocked at my home ready to go at a moment’s notice!

I marked areas of optical isolation with a black marker. This makes it obvious where the potentially dangerous, potentially high-voltage (well, higher than TTL) input comes in. No wires or connections should invade this space on the board. The special connector which will connect this device to the scientific hardware is at the laboratory, and I’ll have to solder it at the time of delivery/installation. I left an extra hole in the back which I guesstimated would fit the wire. I didn’t have any rubber grommets stocked at my home… I need to get some!

Strong copper wires hold the front panel onto the circuit, but this wasn’t actually intentional. I first screwed down the circuit board, soldered everything together, and after I realized a change was needed on the underside of the board an unscrew was required. That’s when I realized that I could unscrew the front panel rather than desolder it, and it held its shape great! At first glance this doesn’t look like a robust construction technique, but is it really any different than soldering stiff coated wires?

Once it was all together, the device seemed to perform well. The test button on the back made it easy to inspect the output. My RF background made me instinctively terminate the output into a 50 ohm resistor for the measurements, but the square waves looked like super wonky RC curves and I realized 50 ohms is far too low impedance. If it’s a TTL signal, let’s assume it’s virtually infinite impedance, and not worry about it. Note that this is a testament to the relatively low maximum output current of the microcontroller pin, and the potential need for a buffered output if anything more than high impedance TTL is to be driven. I think the datasheets suggests limiting its current to 20 mA per pin (requiring termination of no less than 250 Ohms) A 50 Ohm resistor pulled it out of spec. Oh well, I removed it and it survived fine, so let’s make some measurements

An important thing to note is that absolute time precision is preferred over accuracy. Specifically, I want this device to perform identically for years, and highly favor precision over accuracy. With that said, I trust the pulses to be 20ms wide, but not exactly 15 Hz. To do 15 Hz, I’d need 20ms on and 46.666667 ms off. I could probably get pretty close if I wanted to, but I rounded it to 20 ms on and 46 ms off. This gives time for the instruction cycles toggling the output pins to occur (although it’s on an order of magnitude faster time scale), which slightly biases the time in the right direction. I considered adding a _delay_us(666) after the _delay_ms(46) but I’m satisfied with it this knowing it’s within 1% accuracy of 15 Hz and that precision is locked to that of the crystal (around 10 ppm, or 0.001%).

Admittedly the _delay_ms() method of timekeeping is a little clumsy. I considered a few other methods of time keeping, but decided not to implement them (yet?). The schools of thought were largely on three categories, but all relied on the AVR timers. Here’s an awesome guide on the topic, and here’s another. Timers would be preferred if I wanted the program code of the microcontroller to be free to do other things like drive menus or multiplex a display. Think of hardware timers on a MCU like multi-threading on a computer – it helps you out by running in the background.

• Thought 1: timers: Set the timer to overflow every 1 ms. On overflow, a counting variable would be incremented and a function would be called to determine what to do. At pre-programmed time points (with respect to the counting variable), the output pin would be toggled, or the counting variable would be reset.
• Thought 2: output compare registers: Utilize the built-in OCR (output compare register) to turn the output signal on and off. Set the timer to overflow at 15 Hz, turning the output on. Set the OCR (to the fractional point between 0 and the maximum timer value) such that when it is passed, the output is turned off. This way 15 Hz, 20 ms pulses would be continuously running without any code being executed. Input sensing could simply enable and disable the timer.
• Thought 3: input interrupts: Why stop at timers? Polling the input pin for a TTL signal puts the chip in an infinite loop. Relying on the AVR’s external (pin change) hardware interrupts could eliminate this as well. I always rely heavily on the datasheet when setting these interrupts.

Altogether these improvements could come in handy if a more accurate time source is desired, an advanced display is added, or menus are implemented which would benefit from letting the pulsing output operate in the background. For now, I’m happy with my dirt-simple code, and I’m still far within my one afternoon construction timeline goal!

After I was satisfied with construction, I started labeling the enclosure. I want to tip my hat to Onno Hoekstra on this one, as his webpage demonstrating how good clear labels make custom ham radio equipment look (and a personal email he sent me recently) made me start making clear labels for all of my custom equipment. FYI I’m using a DYMO LetraTag LT-100T Plus label maker and clear tape. It’s important to enable the black outline around the text, then cut carefully slightly outside the outline with regular scissors. The results look fantastic!

The morning I delivered my product, I added the final connector which I didn’t have at home. It’s an inelegant knot-retained configuration, but I think it’ll get the job done! Again this is a surprisingly rare fully shielded touchproof connector apparently used only in medical applications. At this point, I’m thinking this figure was chosen to (A) protect the user from accidentally shorting a 28V 8A power source (that’s over 200 watts!), (B) to prevent you from damaging the equipment by plugging in something that doesn’t belong (could you imagine what would happen if this -28V high current source had a BNC connector and you plugged this into something expecting a 5V TTL input?), and (C) prevent you from plugging in anything that wasn’t made by this company. The last option is more likely consumer protection rather than the company trying to maintain a status of sole distributor of accessories, but it does make you wonder. I would have preferred power pole sockets (that’s the ham in me), molded connectors like those on motherboards, or even barrel connectors! Surely there’s a more standard touchproof connector for moderate voltage/currents (although, to be honest, I’m struggling to think of one at the moment). CL-type connectors seem expensive and bulky.

I plugged the device in to the computer, attached the laser, and it worked immediately! I couldn’t say I was surprised that it worked, but it still felt good to watch the blue laser beam trigger like it was supposed to. Another cool one-off project is in the bag, and I got some great pictures for the website. I hope this little box lives many happy years in its laboratory home.

The current software is so simple, it’s not worth discussing! This is the code I loaded onto the microcontroller.

```#define	F_CPU (11059200UL)
#include <avr/io.h>
#include <util/delay.h>

int main (void){
DDRB=(1<<PB0); // TTL output
PORTB=0; // internal pull-down
while(1){
while((PINB&(1<<PB2))==0){} // hang while LOW
PORTB=(1<<PB0); // TTL ON
_delay_ms(20);
PORTB&=~(1<<PB0); // TTL OFF
_delay_ms(46);
}
}
```

Here’s the batch script I used to compile and load the code onto the microcontroller. I compiled the code with AVR-GCC and copied it onto the microcontroller with a Bus Pirate. Note also that I’m setting the fuses to respect an external oscillator.

```@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex
avrdude -c buspirate -p attiny85 -P com3 -U lfuse:w:0xff:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
pause
```

If you have any ideas for how this could device could have been better designed or constructed, let me know!

Bodge note: After a few days I got an email from someone concerned about the current handling capability of the front-end of the circuit. It was noted that a standard 1/4 watt resistor may not be suitable for R1, as a 28V potential would stress it beyond its specs. With 28V applied, R1 (a quarter-watt resistor) would experience P=IE=28mA*28V=784mW of current! It might last (especially if pulsed), but it also might fail with time. The advantage of the R1/D1/R2 system is that the output current will be identical across a wide range of input voltages. The disadvantage is that it’s hard to predict how beefy R1 needs to be. I could have placed five 4.7k resistors in parallel to replace R1 (this would let me handle over 1 watt of power), but I instead simply upped it from 1kOhm to 10kOhm. This further reduced the current that the opto-isolator sees (now only about 0.2 mA) but it seems to work still! So I’m satisfied with this bodge, but a little disappointed I didn’t catch it sooner. Note that the new input resistor (a 10k R1) should only have to dissipate about 80mW, well within its specs.

Note regarding H11B1 minimum current and AC noise: After pondering it for a while, I considered that a 10K input resistor on 28V would only allow 2.8 mA to pass through. Considering only 3.3V will persist after the zener (a 11.7% current retaining ratio, if that’s valid math), I figured that a best 330uA were passing through the opto-isolator. That seems outside of the specs of the device, because their datasheet graphs always start at 1mA. I decided to run some tests at my home for kicks. I determined that a 10k resistor still works with 5V (500 uA into the device), but checking the output on the oscilloscope I realized that the device operates only partially, and slowly at that low voltage/current. The darlington transistor configuration is very high gain, which is the only reason this works at all, but such low currents are sensitive to parasitic capacitance and infiltrating RF currents. As such, I noticed the chip took a few ms to activate and deactivate. Since this application only uses 5s on and 5s off inputs, it’s fine… but I wouldn’t expect highspeed pulsing of the input to work well. Furthermore, in my breadboard I realized I was getting funny output currents. They were oscillating around 60Hz, which made me suspicious that the device was picking up AC somehow. I realized it was from pin 6 (the exposed darlington base). Normally the LED is so strong is blasts the device fully on or off, but hovering on the edge like this, that pin is picking up signals. Since it’s not connected to anything anyway, I cut the pin off as close to the microchip as I could, and noticed an instant improvement in 60Hz rejection. In conclusion, I wouldn’t try to reliably run an optoisolator on less than 1 mW, but it seems to work!

Realtime Audio Visualization in Python

Python’s “batteries included” nature makes it easy to interact with just about anything… except speakers and a microphone! As of this moment, there still are not standard libraries which which allow cross-platform interfacing with audio devices. There are some pretty convenient third-party modules, but I hope in the future a standard solution will be distributed with python. I appreciate the differences of Linux architectures such as ALSA and OSS, but toss in Windows and MacOS in the mix and it gets to be a huge mess. For Linux, would I even need anything fancy? I can run “`cat file.wav > /dev/dsp`” from a command prompt to play audio. There are some standard libraries for operating system specific sound (i.e., winsound), but I want something more versatile. The official audio wiki page on the subject lists a small collection of third-party platform-independent libraries. After excluding those which don’t support microphone access (the ultimate goal of all my poking around in this subject), I dove a little deeper into sounddevice and PyAudio. Both of these I installed with pip (i.e., `pip install pyaudio`)

For a more modern, cleaner, and more complete GUI-based viewer of realtime audio data (and the FFT frequency data), check out my Python Real-time Audio Frequency Monitor project.

I really like the structure and documentation of sounddevice, but I decided to keep developing with PyAudio for now. Sounddevice seemed to take more system resources than PyAudio (in my limited test conditions: Windows 10 with very fast and modern hardware, Python 3), and would audibly “glitch” music as it was being played every time it attached or detached from the microphone stream. I tried streaming, but after about an hour I couldn’t get clean live access to the microphone without glitching audio playback. Furthermore, every few times I ran this script it crashed my python kernel! I very rarely see this happening. iPython complained: “It seems the kernel died unexpectedly. Use ‘Restart kernel’ to continue using this console” and I eventually moved back to PyAudio. For a less “realtime” application, sounddevice might be a great solution. Here’s the minimal case sounddevice script I tested with (that crashed sometimes). If you have a better one to do live high-speed audio capture, let me know!

```import sounddevice #pip install sounddevice

for i in range(30): #30 updates in 1 second
rec = sounddevice.rec(44100/30)
sounddevice.wait()
print(rec.shape)
```

Here’s a simple demo to show how I get realtime microphone audio into numpy arrays using PyAudio. This isn’t really that special. It’s a good starting point though. Note that rather than have the user define a microphone source in the python script (I had a fancy menu system handling this for a while), I allow PyAudio to just look at the operating system’s default input device. This seems like a realistic expectation, and saves time as long as you don’t expect your user to be recording from two different devices at the same time. This script gets some audio from the microphone and shows the values in the console (ten times).

```import pyaudio
import numpy as np

CHUNK = 4096 # number of data points to read at a time
RATE = 44100 # time resolution of the recording device (Hz)

p=pyaudio.PyAudio() # start the PyAudio class
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,
frames_per_buffer=CHUNK) #uses default input device

# create a numpy array holding a single read of audio data
for i in range(10): #to it a few times just to see
print(data)

# close the stream gracefully
stream.stop_stream()
stream.close()
p.terminate()
```

I tried to push the limit a little bit and see how much useful data I could get from this console window. It turns out that it’s pretty responsive! Here’s a slight modification of the code, made to turn the console window into an impromptu VU meter.

```import pyaudio
import numpy as np

CHUNK = 2**11
RATE = 44100

p=pyaudio.PyAudio()
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,
frames_per_buffer=CHUNK)

for i in range(int(10*44100/1024)): #go for a few seconds
peak=np.average(np.abs(data))*2
bars="#"*int(50*peak/2**16)
print("%04d %05d %s"%(i,peak,bars))

stream.stop_stream()
stream.close()
p.terminate()
```

The results are pretty good! The advantage here is that no libraries are required except PyAudio. For people interested in doing simple math (peak detection, frequency detection, etc.) this is a perfect starting point. Here’s a quick cellphone video:

I’ve made realtime audio visualization (realtime FFT) scripts with Python before, but 80% of that code was creating a GUI. I want to see data in real time while I’m developing this code, but I really don’t want to mess with GUI programming. I then had a crazy idea. Everyone has a web browser, which is a pretty good GUI… with a Python script to analyze audio and save graphs (a lot of them, quickly) and some JavaScript running in a browser to keep refreshing those graphs, I could get an idea of what the audio stream is doing in something kind of like real time. It was intended to be a hack, but I never expected it to work so well! Check this out…

Here’s the python script to listen to the microphone and generate graphs:

```import pyaudio
import numpy as np
import pylab
import time

RATE = 44100
CHUNK = int(RATE/20) # RATE / number of updates per second

def soundplot(stream):
t1=time.time()
pylab.plot(data)
pylab.title(i)
pylab.grid()
pylab.axis([0,len(data),-2**16/2,2**16/2])
pylab.savefig("03.png",dpi=50)
pylab.close('all')
print("took %.02f ms"%((time.time()-t1)*1000))

if __name__=="__main__":
p=pyaudio.PyAudio()
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,
frames_per_buffer=CHUNK)
for i in range(int(20*RATE/CHUNK)): #do this for 10 seconds
soundplot(stream)
stream.stop_stream()
stream.close()
p.terminate()
```

```<html>
<script language="javascript">
function RefreshImage(){
document.pic0.src="03.png?a=" + String(Math.random()*99999999);
setTimeout('RefreshImage()',50);
}
</script>
<img name="pic0" src="03.png">
</body>
</html>
```

Here’s the result! I couldn’t believe my eyes. It’s not elegant, but it’s kind of functional!

Why stop there? I went ahead and wrote a microphone listening and processing class which makes this stuff easier. My ultimate goal hasn’t been revealed yet, but I’m sure it’ll be clear in a few weeks. Let’s just say there’s a lot of use in me visualizing streams of continuous data. Anyway, this class is the truly terrible attempt at a word pun by merging the words “SWH”, “ear”, and “Hear”, into the official title “SWHear” which seems to be unique on Google. This class is minimal case, but can be easily modified to implement threaded recording (which won’t cause the rest of the functions to hang) as well as mathematical manipulation of data, such as FFT. With the same HTML file as used above, here’s the new python script and some video of the output:

```import pyaudio
import time
import pylab
import numpy as np

class SWHear(object):
"""
(and mathematically processed) microphone data.
"""

def __init__(self,device=None,startStreaming=True):
"""fire up the SWHear class."""
print(" -- initializing SWHear")

self.chunk = 4096 # number of data points to read at a time
self.rate = 44100 # time resolution of the recording device (Hz)

# for tape recording (continuous "tape" of recent audio)
self.tapeLength=2 #seconds
self.tape=np.empty(self.rate*self.tapeLength)*np.nan

self.p=pyaudio.PyAudio() # start the PyAudio class
if startStreaming:
self.stream_start()

### LOWEST LEVEL AUDIO ACCESS
# keep math, plotting, FFT, etc out of here.

"""return values for a single chunk"""
#print(data)
return data

def stream_start(self):
"""connect to the audio device and start a stream"""
print(" -- stream started")
self.stream=self.p.open(format=pyaudio.paInt16,channels=1,
rate=self.rate,input=True,
frames_per_buffer=self.chunk)

def stream_stop(self):
"""close the stream but keep the PyAudio instance alive."""
if 'stream' in locals():
self.stream.stop_stream()
self.stream.close()
print(" -- stream CLOSED")

def close(self):
"""gently detach from things."""
self.stream_stop()
self.p.terminate()

### TAPE METHODS
# tape is like a circular magnetic ribbon of tape that's continously
# recorded and recorded over in a loop. self.tape contains this data.
# the newest data is always at the end. Don't modify data on the type,
# but rather do math on it (like FFT) as you read from it.

"""add a single chunk to the tape."""
self.tape[:-self.chunk]=self.tape[self.chunk:]

def tape_flush(self):
"""completely fill tape with new data."""
print(" -- flushing %d s tape with %dx%.2f ms reads"%\

def tape_forever(self,plotSec=.25):
t1=0
try:
while True:
if (time.time()-t1)>plotSec:
t1=time.time()
self.tape_plot()
except:
print(" ~~ exception (keyboard?)")
return

def tape_plot(self,saveAs="03.png"):
"""plot what's in the tape."""
pylab.plot(np.arange(len(self.tape))/self.rate,self.tape)
pylab.axis([0,self.tapeLength,-2**16/2,2**16/2])
if saveAs:
t1=time.time()
pylab.savefig(saveAs,dpi=50)
print("plotting saving took %.02f ms"%((time.time()-t1)*1000))
else:
pylab.show()
print() #good for IPython
pylab.close('all')

if __name__=="__main__":
ear=SWHear()
ear.tape_forever()
ear.close()
print("DONE")
```

I don’t really intend anyone to actually do this, but it’s a cool alternative to recording a small portion of audio, plotting it in a pop-up matplotlib window, and waiting for the user to close it to record a new fraction. I had a lot more text in here demonstrating real-time FFT, but I’d rather consolidate everything FFT related into a single post. For now, I’m happy pursuing microphone-related python projects with PyAudio.

UPDATE: Displaying a single frequency

Use Numpy’s FFT() and FFTFREQ() to turn the linear data into frequency. Set that target and grab the FFT value corresponding to that frequency. I haven’t tested this to be sure it’s working, but it should at least be close…

```import pyaudio
import numpy as np
np.set_printoptions(suppress=True) # don't use scientific notation

CHUNK = 4096 # number of data points to read at a time
RATE = 44100 # time resolution of the recording device (Hz)
TARGET = 2100 # show only this one frequency

p=pyaudio.PyAudio() # start the PyAudio class
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,
frames_per_buffer=CHUNK) #uses default input device

# create a numpy array holding a single read of audio data
for i in range(10): #to it a few times just to see
fft = abs(np.fft.fft(data).real)
fft = fft[:int(len(fft)/2)] # keep only first half
freq = np.fft.fftfreq(CHUNK,1/RATE)
freq = freq[:int(len(freq)/2)] # keep only first half
assert freq[-1]>TARGET, "ERROR: increase chunk size"
val = fft[np.where(freq>TARGET)[0][0]]
print(val)

# close the stream gracefully
stream.stop_stream()
stream.close()
p.terminate()
```