By using an Arduino board we are able to make a digital, stereo sound level meter (VU -meter). We use an Arduino Uno board, a classic 2x16 alphanumeric display, an MCP6022 operational amplifier, some passive components and some lines of code. Our VU-meter uses an LCD, but the basic idea presented here could be used for building meters to use any kind of digital display or discrete LEDs.
Block diagram
Let's first look at the block diagram of our digital VU-meter. It is presented on figure 1. There are some basic stages: precision rectifiers, averaging detectors, an analog to digital (A/D) converter located inside the microcontroller, the CPU of the microcontroller and a display unit.
Figure 1. General block diagram of a stereo digital VU-meter with analog inputs
The averaging stage produces an almost DC signal which is proportional to the amplitude of the input signal. The averaging circuit is actually an integrator with appropriate defined time constants for hold and release in order to ensure a proper response for the VU-meter. The response of the VU-meter is not very fast, so that the display on the LEDs is neither flickering nor too slow, so that it can easily follow the noticeably perceived changes of the sound.
The ADC converts the averaged signal to a digital sequence of 10bit digital values. With the aim of the CPU, this digital sequence is used in real time to produce bar-graphs on an LCD.
Rectifying and averaging
By using an active rectifier circuit with some gain in our project, the amplitude of the rectified signal remains proportional to the amplitude of the input signal. Then, an almost DC signal that is proportional to the sound level is derived by smoothing out the rectifier’s output.
There are of course two rectifiers and two smoothing circuits, each pair for each audio channel, respectively. These circuits are based on U1A and U1B, as shown in the circuit schematic of figure 2. We will examine in detail the topology of the Right audio channel. The corresponding circuits of the left channel are identical.
From figure 2, you may notice that we use precision rectifiers instead of simple diode rectifiers. This is because we have to deal with low level signals, some times much lower than the threshold voltage of about 0.7V of conventional silicon diodes.
The majority of precision rectifiers require dual power supply (positive and negative). However, in our project we wished to make a single supply voltage rectifier. This was made possible by the use of the Microchip’s MCP6022 rail to rail operating amplifier. The low voltage output rail of the MCP6022 can be as low as zero without the need for a negative supply voltage. This characteristic makes possible the design of a single supply voltage precision rectifier.
Figure 2. Τhe electronic circuit of the Arduino LCD VU-meter
From figure 2, you may notice that the rectifier circuit (right channel) is actually a non-inverting amplifier which uses the D2 diode, for rectification, in its feedback loop. Since there is no negative supply, even if diode D2 did not exist, the circuit would still function as a rectifier because the amplifier could not amplify the negative half-cycle of the input signal. However, we use D2 to prevent the smoothing capacitor C5 from discharging through the output resistance of the operating amplifier during the negative half-cycle of the input signal.
A smoothing circuit after the rectifier is used to exact the mean value of the input signal. This circuit consists of R6, C5 and R8. This circuit can be viewed as a smoothing circuit or as an integrator with unequal attack and release time constants.
C5 is charged via R6 at every increase of the rectifier’s output signal. It can also discharge via R8 at each decrease of the rectifier’s output signal. The C5 capacitor is charged and discharged from different paths due to D2 which allows current flowing in one way only. This means that there are different time constants for charging and discharging. Due to the very small value of R6, charging is almost instantaneous. On the contrary, the discharge is relatively slow through R8. Because charging is faster than discharging, C5 acts approximately as a peak holding element.
Charging and discharging time constants for C5 determine the overall response of the VU-meter. These constants have been calculated according to trial an error method, and the response of the VU-meter has been adjusted according to the designer's preferences.
This response can be adapted to different aesthetic criteria by modifying C5, R6 and R8 values. C5 can be easily modified but some care is needed for R6 and R8 due to the fact that these two resistors form a voltage divider. R6 should always be much smaller than R8; otherwise there would be some significant attenuation and some dynamic range reduction.
A to D conversion and dynamic range aspects
The ATmega328P microcontroller of the Arduino Uno has an internal 10bit ADC. This means that there are 210 = 1024 possible levels. In db, this corresponds to a dynamic range equal to 20 * log (1024-1) = 60db. That is, the voltage represented by level 1023 is 60db higher than level 1 (1023 times higher).
We use the 3.3V power supply voltage of the Arduino board as a reference for the ADC. This is done by connecting the 3.3V voltage pin to the AREF pin. There is of course the possibility to use a different reference voltage but we choose 3.3V because the signal from the output of the smoothing circuit practically never exceeds 3V.
The maximum signal amplitude at the output of the operating amplifier can reach 5V but the average value of a semi-rectified signal can never be equal to its amplitude unless the signal is DC, which is practically not the case for audio signals. In practice, with a 5V supply voltage, the signal at the output of the averaging circuit is around 2V when the amplitude of the input signal is about 0.5V. This value corresponds to level 614 of the A / D converter and this means that the maximum dynamic range that can be achieved is equal to 20 · log (614) = 55db. In other words, there about a 5db reduction in the dynamic range due to the reference voltage, in relation to the theoretical dynamic range of 60db.
We could practically solve this problem by using an external reference voltage of 2V or less for the A/D converter (it can easily be done with a potentiometer) but anyway, it is not worth the case since we use a much smaller dynamic range in the display (around 30db).
Display
The audio level is mapped on 2 bar-graphs, of 15 segments each. The display has 16 characters in each line but we use one character in each line to display the corresponding audio channel (R or L) so there are 15 characters left in each line for the audio level. The display dynamic range depends on the step value (the difference in db between successive levels). By selecting each step to correspond to 2db, the total dynamic display area will be 2x15 = 30db. The selection is made through the software. It is worth noting that regardless of the step we choose, the total display dynamic range can not exceed the limit of 60db due to the 10bit ADC.
The Arduino VU-meter in a breadboard
The audio level is mapped on 2 bar-graphs, of 15 segments each. The display has 16 characters in each line but we use one character in each line to display the corresponding audio channel (R or L) so there are 15 characters left in each line for the audio level. The display dynamic range depends on the step value (the difference in db between successive levels). By selecting each step to correspond to 2db, the total dynamic display area will be 2x15 = 30db. The selection is made through the software. It is worth noting that regardless of the step we choose, the total display dynamic range can not exceed the limit of 60db due to the 10bit ADC.
The display levels for 2db step are defined in the software in an array of 15 elements as:
int level_2db [15] = {24,30,39,48,61,77,97,122,154,194,244,308,387,488,614}; // Level threshold array
From the statements, you may observe that the maximum level at which the most important segment is activated, corresponds to the value 614 which in turn corresponds to a voltage of about 2V (with the use of a 3.3V reference for the ADC). Of course, you can modify these values in conjunction with the reference voltage of the A / D converter, to possibly make a VU-meter with a different display dynamic range or with more or less display segments.
Let's demonstrate now the way we used to calculate the values for the level_2db array. We think you may find this example useful and you may use it as a guide to calculate your own levels for any step:
Let’s name the 15 segments in each display line as SEG0, SEG1, SEG2 to SEG14, for the least to the most important segment respectively. Then, each SEGi should be activated to a Vi level (V0, V1, V2 to V19). So let us choose the display step to be S = 2db. Then each level Vi, (with i from 0 to 14) should be S db less than the next, Vi + 1. Given the definition of db, we may write:
20 log(Vi+1/Vi)=S⇒ Vi+1/Vi=10S/20⇒ Vi= Vi+1·10-S/20
(1)
From equation (1) we may calculate the value of each level Vi, as long as we know the presenting Vi+1 level. This means that if we know the level V14, we can calculate V13. Then, knowing the level V13, we can calculate the level V12 and so on. Therefore, we can calculate all the levels, as long as we know the display step S, and the value of V14 .
Let’s refer to some facts: The maximum voltage level at ADC’s input is 2V. We have a 10 bit ADC and a reference voltage of 3.3V.
This means that there are 210= 1024 possible levels (from 0 to 1023) and 210-1 = 1023 steps. Level 1 corresponds to a voltage equal to 1/1024 of the reference voltage, ie equal to 3.3/210 = 5/1024 V. Any other level V, corresponds to a voltage
Uv=V·3.3/210
(2)
By setting Uv = 2V in the above equation, which is the maximum voltage level at ADC’s input and solving with respect to V, we find that the voltage of 2V corresponds to the level of 614, approximately, of the A/D converter. Therefore, the most important segment, SEG14, should be activated at the level of 614, ie V19 = 614.
Then, by setting S = 2 and V14 = 614 in equation 1, we find that V13 = 488. Then, from V13 and equation 1, we find that V12 = 387, then that V11 = 308 and so on up to V0. It is worth noting that while all calculations should be done with great accuracy, the final values to be set in the arrays should be rounded to the nearest integer.
Display modes
By changing the logic level on the Arduino D7 pin, from SW1, we can choose between two display modes.
Mode 0: 2db step bar-graph
The audio level is displayed logarithmically in two bars of 15 segments each (one bar is for the right audio channel and the other one is for the left audio channel) with a display step of 2db. This means that if we consider that the most important segment - in each bar corresponds to a 0db level, the next segments in the order, up to the least important, correspond to the levels of -2, -4, -6 ……. up to -28db, respectively. The total dynamic display range is about 30db.
Mode 1: 2db step bar-graph with peak hold
It corresponds to a logarithmic audio level representation in bars with a 2db step, as in mode 0, and the meter also indicates the highest output level at any instant in each bar. The peak at any instant is retained for some time.
Retention time is stated in the software with the statement:
#define dt3 30 //loops - Peak hold time in main loops
In the above statement, the retention time is set to 30 repetition cycles of the main loop.
Additional details
The complete electronic schematic of the Arduino VU-meter is shown in Figure 2. The input signal (audio signal) is connected to the stereo input J1 and the potentiometers RV1 and RV2 are used to adjust the sensitivity of the VU-meter so that it can be adapted to any input level.
The display and all circuits are powered by the 5V output of the Arduino board. The Arduino itself can be powered either from a computer's USB port or from an external power supply.
The RV3 potentiometer is used to adjust the contrast of the screen. For the display background light, we connect a 5V voltage to the pin 15 of the display via the resistor R9. R9 limits the supply current of the display LED and therefore its brightness, so that the circuit can be powered by a common USB port without exceeding the port’s maximum current supply. If you intend to use an external power supply, there will be no current limitation and therefore you will be able to short-circuit the resistor R9 and increase the illumination current of the display.
You can make the circuit on a large breadboard or you could make a suitable printed circuit board that could be fitted as a shield on the Arduino. All the resistors in this project are of 1/4W type and of 5% tolerance appart from R9 which is of an 1/2 W type. All the capacitors we use have a trace of about 5mm (20mils), that is, the horizontal distance between their terminals is around 5mm.
You may program the Arduino with the code we provide below or you can make changes to the code to customize the VU-meter to your liking.
If you now want to elegantly fit the VU-meter in a box or any audio device, it would be good to make a suitable mask for the display, on which you will be able to print a logo and the display levels in db or on %. You can may also use a character LCD with more than 16 characters in each line, for example with 20 or 40 characters per line or even more than 2 lines, and customize the code to display more segments in each bar or insert additional characters and effects.
Attachment
Click here to download the source code for the Arduino VU-meter.