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

Various improvements

This commit is contained in:
Jonathan Hogg
2016-10-23 16:54:56 +01:00
parent 7eb23b38f2
commit 95e07aaa70
2 changed files with 28 additions and 21 deletions

34
scope.py Normal file → Executable file
View File

@ -1,6 +1,9 @@
#!/usr/bin/env python3
import argparse
import asyncio import asyncio
import logging import logging
import os
import struct import struct
import streams import streams
@ -15,8 +18,13 @@ class Scope(vm.VirtualMachine):
PARAMS_MAGIC = 0xb0b2 PARAMS_MAGIC = 0xb0b2
@classmethod @classmethod
async def connect(cls, stream=None): async def connect(cls, device=None):
scope = cls(stream if stream is not None else streams.SerialStream()) if device is None:
scope = cls(streams.SerialStream())
elif os.path.exists(device):
scope = cls(streams.SerialStream(device=device))
else:
raise ValueError("Don't know what to do with '{}'".format(device))
await scope.setup() await scope.setup()
return scope return scope
@ -223,7 +231,6 @@ class Scope(vm.VirtualMachine):
error = abs(frequency - actualf) / frequency error = abs(frequency - actualf) / frequency
if error < max_error: if error < max_error:
possible_params.append(((error == 0, width), (size, nwaves, clock, actualf))) possible_params.append(((error == 0, width), (size, nwaves, clock, actualf)))
clock += 1
if not possible_params: if not possible_params:
raise ValueError("No solution to required frequency/min_samples/max_error") raise ValueError("No solution to required frequency/min_samples/max_error")
size, nwaves, clock, actualf = sorted(possible_params)[-1][1] size, nwaves, clock, actualf = sorted(possible_params)[-1][1]
@ -281,7 +288,6 @@ class Scope(vm.VirtualMachine):
async def calibrate(self, n=33): async def calibrate(self, n=33):
global data global data
import numpy as np import numpy as np
import pandas as pd
from scipy.optimize import leastsq, least_squares from scipy.optimize import leastsq, least_squares
items = [] items = []
await self.start_generator(1000, waveform='square') await self.start_generator(1000, waveform='square')
@ -298,18 +304,18 @@ class Scope(vm.VirtualMachine):
analog_range = 3.3 / ((A3v3 + B3v3)/2 - zero) analog_range = 3.3 / ((A3v3 + B3v3)/2 - zero)
analog_low = -zero * analog_range analog_low = -zero * analog_range
analog_high = analog_low + analog_range analog_high = analog_low + analog_range
ABoffset = (Azero - Bzero) / 2 * analog_range offset = (Azero - Bzero) / 2 * analog_range
items.append({'low': low, 'high': high, 'analog_low': analog_low, 'analog_high': analog_high, 'offset': ABoffset}) items.append((analog_low, analog_high, low, high, offset))
await self.stop_generator() await self.stop_generator()
data = pd.DataFrame(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=(data.analog_low, data.analog_high, data.low, data.high), result = least_squares(f, self.analog_params, args=items.T[:4], bounds=([0, -np.inf, 250, 0, 0], [np.inf, np.inf, 350, np.inf, np.inf]))
bounds=([0, -np.inf, 250, 0, 0], [np.inf, np.inf, 350, np.inf, np.inf]))
if result.success in range(1, 5): if result.success in range(1, 5):
self.analog_params = tuple(result.x) self.analog_params = tuple(result.x)
self.analog_offsets = {'A': -data.offset.mean(), 'B': +data.offset.mean()} offset = items[:,4].mean()
self.analog_offsets = {'A': -offset, 'B': +offset}
else: else:
Log.warning("Calibration failed: {}".format(result.message)) Log.warning("Calibration failed: {}".format(result.message))
print(result.message) print(result.message)
@ -321,7 +327,10 @@ import pandas as pd
async def main(): async def main():
global s, x, y, data global s, x, y, data
s = await Scope.connect(streams.SerialStream(device='/Users/jonathan/test')) parser = argparse.ArgumentParser(description="scopething")
parser.add_argument('device', type=str, help="Device to connect to")
args = parser.parse_args()
s = await Scope.connect(args.device)
x = np.linspace(0, 2*np.pi, s.awg_wavetable_size, endpoint=False) x = np.linspace(0, 2*np.pi, s.awg_wavetable_size, endpoint=False)
y = np.round((np.sin(x)**5)*127 + 128, 0).astype('uint8') y = np.round((np.sin(x)**5)*127 + 128, 0).astype('uint8')
await s.start_generator(1000, wavetable=y) await s.start_generator(1000, wavetable=y)
@ -332,8 +341,7 @@ def capture(*args, **kwargs):
return pd.DataFrame(asyncio.get_event_loop().run_until_complete(s.capture(*args, **kwargs))) return pd.DataFrame(asyncio.get_event_loop().run_until_complete(s.capture(*args, **kwargs)))
if __name__ == '__main__': if __name__ == '__main__':
import logging
import sys import sys
logging.basicConfig(level=logging.DEBUG, stream=sys.stderr) #logging.basicConfig(level=logging.DEBUG, stream=sys.stderr)
asyncio.get_event_loop().run_until_complete(main()) asyncio.get_event_loop().run_until_complete(main())

15
vm.py
View File

@ -1,5 +1,6 @@
import asyncio import asyncio
from enum import IntEnum
import logging import logging
import struct import struct
@ -82,8 +83,7 @@ Registers = {
"MasterClockM": (0xf8, 'U16', "PLL multiplier (MUL M)"), "MasterClockM": (0xf8, 'U16', "PLL multiplier (MUL M)"),
} }
class TraceMode(IntEnum):
class TraceMode:
Analog = 0 Analog = 0
AnalogFast = 4 AnalogFast = 4
AnalogShot = 11 AnalogShot = 11
@ -102,8 +102,7 @@ class TraceMode:
Macro = 18 Macro = 18
MacroChop = 19 MacroChop = 19
class BufferMode(IntEnum):
class BufferMode:
Single = 0 Single = 0
Chop = 1 Chop = 1
Dual = 2 Dual = 2
@ -111,7 +110,7 @@ class BufferMode:
Macro = 4 Macro = 4
MacroChop = 5 MacroChop = 5
class DumpMode: class DumpMode(IntEnum):
Raw = 0 Raw = 0
Burst = 1 Burst = 1
Summed = 2 Summed = 2
@ -121,7 +120,7 @@ class DumpMode:
Filter = 6 Filter = 6
Span = 7 Span = 7
class SpockOption: class SpockOption(IntEnum):
TriggerInvert = 0x40 TriggerInvert = 0x40
TriggerSourceA = 0x04 * 0 TriggerSourceA = 0x04 * 0
TriggerSourceB = 0x04 * 1 TriggerSourceB = 0x04 * 1
@ -129,11 +128,11 @@ class SpockOption:
TriggerTypeSampledAnalog = 0x01 * 0 TriggerTypeSampledAnalog = 0x01 * 0
TriggerTypeHardwareComparator = 0x01 * 1 TriggerTypeHardwareComparator = 0x01 * 1
class KitchenSinkA: class KitchenSinkA(IntEnum):
ChannelAComparatorEnable = 0x80 ChannelAComparatorEnable = 0x80
ChannelBComparatorEnable = 0x40 ChannelBComparatorEnable = 0x40
class KitchenSinkB: class KitchenSinkB(IntEnum):
AnalogFilterEnable = 0x80 AnalogFilterEnable = 0x80
WaveformGeneratorEnable = 0x40 WaveformGeneratorEnable = 0x40