PlainDSP (Part 3)

Part 12, 3, 4

——————————————————————————

Important notice:

The huge popularity of PlainDSP (merge of PlainFFT and PlainADC libraries) and the numerous requests for help drove me to think about a convenient solution for all designers, artists, students, professors, R&D people, prototypists who need to understand, experiment, create systems which feature advanced Digital Signal Processing on Arduino. The result of intense thoughts, design and writing is the collection of PlainDSP kits, starting with the audio kit.

plaindsp_audio_kit_s
Each kit contains a 120 pages guide to DSP, written in the spirit of arduinoos posts, containing many original illustrations and experiments that anyone can replay at home, at university or in his lab. Along with this book comes an original audio shield which reads and amplifies the lowest up to the loudest signals from various inputs. Ultimately the kit comes with an access code to the latest versions of plaindsp libraries. And we offer a web base support for all questions regarding the use of plaindsp kits.

So please, pay a visit to plaindsp web site. By getting one of these kits you not only get a desirable product but you also support a private initiative for popularizing science. Thank you.

——————————————————————————

This post contains an application of the data acquisition and analysis from the PlainDSP library.

The credit of the idea goes to Preston who is currently busy at deadening his truck. In his mail of PlainDSP library request, Preston explained to me his current project, and I found it fun and for some reasons, it is related to one of my current domains of interest (from the pro side). So… here it is. Enjoy and have fun!

Preston needs a simple, affordable and portable real time Sound Level Meter in order to perform relative measurements of noise levels inside the cabin of his truck, before and after installing damping material or replacing parts which are suspected to contribute to the noise.

Although PlainDSP could allow much more sophisticated measurements (e.g. Performing targeted measurements at certain frequencies), I decided to stick to Preston’s request. Let’s firstly talk about the electronics. As I have no real idea about the noise level of Preston’s truck (I understand that is significantly above the noise from inside a Cadillac 😉 ), I decided to design an auto-ranging preamplifier. The first stage will raise the level from the microphone to 50 times its original level. Two more amplifying stages are cascaded in order to achieve gains of  200  (20 * 10)  up to 2000  (20 * 10 * 10).

Micro_DB_MTR

The autoranging preamplifier is built around a TS924 quad op amp. IC1C is wired as a voltage follower which copies the voltage on its non inverting pin (10) to its buffered output pin (8). The input signal is taken from the midpoint of the voltage divider bridge R1 R2 (20k each)  which is decoupled by C3 (10µF). The output voltage (half 3.3V) is used as a virtual ground for the three amplifying stages (IC1A, B and D).

R7 (1k) biases D1 and D2, and this reference voltage is decoupled by C2 (10µF). The microphone cell (electret type) is biased from this reference voltage through R8 (1k). The signal from the microphone is decoupled by C1 (1µF) and the gain (x50) of the first amplifying stage is set by R3 (1k) and R4 (20k). Then two identical amplifying stages are mounted in series with the first stage, each of them having a gain of 10 set by R5 and R10 (1k each) and R6 and R9 (10k each)

Note:  The gain values can be changed, but you will have to change the gain settings in the code.

The signal from each amplifying stage is wired to the analog ports of Arduino: IC1A pin 1 goes to A0, IC1B pin 7 goes to A1, IC1D pin 14 goes to A2. Connect VCC to the 3.3V AND to Vref of Arduino and GND to GND (Not represented on schematics]. That’s it.

Here is an illustration of the prototype that I built using an Arduino Nano and a middle size breadboard

MicroSND_MTR_01

 

I am using a lot preassembled passive components which allow to “cable as you think”.

MicroSND_MTR_02

Thanks to some minimal normalization (e.g. Diodes use yellow wires and the live tip is the cathode), the chances of mixing up components is very low. In addition to quick wiring, the use of insulated extension wires prevents short circuits and allows compact wiring. In the present case, keeping wire lengths short is mandatory for avoiding to pick up noise. In the same spirit, if the microphone is to be used out of the board, consider using a shielded extension cable.

Time for coding. Here is the sketch which will allow repetitive prints of some interesting information:

  • Selected overall gain (for information)
  • Pic to pic noise (in mV)
  • Root Mean  Square of noise (in mV)
  • Sound Pressure Levels (in dB)

