Vibration and Sound measurement through LCD

I have been working on my project, where I am using a piezo vibration sensor and an electret microphone connected to an LCD through an Arduino microprocessor.

I need to tweak it a little and hope that you guys could help me.

I was told that for the sound portion I need to have a sampling rate of at least 40kHz (assuming I want to measure up to 20kHz, and I learned from my comm class something like fs = 2f). How do I apply it to the Arduino? Through some research I found that I need to set the prescaler to 16? How do I apply that to my code?

When running the code below with only vib() inside the void loop(), it outputs good values . But when running this code like below, I get an erroneous output for the vibration portion, because it outputs the values over time, (instead of outputting it every time I touch the vib sensor). It summarizes the values somehow and gives me a strange output that seems to be almost completely random.
I do want the output to be timed, instead of having to touch it every time, but how can I fix the output? Can you guys help me please?

Thank you so much!

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

const int ledPin = 13;      // led connected to digital pin 13
const int knockSensor = A0; // the piezo is connected to analog pin 0
const int threshold = 5;   // threshold value to decide when the detected sound is a knock or not

int sensorReading = 0;      // variable to store the value read from the sensor pin
int ledState = LOW;         // variable used to store the last LED status, to toggle the light
int sum = 0;
int values = 10;
int i = 0;

const int sampleWindow = 50;              // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;



void setup() {
  
  lcd.begin(16, 2);
  pinMode(ledPin, OUTPUT); // declare the ledPin as as OUTPUT
  Serial.begin(9600);       // use the serial port
}

void vib()
{
  // read the sensor and store it in the variable sensorReading:
  sensorReading = analogRead(knockSensor);    

  // if the sensor reading is greater than the threshold:
  if (sensorReading >= threshold) {
    // toggle the status of the ledPin:
    ledState = !ledState;  
    // update the LED pin itself:        
    digitalWrite(ledPin, ledState);
    // send the string "Knock!" back to the computer, followed by newline   

    if (i >= values)
    {
    i = 0; 
    sum = sum/values;
    //Serial.println(sum);
    lcd.setCursor(0, 1);
    lcd.print(sum);
    sum = 0;
    }
    else
    { 
    sum += sensorReading;
    i++;
    }
  }
  delay(10);  
}



void Micro()
{
unsigned long startMillis= millis();      // Start of sample window
unsigned int peakToPeak = 0;              // peak-to-peak level
 
unsigned int signalMax = 0;
unsigned int signalMin = 1024;
 
// collect data for 50 mS
while (millis() - startMillis < sampleWindow)
{
sample = analogRead(1);
//Serial.println(sample);
  if (sample < 1024)                        // toss out spurious readings
    {
    if (sample > signalMax)
    {
    signalMax = sample;                       // save just the max levels
    }
  else if (sample < signalMin)
    {
    signalMin = sample;                       // save just the min levels
    }
  }
}
peakToPeak = signalMax - signalMin;       // max - min = peak-peak amplitude

double volts = (peakToPeak * 3.3) / 1024; // convert to volts

delay(100); 
//Serial.println(volts);
lcd.setCursor(0, 0);
lcd.print(volts);
}



void loop() {
  Micro();
  vib();  
}

Are you trying to measure "sound", or "vibration" ? Yes, they are the same thing, but the way you
would go about it is rather different because of the different frequency ranges at issue.

I was told that for the sound portion I need to have a sampling rate of at least 40kHz (assuming I want to measure up to 20kHz, and I learned from my comm class something like fs = 2f). How do I apply it to the Arduino? Through some research I found that I need to set the prescaler to 16? How do I apply that to my code?

Quite simply you can't. The arduino will not sample analogue data that fast.

michinyon: both, I am able to measure both, but another issue I have is that for the vibration, I get a value from 0 to 1024 that I would like to convert to G. For the sound, I get a value from around 0V to 3V, that I also would like to convert - dB. I can't figure out how to do that.

Grumpy_Mike: Is there a way to at least increase the sampling rate to make it slightly more accurate?

Thanks guys! Appreciate it

Have a look: http://coolarduino.wordpress.com/2013/01/09/audio-vu-meter/
Can't get why do you need to measure vibration? Normally good microphone should be o'k down to 20 Hz.

Sorry, it's my fault for not thoroughly explaining my project. I was posting this in another forum where I have described it better.
I am building a small "portable" sound and vibration device. I can sense vibration through the electret mic but I would like to have a separate/more accurate vibration meter (that I have purchased).
I could post a video to explain what I am doing if that helps.
Magician, your article is nice. My goal however, is to make a sound level meter (and a vibration meter on the side). In your article, the vu meter, you are taking the signal from the input and display it on your LCD. The concept of the sound level meter should be simpler than the vu meter right? How do I make the simple conversion from V do dB? Through rms? Sorry, I am confused.What about the sampling rate?

