I want to build a circuit that shows the real-time frequency components of an audio signal on a number of bar graphs of some sort. Currently, my plan is to build 12 band-pass op-amp filters, and then use a rectifier and RC circuit to create a DC envelope for each output, and then use that signal to drive a LED bargraph or something similar.

The circuit will use a single +3.3V supply, and using 12 band-pass filters is not really negotiable. If I want a 12-channel bar graph, am I stuck using 12 bar-graph LEDs and bar-graph LED Driver pairs? That comes out to $45! Is there a better/less expensive/simpler method of getting a similar result? Ideally, I would not need a microcontroller.


7 Answers 7


I did a seven-channel version of this project a few months ago. I designed 7 separate opamp bandpass filters (using the Bessel filter topology to minimize distortion). I went with the LM3914 and a prepackaged LED bar graph because cost wasn't the issue; development time was, but you can take the opposite route.

I passed the filtered signals through the following peak detector:

alt text

This is a lot cheaper than the opamp circuits you'll find elsewhere. The Vce of the transistor and Vf of the diode should cancel out. The 1uF capacitor and 470k resistor gave a good decay rate for watching the audio signals that I was tracking.

With respect to the cost, the LM3914 that you were looking at is just a cascade of comparators with one input connected through a resistor network to a fixed voltage, and the other to the peak detector input. If you don't need the LED current control that this chip provides, you can probably do it cheaper with a classic quad comparator like the LM339 or LM2901 (you don't need anything fancy), which will run you about $0.30 in quantities of 25 (you need 24 for twelve 8-channel graphs). Assuming that resistors are basically free, you need a diode, a transistor, decoupling caps (also essentially free), a 1uF peak storage capacitor, and an LED graph. Just use some bulk 1206 LEDs for the graph and arrange them on your PCB instead of paying for the prepackaged bar graph. If you go with 8 elements in your graph, and you need 12*8 ~= 100 LEDs, you can do that for $0.042 cents apiece with these green indicator LEDs, or about $0.34 per channel. I'd say you can get away with the bar graph part for under $1 per channel if you shop around.

  • \$\begingroup\$ @bemace - Thanks for fixing that! We used to have \$LaTeX\$ delimiters of $...$, so we had to use that bizarre formatting. It's been fixed, (they're now \$...\$) but we still need to clean up some stuff...want to help? \$\endgroup\$ Commented Jul 18, 2011 at 4:14
  • \$\begingroup\$ I mostly find questions/answer that still need to be fixed in older Q/A which don't get many views anymore, but I fix when I spot them. Thanks for all who participated in the TeX Edit Party. Great cooperation! \$\endgroup\$
    – stevenvh
    Commented Jul 18, 2011 at 6:32
  • \$\begingroup\$ @steven - Well, I'd have said that party was something of a drag... \$\endgroup\$ Commented Jul 18, 2011 at 6:42
  • \$\begingroup\$ Yeah, and come to think of it, the music was lousy too. And the drinks expensive... :-) \$\endgroup\$
    – stevenvh
    Commented Jul 18, 2011 at 6:45
  • 1
    \$\begingroup\$ I'm (quite) late to the punch here, but I wanted to say that this is a fantastic peak detector! It has comparable speed and accuracy to an opamp without the extra footprint and cost. \$\endgroup\$
    – Jay Greco
    Commented Jun 6, 2013 at 20:48

Sometimes it's cheaper to use a general purpose IC and program it to do what you want, then trying to find a bunch of special purpose ICs that aren't programmable, that do exactly what you want.

This guy did a 64-band spectrum analyzer on a low end microcontroller, so doing 12 channels should be cake. (he also included a LCD driver...in your case you would have the software drive a matrix of LEDs instead). The circuit is fairly simple as well.

The microcontroller is cheap. To drive the LEDs, you will have 120 of them (10 x 12). You would just wire them in a matrix, and you could drive it with 4 shift registers which are also cheap. (Would take 6 I/O pins, plus or minus, depending on how you wired it).


LCD output PCB layout


