TDR (Time-domain reflectometer) concept. On the right track?

Riva: I would only use interrupts to count the Q7 (overflow) output until the reflection comparator stops the count and then read Q0-Q7 to get the current count and add (Q7 overflows * 256) to get the total number of clock pulses between the start - end. This I hope will allow me to read a lot longer cable lengths.

The point I was trying to make was that 7.8MHz is faster than you can count on an Arduino, either using interrupts or by using timer 2 in async mode.

Riva: Another good point/idea but for a start I'm intending to just measure Triax so will initially aim for setting to measure that cable.

That cable appears to be specified at frequencies up to only 50MHz. I think you will find that the rise time of the step is very significantly degraded. Satellite cable might be another matter.

dc42: The point I was trying to make was that 7.8MHz is faster than you can count on an Arduino, either using interrupts or by using timer 2 in async mode. I figured it may be hence the "The SY10E137 is an 8 bit counter so it Q7 output frequency will be about 7.8MHz (?) if it's input is 2GHz and I may need another binary counter to slow this further so an arduino interrupt pin can count it easily." Another option might be to use a faster arduino like the Duo or a Teensy3

A long way to go yet (waiting on better data from Micrel) but here is the bones of the idea so far.

TDR_V1.pdf (14.9 KB)

http://kf5iuy.blogspot.com/2012/08/a-poor-mans-introduction-to-tdr.html

Perhaps some ideas...

mrburnette: Perhaps some ideas...

Thanks Ray, A nice find that I had not seen before despite many hours of research. I shows nicely the open circuit effect I'm hoping to measure but I wish to get away from using a scope and make it cheaper and more portable with an arduino, hence the high speed timer/counter circuit.

I’ve got my low-resolution TDR working now. I’m using a single comparator to detect both positive and negative reflections, with the reference input fed from a PWM pin feeding a low-pass filter. The software sets the reference input voltage, allows it to settle, starts timer 1, and sends a pulse into the cable. The comparator output is fed to the ICP1 pin, so that when a reflection is detected, the time of the reflection is captured in ICR1. This is repeated while ramping up the reference voltage, so that the software can look for positive steps in the voltage at the end of the cable. Then it ramps the voltage down, looking for negative steps. From the number and amplitude of the steps found, it can distinguish between no cable connected, short circuit at cable terminals, cable open circuit at (distance), cable short circuit at (distance), and cable correctly terminated (i.e. no reflections).

The biggest problem was stopping the comparator oscillating. It really wanted to oscillate at about 200MHz. The datasheet warns about the importance of good layout, and I was prototyping on a breadboard, so I guess it isn’t too surprising. Eventually, the combination of putting a decoupling capacitor right on the SMD adapter, keeping the output away from the input, grounding unused breadboard rows, and adding a large amount of hysteresis solved the problem. It should be much easier on a PCB.

The resolution is currently only 62.5ns (about 6.4m for cat5 cable) because I am using a 16MHz Arduino for prototyping. Next step is to add an LCD display, and programmable delay line between the mcu and R1 to increase the resolution. I have a DS1023S-25+ on order, which will theoretically provide 0.25ns resolution, although I expect that jitter will reduce that.

Here is the code.

// Time domain reflectometer

const int stepPin = 4;       // digital output pin we generate the step on. Later in the code, we assume this is port D bit 4.
const int refPin = 11;       // PWM output pin that we use to generate the comparator reference voltage. Must be on timer 2.
const int shutdownPin = 7;   // digital output port used to put comparator in shutdown mode - drive HIGH before sleeping

const int maxSteps = 4;      // maximum number of steps in each direction that we capture

// Define the fraction of the speed of light at which waves propagate in the cable
// Some typical values;
//  cat 5 cable 68%
//  RG58 or RG213 coax (solid polyethylene dieletric) 66%
//  Airspaced coax up to 92%
const float propagationFactor = 0.68;  // fraction of speed of light that waves travel in the cable under test

