agp.cooper11/26/2021 at 09:20 1 comment

    PIMD V2

    Reworked the schematic to add an OpAmp (OPA2365).

    Added A0 to the signal output so I can look alternative signal processing options.

    This board uses an IRL540 instead of an IRF540, which reduces the MOSFET voltage drop.

    Here is the assembled board before testing: 

    Two Signal Processing Approaches


    First we could go the ADC route, the board is setup for this.

    With a 1MHz clock, we can do samples every 13 to 14 us without losing accuracy.

    We can trade faster conversion for accuracy.


    The current approach measures the time the signal takes to decay to a specific test voltage (~40mV).

    We could expand the number of voltage tests by controlling the reference voltage using a R-2R resistor ladder. Unfortunately I did not make provision for this with this board.

    TBC ...


  • Update after a long break

    agp.cooper11/10/2021 at 06:19 0 comments

    Adding Gain

    Why do we want to add gain?

    In order to increase detection limits we need to increasing the signal to noise ratio (SNR) of the target response. The SNR can be improved by waiting for the coil and ground response to decay.

    This works because the target response (for medium to large objects) has a longer time period (decays more slowly). We cannot wait too long or the target signal will be swapped by the noise floor (about 1-2uV).

    In general the larger the target the longer the decay time and the longer the time for the optimal SNR measurement.

    Therefore, different setting would optimise for small, medium and large objects.

    Attempting to filter the coil and ground response would be better for small objects.

    Version 2 - PIMD

    Here is my updated schematic:

    And the PCB:

    Note: I have routed the signal to both D7/AIN1 (the comparator negative input) and A5 (an analog input). This allows experimentation with Analog to Digital systems.

    Filtering the Coil and Ground Signal.

    PIMD Version 1 code cancels the coil and ground signal by subtracting an exponentially smoothed long time constant filter from an exponentially smoothed short time constant filter. Basically hold the coil on the ground until the signal decays away. Now it only responses to changes in the signal (dynamically). It works but we could do better.

    It would be nice to give a signal that indicates that the signal curve/shape has changed.

    This can be done with the following code:

    • Signal=(G0-S0)+(G2-S2)-4*(G1-S1)
    • where G0, G1 and G2 are exponentially smoother long term filter values for different sample points.
    • and S0, S1 and S2 are exponentially smoother short term filter values for the same "different" sample points.

    This works for three voltage or three timer readings, and the formula can be adapted for more than 3 sample points.


  • A Toy PIMD

    agp.cooper05/23/2021 at 04:48 0 comments

    A Toy PIMD

    I would describe this PIMD as a "toy". Why? Because it is necessary to detect the target signal immediately after the coil signal has decayed below the target signal, and before the target signal has decayed below the 40 mV threshold. In the field, the ground response will mask the target signal at this point of time.

    Corbyn's paper describes the ground response of iron rich lateritic soils as:

    • g(t) = (1-P)*exp(-t/T1) + P*exp(-t/T2)


    • P = 0.08 to 0.30
    • T1 = 75us
    • T2 = 550us to 800us

    He also presents an estimate for a target response (i.e. decay time constant):

    • T = 1.8*D^2


    • D is the diameter (m) of the target

    For a 1 cm target the estimate for T is:

    • 180 us

    For a 5 cm target:

    • 4.5 ms

    The above target decay time constants indicate that detecting targets less than 2.5 cm in diameter will be difficult in iron rich lateritic soils.

    Detection Strategies

    For large targets (>=5 cm), one strategy is to wait for the ground response to decay well below the target response. For example, if we have an initial  100 mV ground response and a 10 mV target response, then we could wait 4200 us when the ground response is 40 uV and the target response is still 400 uV. Assuming a 10 to 1 signal to noise ratio is desirable.

    If we can filter out 90% of the ground response then we only need to wait 520 us for the same 10 to 1 signal to noise ratio.

    In either case we need more gain to allow signal sampling much later in the pulse cycle.

    Low Pass Input Filter

    I added a 1nF capacitor (blue curve) to signal input (brown curve). This has minimal impact on the signal but filters out any RF above 100kHz. For a 10kHz low pass filter (green curve) the capacitor would be 10nF but it materially delays the decay of the coil signal.

    Noise Floor

    The noise level of the analog comparator is not disclosed in the ATMEGA328 data-sheet but if I use a 741 OpAmp as a model (23nV/sqrt(Hz)), the noise floor for a 100kHz bandwidth and 1k source resistance, will be about 7 uV.

    Reducing the bandwidth to say 10kHz would reduce the noise floor to 2.3uV. At the moment the noise floor is not important.

    Adding Gain

    I don't want to use a split power supply OpAmp to avoid the extra power supply. So let have have a look at the LM324:

    Note: the LM324 is DC coupled and has a gain of x20:

    What you can see here is that the slew rate of the LM324 is far too low (the straight line descending slope) to follow the signal. This is not too surprising as the GBW of the LM324 is 1.2 MHZ and the slew rate just 0.5v/us.

    Compare this with the LM3900 Norton OpAmp with a gain of x50:

    The LM3900  has a 4 MHz GBW and a 20v/us negative slew. But this is about as much gain as you can get with this OpAmp. Here is the lm3900 schematic:

    Note the common mode biasing using the 2x75k ohm and 20k Ohm trimmer. The common mode biasing ensures that the OpAmp has sufficient biasing to the inputs to operate correctly. It was a rather tricky design process to work this out.

    The output diode drops the output offset from ~200 mV to 0 mV.

    Another option is to use a CA3130, it has a slew rate between 10 and 30 v/us and a GBW of 15 MHz. For more gain (per stage), a more modern OpAmp such as the OPA365 is required:

      This OpAmp is rated at a GBW of 50 MHz and a slew of 25 v/uv:

    Note the OPA365 was configured for a gain of x100 but higher gains are possible (x500 per stage).

    Pseudo Gain Control

    For signal processing it would be nice adjust the signal gain to normalising (i.e. make the start of the the signal the same voltage). This makes removing the ground response (i.e. subtracting the reference signal) more efficient.

    While not ideal, we can initially set the analog comparator to the internal 1.25v reference. Start the signal timer at that point, and then measure the time for the signal to decay to the external analog comparator voltage reference (e.i. 40 mv). It is not the same as normalising the signal as there is a time shift but I suspect it will work...

    Read more »

  • Test Run

    agp.cooper05/22/2021 at 05:41 0 comments

    Test Run

    I assembled the board, made a simple coil and powered up the Nano without the coil power supply. Some edits to the code but otherwise it appears to be working.

    Connected the Coil power supply and amazingly it worked. Some tweaks to the exponential filter constants and it detects small coins within half a coil diameter and large coins at about one coil diameter. About as good as similar (honest) detectors on the Internet.

    On the Internet I have seen a demonstration of a PIMD discriminating (not responding to) aluminum foil. This is not real, the detector is just rejecting strong and good conducting targets. Easy to do but does not make a good metal detector.

    Hers is the setup:

    And the Code:

    /* Arduino Pulse Induction Metal Detector */
    // Pin definitions
    #define pulsePin            4                        // For coil MOSFET gates
    #define beepPin             5                        // Buzzer pin
    #define compPlus            6                        // Plus (signal) comparator input pin
    #define compMinus           7                        // Minus (level) comparator input pin
    #define ledPin0            A0                        // Log bar LED0
    #define ledPin1            A1                        // Log bar LED1
    #define ledPin2            A2                        // Log bar LED2
    #define ledPin3            A3                        // Log bar LED3
    #define ledPin4            A4                        // Log bar LED4
    #define ledPin5            A5                        // Log bar LED5
    // Fast versions of digitalWrite(Pin,HIGH); and digitalWrite(Pin,LOW); for all pins on UNO/Nano
    #define fastHighPin(Pin) if ((Pin)<8) PORTD|=1<<(Pin); else if ((Pin)<14) PORTB|=1<<(Pin)-8; else if ((Pin)<20) PORTC|=1<<(Pin)-14;
    #define fastLowPin(Pin) if ((Pin)<8) PORTD&=~(1<<(Pin)); else if ((Pin)<14) PORTB&=~(1<<(Pin)-8); else if ((Pin)<20) PORTC&=~(1<<(Pin)-14);
    volatile unsigned int Magic0=0;
    volatile unsigned int Phase0=0;
    ISR(TIMER0_COMPB_vect) {
      if (Phase0<0x8000) {
      } else {
    void setup() {
      // Set up pulse pin first - Note: Electronics logic is inverted
      // Set up comparator inuts
      // Set up Beeper
      // Set up Config LED
      // Set up LED bar display 
      // Clear LEDs
      // No interrupts (just read the ACO bit)
      // Reset timer 1
      TIMSK1=0x00;                                       // Disable all timer interrupts
      TCCR1A=0x00;                                       // Normal (just count up and roll over) Config
      TCCR1B=0x00;                                       // Stop timer
      // Piggy back tone to timer0
      OCR0B=0x80;                                        // Trigger interrupt away from millis() interrupt
      TIMSK0|=(1<<OCIE0B);                               // Enable Timer0 Compare B interrupt
      // Set Serial - for debug
      // delay(100);
      // Serial.begin(9600);
      // while (!Serial);
      // delay(100);
    void loop() {
      // PIMD constants
      // Repetition rate
      unsigned long previousMillis=0;
      unsigned long currentMillis;
      unsigned long intervalMillis=20;
      // Coil pulse timing
      unsigned long pulseTime=500;                       // Coil on time (us)
      unsigned long startMicros;
      unsigned long endMicros;
      // Signal processing
      unsigned long decayTime;                           // The Signal
      unsigned long refExpFilter=0;                      // Reference exponential filter
      unsigned long sigExpFilter=0;                      // Signal exponential filter
      unsigned long refTest;                             // Reference (smoothed) test value
      unsigned long sigTest;                             // Signal (smoothed) test value
      unsigned int refFilterConst=9;                     // Exponential filter time power constant (setting time about 60 seconds)
      unsigned int sigFilterConst=3;                     // Exponential filter response time: lower is faster but more noisy
      unsigned int thresholdConst=1;                     // Sensitivity 
      // Beeper frequency
      unsigned int magicNum=0;                           // magicNum=Freq*67.108864;
      // Stop tone and set beepPin LOW
      // Clear configuration
      bool configState=true;                             
      unsigned int Config=0;                             //...
    Read more »

  • Modelling the Flip Coil

    agp.cooper05/07/2021 at 06:20 1 comment

    Modelling the Flip Coil

    Here is a schematic based on Mirko Pavleski's Pulse Induction Metal Detector (PIMD) (https://hackaday.io/project/176291-diy-simple-sensitive-arduino-metal-detector):

    (Note: I think the 62k/47k output resistor divider should be moved from the inverter input of the op-amp to the output of the op-amp?).

    Mirko's design really appeals to me because of its simplicity.

    The main problem I see is that power supply is not isolated from the inductive voltage spikes from the coil. It would work with a low internal resistance battery but an electronic power supply could be a problem. There is a risk that the inductive voltage spike could be upset and/or damage the op-amp and/or the Nano.

    Here is Lammert Bies' PIMD (https://www.lammertbies.nl/electronics/pi-metal-detector):

    Here he isolated the coil from the battery using the 10R resistor and the 4m7 F capacitor. He also adds a positive power supply for the op-amp (otherwise the op-amp would be operating near its power supply voltage should DC signal processing be considered).

    My favourite however, is the "Flip Coil" by JorBi (https://www.instructables.com/Arduino-Based-Pulse-Induction-Detector/):

    Here he uses R1 to ground the negative inductive voltage side of the coil during the receive period. He also isolates the coil by switching off both MOSFETs during the receive period. This is very clever!

    He also uses the ATMega's analog comparator to time the decay of the signal to reference voltage (40mV). Rather than the analog to digital converter (ADC). Again, a very clever solution.

    Some notes/faults with his design are:

    • No protective diodes for the Nano (he relies on the Nano's internal diodes).
    • No power supply decoupling. Risk of inductive voltage spikes upsetting the Nano.
    • MOSFET Q2 should have a higher breakdown voltage to shorten the coil current decay. I would use an IRL740 (400v) or an IRL840 (600v) or equivalent. MOSFET Q2 has to be an IRLXXX type in order to be directly driven by the Nano.
    • MOSFET Q1 really does need to be an IRLxxx version to minimize the voltage drop across the MOSFET.
    • Rather than use D8 to power the reference voltage potentiometer he should used the Nano 3v3 voltage supply.
    • The speaker line should include a 220R current limit resistor.
    • The I2C lines should have 4k7 pull up resistors.

    MOSFET Types

    As I was researching this project it took a while to realize that there are "normal" MOSFETs (i.e. IRF540) with a gate threshold between 2 and 4 volts (read 4 volts) and "logic" MOSFETs (i.e. IRL540) with a gate threshold between 1 and 2 volts (read 2 volts).

    In my case I used an IRF540 and an IRF740 until I realized benefit of using the IRLxxx series for this application. Unfortunately I had already sent of a PCB for manufacture.

    My Schematic

    My schematic does not reflect the use of the IRLxxx series of MOSFETs:

    Some novel features are:

    • A direct XT connection on the PCB for 7.4v or 11.1v rechargeable LiPo battery packs.
    • A logarithmic LED display.
    • Not immediately obvious are two switches that use the often unused A6 and A7 pins of the Nano. To use these pins, an analogRead() is required:

        // Check for power down and restart loop();
        if (analogRead(A6)<=511) {
          while (analogRead(A6)<=511);      // Wait for buton release
          delay(20);                                     // Wait for debounce
          Start=false;                                   // Set flag off

    • I have used four resistors (1k5) in parallel...
    Read more »