From 24f42a4208cc8a94a6cd6975b30fbbea479f7830 Mon Sep 17 00:00:00 2001 From: Jonathan Hogg Date: Tue, 11 Jul 2017 18:09:14 +0100 Subject: [PATCH] Just poking around really --- scope.py | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/scope.py b/scope.py index 458189b..e3a5c09 100755 --- a/scope.py +++ b/scope.py @@ -54,15 +54,17 @@ class Scope(vm.VirtualMachine): self.awg_sample_buffer_size = 1024 self.awg_minimum_clock = 33 self.awg_maximum_voltage = 3.33 - self.analog_params = self.AnalogParams(20.2, -4.9, 300, 18.333, -7.517) - self.analog_offsets = {'A': 0, 'B': 0} - self.analog_min = -5.7 + #self.analog_params = self.AnalogParams(20, -5, 300, 18.3, -7.5) + #self.analog_offsets = {'A': 0, 'B': 0} + 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.capture_clock_period = 25e-9 self.capture_buffer_size = 12<<10 self.timeout_clock_period = 6.4e-6 else: - raise RuntimeError(f"Unsupported scope revision: {revision}") + raise RuntimeError(f"Unsupported scope, revision: {revision}") self._awg_running = False 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) l = (low - params.offset) / params.scale h = (high - params.offset) / params.scale - al = params.d + params.f * (2*l-1)**2 - ah = params.d + params.f * (2*h-1)**2 - dl = l + (2*l-h)*al/params.b - dh = h + (2*h-l-1)*ah/params.b + al = params.d + params.f*(2*l-1)**2 + ah = params.d + params.f*(2*h-1)**2 + dl = l - al*(h-2*l)/params.b + dh = h + ah*(2*h-l-1)/params.b return dl, dh 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): import numpy as np from scipy.optimize import least_squares - global items items = [] await self.start_generator(frequency=1000, waveform='square') i = 0 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) - for low in np.linspace(low_min, low_max*0.9, n): - for high in np.linspace(high_min*1.1, high_max, n): + for low in np.linspace(low_min, low_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) A = np.fromiter(data['A'].values(), dtype='float') A.sort() B = np.fromiter(data['B'].values(), dtype='float') B.sort() - Azero, Amax = A[10:490].mean(), A[510:990].mean() - Bzero, Bmax = B[10:490].mean(), B[510:990].mean() - zero = (Azero + Bzero) / 2 - analog_range = self.awg_maximum_voltage / ((Amax + Bmax)/2 - zero) - analog_low = -zero * analog_range - analog_high = analog_low + analog_range - offset = ((Amax - Bmax) + (Azero - Bzero))/2 * analog_range - items.append((analog_low, analog_high, low, high, offset)) + Azero, Amax = A[25:475].mean(), A[525:975].mean() + Bzero, Bmax = B[25:475].mean(), B[525:975].mean() + if Azero > 0.1 and Bzero > 0.1 and Amax < 0.9 and Bmax < 0.9: + zero = (Azero + Bzero) / 2 + analog_range = self.awg_maximum_voltage / ((Amax + Bmax)/2 - zero) + analog_low = -zero * analog_range + analog_high = analog_low + analog_range + offset = ((Amax - Bmax) + (Azero - Bzero))/2 * analog_range + items.append((analog_low, analog_high, low, high, offset)) i += 1 await self.stop_generator() items = np.array(items) def f(params, analog_low, analog_high, low, high): lo, hi = self.calculate_lo_hi(analog_low, analog_high, params) return np.sqrt((low - lo) ** 2 + (high - hi) ** 2) - result = least_squares(f, self.analog_params, args=items.T[:4], max_nfev=10000, - bounds=([0, -np.inf, 285, 17.4, -7.89], [np.inf, np.inf, 315, 19.2, -7.14])) + result = least_squares(f, self.analog_params, args=items.T[:4], xtol=1e-9, max_nfev=10000, + bounds=([0, -np.inf, 200, 0, -np.inf], + [np.inf, np.inf, 400, np.inf, 0])) if result.success in range(1, 5): Log.info(f"Calibration succeeded: {result.success}") 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") + 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] 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} else: Log.warning(f"Calibration failed: {result.message}")