void setup()
{
  pinMode(stepPin, OUTPUT);
  pinMode(refPin, OUTPUT);
  pinMode(shutdownPin, OUTPUT);
  
  TCCR1A = 0;
  TCCR1B = (1 << ICNC1);   // input capture noise canceller enabled, capture on falling edge
  TIMSK1 = 0;              // timer 1 interrupts disabled
  ACSR = 0;                // input capture from ICP1 pin
  
  TCCR2B = (1 << CS20);    // change timer 2 PWM frequency to 31.25kHz because we're using pin 11 as a DAC
  
  Serial.begin(19200);
}

struct Step
{
  unsigned int time;
  unsigned int amplitude;
};

// Take a single measurement, using either a positive or negative edge from the comparator.
// The comparator reference voltage must have been set up and allowed to stablise before calling this.
unsigned int takeMeasurement(bool posEdge)
{
  byte reg1b = (posEdge) ? 0 : (1 << ICES1);    // input capture noise canceller disabled, set up input capture polarity, stop timer
  reg1b |= (1 << CS10);
  TCCR1B = reg1b;
  TCNT1H = 0;
  TCNT1L = 0;              // clear timer
  unsigned int capture = 0;
  unsigned long start = micros();  // get the time
  
  cli();
  TCNT1H = 0;
  TCNT1L = 0;              // clear timer
  TIFR1 = (1 << ICF1);     // clear timer 1 input capture bit
  PORTD |= (1 << 4);       // set output high
  sei();

  do
  {
    if ((TIFR1 & (1 << ICF1)) && capture == 0)
    {
      byte temp = ICR1L;
      capture = (ICR1H << 8) | temp;
    }
  } while (micros() - start < 100);
  
  PORTD &= ~(1 << 4);          // set output low
  return capture;
}

size_t findSteps(bool positive, struct Step *results, size_t maxResults)
{
  byte amplitude = (positive) ? 5 : 250;
  analogWrite(refPin, amplitude);
  delay(100);      // wait 100ms for the output to stabilise
  unsigned int lastReading = 0;
  size_t numResults = 0;
  unsigned int stepSize = 0;        // 0 means not in a step
#ifdef DEBUG  
  Serial.print((positive) ? "pos " : "neg ");
#endif
  for (int i = 0; i < 50; ++i)
  {
    analogWrite(refPin, amplitude);
    delay(10);
    unsigned int currentReading = takeMeasurement(positive);
    unsigned int currentDiff = currentReading - lastReading;    // diff since start of possible step
    if (stepSize == 0)
    {
      // Not currently in a step
      if (i != 0 && currentReading != 0 && currentDiff == 0)
      {
        // Found the start of a possible step
        ++stepSize;
      }
      lastReading = currentReading;
    }
    else
    {
      if (currentDiff > 2 || i + 1 == 50)
      {
        // Step has endeed, so record it if it is big enough
        if (stepSize >= 2)
        {
          results->time = lastReading;
          results->amplitude = amplitude - 5;
          ++results;
          ++numResults;
          if (numResults == maxResults) break;
        }
        stepSize = 0;
        lastReading = currentReading;
      }
      else if (currentDiff == 0)
      {
        ++stepSize;
      }
    }
#ifdef DEBUG    
    if (i != 0) Serial.write(',');
    Serial.print(currentReading);
#endif    
    if (positive)
    {
      amplitude += 5;
    }
    else
    {
      amplitude -= 5;
    }
  }
#ifdef DEBUG  
  Serial.println();
#endif
  return numResults;
}

// Convert a number of clocks delay to a cable length in metres
float clocksToMetres(unsigned int clocks)
{
  float delayTime = (float)clocks/(float)F_CPU;    // delay in seconds
  return (delayTime * 3.0e8 * propagationFactor)/2.0;
}

