mirror of
https://github.com/jonathanhogg/scopething
synced 2025-07-14 11:12:09 +01:00
Various improvements
This commit is contained in:
34
scope.py
Normal file → Executable file
34
scope.py
Normal file → Executable 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
15
vm.py
@ -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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user