An alternative to dedicated drivers and LED arrays is to make your own, borrowing the idea behind R2R ladders and flash ADCs. The output from the aforementioned edge detector is fed through something similar to an R2R ladder (not necessarily with equal value resistors), which provides a number of nodes with voltages from the input to ground. A FET can be selected such that its knee voltage or turn-on voltage is something manageable, like 0.5V to 1V, its source grounded and gate connected to the various R2R nodes. When a node exceeds the knee voltage, the FET turns on and drives an LED.

Sound amplitude is traditionally (and biologically!) logarithmic, so the voltage at which each should turn on is linear on a logarithmic scale. For an input of max 3.3V to light 10 LED's per channel logarithmically with voltage, assuming a knee voltage of 0.5V, the absolute node voltages will be: (MATLAB)

EDU>> logspace(log10(0.5),log10(3.3),10)
ans =
    0.5  0.6166  0.7605  0.9379  1.1567  1.4265  1.7593  2.1697  2.6758  3.3

If one aims for a maximum current of ~1mA, total R2R resistance should be near 3.3kΩ. This reveals resistor values of: (use voltage divider iteratively)

R1 = 624.2  (620)
R2 = 506.1  (510)
R3 = 410.4  (430)
R4 = 332.8  (300)
R5 = 269.8  (270)
R6 = 218.8  (240)
R7 = 177.4  (160)
R8 = 143.9  (150)
R9 = 116.6  (120)
R10= 500    (500)

Note: standard 5% resistor values in brackets are not simply the closest match, but are calculated iteratively. To redo calculations with other standard values or specs, the formula is: Ri = RTOTAL x (1 - Vi / 3.3V) - {sum from 1 to i of Ri}, derived from voltage divider formula.

Final circuit will look something like this:
alt text

Another method of achieving this effect is to use diode drops. 3.3V can support about 8 Schottky drops (~0.4V) if transistor threshold voltage is less than or equal to 0.4V (otherwise, 7 drops). In a chain of 8 Schottky diodes, pull down voltages at each intermediate node with a resistor that will also function as a current limiter (allow something close to the test current from the datasheet to flow when diode is forward biased). Each node is then connected to transistors in the same way as above. Current through the diodes will change by over 8X, based on how many diodes are forward biased, so ensure each will work in all cases. This method is linear w.r.t. voltage or amplitude, which isn't quite authentic. Also, Schottky's are more expensive than 5% resistors...

A final hint -- one I haven't explored -- is to use the BE-drop in BJT transistors instead of Schottky diodes, saving several parts per LED but also having to deal with a larger diode drop and bipolars.


Analog spectrum analyzers mix down the input over a range of frequencies and display the RMS or power level of a thin, low frequency passband range - you could do the same. Instead of using op-amp filters at your input, you can use an input antialiasing filter (10kHz-20kHz LPF) followed by a mixer with LO input from a VCO driven by a ramp (the swept part of swept-tuned spectrum analyzer), then a great bandpass filter. The mentioned peak detector follows. This approach is quite a bit more involved than a bank of filters followed by amplifiers, but way more fun. Much hair-pulling and brain-fuzzing will result.

You likely know more about mixers than I do, so I'll leave that alone. Note that an "audio mixer" is not the same thing.

Wikipedia has an audio VCO example, and leads to some popular designs. Dedicated VCO and voltage-to-frequency converter ICs are available, but they are mostly for the 100's of MHz-range; this one may be of use, but generates square waves. (Another question may be in order to determine an ideal VCO for this application.)

A simple diode peak detector can be improved with two op-amps, as described in AoE on pg. 217. Especially useful for small amplitude input signals (error ~0.6/Vp). alt text

  • \$\begingroup\$ Unfortunately my project must include the 12 filters. \$\endgroup\$
    – W5VO
    Commented Jan 12, 2011 at 21:46
  • \$\begingroup\$ @W5VO - Ah, I'd read "non-negotiable" to mean you didn't want to implement the filters due to design/cost/space constraints. Can you take the input to your bar graph part before the filtering? \$\endgroup\$ Commented Jan 13, 2011 at 1:13