// Diagnose the cable condition. We have the following common possibilities:
// 1. No cable connected, or a very short open-circuit cable connected.
//    In this case we should see the original positive step, very close to zero delay, with amplitude nearly 5V.
// 2. Direct short, or very short cable with shorted end.
//    In this case, we will not even see the original positive-going step, or it will have a very low amplitude.
// 3. Cable with open circuit.
//    We see the original positive step close to zero delay, and a further positive step going to nearly twice the amplitude later.
// 4. Cable with short circuit.
//    We see the original positive step close to zero delay, and a negative step going back down to nearly zero later.
// 5. Correctly terminated cable.
//    We see only the original positive step, with amplitudfe well below 5V.
void loop()
{
  Step posSteps[maxSteps], negSteps[maxSteps];
  size_t numPosSteps = findSteps(true, posSteps, maxSteps);
  size_t numNegSteps = findSteps(false, negSteps, maxSteps);
  if (numPosSteps == 0)
  {
    Serial.print("Direct short");
  }
  else if (numPosSteps == 1 && numNegSteps == 0)
  {
    if (posSteps[0].amplitude >= 200)
    {
      Serial.print("No cable connected");
    }
    else
    {
      Serial.print("Cable correctly terminated");
    }
  }
  else if (numPosSteps >= 2 && numNegSteps == 0)
  {
    Serial.print("Open at ");
    Serial.print(clocksToMetres(posSteps[1].time - posSteps[0].time), 1);
  }
  else if (numPosSteps == 1 && numNegSteps == 1)
  {
    Serial.print("Short at ");
    Serial.print(clocksToMetres(negSteps[0].time - posSteps[0].time), 1);
  }
  else
  {
    Serial.print("Failed to diagnose fault");
  }

#ifdef DEBUG
  Serial.print(" (pos=");
  for (size_t i = 0; i < numPosSteps; ++i)
  {
    if (i != 0)
    {
      Serial.write(',');
    }
    Serial.print(posSteps[i].time);
    Serial.write('|');
    Serial.print(posSteps[i].amplitude);    
  }
  Serial.print(" neg=");
  for (size_t i = 0; i < numNegSteps; ++i)
  {
    if (i != 0)
    {
      Serial.write(',');
    }
    Serial.print(negSteps[i].time);
    Serial.write('|');
    Serial.print(negSteps[i].amplitude);    
  }
  Serial.println(")");
#else
  Serial.println();
#endif
}

dc42: I've got my low-resolution TDR working now. I'm using a single comparator to detect both positive and negative reflections, with the reference input fed from a PWM pin feeding a low-pass filter. The software sets the reference input voltage, allows it to settle, starts timer 1, and sends a pulse into the cable. The comparator output is fed to the ICP1 pin, so that when a reflection is detected, the time of the reflection is captured in ICR1. This is repeated while ramping up the reference voltage, so that the software can look for positive steps in the voltage at the end of the cable. Then it ramps the voltage down, looking for negative steps. From the number and amplitude of the steps found, it can distinguish between no cable connected, short circuit at cable terminals, cable open circuit at (distance), cable short circuit at (distance), and cable correctly terminated (i.e. no reflections). You have managed to get further than me sofar. I'm still in the back of fag packet/napkin stage and still hunting for suitable component. To throw a spanner in the works I just discovered (today) you can get TDC chips that can measure with >360ps resolution so I'm now trying to fine out more info and costs for these chips. I will probably only be interested in open/short circuit testing as I cannot predict the consequences of testing with equipment hanging off the end of the cable. The biggest problem was stopping the comparator oscillating. It really wanted to oscillate at about 200MHz. The datasheet warns about the importance of good layout, and I was prototyping on a breadboard, so I guess it isn't too surprising. Eventually, the combination of putting a decoupling capacitor right on the SMD adapter, keeping the output away from the input, grounding unused breadboard rows, and adding a large amount of hysteresis solved the problem. It should be much easier on a PCB. This will be a big headache for me if I'm trying to use 2GHz signals. I don't feel I'm up to designing a stable platform.

