forked from JamesHarrison/otdrs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdemo.py
68 lines (61 loc) · 4.38 KB
/
demo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/bin/env python3
# Simple demo script to call otdrs, parse out a few variables, and draw a data point graph with the front panel marked as a line with everything scaled appropriately
# Assumes metres are the units used in the SOR file.
import numpy as np
# You can use CBOR instead of JSON by swapping this and adding the --format cbor option below
# import cbor
import json
import subprocess
import matplotlib.pyplot as plt
# Requires otdrs on the PATH - "cargo install otdrs" will achieve this, or include target/debug on your PATH
# CBOR version:
# proc = subprocess.Popen(["otdrs", "--format", "cbor", "data/example1-noyes-ofl280.sor"], stdout=subprocess.PIPE)
# JSON version:
proc = subprocess.Popen(["otdrs", "data/example1-noyes-ofl280.sor"], stdout=subprocess.PIPE)
out = proc.communicate()[0]
# Parse the data - we could load direct with pandas but want to be more prescriptive
# CBOR version:
# otdrs_out = cbor.loads(out)
otdrs_out = json.loads(out)
# To properly scale distances, we need to calculate the speed of light in fibre. This varies from fibre to fibre, but is about 1.47ish.
speed_of_light = 299792458.0 # m/s
# To accommodate this variation, the group index may be stored in the data (though if this is 0 you should use 146800)
refractive_index = otdrs_out['fixed_parameters']['group_index'] / 100000.0
speed_of_light_in_fibre = speed_of_light / refractive_index # Calculate our speed of light for the reported group index/refractive index
# The following assumes only one pulse width used - this is true for almost all OTDR traces.
# Even acquisition regimes such as EXFO iOLM don't use the multiple pulse width/spacing convention, and just store data in proprietary blobs.
seconds_per_10k_points = (otdrs_out['fixed_parameters']['data_spacing'][0]/1e10) # convert from picoseconds up
metres_per_data_spacing = (((seconds_per_10k_points/10000.0)) * speed_of_light_in_fibre) # FIXME: actually check this maths is right!
# Assumes only one scale factor used - same as above, this is generally "safe"!
sf = otdrs_out['data_points']['scale_factors'][0]['scale_factor'] # multiplier for the data
scaled_data = -(65535-np.array(otdrs_out['data_points']['scale_factors'][0]['data']))/float(sf) # Apply the scale factor to the whole dataset
# Just for cosmetics (in this example) we'll draw lines at the front panel point and the launch connector point
seconds_to_front_panel = otdrs_out['fixed_parameters']['front_panel_offset']/1e10
seconds_to_launch_connector = otdrs_out['general_parameters']['user_offset']/1e10
# And in metres, that's distance = time * speed
metres_to_front_panel = seconds_to_front_panel * speed_of_light_in_fibre
# Same again for launch - but we do need to offset from the front panel...
metres_to_launch_connector = (seconds_to_launch_connector * speed_of_light_in_fibre) + metres_to_front_panel
# Let's print out our key events - helper function to avoid duplication for last_key_event...
def print_key_event(ke, sf, sol, fpo):
loss = ke['event_loss']/sf
reflectance = ke['event_reflectance']/sf
seconds_to_event = ke['event_propogation_time']/1e10
metres_to_event = (seconds_to_event * sol) + fpo
print("Event {}: {}dB loss, {}dB reflectance, {}m".format(ke['event_number'], loss, reflectance, metres_to_event))
# Now print the lot
for ke in otdrs_out['key_events']['key_events']:
print_key_event(ke, sf, speed_of_light_in_fibre, metres_to_front_panel)
print_key_event(otdrs_out['key_events']['last_key_event'], sf, speed_of_light_in_fibre, metres_to_front_panel)
print("E2E loss {}dB".format(otdrs_out['key_events']['last_key_event']['end_to_end_loss']/sf))
# Plot our data - we calculate our X axis values based on the spacing interval and number of points to plot, on our scale of metres
# Note that "0" will be from the first data point, behind the front panel - normally we'd want to offset everything
# so that the 0 point is the launch connector, since that makes our subsequent event data make sense!
spacing = np.arange(0, metres_per_data_spacing*otdrs_out['data_points']['scale_factors'][0]['n_points'], metres_per_data_spacing)[0:otdrs_out['data_points']['scale_factors'][0]['n_points']]
plt.plot(spacing, scaled_data, linewidth=1, )
plt.axvline(x=metres_to_front_panel) # draw a line at the front panel
plt.axvline(x=metres_to_launch_connector) # draw a line at the front panel
plt.xlabel("Metres from OTDR module (not front panel/launch)")
plt.ylabel("dB")
plt.gca().invert_yaxis()
plt.show()