Have you download the sketch?

#define  SMP_RATE                   40       // Sampling Rate, in kHz
#define  SMP_TMR1 ((16000/SMP_RATE) -1)      // Sampling Period of Timer1

The concept of the sound level meter should be simpler than the vu meter right?

No, it's the same. To get sound level you need preamplifier and mic, everything else similar.

RMS Voltage in time discrete samples domain , calculates
Vrms = sqrt ( V1^2 + V2^2 +.... );, or square root of the summ of squared up samples.
Log (dB) scales computes in this line of code:

  rms_Level = 20.0 * log10(temp +1);  // Calculated, available over Serial

Thanks!! That helped me a little, plus I got to understand it a little better!
Let me experiment with this and get back if/when I have more questions. Thanks!

Hi guys, I've been working on this, and think that the coding part is almost complete for the most part. I am just encountering the problem that the output (on my LCD) of the vibration meter is jumping up and down. In resting state it jumps between values from -0.1 to around 0.250 (the value is supposed to be at or almost at 0 of course, that is another problem I have that I hope to be able to fix through finding/adding a scale factor to it).

I am attaching the vibration meter to a DC motor that I have. I also have a "professional" vibration meter to compare it to my "self built" vibration meter. The professional one gives me an output of around 2G, which sounds about right. My self built one just jumps to values from 0 to 3.5G.
Now I am not sure why it jumps up and down, I want to find out if it's in the code, or if it's because of the motor. Do I need to tweak and adjust the code a little? What do you guys think?

void vib() {
  // read the sensor and store it in the variable sensorReading:
  sensorReading = analogRead(knockSensor);    

  // if the sensor reading is greater than the threshold:
  if (sensorReading >= threshold) {   // toggle the status of the ledPin:
    
    ledState = !ledState;             // update the LED pin itself:    
        
    digitalWrite(ledPin, ledState);

    lcd.setCursor(0, 1);
    float Vsense = analogRead(knockSensor) * 0.00489; // ADCcount/1023 = Vsense/5
    float G = Vsense/0.2;
      
    if (i >= values) {
    i = 0; 
    sum = sum/values;
    lcd.setCursor(0, 1);
   
    lcd.print(G);
   
    sum = 0;
    }
    else { 
    sum += sensorReading;
    i++;
    }
  }
  delay(10);  
  lcd.setCursor(6, 1);
  lcd.print("G");
}

What kind of sensor you have? Do you have a specification , better calibration report? How it's wired up? W/o this info, lines of code :

float Vsense = analogRead(knockSensor) * 0.00489; // ADCcount/1023 = Vsense/5
    float G = Vsense/0.2;

just complete non-sense.

I am using this sensor.

On page 2, of the following datasheet, there is a table with the specification of sensitivity included

I am wiring it very similarly to the Knock Tutorial

float Vsense = analogRead(knockSensor) * 0.00489; // ADCcount/1023 = Vsense/5
float G = Vsense/0.2;

I am assuming I have to assume Vsense by 0.2, because of the 200mV sensitivity, and the line before that I have been told by somebody when I asked for the relationship of the analogread (0 to 1023) and Voltage. (The output of the Knock Tutorial is 0 to 1023 and I wanted to convert it to V and then to G.

Sensor you linked above isn't design to "measure" , only "detect" if vibration is reaching some threshold. Adding up high non-linearity over frequency axis it's only good as knock sensor, with two state output -high/low.
Search accelerometers.

Thanks. Is there a way to make it work to measure vibration though? I got it to measure it (or at least I think it does when comparing to a meter) but the numbers jump around. I have limited time left, so it'd be great if it would work out to measure vibration somewhat accurately. Accelerometers will definitely work, but for this project, I am limited to that sensor. Is there any way I can do that?

You need same chart, like on page 2, accurately drawn for your sensor (each sensor is slightly different from others). So you taking arduino, flashing code from link in replay #4, than using voltage divider and buffer amplifier you connecting sensor to arduino analog input.
Next step, is a calibration, when you setting two sensors side by side on the same surface, and changing frequency you getting data for chart. Last step, would be create look-up table.

Thanks. But what if I assume/know that the vibrations is within 0-50Hz, so within the 3dB frequency range? That wouldn't explain the jump of numbers. I don't understand why the numbers would jump up and down

Because sensor outputs AC , up to 90 V. Arduino can only measure in 0 - +5 V. So you need to rescale / shrink input down, and rectify AC to DC before you connecting it to analog input.
To shrink input voltage is easy part, you just have to connect a resistor in parallel with sensor, 1k - 1 MoHm depends on sensitiity. Than you need to rectify AC to DC, in hardware - using LM3914 chip, or in software - in similar way to audio VU meter.