The resolution is currently only 62.5ns (about 6.4m for cat5 cable) because I am using a 16MHz Arduino for prototyping. Next step is to add an LCD display, and programmable delay line between the mcu and R1 to increase the resolution. I have a DS1023S-25+ on order, which will theoretically provide 0.25ns resolution, although I expect that jitter will reduce that. Maybe a job for a Duo? All in all good to see your off the ground and running. It would be nice if then DS1023S could get down to about 100mm resolution. What is the shortest cable you can measure?

Riva: Maybe a job for a Duo?

I'm not familiar with the Due, however if I read the processor datasheet correctly, then with the processor running at 84MHz, the fastest I can clock the timer/counters is 42MHz. So without the delay line, it would offer a bit more than twice the resolution of a 20MHz atmega328 without the delay line. If I clocked the Due processor at a slower speed direct from the crystal oscillator, then I think I could clock the timers at up to 96MHz and get better resolution. However, the power consumption of the Due is much higher than for the atmega328p, so battery operation would be less practical. I am hoping to run this from a 9V battery.

Riva: What is the shortest cable you can measure?

Since my resolution is currently about 6.4m, this ought to be 6.4m. I connected a piece of 5.5m coax and observed on the oscilloscope that the reflected step is about 60ns later that the transmitted step. Since the reflected step has slower rise time than the transmitted step, the software is reading 5 clocks to the first (transmitted) step and 6 clocks to the second (reflected) step. However, due to quantization, the pattern (5,5,5,5...5,5,6,6,6,.....) could be generated from either a two steps about 62.5ns apart, or a single step of twice the amplitude and slower rise time. So the software records it as a single step, and the shortest distance I can measure an open circuit cable is about 12m. Maybe I should modify the software to assume that the outgoing step always has a fast rise time, then I could detect a second step only 1 clock later. When I have the programmable delay, it should be easier to distinguish between two steps close together.

In fact, with a 5.5m cable, the software tells me I have an open circuit at 12m, because it registers a step due to the second reflection (it is 75 ohm coax and I am driving it from 150 ohms, so some of the incoming reflection is reflected back again).

Short circuit are easier to measure, because the reflected step has opposite polarity, so it can't be confused with the outgoing step. The software are is correctly diagnosing a 5.5m shorted cable.

PS - I've now decided to connect the programmable delay line between the comparator output and the ICP1 microcontroller input, because it saves me having to add a buffer to drive the cable. I'll probably change to using 2 output pins in parallel to drive the cable, so that I can use a lower drive resistor than 150 ohms.

I use TDR a fair bit when using low voltage and high voltage cable fault location equipment on distribution networks.

I never even considered it as something that could be done based on Arduino/AVR uC.

Watching what you guys are doing with interest to see what you come up with.

I am stalled at the moment trying to get more/better information for the high speed counter from Micrel. They are not responding to my requests so assume they are not interested in little fish. I do have a plan B but once again I am waiting on the distributor to reply but as I only fired the requests off over the weekend I am not expecting anything for a few days yet. The link in my first post shows it being done (in a different way) using a PIC microcontroller and if all else fails I may build that instead but I prefer to 'roll my own' with less limitations / better features.

The PIC approach looks interesting, although I haven't yet found any data on how stable the constant current source is with temperature (or supply voltage). The datasheet for that PIC suggests that the purpose of that current source is to implement touch-sensitivity, rather than precision measurement.

Having seen on a 'scope how the rise time of the reflected signal is severely degraded (even by a short length of coax), I'm of the opinion that being able to adjust the comparator threshold(s) is highly desirable, so as to better locate the start of the reflection. It's occurred to me that this would also allow me to display an oscillograph of the signal on a GLCD, with the restriction that the signal can only be shown from the start up to the first maximum and then as far the first minimum.

I'm watching this thread with great interest.

