CheapChop: measuring DC with a sound card

Marko Cebokli, S57UUU

CheapChop on a hand

Most people are unaware of the fact, that a humble PC sound card is really a very powerful measuring instrument. Just compare: an 3 1/2 digit ("1999") DMM converts with not quite 12 bits (11 + sign) at maybe 10 samples per second. Most sound cards can convert two channels with 16 bits, at 48000 samples per second.

So why aren't they used more often for measurement purposes?

I can see mainly three reasons:

1. The greatest bane of sound card measurement precision is the "Mixer", where normally audio levels are set - if you change the "recording level" or "mic gain" or "input boost" or whatever, your calibration goes goodbye!. Almost every sound card has a different mixer interface, so it is virtually impossible to write a program, that would have the mixer under total control.
This variable gain analog circuit in front of the A/D converter can also increase noise, cause nonlinearities and have a temperature dependent gain.

2. Most computers are quite noisy, swamping the lower bits with useless garbage.

3. Inputs of sound cards are AC coupled, which is OK for their intended application, but precludes direct measurement of DC voltages.

Concerning 1, I have no solution for the changing mixer settings, but luckily I have not yet seen big nonlinearity problems in the mixer.
Concerning 2, the good news is that the noise is usually not white, but restricted to a few bands, like 1/f noise and powerline hum at the lower end. In many cases, using some DSP filtering one can get rid of most of the noise.
And concerning 3, this article presents a solution.

The hardware

I have developed a very simple and cheap circuit, which makes DC measurements with sound cards possible, by chopping the DC into a cca 5kHz square wave. I mainly intended it to measure the output of log detector ICs like AD8703.
But being a chopper, it is also very well suited for measurement of small DC voltages, especially from low Z sources, like thermocouples.
By modifying the program to write into a file, it can be used for long term monitoring, replacing strip chart recorders etc...

The schematic is very simple:

CheapChop schematic diagram

It uses a single 74HC4066 chip containing four CMOS switches, and a few resistors and capacitors. The components in the above schematic will cost about a couple of Euros, but you will probably want to spend a little more for a small box and some connectors.

The circuit is supplied with nominally 5V, and can chop DC voltages between zero volts and the supply voltage. It draws cca 5mA at 5V.
It would be possible to supply it directly from an 4.5 or 6V battery, too - but for good accuracy, a stable supply voltage is beneficial.
Maximum allowed supply voltage for 74HC logic is 7V. Using a "classic" (non-HC) 4066, operating voltages up to 18V are possible. However, for operation at 6V or less, I recommend using the HC version of the chip, which has lower "on" resistance at these voltages.

Two of the CMOS switches make up an astable multivibrator, that oscillates at cca 5kHz. Their outputs control the remaining two CMOS switches, that chop two DC voltages for the two sound card channels.

I've made the circuit fully symmetrical, to reduce crosstalks. The two chopping switches are operated anti phase, and could be connected as a SPDT switch, if needed.

Compared to most other DC measuring instruments, like DMMs, the input impedance of this circuit is very low, in the low kOhm range. One can increase it a bit by increasing the value of R1 and R2, but with the typically 10 kOhm input impedance of sound cards, one can not go too high here.
So, if you need to measure a high Z source (like a diode RF detector), a buffer amp will be more or less indispensable.

When measuring voltages higher than the supply voltage, it is NOT enough to just connect a resistor in series with the input!!! Namely, in the "OFF" state of the switch, the whole voltage would be on the switch, killing it instantly! Therefore, a "full" voltage divider with two resistors must be used in front of the chopper, to keep the chopper input voltage below supply at all times.
Another possibility would be to use a 5V zener instead of the "lower" resistor in the divider. This zener would just protect the switch, and would have no effect on the voltage division ratio, which in this case would be determined by the series resistor and R1 or R2, respectively.

Built on a small protoboard, it looks like this:

CheapChop, top sideCheapChop, bottom side

