Changeset 4633
- Timestamp:
- 09/08/08 07:11:00 (5 years ago)
- Location:
- developers/werner/ahrt/host/tmc
- Files:
-
- 3 added
- 10 edited
-
README (modified) (3 diffs)
-
demo/deglitch.py (modified) (3 diffs)
-
demo/digitize.py (added)
-
demo/fft.py (modified) (2 diffs)
-
demo/screen.py (modified) (1 diff)
-
demo/spi.py (added)
-
demo/wavemath.py (added)
-
lib/instrument.py (modified) (1 diff)
-
lib/scope.py (modified) (13 diffs)
-
lib/shape.py (modified) (5 diffs)
-
lib/trigger.py (modified) (1 diff)
-
lib/wave.py (modified) (10 diffs)
-
setup.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
developers/werner/ahrt/host/tmc/README
r4228 r4633 26 26 =============== 27 27 28 The tmc package contains a set of functions to communicate with test 29 and measurement instruments. (Currently always using SCPI, but devices 30 speaking different protocols could also be supported.) 31 32 These basic functions are described below. 33 34 On top of basic communication, tmc provides a rich set of abstractions 35 and libraries with helper functions written in Python. The goal is to 36 allow routine tasks to be expressed in a concise and understandable 37 way, and to facilitate the construction of complex automated experiments. 38 39 These libraries are not documented yet, but there is a number of 40 annotated examples in the demo/ directory. 41 42 43 Low-level interface 44 =================== 45 28 46 This suite supports instruments that speak SCPI or a dialect thereof 29 47 using one of the following transport protocols: … … 50 68 of the tmc.Instr class: 51 69 52 import tmc53 54 instr = tmc.Instr(transport, arg, ...)70 import _tmc 71 72 instr = _tmc.Instr(transport, arg, ...) 55 73 56 74 … … 118 136 Debug output can be enabled or disabled with 119 137 120 tmc.debug(level)138 _tmc.debug(level) 121 139 122 140 Level 0 turns debug output off. -
developers/werner/ahrt/host/tmc/demo/deglitch.py
r4631 r4633 5 5 6 6 from tmc.shape import arbitrary 7 from tmc.wave import digital _wave7 from tmc.wave import digital 8 8 from math import floor 9 9 … … 20 20 w = shape.wave(0, 100, 1e-3) 21 21 22 # C rudely convert the analog waveform into a digital one.22 # Convert the analog waveform into a digital one. 23 23 24 dw = digital_wave() 25 for p in w: 26 dw.append(p[0], p[1]) 24 dw = w.digitize(0.5) 27 25 28 26 # Dump the original waveform to a file 29 27 30 dw. dump("before")28 dw.save("before") 31 29 32 30 # Remove all transients with a duration of less than 0.1 units. … … 39 37 # Dump the deglitched waveform to a file 40 38 41 dw. dump("after")39 dw.save("after") 42 40 43 41 # -
developers/werner/ahrt/host/tmc/demo/fft.py
r4631 r4633 13 13 14 14 # Describe a 100Hz square wave with amplitude = 5 15 15 16 shape = tmc.shape.square(high = 5, freq = 100) 16 17 17 18 # Generate a waveform over t = [0, 1) with 10kSa/s 19 18 20 wave = shape.wave(0, 1, 1e-4) 19 21 … … 24 26 25 27 # convert the waveform into a NumPy array 28 26 29 a = map(lambda p: p[1], wave) 27 30 28 31 # get the duration of the waveform 32 29 33 width = wave.end()-wave.start() 30 34 31 35 # get the number of samples 36 32 37 n = len(wave) 33 38 34 39 # do a discrete Fourier transform using the Hann(ing) window 40 35 41 fa = abs(fft(array(a)*hanning(n)))/n 36 42 37 43 # obtain the frequency components and put the positive half of the spectrum 38 44 # into a file with one (frequency, amplitude) tuple per line 45 39 46 savetxt("fft.out", transpose((fftfreq(n, d = width/n)[0:n/2], fa[0:n/2]))) -
developers/werner/ahrt/host/tmc/demo/screen.py
r4631 r4633 12 12 13 13 # Open the Rigol DS1000 14 14 15 scope = tmc.scope.rigol_ds1000c() 15 16 16 17 # Open a pipe to a process running "convert" from ImageMagick 18 17 19 pipe = popen("convert - "+argv[1], "w") 18 20 19 21 # Retrieve the screendump as PPM file and send it to the converter 22 20 23 pipe.write(scope.screendump()) 21 24 22 25 # Flush the pipe and terminate 26 23 27 pipe.close() -
developers/werner/ahrt/host/tmc/lib/instrument.py
r4631 r4633 26 26 27 27 class settings(object): 28 pass 28 def __init__(self, init, set = None, get = None): 29 self.value = init 30 self.__set = set 31 self.__get = get 32 33 def get(self): 34 if self.__get is None: 35 return self.value 36 else: 37 value = self.__get() 38 self.value = value 39 return value 40 41 def set(self, value): 42 if self.__set is not None: 43 self.__set(value) 44 self.value = value 45 29 46 30 47 class setting(settings): -
developers/werner/ahrt/host/tmc/lib/scope.py
r4631 r4633 29 29 30 30 import time 31 from tmc.instrument import setting, settable, instrument 32 from tmc.wave import analog_wave, digital_wave 31 from tmc.instrument import settings, setting, settable, instrument 32 from tmc.wave import analog, digital 33 from tmc.trigger import trigger 33 34 34 35 … … 87 88 self.scope = scope 88 89 self.number = number 90 self.name = "CH"+str(number) 89 91 90 92 self.on = setting(scope, ":CHAN"+str(number)+":DISP", … … 120 122 # --- wave download ------------------------------------------------------- 121 123 124 # obsolete ! 122 125 123 126 def wave(self, start = None, end = None, step = None): … … 129 132 130 133 134 class sweep: 135 Auto, Normal, Single = range(3) 136 137 138 class state: 139 Run, Stop, Triggered, Wait, Scan, Auto = range(6) 140 141 142 class horizontal_trigger_setting(settings): 143 144 def __init__(self, scope, set = None, get = None): 145 self.scope = scope 146 self.trigger_set = set 147 self.trigger_get = get 148 settings.__init__(self, None, set = self.pass_set, get = self.pass_get) 149 150 def pass_set(self, value): 151 if self.scope.trigger is not None and self.trigger_set is not None: 152 self.trigger_set(self.scope.trigger, value) 153 154 def pass_get(self): 155 if self.scope.trigger is not None and self.trigger_get is not None: 156 return self.trigger_get(self.scope.trigger) 157 158 131 159 class horizontal(settable): 160 161 state_map = ( "RUN", "STOP", "T'D", "WAIT", "SCAN", "AUTO" ) 132 162 133 163 def __init__(self, scope): … … 139 169 lambda x: float(x), 140 170 lambda x: "%.9f" % x) 171 self.sweep = horizontal_trigger_setting(scope, 172 trigger.set_sweep, trigger.get_sweep) 141 173 self.forget() 142 174 … … 144 176 self.pos = None 145 177 self.scale = None 146 147 148 # === trigger ================================================================= 149 150 151 class trigger(settable): 152 153 def __init__(self, scope): 154 self.scope = scope 155 #self.forget() 156 157 def forget(self): 158 self.mode.forget() 159 self.source.forget() 160 self.type.forget() 161 self.level.forget() 162 self.holdoff.forget() 163 164 def mode(self, value): 165 if value != None: 166 if value != self.mode: 167 self.scope.send(":TRIG"+str(self.number)+":SCAL "+str(value)) 168 self.scale = value 169 else: 170 pass 171 return self.scale 172 173 def source(self, value): 174 if value != None: 175 if value != self.scale: 176 self.scope.send(":CHAN"+str(self.number)+":SCAL "+str(value)) 177 self.scale = value 178 else: 179 self.scale = self.scope.query(":CHAN"+str(self.number)+":SCAL?") 180 return self.scale 181 182 def sweep(self, value): 183 if value != None: 184 if value != self.sweep: 185 self.scope.send(":CHAN"+self.mode+":SWE "+str(value)) 186 self.sweep = value 187 else: 188 self.sweep = self.scope.query(":CHAN"+self.mode+":SWE?") 189 return self.sweep 190 191 def level(self, value): 192 if value != None: 193 if value != self.level: 194 self.scope.send(":TRIG:"+self.mode+":LEV "+str(value)) 195 self.scale = level 196 else: 197 self.level = self.scope.query(":TRIG:"+self.mode+":LEV?") 198 return self.leve 199 200 def holdoff(self, value): 201 if value != None: 202 if value != self.scale: 203 self.scope.send(":CHAN"+str(self.number)+":SCAL "+str(value)) 204 self.scale = value 205 else: 206 self.scale = self.scope.query(":CHAN"+str(self.number)+":SCAL?") 207 return self.scale 178 self.sweep = None 208 179 209 180 def force(self): … … 211 182 212 183 def state(self): 213 return self.scope.query(":TRIG:STAT?") 214 215 216 # ==== 184 return self.state_map.index(self.scope.query(":TRIG:STAT?")) 185 186 187 # === Scope class ============================================================= 188 217 189 218 190 class scope(instrument): … … 235 207 236 208 def rigol_channel_data(s, t0, td, v0, vd): 237 res = analog _wave()209 res = analog() 238 210 i = 212 239 211 while i != 812: … … 250 222 res = [] 251 223 for b in range(0, 16): 252 res.append(digital _wave())224 res.append(digital()) 253 225 i = 424 254 226 while i != 1624: … … 332 304 "vendor=0x0400", "product=0x05dc") 333 305 self.ch = [] 306 self.d = map(lambda x: x, range(0, 16)) 334 307 for n in range(1, self.channels+1): 335 308 self.ch.append(channel(self, n)) 309 self.trigger = None 336 310 self.hor = horizontal(self) 337 self.trigger = trigger(self)338 311 339 312 def forget(self): … … 341 314 ch.forget() 342 315 self.hor.forget() 343 self.trigger.forget()344 316 345 317 def send(self, s): … … 361 333 362 334 def download_wave(self, channel, start, end, step): 363 c_num = None364 for n in range(0, len(self.ch)):365 if self.ch[n] == channel:366 c_num = n+1367 335 return rigol_wave(self, start, end, step, 368 ":WAV:DATA? CHAN"+str(c _num),336 ":WAV:DATA? CHAN"+str(channel.number), 369 337 lambda a, b: a.extend(b), 370 338 rigol_channel_data, channel.pos, channel.scale) … … 383 351 self.send(":HARDCOPY") 384 352 return rigol_to_ppm(self.query(":LCD:DATA?")) 353 354 def wave(self, channels, start = None, end = None, step = None): 355 if not isinstance(channels, array): 356 return self.download([channels], start, end, step)[0] 357 la = None 358 res = [] 359 for ch in channels: 360 if isinstance(ch, channel): 361 res.append(download_wave, start, end, step) 362 else: 363 if la is None: 364 la = self.download_la(start, end, step) 365 res.append(la[ch]) 366 return res -
developers/werner/ahrt/host/tmc/lib/shape.py
r4631 r4633 25 25 from math import pi, sin, floor 26 26 from tmc.instrument import settable, settings 27 from tmc.wave import analog_wave 28 29 30 def set_low(shape, y): 31 if shape.high < y: 32 shape.high = y 33 34 35 def set_high(shape, y): 36 if shape.low > y: 37 shape.low = y 38 39 40 def set_offset(shape, y): 41 peak = shape.peak 42 shape.low = y-peak/2.0 43 shape.high = y+peak/2.0 44 45 46 def set_peak(shape, y): 47 if y < 0: 48 raise hell 49 offset = shape.offset 50 shape.low = offset-y/2.0 51 shape.high = offset+y/2.0 52 53 54 def set_freq(shape, f): 55 if f < 0: 56 raise hell 57 58 59 def set_period(shape, t): 60 if t < 0: 61 raise hell 62 shape.freq = 1.0/t 63 64 65 def set_duty(shape, n): 66 if n < 0 or n > 1: 67 raise hell 68 69 70 def set_width(shape, n): 71 if n <= 0 or 1.0/n > shape.freq: 72 raise hell 73 shape.duty = shape.freq*n 27 from tmc.wave import analog 74 28 75 29 76 30 class shape_setting(settings): 77 31 78 def __init__(self, shape, init, set_fn = None, get_fn = None): 32 def __init__(self, shape, init, set = None, get = None): 33 settings.__init__(self, init, set, get) 79 34 self.shape = shape 80 35 self.value = init 81 self.set_fn = set_fn82 self.get_fn = get_fn83 84 def get(self):85 if self.get_fn is None:86 return self.value87 else:88 return self.get_fn(self.shape)89 36 90 37 def set(self, value): 91 38 prev = self.value 92 if self.set_fn is not None: 93 self.set_fn(self.shape, value) 94 self.value = value 39 settings.set(self, value) 95 40 if self.shape.notify is not None: 96 41 self.shape.notify(shape, self, prev, self.value) … … 102 47 self.notify = None 103 48 104 self.low = shape_setting(self, 0, set_low) 105 self.high = shape_setting(self, 0, set_high) 106 self.offset = shape_setting(self, None, set_offset, 107 lambda shape: (shape.low+shape.high)/2.0) 108 self.peak = shape_setting(self, None, set_peak, 109 lambda shape: shape.high-shape.low) 110 self.freq = shape_setting(self, 0, set_freq) 111 self.period = shape_setting(self, None, set_period) 49 self.low = shape_setting(self, 0, self.__set_low) 50 self.high = shape_setting(self, 0, self.__set_high) 51 self.offset = shape_setting(self, None, 52 self.__set_offset, self.__get_offset) 53 self.peak = shape_setting(self, None, self.__set_peak, self.__get_peak) 54 self.freq = shape_setting(self, 0, self.__set_freq) 55 self.period = shape_setting(self, None, self.__set_period) 112 56 113 57 self.set(**list) 114 58 59 def __set_low(self, y): 60 if self.high < y: 61 self.high = y 62 63 def __set_high(self, y): 64 if self.low > y: 65 self.low = y 66 67 def __set_offset(self, y): 68 peak = self.peak 69 self.low = y-peak/2.0 70 self.high = y+peak/2.0 71 72 def __get_offset(self): 73 return (self.low+self.high)/2.0 74 75 def __set_peak(self, y): 76 if y < 0: 77 raise hell 78 offset = self.offset 79 self.low = offset-y/2.0 80 self.high = offset+y/2.0 81 82 def __get_peak(self): 83 return self.high-self.low 84 85 def __set_freq(self, f): 86 if f < 0: 87 raise hell 88 89 def __set_period(self, t): 90 if t <= 0: 91 raise hell 92 self.freq = 1.0/t 93 115 94 def wave(self, start, end, step): 116 wave = analog _wave()95 wave = analog() 117 96 t = start 118 97 while t <= end: … … 128 107 129 108 130 class square(shape): 109 class __shape_with_duty(shape): 110 111 def __init__(self, init, **list): 112 self.duty = shape_setting(self, init, self.__set_duty) 113 shape.__init__(self, **list) 114 115 def __set_duty(self, n): 116 if n < 0 or n > 1: 117 raise hell 118 119 def __set_width(self, n): 120 if n <= 0 or 1.0/n > self.freq: 121 raise hell 122 self.duty = self.freq*n 123 124 125 class square(__shape_with_duty): 131 126 132 127 def __init__(self, **list): 133 self.duty = shape_setting(self, 0.5, set_duty) 134 shape.__init__(self, **list) 128 __shape_with_duty(self, 0.5, **list) 135 129 136 130 def get(self, t): … … 139 133 140 134 141 class ramp( shape):135 class ramp(__shape_with_duty): 142 136 143 137 def __init__(self, **list): 144 self.duty = shape_setting(self, 1, set_duty) 145 shape.__init__(self, **list) 138 __shape_with_duty(self, 1, **list) 146 139 147 140 def get(self, t): … … 165 158 def __init__(self, **list): 166 159 self.fn = shape_setting(self, lambda t: 0, None) 167 # self.arg = shape_setting(self, None, None)168 160 shape.__init__(self, **list) 169 161 -
developers/werner/ahrt/host/tmc/lib/trigger.py
r4631 r4633 13 13 14 14 # 15 # @@@ old-style. needs rewriting. 15 # @@@ The callback logic isn't quite right - we could have multiple users of 16 # the same trigger settings, so just attaching it to a scope channel is wrong. 16 17 # 17 18 18 class trigger(object):19 19 20 def __init__(self, scope): 21 self.scope = scope 20 from tmc.instrument import settable, setting 21 22 23 class coupling: 24 DC, AC, HF, LF = range(4) 25 26 27 class trigger(settable): 28 coupling_map = [ "DC", "AC", "HF", "LF" ] 29 sweep_map = [ "AUTO", "NORMAL", "SINGLE" ] 30 31 def __init__(self): 32 self.channel = None 33 self.scope = None 34 35 def source(self, channel, coupling = None): 36 if self.scope is not None: 37 self.scope.trigger = None 38 self.channel = channel 39 if channel is None: 40 self.scope = None 41 else: 42 self.scope = channel.scope 43 self.scope.trigger = self 44 self.scope.send(":TRIG:MODE "+self.mode) 45 self.scope.send(":TRIG:"+self.mode+":SOUR "+channel.name) 46 if coupling is not None: 47 self.scope.send( 48 ":TRIG:"+self.mode+":COUP "+self.coupling_map[coupling]) 49 self.scope.send(":TRIG:"+self.mode+":SWE "+scope.sweep) 50 self.update() 51 52 def send(self, *args): 53 if self.scope is not None: 54 self.scope.send(*args) 55 56 def query(self, *args): 57 if self.scope is None: 58 raise hell 59 return self.scope.query(*args) 60 61 def set_sweep(self, value): 62 self.scope.send(":TRIG:"+self.mode+":SWE "+self.sweep_map[value]) 63 64 def get_sweep(self): 65 return self.sweep_map.index(self.scope.query(":TRIG:"+self.mode+":SWE")) 66 67 class slope: 68 Rising, Falling, Both = range(3) 69 70 71 class edge(trigger): 72 mode = "EDGE" 73 slope_map = [ "POSITIVE", "NEGATIVE", "BOTH?" ] # @@@ 74 75 def __init__(self, **list): 76 trigger.__init__(self) 77 self.level = setting(self, ":TRIG:"+self.mode+":LEV", 78 lambda x: float(x), 79 lambda x: "%.9f" % x) 80 self.slope = setting(self, ":TRIG:"+self.mode+":SLOP", 81 lambda x: self.slope_map.index(x), 82 lambda x: self.slope_map[x]) 22 83 self.forget() 84 self.set(**list) 23 85 24 86 def forget(self): 25 mode = None 26 source = None 27 type = None 28 level = None 29 holdoff = None 87 self.level = None 88 self.slope = None 30 89 31 def mode(self, value): 32 if value != None: 33 if value != self.mode: 34 self.scope.send(":TRIG"+str(self.number)+":SCAL "+str(value)) 35 self.scale = value 36 else: 37 self.scale = self.scope.query(":CHAN"+str(self.number)+":SCAL?") 38 return self.scale 90 def update(self): 91 self.level = self.level 92 self.slope = self.slope 39 93 40 def source(self, value): 41 if value != None: 42 if value != self.scale: 43 self.scope.send(":CHAN"+str(self.number)+":SCAL "+str(value)) 44 self.scale = value 45 else: 46 self.scale = self.scope.query(":CHAN"+str(self.number)+":SCAL?") 47 return self.scale 48 49 def sweep(self, value): 50 if value != None: 51 if value != self.sweep: 52 self.scope.send(":CHAN"+self.mode+":SWE "+str(value)) 53 self.sweep = value 54 else: 55 self.sweep = self.scope.query(":CHAN"+self.mode+":SWE?") 56 return self.sweep 57 58 def level(self, value): 59 if value != None: 60 if value != self.level: 61 self.scope.send(":TRIG:"+self.mode+":LEV "+str(value)) 62 self.scale = level 63 else: 64 self.level = self.scope.query(":TRIG:"+self.mode+":LEV?") 65 return self.leve 66 67 def holdoff(self, value): 68 if value != None: 69 if value != self.scale: 70 self.scope.send(":CHAN"+str(self.number)+":SCAL "+str(value)) 71 self.scale = value 72 else: 73 self.scale = self.scope.query(":CHAN"+str(self.number)+":SCAL?") 74 return self.scale 94 def apply(self, wave): 95 # @@@ only digital waves for now 96 # @@@ need to include holdoff time as well 97 if self.level <= 0 or self.level >= 1: 98 return [] 99 if self.slope == slope.Both: 100 return wave.data[:] 101 res = [] 102 i = int(wave.initial ^ self.slope == slope.Falling)+1 103 while i < len(wave.data): 104 res.append(wave.data[i]) 105 i += 2 106 return res -
developers/werner/ahrt/host/tmc/lib/wave.py
r4631 r4633 36 36 # or (s0, t*) x t* -> v* 37 37 38 # de-interpolation (analog): remove points that can be interpolated 39 40 41 # 42 # Known restrictions: 43 # - waves.load has no way of knowing what kind of wave it is loading, so it 44 # just makes everything an analog wave. Should perhaps add a comment on top 45 # of the file with same hints. Or let provide a means for the user to tell 46 # waves.load what the waves are like. An even more radical approach may be 47 # to automatically convert waves consisting only of 0 and 1 and with only 48 # vertical transitions to digital. CPU time is cheap :-) 49 # 50 51 import re 38 52 39 53 … … 43 57 class wave(object): 44 58 45 def dump(self, name, append = False):59 def save(self, name, append = False): 46 60 f = open(name, ("w", "a")[append]) 47 61 if append: … … 49 63 for xy in self: 50 64 print >>f, xy[0], xy[1] 65 f.close() 66 67 def load(self, name, step = None): 68 self.__init__() 69 empty = re.compile("^\s*(#.*)$") 70 if step is None: 71 numbers = re.compile("^\s*(\S+)\s*(\S+)\s*") 72 else: 73 numbers = re.compile("^\s*(\S+)?\s*(\S+)\s*") 74 t = 0 75 f = open(name, "r") 76 while True: 77 line = f.readline() 78 if line == "": 79 break 80 if empty.match(line): 81 continue 82 m = numbers.match(line) 83 if m is None: 84 raise hell 85 if step is None: 86 self.append(float(m.group(1)), float(m.group(2))) 87 else: 88 self.append(t, float(m.group(2))) 89 t += step 51 90 f.close() 52 91 … … 60 99 return self.get_one(t) 61 100 101 def unary(self, op): 102 res = analog() 103 for p in self: 104 res.append(float(p[0]), float(op(p[1]))) 105 return res 106 107 def binary(self, other, op): 108 res = analog() 109 if isinstance(self, wave): 110 if isinstance(other, wave): 111 for v in waves(self, other).iterate(): 112 res.append(v[0], op(float(v[1]), float(v[2]))) 113 else: 114 for p in self: 115 res.append(p[0], op(float(p[1]), float(other))) 116 else: 117 for p in other: 118 res.append(p[0], op(float(self), float(p[1]))) 119 return res 120 121 def __add__(self, other): 122 return self.binary(other, float.__add__) 123 124 def __sub__(self, other): 125 return self.binary(other, float.__sub__) 126 127 def __mul__(self, other): 128 return self.binary(other, float.__mul__) 129 130 def __pow__(self, other): 131 return self.binary(other, float.__pow__) 132 133 def __div__(self, other): 134 return self.binary(other, float.__div__) 135 136 def __truediv__(self, other): 137 return self.binary(other, float.__truediv__) 138 139 def __radd__(self, other): 140 return self.binary(other, float.__radd__) 141 142 def __rsub__(self, other): 143 return self.binary(other, float.__rsub__) 144 145 def __rmul__(self, other): 146 return self.binary(other, float.__rmul__) 147 148 def __rpow__(self, other): 149 return self.binary(other, float.__rpow__) 150 151 def __rdiv__(self, other): 152 return self.binary(other, float.__rdiv__) 153 154 def __rtruediv__(self, other): 155 return self.binary(other, float.__rtruediv__) 156 157 def __neg__(self): 158 return self.unary(float.__neg__) 159 160 def __abs__(self): 161 return self.unary(float.__abs__) 162 163 164 # === Wave groups ============================================================= 165 166 167 def next_or_none(iter): 168 try: 169 return iter.next() 170 except StopIteration: 171 return None 172 173 174 # The iteration is a bit tricky, because waves may have different sample 175 # intervals, so we need to interpolate, and they may have multiple samples with 176 # the same time (in the case of digital waves), so we need to make sure we stop 177 # at a given time until all samples have been extraced. 178 179 class waves_iter: 180 181 def __init__(self, waves): 182 self.iter = [] 183 self.cur = [] 184 self.nxt = [] 185 self.t = None 186 for w in waves: 187 i = w.__iter__() 188 v = next_or_none(i) 189 self.iter.append(i) 190 self.nxt.append(v) 191 self.cur.append(None) 192 if self.t is None: 193 if v is not None and (self.t is None or v[0] < self.t): 194 self.t = v[0] 195 196 def __iter__(self): 197 return self 198 199 def next(self): 200 if self.t is None: 201 raise StopIteration 202 next_t = None 203 res = [ self.t ] 204 for i in range(0, len(self.cur)): 205 if self.nxt[i] is not None and self.nxt[i][0] == self.t: 206 self.cur[i] = self.nxt[i] 207 self.nxt[i] = next_or_none(self.iter[i]) 208 if self.nxt[i] is not None and \ 209 (next_t is None or self.nxt[i][0] < next_t): 210 next_t = self.nxt[i][0] 211 if self.cur[i] is None: 212 if self.nxt[i] is None: 213 v = 0 214 else: 215 v = self.nxt[i][1] 216 else: 217 if self.nxt[i] is None or self.cur[i][0] == self.t: 218 v = self.cur[i][1] 219 else: 220 v = self.cur[i][1]+(self.nxt[i][1]-self.cur[i][1])* \ 221 (self.t-self.cur[i][0])/ \ 222 float(self.nxt[i][0]-self.cur[i][0]) 223 res.append(v) 224 self.t = next_t 225 return res 226 227 228 class waves(list): 229 230 def __init__(self, *args): 231 list.__init__(self) 232 self.extend(args) 233 234 def iterate(self): 235 return waves_iter(self) 236 237 def save(self, name, append = False): 238 f = open(name, ("w", "a")[append]) 239 if append: 240 print >>f 241 for v in self.iterate(): 242 for i in range(0, len(v)-1): 243 print >>f, v[i], 244 print >>f, v[-1] 245 f.close() 246 247 def load(self, name, step = None): 248 list.__init__(self) 249 empty = re.compile("^\s*(#.*)$") 250 space = re.compile("\s+") 251 first = True 252 skip = step is None 253 t = 0 254 f = open(name, "r") 255 while True: 256 line = f.readline() 257 if line == "": 258 break 259 if empty.match(line): 260 continue 261 m = space.split(line.lstrip().rstrip()) 262 if first: 263 for i in range(0, len(m)-skip): 264 self.append(analog()) 265 first = False 266 else: 267 if len(m)-skip != len(self): 268 raise hell 269 if step is None: 270 for i in range(0, len(m)-1): 271 self[i].append(float(m[0]), float(m[i+1])) 272 else: 273 for i in range(0, len(m)): 274 self[i].append(t, float(m[i])) 275 t += step 276 f.close() 277 62 278 63 279 # === Analog waves ============================================================ 64 280 65 281 66 class analog_ wave_iter:282 class analog_iter: 67 283 68 284 def __init__(self, wave): … … 100 316 101 317 102 class analog _wave(wave):318 class analog(wave): 103 319 104 320 def __init__(self): … … 116 332 117 333 def append(self, t, y): 118 if len(self.data) and t <= self.data[-1][0]: 119 raise hell 334 if len(self.data): 335 if t < self.data[-1][0]: 336 raise hell 337 if t == self.data[-1][0] and y == self.data[-1][1]: 338 return 120 339 self.data.append((t, y)) 121 340 … … 132 351 133 352 def __iter__(self): 134 return analog_ wave_iter(self)353 return analog_iter(self) 135 354 136 355 def __len__(self): 137 356 return len(self.data) 138 357 358 def digitize(self, low, high = None): 359 if high is None: 360 high = low 361 res = digital() 362 state = None 363 for p in self.data: 364 if p[1] >= high: 365 if state is None or not state: 366 res.append(p[0], 1) 367 state = True 368 elif p[1] <= low: 369 if state is None or state: 370 res.append(p[0], 0) 371 state = False 372 return res 373 139 374 140 375 # === Digital waves =========================================================== 141 376 142 377 143 class digital_ wave_iter:378 class digital_iter: 144 379 145 380 def __init__(self, wave): … … 163 398 164 399 165 class digital _wave(wave):400 class digital(wave): 166 401 167 402 def __init__(self): … … 210 445 211 446 def __iter__(self): 212 return digital_wave_iter(self) 213 214 # @@@ experimental ! maybe use triggers instead ? 215 216 def edges(self, rising, falling = None): 217 if falling is None: 218 falling = not rising 219 if (not falling) and (not rising): 220 return [] 221 res = [] 222 if falling and rising: 223 i = 1 224 while i != len(self.data): 225 res.append(self.data[i]) 226 i += 1 227 return res 228 else: 229 i = int(self.initial ^ (not rising))+1 230 while i < len(self.data): 231 res.append(self.data[i]) 232 i += 2 233 return res 234 235 # @@@ experimental ! 447 return digital_iter(self) 236 448 237 449 def debounce(self, t): … … 246 458 def __len__(self): 247 459 return len(self.data)*2 248 249 250 # === @@@ Work in progress ====================================================251 252 253 def digitize(wave, vl, vh):254 delta = []255 state = 0 # high: 2, rise: 1, unknown: 0, fall: -1, low: -2256 s0 = None257 t0 = None258 for p in wave:259 if p[1] >= vh:260 pass261 elif p1[x] <= vl:262 pass263 else:264 pass265 if state == 2: # high266 pass267 elif state == -2: # low268 pass269 elif state == 1: # rise270 pass271 elif state == -1: # fall272 pass273 else: # unknown274 pass275 if s0 == None:276 return None277 return (s0, delta) -
developers/werner/ahrt/host/tmc/setup.py
r4631 r4633 5 5 description = "Test and Measurement Control", 6 6 py_modules = [ "tmc.instrument", 7 "tmc.wave", "tmc. shape",7 "tmc.wave", "tmc.trigger", "tmc.shape", 8 8 "tmc.meter", "tmc.scope", "tmc.power", "tmc.function" ], 9 9 package_dir = { "tmc": "lib" },
Note: See TracChangeset
for help on using the changeset viewer.
