-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
1 changed file
with
75 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
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)) | ||
|
||
def rep(self, t): | ||
This comment has been minimized.
Sorry, something went wrong. |
||
self.t = t | ||
|
||
@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.rep(t) | ||
|
||
@kernel | ||
def one(self, t, p): | ||
with parallel: | ||
self.pmt0.gate_both_mu(2*p) | ||
with sequential: | ||
t0 = now_mu() | ||
This comment has been minimized.
Sorry, something went wrong.
sbourdeauducq
Member
|
||
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() | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
jordens
Author
Member
|
This isn't necessary, the compiler can handle
self.t = xxx
directly in kernel code.