Note: Although the three first results were enough for Preston, I think that adding the SPL gives an additional interesting information that one can relate to the following table which gives examples of sound sources (noise)

  •  Jet aircraft, 50 m away: 140 dB
  • Threshold of pain: 130 dB
  • Threshold of discomfort: 120 dB
  • Chainsaw, 1 m distance: 110 dB
  • Disco, 1 m from speaker: 100 dB
  • Diesel truck, 10 m away: 90 dB
  • Kerbside of busy road, 5 m: 80 dB
  • Vacuum cleaner, distance 1 m: 70 dB
  • Conversational speech, 1 m: 60 dB
  • Average home: 50 dB
  • Quiet library: 40 dB
  • Quiet bedroom at night: 30 dB
  • Background in TV studio: 20 dB
  • Rustling leaves in the distance: 10 dB
  • Hearing threshold: 0 dB

For those who want to learn more about measurement of sounds, please check this excellent site (English version available)

/*

	MicroSNDMTR: Micro sound meter
	Exemple of use of the PlainDSP library
	Tested with ATmega328 powered Arduino
	Copyright (C) 2012-2013 Didier Longueville

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <PlainDSP.h>

/* Create objects */
PlainDSP DSP; 

/* Acquisition parameters */
const uint16_t _samples = 128; /* Max value depends upon available memory space */
const double _samplingFrequency = 22100.0; /* From 0.125 Hz to 80 kHz */
const uint16_t _defAdcChannel = 0; /* From 0 to 5 on ATmega328 powered Arduinos */
const uint16_t _refVoltage = DSP_REF_VOL_EXTERNAL; /* External: 3.3V */
const uint8_t _options = (DSP_OPT_DIS_TIM_0 | DSP_OPT_DIS_TIM_2 | DSP_OPT_NOI_CANCELLER);
uint8_t _adcChannel;
const float _refPressure = 20E-6;
/* Custom data */
const float _vGains[] = {50.0, 10.0, 10.0}; /* gain of first stage on first place and so on */
const float _microphoneSensitivity = 2.5; /* unit Pa/mV, read from moicrophone datasheet */

/* Control led parameters */
#define LED_PORT &PORTB
#define LED_PIN PINB5

void setup()
{
	/* Initialize serial comm port */
	Serial.begin(115200); 
	/* Set data acquisition parameters */
	DSP.SetAcquisitionEngine(_defAdcChannel, _refVoltage,  _samplingFrequency, _samples, _options);	
	/* Mark event */
	BlinkLed(3);
};

void loop() 
{		
	/* Start reading the most amplified signal from 3d stage */
	_adcChannel = 3;
	uint8_t saturated = 1;
	/* Reads preamlifier stages sequentially, starting from the highest gain */
	do  {
		/* Set channel */
		_adcChannel -= 1;
		/* Set channel */
		DSP.Channel(_adcChannel);
		/* Acquire data */
		DSP.GetScanData();
		/* Check signal */
		if ((DSP.Min() >= 1.0) && (DSP.Max() <= 1023.0)) {
			saturated = 0;
		}
	} while ((saturated == 1) && (_adcChannel != 0));
	/* Compute gain factor */
	float gain = 1.0;
	for (uint8_t i = 0; i <= _adcChannel; i++) {
		gain *= _vGains[i];
	}
	/* Compute scaling factor for mV */
	float scalingFactor = (3.3 / (1.024 * gain));
	/* Reset offset */
	DSP.ResetOffset();
	/* Rescale data */
	DSP.Gain(scalingFactor);
	/* Compute and print statictics */
	float rmsSignal = DSP.RMS();
	float rmsPressure = (20 * log10(rmsSignal / (_refPressure * _microphoneSensitivity)));
	Serial.print("G: ");
	Serial.print(uint16_t(gain));
	Serial.print(", ");
	Serial.print("P/P: ");
	Serial.print((DSP.Max() - DSP.Min()), 3);
	Serial.print(" mV");
	Serial.print(", ");
	Serial.print("RMS: ");
	Serial.print(rmsSignal, 3);
	Serial.print(" mV");
	Serial.print(", ");
	Serial.print("SPL: "); /* Sound pressure level */
	Serial.print(int16_t(rmsPressure));
	Serial.print(" dB");
	Serial.println();
	/* Print raw data */
	// PrintData(); /* Uncomment as appropriate */
	/* Mark event */
	BlinkLed(1);
	/* Uncomment next lines as appropriate */
	// while(true); /* Run Once */
	delay(1000); /* Repeat after delay */
};

void PrintData() 
{
	for (uint16_t i = 0; i < _samples; i++) {
		double abscissa = (i / _samplingFrequency);
		Serial.print(abscissa, 6);
		Serial.print("\t");
		double ordinate = DSP.ReadData(i);
		Serial.print(ordinate , 6);
		Serial.println();
	}
	Serial.println();
}