One option is to use a small microcontroller to perform an FFT. A PIC 18F is capable of doing this, as this example demonstrates (code is open source) - 10 fps isn't difficult, and you could improve the apparent update rate by averaging between subsequent FFTs or by adding in random noise. You can then use charlieplexing or some other form of multiplexing to drive the display.

If FFT sounds too difficult, or requires too much processing power for you, you can try doing it by mixing analog and digital concepts.

You could make a configurable band pass filter by using capacitors connected to microcontroller IOs. Connect a 1k or so in series to an ADC input. Make the IO high impedance to effectively disconnect the capacitor, and drive the output low to connect it. By using almost binary values of capacitor, such as 10n, 22n, 39n and 82n, you can make a 16-way filter. That's for the high pass part; to do the low pass part, put a 100n cap (or so) in series at the middle node of the RC high-pass, and use resistors on the IOs (again, using binary values of 1k, 2.2k, 3.9k and 8.2k), doing the same with the caps: drive them low to use them, and drive them to high-Z to disconnect them.

Then, you can either use a peak detector circuit to measure the peaks, or just take a series of measurements from the ADC and average them out. If you only need an 8 way filter, that's 6 IOs, plus the ADC input, so 7 IOs total, and a 8x8 display will take only 9 IOs to control using charlieplexing.

  • 1
    \$\begingroup\$ If one wants twelve frequency bands and they're not equally spaced, would it be better to do an FFT, or to simply compute twelve pairs of integrals of reference-wave-times-original? The PIC 18 series isn't set up terribly well for that, but a DSP or an ARM should be able to handle it well enough. \$\endgroup\$
    – supercat
    Commented May 8, 2011 at 19:40

An ARM might be able to do a good job of estimating the energy in each frequency component, at least if one uses a little assembly language and is using a nice ARM variant (e.g. Cortex-M3 or ARM7-TDMI, rather than a Cortex-M0).

Assuming the original data and reference wave are 16 bits, and one has separate copies of the reference waveform for each frequency of interest (probably not too hard if there are only twelve of them) the inner loop might look something like:

; R0 - Data source pointer
; R1 - Reference wave pointer
; R2 - Data source end, plus one
; R3 - Reference wave end
; R4 - Reference wave length
; R5 - Reference wave cosine delta
; R8 - Sine total L
; R9 - Sine total H
; R10 - Cosine total L
; R11 - Cosine total H

  ldrsh r6,[r0],#2  ; I forget the syntax for post-increment
  ldrsh r7,[r2,r5]  ; Fetch cosine reference
  smlal r10,r11,r6,r7
  ldrsh r7,[r2],#2
  smlal r8,r9,r6,r7
  ; Repeat the above a few times if desired, if wave length will always be
  ; a multiple of the number of repetitions.  Note that the reference wave
  ; may need to be extended a bit to accommodate this (it must be extended
  ; be a quarter-wavelength to accommodate the cosine term).
  cmp r1,r3 ; Carry set if r1 has gotten as bit as r3
  subcs r1,r4 ; If passed end of wave, wrap
  cmp r0,r2 ; See if at end of wave
  bcc lp

I think that inner loop would take about 20 cycles to process the sine and cosine terms for one same of one frequency. So for twelve frequencies, you'd have to spend 240 cycles of front-line processing. Even a 16MHz ARM should have no trouble handling that.


I'm not sure I understand what the problem is; you've locked down your requirements pretty well. The 12 bandpass filters cannot be avoided, and you want to use 12-LEDs per bandpass filter; you could eliminate the LM3914 and use a single microcontroller with 12 ADC inputs, or include an external MUX. You could eliminate the RC filter and envelope circuit and do it in software if you're sampling fast enough, and if you would relax the 12 bandpass filter requirement you could even calculate the FFT in software.

Basically what I am saying is that given your requirements I'm not really sure why $45 in parts for the bar graph driver and output LEDs is such an issue. You haven't really left yourself a lot of flexibility.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.