Measuring frequency (up to 3000Hz) of mV analog signals


I have a vibrating wire sensor which vibrates at frequencies between 2000hz and 3000hz depending upon the pressure of the medium that the sensor is located in.
The vibrating wire generates analog signals of between 0 and 20mV.

An analogy of how the signals are generated: Think of a guitar string, pull the string and release it (i.e. pluck the string). The loudest response is just after you release the string.
The sound eventually dies down over time. From the initial pluck until the vibration stops, the string keeps vibrating at the same frequency but with decreasing Peak to Peak amplitude.

This is how the sensor I have, works. Once the wire is plucked, it generates around 20mV on first peak and dies down to 0mV over the duration of approximately 500ms.
The frequency of the signal is around 3000 to 2000 hz.

I would like to use an arduino to measure the frequency of the signal (probably with the help of external hardware).

This is where I would like some guidance.

Two ways I can think of doing this task are:

  1. Amplify the signal via Opamp or instrument amp? by a factor of 200 to 250 i.e. such that the maximum amplified voltage is between 4V and 5V and use an Interrupt on D2 of the arduino nano to detect the rising edge.
    Count number of pulses over a duration of 50ms. At t=50ms (t=0ms is the pluck string start time) the peak voltage would be greater than 10mV.
    Kevin Durrah has a video on his youtube channel which deals with a falling edge conter, I would use this as the basis for my code.

  2. Use an ADC with software to identify cycles.
    pseudo code:

Int NewWaveDetect
Int Frequency
Int Pulsecount

Pluckstring() //Some function to pluck the wire
startpluck = millis()

While (millis()-startpluck<50){// count the pulses in the first 50ms only, 50ms is an arbitrary value, could do more or less
Read ADC value

  If (ADC > 100) {//for 16bit ADC, 100 corresponds to 7.6mV (at 5v Vcc), 7.6mV is an arbitrary point I picked to identify a rising edge
      If (NewWaveDetect == 0){
         Pulsecount = Pulsecount + 1
         NewWaveDetect = 1

  If (ADC<=100){

Frequency = Pulsecount * 20 //20*50ms = 1 second, therefore converting Pulsecount to hz

For option 1, I have no experience with amps and need help with what amplifier would suit this application.
I also do no know what happens to the arduino when the voltage drops to negative, i.e. the wave generated from the vibrating wire would be ± 20mV, so once that is amplified by say 250 times, it would be ±5v.
I know arduino can take the +5v, but presumably breaks at -5V? How do I deal with this, is there an amplifier which only amplifies the positive voltage?

For option 2, I’m not sure if the code would run fast enough to detect the pulses, I have found some ADC on ebay (although a bit expensive, $40, could live with the price if no other options) which report 50ksps to 100ksps which I would assume is enough. If you have suggestions on an ADC, they are welcome too.

Help is much appreciated.


That sounds like an interesting project.

I think I would try to use zero crossing events, from the signal with a variable reluctance signal conditioner.

The output of that signal conditioner could drive the input capture pin (e.g. ICP1 is on Uno pin 8 ) to measure the event times. The Uno does not have a crystal, but if you look around you can find some clones that do.

So I guess my suggestion was to not use the ADC at all.

I think you should definitely amplify the signal far away from the Arduino itself. I wouldn't trust the Arduino ADC inputs, or even its power supply, to have less than 20mV of noise.
If you amplify to 3.3V instead of 5V, you'd be compatible with a broader range of boards.
(you'd want 2.7V if you were planning on piping into lots of different ADC boards; apparently some of the ARM chips have a 2.7V limit even when running from a 3.3V supply.)

I would use an arduino due with the tc_lib library