Skip to content

Commit 278570f

Browse files
committedJul 29, 2015
examples: add TDR toy example
1 parent 9036841 commit 278570f

File tree

1 file changed

+75
-0
lines changed
  • examples/master/repository

1 file changed

+75
-0
lines changed
 

Diff for: ‎examples/master/repository/tdr.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from artiq import *
2+
3+
4+
class PulseNotReceivedError(Exception):
5+
pass
6+
7+
8+
class TDR(EnvExperiment):
9+
"""Time domain reflectometer.
10+
11+
From ttl2 an impedance matched pulse is send onto a coax
12+
cable with an open end. pmt0 (very short stub, high impedance) also
13+
listens on the transmission line near ttl2.
14+
15+
When the forward propagating pulse passes pmt0, the voltage is half of the
16+
logic voltage and does not register as a rising edge. Once the
17+
rising edge is reflected at an open end (same sign) and passes by pmt0 on
18+
its way back to ttl2, it is detected. Analogously, hysteresis leads to
19+
detection of the falling edge once the reflection reaches pmt0 after
20+
one round trip time.
21+
22+
This works marginally and is just a proof of principle: it relies on
23+
hysteresis at FPGA inputs around half voltage and good impedance steps,
24+
as well as reasonably low loss cable. It does not work well for longer
25+
cables (>100 ns RTT). The default drive strength of 12 mA and 3.3 V would
26+
be ~300 Ω but it seems 40 Ω series impedance at the output matches
27+
the hysteresis of the input.
28+
29+
This is also equivalent to a loopback tester or a delay measurement.
30+
"""
31+
def build(self):
32+
self.attr_device("core")
33+
self.attr_device("pmt0")
34+
self.attr_device("ttl2")
35+
36+
def run(self):
37+
n = 1000 # repetitions
38+
latency = 50e-9 # calibrated latency without a transmission line
39+
pulse = 1e-6 # pulse length, larger than rtt
40+
try:
41+
self.many(n, seconds_to_mu(pulse, self.core))
42+
except PulseNotReceivedError:
43+
print("to few edges: cable too long or wiring bad")
44+
else:
45+
print(self.t)
46+
t_rise = mu_to_seconds(self.t[0], self.core)/n - latency
47+
t_fall = mu_to_seconds(self.t[1], self.core)/n - latency - pulse
48+
print("round trip times:")
49+
print("rising: {:5g} ns, falling {:5g} ns".format(
50+
t_rise/1e-9, t_fall/1e-9))
51+
52+
def rep(self, t):
Has a conversation. Original line has a conversation.
53+
self.t = t
54+
55+
@kernel
56+
def many(self, n, p):
57+
t = [0 for i in range(2)]
58+
self.core.break_realtime()
59+
for i in range(n):
60+
self.one(t, p)
61+
self.rep(t)
62+
63+
@kernel
64+
def one(self, t, p):
65+
with parallel:
66+
self.pmt0.gate_both_mu(2*p)
67+
with sequential:
68+
t0 = now_mu()
Has a conversation. Original line has a conversation.
69+
self.ttl2.pulse_mu(p)
70+
for i in range(len(t)):
71+
ti = self.pmt0.timestamp_mu()
72+
if ti <= 0:
73+
raise PulseNotReceivedError
74+
t[i] += ti - t0
75+
self.pmt0.count()
Has conversations. Original line has conversations.

0 commit comments

Comments
 (0)
Please sign in to comment.