The software

Of course, some software is needed, to read the DC voltage from the chopped waveform. I have written a small program for this. It handles the sound card the OSS way, but since ALSA emulates OSS, most penguins should be able to swallow it without complaints.

The program is here: cheapchop.c Compile it with:
gcc -lm cheapchop.c -o cheapchop
It uses a simple FIR bandpass filter for the chop frequency, to reduce the impact of sound card (and PC) noise. It is just a "bare bones" program, consisting of the essential functions for the basic measurement. The user should add to it whatever calibration/display options, data logging etc., are required by his application.

To work properly, the filter in the program has to be tuned to the actual chopper frequency. As-is, the filter is tuned to 5000 Hz, the approximate frequency where the oscillator runs when the components have their nominal values.
There is no need to use tight tolerance components, more important is that they are stable, especially the capacitors in the oscillator. If you measure the frequency after you have built the circuit (for example with an FFT program for the sound card...), you can write it into the source code, variable "fc", assigned in line 148. This will tune the detection filter to the frequency of your particular CheapChop hardware.
If you lack suitable frequency measuring instrumentation (software), just connect some DC voltage to the input of the CheapChop and change the frequency variable up or down in 50Hz steps, until you get the max reading. This will be a bit tedious, because you need to recompile each time.
The filter should be tuned at least within 100Hz of the actual oscillator frequency. I do suggest the use of 10nF capacitors with a bit better thermal stability (polypropylene, styroflex...), so that the frequency will not drift out of the filter bandpass... The cheap "supply blocking" ceramic caps can be quite horrible in this respect!

NOTE: Sometimes I have observed that if I overload (saturate) the MIC input, the program will stop (waiting for samples from the sound card). So if you start the program, and nothing appears, first check your inputs - try disconnecting everything from the sound card inputs.

Using the CheapChop

When run from a console (or X terminal), the program simply continuously prints out the measured values for both channels. For example, on my computer, with 3V at one channel and 0V at the other, the output looks like this:
CH1 = 29739.8     CH2 =     8.0
CH1 = 29739.0     CH2 =     7.9
CH1 = 29738.6     CH2 =     8.0
CH1 = 29737.9     CH2 =     8.0
CH1 = 29739.6     CH2 =     8.0
CH1 = 29736.2     CH2 =     8.0
CH1 = 29735.6     CH2 =     8.0
CH1 = 29735.0     CH2 =     7.9
CH1 = 29734.5     CH2 =     8.0
CH1 = 29733.6     CH2 =     8.0
On your computer, the values will very probably be different. Because the mixer precludes absolute calibration, the values are not in volts, but some arbitrary units.
If you decide to keep your mixer always at the same setting, you can measure how many of these arbitrary units makes up one volt on your system, and then change the program source to divide the measured value with that number (lines 195,196), to get a display in (milli)volts. In the example above, we get cca 29735 units for 3V, that is 9911.6 units per volt, or put another way, one unit equals 100.89 microvolts, and the printout resolution (0.1 unit) is 10 uV.

CH2 above shows some crosstalk between the channels. Partly it is in the audio cable, where both wires are in the same shield, and partly inside the sound card / PC. In the above case, 20*log10(29735/8)=71.4dB, which is very good, as far as audio standards go...

When both inputs are at zero, the output is:
CH1 =     0.5     CH2 =     0.5
CH1 =     0.4     CH2 =     0.6
CH1 =     0.5     CH2 =     0.5
CH1 =     0.5     CH2 =     0.6
CH1 =     0.5     CH2 =     0.6
The numbers aren't zeros because there is some crosstalk in the CheapChop circuit itself, and some sound card / PC noise gets through the bandpass filter, too. Here, the offset caused by noise and crosstalk is cca 0.5 unit, and the noise in the measurement (fluctuation of the numbers) is less than 0.1 unit. The offset is usually pretty stable, and could be subtracted.

