artiq/examples/master/repository/tdr.py
Robert Jordens 01416bb0be copyright: claim contributions
These are contributions of >= 30% or >= 20 lines (half-automated).

I hereby resubmit all my previous contributions to the ARTIQ project
under the following terms:

    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/>.

Closes #130

Signed-off-by: Robert Jordens <jordens@gmail.com>
2015-09-06 16:08:57 -06:00

74 lines
2.6 KiB
Python

# Copyright (C) 2014, 2015 Robert Jordens <jordens@gmail.com>
from artiq import *
class PulseNotReceivedError(Exception):
pass
class TDR(EnvExperiment):
"""Time domain reflectometer.
From ttl2 an impedance matched pulse is send onto a coax
cable with an open end. pmt0 (very short stub, high impedance) also
listens on the transmission line near ttl2.
When the forward propagating pulse passes pmt0, the voltage is half of the
logic voltage and does not register as a rising edge. Once the
rising edge is reflected at an open end (same sign) and passes by pmt0 on
its way back to ttl2, it is detected. Analogously, hysteresis leads to
detection of the falling edge once the reflection reaches pmt0 after
one round trip time.
This works marginally and is just a proof of principle: it relies on
hysteresis at FPGA inputs around half voltage and good impedance steps,
as well as reasonably low loss cable. It does not work well for longer
cables (>100 ns RTT). The default drive strength of 12 mA and 3.3 V would
be ~300 Ω but it seems 40 Ω series impedance at the output matches
the hysteresis of the input.
This is also equivalent to a loopback tester or a delay measurement.
"""
def build(self):
self.attr_device("core")
self.attr_device("pmt0")
self.attr_device("ttl2")
def run(self):
n = 1000 # repetitions
latency = 50e-9 # calibrated latency without a transmission line
pulse = 1e-6 # pulse length, larger than rtt
try:
self.many(n, seconds_to_mu(pulse, self.core))
except PulseNotReceivedError:
print("to few edges: cable too long or wiring bad")
else:
print(self.t)
t_rise = mu_to_seconds(self.t[0], self.core)/n - latency
t_fall = mu_to_seconds(self.t[1], self.core)/n - latency - pulse
print("round trip times:")
print("rising: {:5g} ns, falling {:5g} ns".format(
t_rise/1e-9, t_fall/1e-9))
@kernel
def many(self, n, p):
t = [0 for i in range(2)]
self.core.break_realtime()
for i in range(n):
self.one(t, p)
self.t = t
@kernel
def one(self, t, p):
t0 = now_mu()
with parallel:
self.pmt0.gate_both_mu(2*p)
self.ttl2.pulse_mu(p)
for i in range(len(t)):
ti = self.pmt0.timestamp_mu()
if ti <= 0:
raise PulseNotReceivedError
t[i] += ti - t0
self.pmt0.count() # flush