0

I am working on detecting the amplitude of a signal coming from a guitar pickup. I am using an esp32 and an LM386 module for amplifying the signal.

I get quite stable readings with a multimeter, but the readings on the Arduino IDE show peaks and also peaks come when no signal should be there.

enter image description here

Here is a link for short videos of both the esp32 readings and the multimeter:

https://drive.google.com/drive/folders/1gpvkN_sz627jG0TNPpUps82105EB89OF?usp=sharing

Thanks!

EDIT (Adding simple code being used) :

int ampedVoltagePin = 12;

void setup() {
  pinMode(ampedVoltagePin, INPUT);
  Serial.begin(9600);
}

void loop() {
  Serial.println(analogRead(ampedVoltagePin));
  delay(100);
}

EDIT (Adding diagram):

enter image description here

4
  • 1
    And what happens, if you take the average over a longer time and show that? Because thats, what a multimeter does. My multimeter seems to average over about 500ms. Also you would need to take the min and max values before averaging to get the amplitude, since otherwise taking the average of the wave directly would mostly cancel out. Please show the code and the wiring of your project. – chrisl May 10 at 9:45
  • How is the ESP32 connected to the output of the amplifier? What kind of signal is this? – StarCat May 10 at 10:08
  • @chrisl, I just added diagram and code. I will now try your suggestion of getting the average – Alejandro Camus May 10 at 10:14
  • @StarCat, I hope the newly diagram helps with the questions. Otherwise I'll try to clarify further – Alejandro Camus May 10 at 10:16
4

I see multiple problems with your setup:

  • You only take a measurement every 100ms. That measurement takes the voltage during a very short time span. But the lowest string on a guitar in standard tuning has 82.41Hz (E2). You are measuring at 10Hz. According to the Nyquist–Shannon sampling theorem you need to measure at at least twice the frequency of your lowest frequency to measure. Otherwise your measured data will not have any real meaning and will not represent the input wave. So you need to measure at least with 165Hz.

  • The amplifier can output voltages up to it's supply voltage, so 5V. You connect the output directly to the ESP32, which is a 3.3V device. That can damage the pin, that you are using.

  • Currently you are trying to measure the signal directly. But you wrote, that you want to have the amplitude. Currently you would need to calculate that in code (for example by taking the min and max value over a time range greater than one period of the lowest frequency, so at least 12ms (1/82.4Hz)). A multimeter most likely will do that in hardware with analog electronics.

  • I'm not sure if it is good to connect a speaker and the ESP in parallel. As a speaker is basically an inductor moving in a magnetic field, you might get backwards voltage induced by it. That might be harmful to the ESP. Others here might know more about that.

  • You connect the Arduino ground to speaker ground. But that is most likely not the same as the amplifiers ground. Most likely the amplifier drives the speaker symmetrically, so also with negative voltages in reference to the speaker ground. That can damage the ADC of the Arduino. Also it's unclear, how good that ground actually is. That pin is not meant for grounding a microcontroller. Driving a speaker is different from measuring the voltage with an Arduino, so you would need different amplifiers to do it.

I'm not an expert in the field of analog electronics, but I guess you could use a diode to get one half-wave and then feeding it into a low pass filter. The resulting voltage is relatively steady (depending on the cut-off frequency of the filter) and can then be measured by the ESP. I'm sure, that this will only give you a rough measurement of the amplitude, but enough for typical applications like amplitude visualization. For really precise measurements you most likely need to use a more complex electronics setup to work against the non-linearities of the parts (especially the diode).

5
  • Thanks, very good points. 1. You only take a measurement every 100ms: This I fixed by taking a larger sample and getting the average. 2. The amplifier can output voltages up to it's supply voltage, so 5V: I can regulate this with a volume knob in the LM386 module 3. I'm not sure if it is good to connect a speaker and the ESP in parallel: This is the only way I've found to get readings that make sense. If the speaker is not there I get high values that don't reflect anything from the actual input. – Alejandro Camus May 10 at 11:20
  • I am wondering about why it works only with the speaker connected and how can I get rid of it as I don't really need a speaker on my setup – Alejandro Camus May 10 at 11:44
  • Mhh, the amplifier most likely acts like a current source and will raise the voltage, until the needed current flows or the limit is reached. So the problem is the type of amplifier. With a different amplifier you should be able to ditch the speaker. Though - as I wrote - I'm really no expert in that field. – chrisl May 10 at 11:45
  • @AlejandroCamus Taking samples and calculating the average to find the amplitude is meaningless. Imagine a single cycle of a pure sine wave. Think about sampling at regular points along that waveform. What will the average be? Now reduce the amplitude but keep the offset the same and do it again. What will the result be? You see the average has no relation to the amplitude - it only gives you the "DC offset" of the waveform. Instead you need to take lots of samples and find the MAX and MIN values over that period. The difference between the two values is the amplitude. – Majenko May 10 at 14:25
  • @Majenko Actually I think the OP gets satisfying results, because he tries to use the speaker ground as ground for the Arduino. Most likely the amplifier outputs a symmetrical wave around the speaker ground. But the ADC doesn't measure the negative voltages, thus the OP actually only measures one half wave. The average still doesn't give the real amplitude, but that still might be sufficient for the OPs application. At least that is my theory whats happening. – chrisl May 11 at 8:29
0

I managed to get accurate readings by following @chrisl's suggestion in the comment.

Instead of trying to get values at given points I am now averaging 500 values and the readings are as expected.

New code:

int ampedVoltagePin = 12;
int counter = 0;
int sumOfVoltages = 0;
int sampleSize = 500;
int average;

void setup() {
  pinMode(ampedVoltagePin, INPUT);
  Serial.begin(9600);
}

void loop() {

  sumOfVoltages += analogRead(ampedVoltagePin);
  
  if (counter > sampleSize -2) {
    average = sumOfVoltages/sampleSize;
    Serial.println(average);
    sumOfVoltages = 0;
    counter = 0;
  }
  
  counter ++;
}
0

Yes, you do need to sample at a rate at least 2x the highest harmonic you want to consider. But that's not your biggest problem.

The LM386 is normally used with an output capacitor. The chip specs say it is "self balancing", which means its output sits at half the supply voltage when there is no signal present, then swings up and down from that. The inductance of the speaker is not the issue here, it's that it has a very low DC resistance (8 ohms, typically) and you are putting it across a 2.5V DC source (the LM386 output). This not good for the amp, and it's terrible for the speaker since it is outside its normal centered operating point.

So use a big electrolytic capacitor between the LM386 and the speaker. The data sheet shows 250 uFd, but that's not critical. Note that the + pin of the capacitor must connect to the LM386 output. But the Arduino input must connect to the amp directly, as you are doing now, and you must subtract +2.5V from every reading to get an AC waveform. You can then handle that as you wish, such as by taking the absolute value and filtering (averaging with a time constant).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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