The maximum possible value for a clean square wave would be cca 41000, but because of noise etc., saturation will be reached at lower values. Two asterisks next to the displayed value indicate that a channel is close to amplitude saturation, like this:
CH1 = 35723.9**   CH2 =     9.7
CH1 = 35725.3**   CH2 =     9.7
CH1 = 35722.5**   CH2 =     9.7
CH1 = 35720.8**   CH2 =     9.7
CH1 = 35721.1**   CH2 =     9.8
CH1 = 35722.0**   CH2 =     9.7
In this case, you should not trust the displayed value.

Input range

The range of the voltages that can be measured, depends on the mixer settings. The upper limit will be either 5V (Cheap Chop supply voltage) or, if your sound card saturates before that, whatever the saturation voltage of your sound card is.
The lower limit will be determined by crosstalk and noise.

The table below shows what I got on my old HP "Vectra VL", with the default values for filter length and averaging:

			scale	scale	offset	noise	saturation
			V/unit	units/V	  V	  V	    V
line, min		197u	  5062	 59u	9.9u	  (>5v)
line, max		15.2u	 65615	 45u	3.8u	  0.5
mic, min, boost=0	86.5u	 11558	 43u	2.6u	  2.9
mic, max, boost=0	6.73u	148.5k	 40u	2.7u	  220m
min, min, boost=1	8.85u	113.0k	 40u	3.5u	  300m
mic, max, boost=1	0.77u	 1.30M	 38u	2.3u	   20m

On the line input, when I set "capture" in the mixer to minimum, full 5V on the input of CheapChop will not saturate the input.

From the above it can be seen, that at least on this machine, using the MIC input does not provide any significant increase in sensitivity - but that is not much of a problem, since we already are at the microvolt level!!

The "noise" in the above table is just true random noise, when zero volts are connected to the input. With a nonzero input voltage, there will be some additional "pseudo noise", caused by the fact, that the chopper waveform does not have a fixed phase relationship with the sampling clock. With the default filtering and averaging, this noise is cca 0.005% of the measured value. Therefore it will only become significant at higher input voltages, and will not affect the CheapChop's ability to measure very small voltages.

If you desperately want still higher sensitivity, maybe a low noise audio preamplifier between the CheapChop outputs and the sound card input could help.

Averaging and filtering

By default, the program uses a filter of length 64, and averages 64 measurements. Decimation is equal to filter length, so with an 48kHz sample rate, it prints out cca ten data points per second, with about four stable digits.

Averaging and filter length can be changed in the source, filter length is determined by the variable "nf", assigned in line 149, and the amount of averaging by the variable "navg", assigned in line 150.

The filter length and amount of averaging affect both the rate at which the measurements are available, and the precision and noise in the measurements. Increasing either will reduce the speed of the measurement, but improve its precision and sensitivity.
Increasing filter length is more effective in reducing the measurement noise, however because it also decreases the filter's bandwidth, it makes precise adjustment of the filter to the chopper frequency more important and difficult.

Decreasing the averaging to one (no averaging) and filter length to 48, one can get 1000 measurements per second, but they will be quite noisy. I don't recommend using filters shorter than about 20 taps.

Measuring the output of RF log detector ICs

Most of these log chips are "from DC up", so especially if you want to measure low level RF, take great care to prevent the chopper's 5kHz entering the log chip's input! Don't place the CheapChop too close to the log chip (separate boxes maybe...) and watch your grounds and filter your supply lines!

Provided that the 5kHz do not intrude via ground or supply, a suitable high-pass located as close to the input of the log chip as possible can help. If your frequencies are in the HF range, it seems it should be easy to separate them from 5kHz, but 74HC logic is fast, and harmonics of the 5kHz square wave can reach quite high. Putting simple RC lowpasses directly onto the CheapChop outputs might help.
If you need to measure only a single RF frequency, use a bandpass at the input of the log chip.


It should be clear, this is no precision instrument.