Just a quick update on this…
I have abandoned the ideal of using high speed counters due to the complexity of designing/managing 2GHz signals. I have since discovered TDC chips that do all the counting for me and give the results over SPI interface.
The device is an ACAM GP22 TDC.
The resolution should also be better as we are talking >90ps and a measurement range up to 2.4us (more than enough for the length of cables I’m interested in) and possibly 4ms. I’m now waiting on PCB’s to knock together a test rig (if I can figure out how to solder a 5mm square QFN32 package). The attached drawing shows an UNO but if I uses a 3.3V arduino instead I should be able to reduce the component count.

TDR_V4.pdf (12.8 KB)

dc42: It's occurred to me that this would also allow me to display an oscillograph of the signal on a GLCD, with the restriction that the signal can only be shown from the start up to the first maximum and then as far the first minimum.

I some how missed your reply?? How do you expect to generate the graph as the resolution far exceeds arduino ADC sample rates.

Riva: I some how missed your reply??

I'm just back from holiday. The TDC-GP22 is an interesting chip! Please let us know how you get on.

Riva: How do you expect to generate the graph as the resolution far exceeds arduino ADC sample rates.

I will be relying on the assumption that for every pulse the Arduino generates, the signal appearing on the cable (comprising the transmitted + reflected signal) will be the same. By sending a lot of pulses and changing the comparator reference voltage and/or delay line time between pulses, I can build up a graph of the signal. As I will only be capturing the first transition of the comparator, at most I can construct the signal graph as far as one maximum and one minimum. Even that limitation could be overcome by delaying the start of the timer 1 clock signal from the start of the pulse.

Here is the latest schematic for my TDR (because I have just been asked for it). I still need to add a voltage regulator so that I can run it from a battery, and an LCD to display the result. The software needs to be updated because I am now using 2 pins to produce the voltage step to drive the cable, so that I can use a lower value resistor (75 ohms). This will be a better match to most cables than the 150 ohms that I was using previously.

Glad to see your progressing with the project. Once again I am waiting for parts/information, this time a solder mask for the QFN32 chip from a company in Canada though I'm tempted to order one of these as I could have it here next day and no need of a mask. I found an application note for the GP22 for using it in a laser range finder so hopefully I'm on the right track here (instead of using 2GHz clocks).

Hi, I'm doing a final year electronics project and have chosen to build a TDR for finding faults in a electric cattle fence.the resolution does not need to be that small because faults can be physically seen. the aim of the project is to speed up the process of troubleshooting an electric fence. i am considering whether I will use mBed or Arduino. I am told that the arduino uno/leonardo, etc. gives trouble when connecting through the laptop through the serial port and also posed other problems while programming when a shield was attached. Therefore i want to avoid using these. The arduino Mega was ok though. The mBed LPC1768 has a faster clock speed (96MHz) than the mega which should mean that it should give a better resolution. However i have read that the pulse-width is limited to 10us nut this is while the clock is at a default speed of 12MHz so hopefully i can get a fast rise-time out of it if i increase the clock speed. I am conscious though that i cannot find any sample code for a tdr for mbed and converting code for an arduino to suit mbed may be problematic. so i may be better off using an arduino and using external electronics to speed it up. Any advice would be greatly appreciated.

Hi,

I'm not sure what you mean by "the arduino uno/leonardo, etc. gives trouble when connecting through the laptop through the serial port and also posed other problems while programming when a shield was attached". Lots of people are using these Arduinos. If you use a Leonardo then you don't program via the Arduino serial port, you program directly through the USB port.

What resolution do you require? You will find several different approaches described earlier in this thread, including:

  1. My very simple TDR using an Arduino and a high-speed comparator. Resolution is limited to 62.5ns (about 15 to 30 feet depending on cable type) using a standard 16MHz Arduino, although by migrating the design to a 20MHz standalone atmega328p, you could improve this to 50ns (about 12.5 to 25 feet).

  2. A modification to my TDR design which adds a variable delay line, improving the resolution to 1ns or better.

  3. Riva's idea for a TDR using the GP22 chip. This is a very nice looking chip and should provide very high resolution.