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

I have been thinking about building a [TDR](http://Time-domain reflectometer) using arduino and have the basics of an idea that needs some help in fleshing out the details or (nicely) shooting it down in flames.

The basic principle is somewhat based on this article but instead of using a PIC and it's CTMU to measure the reflection time I was hoping to improve accuracy using a high speed oscillator connected to a binary/ripple counter.

The principle is to use the arduino to reset the counter and send a pulse down the output. One comparator (IC3) will trigger the counter to start when the voltage gets to about 1/4 range and the other comparator (IC2) will stop the counter at 3/4 range caused by the reflection. The arduino will then read the counter and determine how many clock cycles have happened between the two and work out the length of the cable.
I have knocked up a basic circuit idea (attached) but it is a bit vague on some details like oscillator, resistors & capacitors and the negative VEE voltages.
The ripple counter (SY10E137) will run at 2GHz+ but I have not found a cheap oscillator to work at this speed so currently have just drawn a basic crystal for it's input. 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.
Obviously the faster I can clock the counter at the more accurate the device would be. At 2GHz I'm hoping to measure a distance to an accuracy of >100mm
Not drawn is the NOT output from the comparators so I hopefully won't need logic inverters (= time delays) to get correct logic on the Enable 1 & Enable 2 inputs to the counter.

The questions are...
Will it/should it/could it work in principle.
Any ideas about a (budget) way to generate a 2GHz clock for the counter.
What have I got wrong (and how to fix it) on the drawing.

TDR_V1.pdf (7.33 KB)

1 Like

That's a nice idea, but generating the 2GHz signal is likely to be difficult. I think the usual approach would be to start with a crystal oscillator at a lower frequency (e.g. 250MHz) and use a VCO and divider configured as a PLL to multiply it up to 2GHz.

At 2GHz, your counter will overflow in 128ns, which means that the maximum length of cable you can handle may be as low as 10m, depending on the type of cable. The 7.8MHz output from the counter is probably too fast to count on the Arduino.

I've been looking at making an Arduino-based TDR too, although not with such high resolution. My plan was to get course resolution (50ns) by clocking the mcu at 20MHz and using the Timer 1 input capture facility to record the count when the reflected pulse arrives (so no external counter needed). Then I was going to use a programmable delay line to provide about 0 to 45ns delay to the outgoing pulse in 5ns steps, thereby increasing the resolution to 5ns, which is about 0.5m of cable length. You could do something similar but using higher frequencies, e.g. run the counter at 200MHz to get 5ns course resolution, and use a programmable delay line to get fine resolution. This one http://uk.farnell.com/on-semiconductor/mc100ep196fag/ic-delay-line-programmable/dp/1703312 provides up to 10ns delay in 10ps increments, giving you a theoretical resolution of around 1mm, although in practice the resolution will be limited by jitter.

Two more things to bear in mind:

  1. The sign of the reflected pulse depends on whether the cable has a break or a short. So you may need a third comparator, or extra logic to switch the second comparator between looking for positive or negative reflected pulses.

  2. Unless the cable is designed for high frequencies, the reflected edge is not as sharp as the transmitted edge. So the delay you measure will depend on the comparator threshold. My design uses a variable comparator threshold (by using one of the PWM pins as a cheap DAC) so that the mcu can look for the start of the pulse.

EDIT: I just discovered the Maxim DS1023S-25+ delay line. This can give me up to 63.75ns delay in 0.25ns increments. So I may be able to achieve the sort of resolution you are looking for, without needing a high speed counter.

You'd need to find a clock-generator chip that accepts a crystal input reference - I briefly
looked at the AD9517 but not sure if it does this - will go upto > 2GHz though. You'd need
a lot of care with the layout with such high-speed parts (and an octal ECL->CMOS level
shifter of some sort for the counter outputs?

At 2GHz, your counter will overflow in 128ns, which means that the maximum length of cable you can handle may be as low as 10m, depending on the type of cable. The 7.8MHz output from the counter is probably too fast to count on the Arduino.

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 sign of the reflected pulse depends on whether the cable has a break or a short. So you may need a third comparator, or extra logic to switch the second comparator between looking for positive or negative reflected pulses.

Good point, I'm mostly interested in cable breaks but an adjustable/third comparator might be an option.

Unless the cable is designed for high frequencies, the reflected edge is not as sharp as the transmitted edge. So the delay you measure will depend on the comparator threshold. My design uses a variable comparator threshold (by using one of the PWM pins as a cheap DAC) so that the mcu can look for the start of the pulse.

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.

You'd need to find a clock-generator chip that accepts a crystal input reference - I briefly
looked at the AD9517 but not sure if it does this - will go upto > 2GHz though.

I had seen this (or something similar) in my searches but lost the link (my head was exploding from searching and reading data sheets). Thanks for the heads up though, the AD9517-3 looks promising.

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)

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
}

1 Like

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.