In the CheapChop circuit itself, one error source will be the change of the "ON" resistance of the CMOS switches with temperature. The influence of this could be reduced somewhat by increasing the value of resistors R1 and R2, keeping in mind the input impedance of the sound card - otherwise an high impedance input audio amplifier will be needed between CheapChop and sound card.

Next is the drifting frequency of the oscillator - it will travel along the FIR filter's frequency response, changing the displayed value. If you use ceramic 10nf caps in the oscillator, this will be by far the biggest error source.

And then, the sound card. Audio codecs are designed for everything but DC accuracy. The gain of the mixer circuit will depend on temperature, and the interior of a PC is anything but a stable thermal environment.

PCs vary wildly in their noise levels, especially laptops tend to have high noise levels. I've seen differences in noise between PCs of up to 30dB!

All these caveats aside, I found the CheapChop to be surprisingly stable, and quite accurate, if built with quality components like metal film resistors and foil capacitors.

To test the stability, I set up the following test. Measuring a fixed voltage of 4V, I've monitored the program's output, comparing it to a HP34401A DMM. I did this on my trusty old Vectra VL, after giving everything an hour of warm-up time. The air condition probably kept the room temperature constant to a few degrees C.
Initially, I set the scaling variable in the program, so that the displayed value was exactly the same as on the HP34401. During a 3 hour period, the displayed value stayed within +-0.4mV (+-0.01%) of the HP34401.
Next, I sprayed the CheapChop circuit with "Freeze Spray", cooling it to cca -20C, and the error went to +8mV. Surprisingly, most of the change occured above cca 5C, going colder did not increase the error very much.
After that, I used a hot air gun to heat it to cca +50C, which sent the error to -20mV. Most of the change was probably due to the chop frequency going down by cca 80Hz.
I was quite happy to see such good results! Honestly, I was expecting worse.

For a crude accuracy test, I measured voltages from 0 to 5V in 0.5V steps, and compared the readings to the HP34401.
  voltage	error
   0.0V		+0.4mV
   0.5V		-1.6mV
   1.0V		-7.0mV
   1.5V		-9.0mV
   2.0V		-9.0mV
   2.5V		-4.3mV
   3.0V		-2.0mV
   3.5V		-1.5mV
   4.0V		-0.7mV
   4.5V		+20mV
   5.0V		+44mV
Obviously, when approaching the supply voltage, we run into some nonlinearity. But discarding the upper two measurements and centering the values, the error could be held around 0.1% of full scale, which is comparable to what the cheap 3 1/2 digit DMMs are declared to be - but don't always achieve...

And last, I tested the influence of the supply voltage. Measuring 4V, when changing the supply voltage from 4.5 to 5.5V, the maximum error was +11mV at 5.5V supply.

So, how does CheapChop compare to...

There are many ways to measure a DC voltage, and get the reading into a PC, and many poeple ask me, why bother with this circuit?
One of the obvious advantages of CheapChop is no doubt its extremely low price tag. Another is, that it does not occupy an useful interface port like parallel or serial, but instead a rarely used sound card input. And there are probably some others - here I try to give a comparison with some of the other possibilities:

An RS232 equipped DMM

DMM advantages:
1. greater range of input voltages (built in switchable voltage divider)
2. better accuracy (especially if a 4 1/2 digit or better DMM)
3. higher input impedance

CheapChop advantages:
1. higher possible measurement rate
2. better resolution (especially compared to an 3 1/2 digit DMM)

MAX186 and ilk

MAX advantages:
1. better accuracy

CheapChop advantages:
1. better resolution
2. greater range of input voltages thru mixer settings

An microcontroller with built in A/D

uC advantages:
1. can do other things besides A/D
2. could have better accuracy (depends on the built in A/D)

CheapChop advantages:
1. no need for specialized programming tools & hardware
2. very probably a better resolution

Up to S57UUU Home Page

Copyright info