1
0
mirror of https://github.com/jonathanhogg/scopething synced 2025-07-14 03:02:09 +01:00

Just poking around really

This commit is contained in:
Jonathan Hogg
2017-07-11 18:09:14 +01:00
parent be7e7e97c1
commit 24f42a4208

View File

@ -54,15 +54,17 @@ class Scope(vm.VirtualMachine):
self.awg_sample_buffer_size = 1024 self.awg_sample_buffer_size = 1024
self.awg_minimum_clock = 33 self.awg_minimum_clock = 33
self.awg_maximum_voltage = 3.33 self.awg_maximum_voltage = 3.33
self.analog_params = self.AnalogParams(20.2, -4.9, 300, 18.333, -7.517) #self.analog_params = self.AnalogParams(20, -5, 300, 18.3, -7.5)
self.analog_offsets = {'A': 0, 'B': 0} #self.analog_offsets = {'A': 0, 'B': 0}
self.analog_min = -5.7 self.analog_params = self.AnalogParams(19.7, -4.86, 298.6, 18.361, -7.496)
self.analog_offsets = {'A': -0.00937, 'B': 0.00937}
self.analog_min = -5.5
self.analog_max = 8 self.analog_max = 8
self.capture_clock_period = 25e-9 self.capture_clock_period = 25e-9
self.capture_buffer_size = 12<<10 self.capture_buffer_size = 12<<10
self.timeout_clock_period = 6.4e-6 self.timeout_clock_period = 6.4e-6
else: else:
raise RuntimeError(f"Unsupported scope revision: {revision}") raise RuntimeError(f"Unsupported scope, revision: {revision}")
self._awg_running = False self._awg_running = False
Log.info(f"Initialised scope, revision: {revision}") Log.info(f"Initialised scope, revision: {revision}")
@ -78,10 +80,10 @@ class Scope(vm.VirtualMachine):
params = self.analog_params if params is None else self.AnalogParams(*params) params = self.analog_params if params is None else self.AnalogParams(*params)
l = (low - params.offset) / params.scale l = (low - params.offset) / params.scale
h = (high - params.offset) / params.scale h = (high - params.offset) / params.scale
al = params.d + params.f * (2*l-1)**2 al = params.d + params.f*(2*l-1)**2
ah = params.d + params.f * (2*h-1)**2 ah = params.d + params.f*(2*h-1)**2
dl = l + (2*l-h)*al/params.b dl = l - al*(h-2*l)/params.b
dh = h + (2*h-l-1)*ah/params.b dh = h + ah*(2*h-l-1)/params.b
return dl, dh return dl, dh
async def capture(self, channels=['A'], trigger=None, trigger_level=None, trigger_type='rising', hair_trigger=False, async def capture(self, channels=['A'], trigger=None, trigger_level=None, trigger_type='rising', hair_trigger=False,
@ -323,42 +325,46 @@ class Scope(vm.VirtualMachine):
async def calibrate(self, n=32): async def calibrate(self, n=32):
import numpy as np import numpy as np
from scipy.optimize import least_squares from scipy.optimize import least_squares
global items
items = [] items = []
await self.start_generator(frequency=1000, waveform='square') await self.start_generator(frequency=1000, waveform='square')
i = 0 i = 0
low_min, high_max = self.calculate_lo_hi(self.analog_min, self.analog_max) low_min, high_max = self.calculate_lo_hi(self.analog_min, self.analog_max)
low_max, high_min = self.calculate_lo_hi(0, self.awg_maximum_voltage) low_max, high_min = self.calculate_lo_hi(0, self.awg_maximum_voltage)
for low in np.linspace(low_min, low_max*0.9, n): for low in np.linspace(low_min, low_max, n):
for high in np.linspace(high_min*1.1, high_max, n): for high in np.linspace(high_min, high_max, n):
data = await self.capture(channels=['A','B'], period=2e-3 if i%2 == 0 else 1e-3, nsamples=2000, low=low, high=high, timeout=0, raw=True) data = await self.capture(channels=['A','B'], period=2e-3 if i%2 == 0 else 1e-3, nsamples=2000, low=low, high=high, timeout=0, raw=True)
A = np.fromiter(data['A'].values(), dtype='float') A = np.fromiter(data['A'].values(), dtype='float')
A.sort() A.sort()
B = np.fromiter(data['B'].values(), dtype='float') B = np.fromiter(data['B'].values(), dtype='float')
B.sort() B.sort()
Azero, Amax = A[10:490].mean(), A[510:990].mean() Azero, Amax = A[25:475].mean(), A[525:975].mean()
Bzero, Bmax = B[10:490].mean(), B[510:990].mean() Bzero, Bmax = B[25:475].mean(), B[525:975].mean()
zero = (Azero + Bzero) / 2 if Azero > 0.1 and Bzero > 0.1 and Amax < 0.9 and Bmax < 0.9:
analog_range = self.awg_maximum_voltage / ((Amax + Bmax)/2 - zero) zero = (Azero + Bzero) / 2
analog_low = -zero * analog_range analog_range = self.awg_maximum_voltage / ((Amax + Bmax)/2 - zero)
analog_high = analog_low + analog_range analog_low = -zero * analog_range
offset = ((Amax - Bmax) + (Azero - Bzero))/2 * analog_range analog_high = analog_low + analog_range
items.append((analog_low, analog_high, low, high, offset)) offset = ((Amax - Bmax) + (Azero - Bzero))/2 * analog_range
items.append((analog_low, analog_high, low, high, offset))
i += 1 i += 1
await self.stop_generator() await self.stop_generator()
items = np.array(items) items = np.array(items)
def f(params, analog_low, analog_high, low, high): def f(params, analog_low, analog_high, low, high):
lo, hi = self.calculate_lo_hi(analog_low, analog_high, params) lo, hi = self.calculate_lo_hi(analog_low, analog_high, params)
return np.sqrt((low - lo) ** 2 + (high - hi) ** 2) return np.sqrt((low - lo) ** 2 + (high - hi) ** 2)
result = least_squares(f, self.analog_params, args=items.T[:4], max_nfev=10000, result = least_squares(f, self.analog_params, args=items.T[:4], xtol=1e-9, max_nfev=10000,
bounds=([0, -np.inf, 285, 17.4, -7.89], [np.inf, np.inf, 315, 19.2, -7.14])) bounds=([0, -np.inf, 200, 0, -np.inf],
[np.inf, np.inf, 400, np.inf, 0]))
if result.success in range(1, 5): if result.success in range(1, 5):
Log.info(f"Calibration succeeded: {result.success}") Log.info(f"Calibration succeeded: {result.success}")
self.analog_params = params = self.AnalogParams(*result.x) self.analog_params = params = self.AnalogParams(*result.x)
Log.info(f"Analog parameters: d={params.d:.1f}Ω f={params.f:.2f}Ω b={params.b:.1f}Ω scale={params.scale:.3f}V offset={params.offset:.3f}V") Log.info(f"Analog parameters: d={params.d:.1f}Ω f={params.f:.2f}Ω b={params.b:.1f}Ω scale={params.scale:.3f}V offset={params.offset:.3f}V")
clow, chigh = self.calculate_lo_hi(items[:,0], items[:,1])
diff = np.sqrt((((clow-items[:,2])**2).mean() + ((chigh-items[:,3])**2).mean()) / 2)
Log.info(f"Mean error: {diff*10000:.1f}bps")
offsets = items[:,4] offsets = items[:,4]
offset = offsets.mean() offset = offsets.mean()
Log.info(f"Mean A-B offset is {offset*1000:.1f}mV (+/- {100*offsets.std()/offset:.1f}%)") Log.info(f"Mean A-B offset: {offset*1000:.1f}mV (+/- {100*offsets.std()/offset:.1f}%)")
self.analog_offsets = {'A': -offset/2, 'B': +offset/2} self.analog_offsets = {'A': -offset/2, 'B': +offset/2}
else: else:
Log.warning(f"Calibration failed: {result.message}") Log.warning(f"Calibration failed: {result.message}")