void BlinkLed(uint16_t cycles) 
/* Blink control led */
{
	/* Make the led pin an output pin */
	*(LED_PORT - 1) |= (1 << LED_PIN);
	/* Reset pin state */
	*LED_PORT &= ~(1 << LED_PIN); /* Turn control led off */
	for (uint8_t i = 0; i < (cycles << 1); i++)	{
		delay(200);
		*LED_PORT ^= (1 << LED_PIN);
	}
};

Except for the SPL calculation, PlainDSP contains all the functions required to make this application work.

Do not expect to get down to 0dB using a breadboard assembled module! The measured noise on the illustrated assembly shows a background RMS noise of 0.006 mV, leading to 40dB SPL!

Important: Please do not test the equipment next to loud noises without ear protections. I will accept no complains from those who will try it next to a rocket launch pad. 🙁

Coming next: same as before with LCD for portable applications.

13 Comments

  1. mymadi says:

    Hi Arduinoos,

    It is possible I Change the Op-Amp TS924 to this one:

    http://www.cytron.com.my/datasheet/IC/linear/LM324N.pdf

    Thank You

  2. mymadi says:

    Sorry one more thing.. it is the diode you use is ‘Diodes 1N4148’?

    Thanks

  3. Didier says:

    This is not a good idea. The LM324 is a good beast, but its output swings from 0V to VCC – 1.5V! So that you would have to feed the circuit with +5V and play a little bit with the mid point, which would be at about ((5 – 1.5) / 2)V, so as to say 1.75V while the reference voltage should still be 3.3V. On the other hand, the LM324 has not a strong reputation in terms of noise. But noise might not be an issue and even help improving adc resolution http://goo.gl/qpbnL !

  4. mymadi says:

    Thank you for your comment.. from your opinion this opamp is possible or not:

    http://www.ti.com/lit/ds/symlink/opa344.pdf

    * One more thing, if I have the microphone with frequency range 10-10000Hz, then we do a sampling frequency at 22100Hz.. it is we lost something?

    Thank You

    • Didier says:

      Nice chip indeed: Rail to rail, from 2.5 o 5.5 Volts power supply, high slew rate, low noise, excellent bandwidth and it’s cheap, what else could you expect?

      * One more answer …
      Why would you measure signal at frequencies that your microphone cannot “hear”? Useless. Scanning from 0 to 10kHz will double the resolution of your frequency spectrum, and also take twice the time required to scan from 0 to 22kHz…

      • mymadi says:

        For the chip, I will go for it.. because I have the chip in my hand…

        * So meaning that if my microphone capable until 10KHz, so we do sampling frequency at arduino code for 10KHz also, it is right?

        Thank You

  5. mymadi says:

    Hi Didier,

    Actually I’m confused regarding the microphone frequency and sampling frequency. I have the microphone with frequency range:

    1) 100Hz – 10000Hz
    2) 100Hz – 15000Hz
    3) 20Hz – 20000Hz

    For example I want to fully use the range of microphone frequency (20Hz – 20000Hz). From your link here (http://www.arduinoos.com/2010/10/sound-capture-cont/) you said:

    “So that we may arbitrary decide to measure frequencies up to 10 kHz. Applying the Nyquist sampling theorem, we finally need to sample the wave signal at 20 kHz”

    It is If I want to use until 20 Khz, I need to do the sampling frequency at 40KHz? It is true?

    “const double _samplingFrequency = 40000.0;”

    Thank You

    • Didier says:

      You face the physical limitation of your input device. If the microphone is limited to 20kHz, use 20kHz as a sampling rate and you will be able to measure frequencies up to 10kHz.

      For the same reasons, sounds from your CD are sampled at 44100Hz which is twice the highest frequency a man can detect. Most people will listen to frequencies as high as 16kHz, and this limit decreases over the time and depends very much on how loud you listen to music!

  6. mymadi says:

    Hi Didier,

    From your PlainDSP code, can or not we evaluate the Decibels value using 1/3 Octave bands Filter:

    http://www.sengpielaudio.com/calculator-octave.htm

    and also A-weigthing

    http://www.sengpielaudio.com/calculator-dba-spl.htm
    http://www.engineeringtoolbox.com/decibel-d_59.html

    Thank You

  7. mymadi says:

    hi Didier,

    can you give some idea to start,how to scale the frequency axis appropriately. Because 1/3 octave will have center frequency, lower frequency and upper frequency. Normally, we will got the bandwidth then we will apply bandpass filter (Butterworth Filter).

    Then I found this:

    http://www.mstarlabs.com/docs/tn257.html#Bands

    but I don’t have any idea to start, if you can see the link, there are some related number of FFT bin with 1/3 octave..

    Thanks

Leave a Reply

You must be logged in to post a comment.