I dont know if this is the right place to ask this question, but I am asking anyways. I am working on a metal detector basically I am writing its firmware. What I need to do is that data coming from metal detector,I need to analyze and according to that signal if there is metal in front of detector I need to sound the buzzer. Now what problem I am facing is that there is no reference signal, there is only one signal which is coming from metal detector and that signal range is from 0 to 8v(obv i am not giving 8v into controller, i am using voltage divider to bring it down) . What my goal is that when there is metal in front of detector then obv the signal changes a bit but that change is only little bit but ofcourse controller can catch it. So how do I program to tell the controller how to detect that change. So for that reason I was searching on for IIR and FIR filter and I think my answer lies in these filters. But I don't understand what really they do and how can I implement them.
Filters change a signal, they don't recognize it or measure it.
You need to use correlation or simply amplitude/phase analysis (which without a reference really only leads determining the rms amplitude I think). Finding the mean square isn't too complicated, you determine the mean DC offset and average the square of the differences of each sample from this DC offset.
this sounds similar to what we've done to detect speech given background noise.
while the signal may be filtered, somewhat different signal processing is used to measure the signal levels
the absolute amplitude (i.e. rectified) of the signal is needed. we used conditional leaky integration
if (seg > avg)
avg += (sig - avg ) * kAttack;
else
avg += (sig - avg ) * kDecay;
in general, think of k = 1/N and that the avg will reach 95% of sig in 3N iterations (like an RC time constant)
to "measure" speech, the attack rate (kAttck) is > the decay rate. to measure noise, the decay rate is >> attack rate so that it quickly reacts to a drop in noise level
finally, speech is detected when the measured speech level exceeds the measured noise level by some amount (we used 6dB)
I would compare the input value to a threshold.
const int Threshold = 200; // Maybe use a knob to adjust this in the field
const byte InputPin = A0;
const byte BuzzerPin = 4;
void setup()
{
digitlWrite(BuzzerPin, LOW);
pinMode(BuzerPin, OUTPUT);
}
void loop()
{
if (analogRead(InputPin) > Threshold)
digitalWrite(BuzzerPin, HIGH);
else
digitalWrite(BuzzerPin, LOW);
}
If the Threshold has to change over time you could use a moving average in place of the fixed Threshold.
If you describe the signal, and this change in enough detail, forum members can explain how to detect it.
thanks for reply everyone
so this is the signal which I am trying to detect.
as u can see in map002 picture there is no target(by target I mean metal) available
in map003 picture there is target but on 1 feet distance
in map004 target is completely touching the coil. this is the signal I am trying to work on
in my opinion change is significant and can be detected
and as I said earlier the signal is not going below 0 volt
just focus on A.out signal the delay signal is for switches that is doing sampling in the analog circuit . I am taking in A.out signal in controller
I was thinking about same solution to give the detector threshold value by going in field and calculating the threshold, but the thing is I need to create sound like VCO I mean as the target gets closer and closer to metal detector the sound increases, do u get what I mean.
I have actually made a code for it. but I am not tested it right now. I like to show it to you guys, if u can figure out will it work or not. what it does it takes 2 averages one move faster and other move slower. and for output on buzzer if fast average is greater than slower the target is detected, but that I will figure out when I test it in field.
This code I made from by reading from different detector related projects
and if u all are wondering what controller I am using. I am working with attiny1617.
#define sampleAveShift 5
#define sampleArraySize 32
#define trackAveShift 6
#define trackArraySize 64
const byte adc = A0;
unsigned int CurrentSample; //holds value from adc
unsigned int SampleAve = 0; // this is fast average 4*32 =128 samples
unsigned int TrackAve = 0; //this is slower average 4*32*64 samples
void setup()
{
Serial.begin(115200);
}
void loop()
{
CurrentSample = analogRead(adc);
ProcessSample();
}
void ProcessSample(void)
{
static unsigned int sampleArray[sampleArraySize];
static unsigned int trackArray[trackArraySize];
static char sampleIndex = 0, trackIndex = 0;
static unsigned int tmp = 0;
static char i, sampleCount;
tmp += CurrentSample; // tmp is effectively a 12-bit value
sampleCount++;
if (sampleCount == 4) // If we've accumulated 4 samples, store
{
sampleArray[sampleIndex] = tmp >> 2; // Store the current sample - 10 bits
sampleCount = 0;
tmp = 0;
sampleIndex++; // Increment the array pointer
if (sampleIndex == sampleArraySize) // If we're wrapping around...
sampleIndex = 0; // Set the pointer back to the beginning
SampleAve = 0;
for (i = 0; i < sampleArraySize; i++) // Average all the samples
SampleAve += sampleArray[i]; // This is effectively a 15-bit value
SampleAve >>= sampleAveShift; // Divide back down to a 10-bit value
Serial.println(SampleAve);
trackArray[trackIndex] = SampleAve; // Store the average
trackIndex++; // Increment the array pointer
if (trackIndex == trackArraySize) // If we're wrapping around...
trackIndex = 0; // Set pointer back to the beginning
TrackAve = 0;
for (i = 0; i < trackArraySize; i++) // Average all the averages
TrackAve += trackArray[i]; // This is effectively a 16-bit value
TrackAve >>= trackAveShift; // Divide back down to a 10-bit value
Serial.print("TrackAve");
Serial.println(TrackAve);
}
}
It appears to me you could get what you want by simply integrating the signal for a fixed amount of time AFTER the initial rising edge of the area in question. The result of the integration will give you a single value that will be a function of the distance. A simple calibration process will let you determine the values resulting from no target, a target touching the sensor, and any other points of interest in-between. Assuming a reasonable sample rate relative to the signal frequency, the integration itself will have the effect of filtering the signal, so no additional filtering should be needed.
From your oscillscope traces, it looks like the region of interest is the about 50us wide, starting 90us after the A.out rise.
Since analogRead() takes about 100us per analogRead() - Arduino Reference so you could get a value in the window, and with the target at 1 foot out it's pretty much back to baseline by t+200us.
About the best you can do (without low-level, fast ADC trickery) is start one single analogRead() after or in sync with the pulse and use that value.
It looks like the rising edge of Channel 2 is the place to sample the blue line. Then just use the value to set the tone(). I would use a pot for a 'squelch' and turn off the audio if the sampled value is below the squelch threshold.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.