move to a more standard python packaging structure
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import serial
|
||||
import re
|
||||
import operator
|
||||
from functools import reduce
|
||||
|
||||
|
||||
DEBUG=False
|
||||
|
||||
reply_pattern = re.compile(r"\x02..(.*)\x03.", re.DOTALL)
|
||||
# example answer '\x02PV279.8\x03/'
|
||||
# [EOT] = \x04
|
||||
# [STX] = \x02
|
||||
# [ENQ] = \x05
|
||||
# [ETX] = \x03
|
||||
# [ACK] = \x06
|
||||
# BCC = checksum
|
||||
|
||||
standard_device='0011'
|
||||
EOT = '\x04'
|
||||
STX = '\x02'
|
||||
ENQ = '\x05'
|
||||
ETX = '\x03'
|
||||
ACK = '\x06'
|
||||
NAK = '\x15'
|
||||
|
||||
|
||||
"""
|
||||
Paramter read example:
|
||||
|
||||
Master: [EOT]0011PV[ENQ]
|
||||
Instrument: [STX]PV16.4[ETX]{BCC}
|
||||
|
||||
Writing data:
|
||||
|
||||
Master: [EOT] {GID}{GID}{UID}{UID}[STX]{CHAN}(c1)(c2)<DATA>[ETX](BCC)
|
||||
|
||||
"""
|
||||
|
||||
def checksum(message):
|
||||
bcc = (reduce(operator.xor, list(map(ord,message))))
|
||||
return chr(bcc)
|
||||
|
||||
class Eurotherm(object):
|
||||
def __init__(self, serial_device, baudrate = 19200):
|
||||
self.device = standard_device
|
||||
# timeout: 110 ms to get all answers.
|
||||
self.s = serial.Serial(serial_device,
|
||||
baudrate = baudrate,
|
||||
bytesize=7,
|
||||
parity='E',
|
||||
stopbits=1,
|
||||
timeout=0.11)
|
||||
self._expect_len = 50
|
||||
|
||||
def send_read_param(self, param):
|
||||
self.s.write(EOT + self.device + param + ENQ)
|
||||
|
||||
def read_param(self, param):
|
||||
self.s.flushInput()
|
||||
self.send_read_param(param)
|
||||
answer = self.s.read(self._expect_len)
|
||||
m = reply_pattern.search(answer)
|
||||
if m is None:
|
||||
# Reading _expect_len bytes was not enough...
|
||||
answer += self.s.read(200)
|
||||
m = reply_pattern.search(answer)
|
||||
if m is not None:
|
||||
self._expect_len = len(answer)
|
||||
return m.group(1)
|
||||
else:
|
||||
print("received:", repr(answer))
|
||||
return None
|
||||
|
||||
def write_param(self, mnemonic, data):
|
||||
if len(mnemonic) > 2:
|
||||
raise ValueError
|
||||
bcc = checksum(mnemonic + data + ETX)
|
||||
mes = EOT+self.device+STX+mnemonic+data+ETX+bcc
|
||||
if DEBUG:
|
||||
for i in mes:
|
||||
print(i,hex(ord(i)))
|
||||
self.s.flushInput()
|
||||
self.s.write(mes)
|
||||
answer = self.s.read(1)
|
||||
# print "received:", repr(answer)
|
||||
if answer == "":
|
||||
# raise IOError("No answer from device")
|
||||
return None
|
||||
return answer[-1] == ACK
|
||||
|
||||
def get_current_temperature(self):
|
||||
temp = self.read_param('PV')
|
||||
if temp is None:
|
||||
temp = "0"
|
||||
return temp
|
||||
|
||||
def set_temperature(self, temperature):
|
||||
return self.write_param('SL', str(temperature))
|
||||
|
||||
def get_setpoint_temperature(self):
|
||||
return self.read_param('SL')
|
||||
|
||||
if __name__ == '__main__':
|
||||
import time
|
||||
delta=5
|
||||
date = time.strftime('%Y-%m-%d')
|
||||
f = open('templog_%s'%date,'w')
|
||||
f.write('# Start time: %s\n#delta t : %.1f s\n'%(time.asctime(), delta))
|
||||
et = Eurotherm("/dev/ttyUSB0")
|
||||
while True:
|
||||
for i in range(120):
|
||||
time.sleep(delta)
|
||||
#t = time.strftime()
|
||||
T = et.get_current_temperature()
|
||||
|
||||
l = '%f %s\n'%(time.time(),T)
|
||||
print(time.asctime(), T)
|
||||
f.write(l)
|
||||
f.flush()
|
||||
f.write('# MARK -- %s --\n'%(time.asctime()))
|
||||
Executable
+246
@@ -0,0 +1,246 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- encoding: utf-8 -*-
|
||||
import optparse
|
||||
import os, sys
|
||||
import serial
|
||||
import numpy as N
|
||||
import struct
|
||||
import binascii
|
||||
import time
|
||||
|
||||
DEBUG = False
|
||||
|
||||
crc_test = "\x0d\x01\x00\x62\x00\x33"
|
||||
crc_expected = 0xddd
|
||||
|
||||
|
||||
def crc(message):
|
||||
"""
|
||||
(from "Modbus_over_serial_line_V1_02.pdf" at http://www.modbus.org)
|
||||
|
||||
6.2.2 CRC Generation
|
||||
====================
|
||||
The Cyclical Redundancy Checking (CRC) field is two bytes, containing a 16–bit binary value. The CRC value is calculated by the
|
||||
transmitting device, which appends the CRC to the message. The device that receives recalculates a CRC during receipt of the
|
||||
message, and compares the calculated value to the actual value it received in the CRC field. If the two values are not equal, an error
|
||||
results.
|
||||
|
||||
The CRC is started by first preloading a 16–bit register to all 1’s. Then a process begins of applying successive 8–bit bytes of the
|
||||
message to the current contents of the register. Only the eight bits of data in each character are used for generating the CRC. Start
|
||||
and stop bits and the parity bit, do not apply to the CRC.
|
||||
During generation of the CRC, each 8–bit character is exclusive ORed with the register contents. Then the result is shifted in the
|
||||
direction of the least significant bit (LSB), with a zero filled into the most significant bit (MSB) position. The LSB is extracted and
|
||||
examined. If the LSB was a 1, the register is then exclusive ORed with a preset, fixed value. If the LSB was a 0, no exclusive OR takes
|
||||
place.
|
||||
|
||||
This process is repeated until eight shifts have been performed. After the last (eighth) shift, the next 8–bit character is exclusive ORed
|
||||
with the register’s current value, and the process repeats for eight more shifts as described above. The final content of the register,
|
||||
after all the characters of the message have been applied, is the CRC value.
|
||||
A procedure for generating a CRC is:
|
||||
|
||||
1. Load a 16–bit register with FFFF hex (all 1’s). Call this the CRC register.
|
||||
2. Exclusive OR the first 8–bit byte of the message with the low–order byte of the 16–bit CRC register, putting the result in the
|
||||
CRC register.
|
||||
3. Shift the CRC register one bit to the right (toward the LSB), zero–filling the MSB. Extract and examine the LSB.
|
||||
4. (If the LSB was 0): Repeat Step 3 (another shift).
|
||||
(If the LSB was 1): Exclusive OR the CRC register with the polynomial value 0xA001 (1010 0000 0000 0001).
|
||||
5. Repeat Steps 3 and 4 until 8 shifts have been performed. When this is done, a complete 8–bit byte will have been
|
||||
processed.
|
||||
6. Repeat Steps 2 through 5 for the next 8–bit byte of the message. Continue doing this until all bytes have been processed.
|
||||
7. The final content of the CRC register is the CRC value.
|
||||
8. When the CRC is placed into the message, its upper and lower bytes must be swapped as described below.
|
||||
|
||||
Placing the CRC into the Message
|
||||
When the 16–bit CRC (two 8–bit bytes) is transmitted in the message, the low-order byte will be transmitted first, followed by the high-
|
||||
order byte.
|
||||
"""
|
||||
|
||||
crc = 0xffff # step 1
|
||||
for byte in message:
|
||||
if type(byte) == type(str):
|
||||
crc ^= ord(byte) # step 2: xor with lower byte of crc
|
||||
else:
|
||||
crc ^= byte # step 2: xor with lower byte of crc
|
||||
for i in range(8): # step 5: repeat 2-4 until 8 shifts were performed
|
||||
if (crc & 0x1) == 0: # step 4: check LSB
|
||||
mask = 0x0
|
||||
else:
|
||||
mask = 0xa001
|
||||
crc >>= 1 # step 3: shift one bit to the right
|
||||
crc ^= mask
|
||||
if DEBUG: print("Message:", [i for i in message], " CRC:", hex(crc))
|
||||
return chr(crc & 0xff) + chr(
|
||||
(crc >> 8) & 0xff) # return lower byte, upper byte (shift to the right, return last byte) i
|
||||
|
||||
|
||||
class Flow:
|
||||
def __init__(self, device="/dev/ttyUSB0"):
|
||||
self.s = serial.Serial(port=device, timeout=0.02)
|
||||
self.s.readline()
|
||||
self.s.timeout = 0.2
|
||||
self.address = bytearray([0x3])
|
||||
self.rcommands = {
|
||||
"flow": [bytearray([0x3, 0x0, 0x0, 0x0, 0x2]), ">f"],
|
||||
"temperature": [bytearray([0x3, 0x0, 0x2, 0x0, 0x2]), ">f"],
|
||||
"setflow": [bytearray([0x3, 0x0, 0x6, 0x0, 0x2]), ">f"],
|
||||
"total": [bytearray([0x3, 0x0, 0x8, 0x0, 0x2]), ">f"],
|
||||
"alarm": [bytearray([0x3, 0x0, 0xc, 0x0, 0x1]), ">H"],
|
||||
"hwerror": [bytearray([0x3, 0x0, 0xd, 0x0, 0x1]), ">H"],
|
||||
"unit_flow": [bytearray([0x3, 0x0, 0x16, 0x0, 0x4]), ">8s"],
|
||||
"medium": [bytearray([0x3, 0x00, 0x1a, 0x0, 0x4]), ">8s"],
|
||||
"device": [bytearray([0x3, 0x00, 0x23, 0x0, 0x4]), ">8s"],
|
||||
"unit_total": [bytearray([0x3, 0x40, 0x48, 0x0, 0x4]), ">8s"],
|
||||
}
|
||||
|
||||
self.wcommands = {
|
||||
"flow": [bytearray([0x06, 0x0, 0x6]), ">f"]
|
||||
}
|
||||
|
||||
def send_data(self, data_and_type):
|
||||
"""
|
||||
send data to the device at self.address.
|
||||
|
||||
"""
|
||||
data, type = data_and_type
|
||||
if DEBUG: print("send", data_and_type, "data:", binascii.hexlify(data), "type:", type, self.address)
|
||||
msg = self.address + data
|
||||
msg_crc = msg + crc(msg)
|
||||
if DEBUG: print("send:", repr(str(msg_crc)))
|
||||
nbytes_sent = self.s.write(str(msg_crc))
|
||||
if DEBUG: print("send:", self.s)
|
||||
if DEBUG: print("Sent bytes:", nbytes_sent)
|
||||
time.sleep(0.1) # this is necessary, otherwise no data can be received
|
||||
|
||||
return msg_crc
|
||||
|
||||
def recv_data(self):
|
||||
"""
|
||||
Reading Data
|
||||
============
|
||||
|
||||
Function: 0x3
|
||||
Format of the resulting string
|
||||
|
||||
Addr Func NoBytes Byte1...N CRCHi CRCLo
|
||||
|
||||
"""
|
||||
message = bytearray(self.s.read(3))
|
||||
if DEBUG: print("recv_data: header:", binascii.hexlify(message))
|
||||
if message == "":
|
||||
return
|
||||
addr, func, nbytes = message
|
||||
if func == 0x03:
|
||||
data = self.s.read(nbytes)
|
||||
if DEBUG: print("recv_data: data: %i %s" % (nbytes, binascii.hexlify(data)))
|
||||
message += data
|
||||
crc_data = self.s.read(2)
|
||||
if DEBUG: print("recv_data: crc", repr(str(crc_data)))
|
||||
if crc(message) != crc_data:
|
||||
print("mismatch", crc(message), crc_data)
|
||||
return data
|
||||
|
||||
def get_var(self, named_type="flow"):
|
||||
"""
|
||||
get variable from device, variables are definde in self.rcommands as list [bytearray[hiAd, loAd, numHi, numLo], type]
|
||||
"""
|
||||
cmd,fmt = self.rcommands[named_type]
|
||||
if DEBUG: print("get_var", cmd,fmt)
|
||||
self.send_data([cmd,fmt])
|
||||
d = self.recv_data()
|
||||
if d:
|
||||
d = struct.unpack(fmt, d)[0]
|
||||
return d
|
||||
# msg = self.recv_data()
|
||||
# print str(msg)
|
||||
|
||||
# float struct.unpack('>f', "4byte string")
|
||||
# ushort struct.unpack('>H', "2byte string")
|
||||
|
||||
|
||||
|
||||
def current_flow(self):
|
||||
# start register 0x0000
|
||||
# 2 bytes
|
||||
cmd = self.address + bytearray([0x3, 0x0, 0x0, 0x0, 0x2])
|
||||
return cmd + crc(cmd)
|
||||
|
||||
def current_temperature(self):
|
||||
# start register 0x0002
|
||||
#
|
||||
#
|
||||
cmd = self.address + bytearray([0x3, 0x0, 0x2, 0x0, 0x2])
|
||||
return cmd + crc(cmd)
|
||||
|
||||
def set_flow(self, flow):
|
||||
"""
|
||||
write multiple registers: 0x10
|
||||
startHi
|
||||
startLo
|
||||
numregHi
|
||||
numregLo
|
||||
numbytes
|
||||
"""
|
||||
_flow = struct.pack(">f", flow)
|
||||
# cmd = address + bytearray([0x10,0x0,0x6, 0x0, 0x2, 0x2]) + _flow
|
||||
cmd1 = self.address + bytearray([0x06, 0x0, 0x6]) + _flow
|
||||
self.s.write(cmd1 + crc(cmd1))
|
||||
time.sleep(0.01)
|
||||
# print self.s.readline()
|
||||
# self.recv_data()
|
||||
|
||||
def cmd(self, data):
|
||||
cmds = self.address + data
|
||||
for i in cmds:
|
||||
print(hex(ord(i)), end=' ')
|
||||
return cmds + crc(cmds)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
This is the command line program to control the red-y flow control series.
|
||||
Usage: ./flow_control.py [FLOW]
|
||||
|
||||
Several parameters are printed on every execution
|
||||
|
||||
The default serial device is /dev/ttyUSB0. If you want to change that create a
|
||||
file called "~/.flow" with the first line containing an alternate path, i.e. /dev/ttyUSB1
|
||||
|
||||
If you want to enable debug output edit the script and set DEBUG=True.
|
||||
|
||||
Sample output:
|
||||
|
||||
user@pfg # flow
|
||||
Device: GSCC9SA
|
||||
Medium: N2B
|
||||
Current Flow: 0.00
|
||||
Current Set Flow: 0.00
|
||||
Flow Unit: ln/min
|
||||
Total Gas: 0.00
|
||||
Total Unit: lnF
|
||||
Current Temperature: 22.38 C
|
||||
Alarm: 0
|
||||
HW Error: 0
|
||||
|
||||
"""
|
||||
conf = os.path.expanduser('~/.flow')
|
||||
if os.path.exists(conf):
|
||||
dev = open(conf).readlines()[0].strip()
|
||||
redy = Flow(device=dev)
|
||||
print("Device: %6s" % (redy.get_var("device")))
|
||||
print("Medium: %6s" % (redy.get_var("medium")))
|
||||
print("Current Flow: %6.2f" % (redy.get_var("flow")))
|
||||
print("Current Set Flow: %6.2f" % (redy.get_var("setflow")))
|
||||
print("Flow Unit: %6s" % (redy.get_var("unit_flow")))
|
||||
print("Total Gas: %6.2f" % (redy.get_var("total")))
|
||||
print("Total Unit: %6s" % (redy.get_var("unit_total")))
|
||||
print("Current Temperature: %6.2f C" % (redy.get_var("temperature")))
|
||||
print("Alarm: %8i" % (redy.get_var("alarm")))
|
||||
print("HW Error: %8i" % (redy.get_var("hwerror")))
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
try:
|
||||
float(sys.argv[1])
|
||||
except:
|
||||
raise SyntaxError("usage: %s <flow> # to set flow or empty to get current flow\nfirst line in ~/.flow defines serial tty, default: /dev/ttyUSB0" % (sys.argv[0]))
|
||||
print("Set flow: %6.2f"%(float(sys.argv[1])))
|
||||
redy.set_flow(float(sys.argv[1]))
|
||||
@@ -0,0 +1,125 @@
|
||||
__author__ = 'Markus Rosenstihl <markus.rosenstihl@physik.tu-darmstadt.de>'
|
||||
|
||||
import re
|
||||
import serial
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
logfile = os.path.expanduser("~/.goniometer.log")
|
||||
logging.basicConfig(filename=logfile,level=logging.INFO)
|
||||
logger = logging.getLogger()
|
||||
logger.name = "goniometer"
|
||||
|
||||
class goniometer:
|
||||
"""
|
||||
This class is meant to control the goniometer probe head from Marco Braun (AXYs)
|
||||
"""
|
||||
def __init__(self, dev="/dev/ttyUSB0",
|
||||
baudrate=38400,
|
||||
timeout=1,
|
||||
return_to_origin=True,
|
||||
loglevel=2,
|
||||
logangle=False):
|
||||
"""
|
||||
Upon creating an instance the goniometer will be initialised and the current angle defined as being 0.
|
||||
The goniometer log can be found in `~/.goniometer.log`.
|
||||
|
||||
:param return_to_origin: Set to true if you want the stepper to return to the beginning when
|
||||
the class instance is deleted (for example with "del" ). Default: True
|
||||
:type return_to_origin: bool
|
||||
:param loglevel: This sets the log level 0=DEBUG,1=INFO,2=WARNING. Default: 2
|
||||
:type loglevel: int
|
||||
:param logangle: Should a history of the angles be kept? The log can be accessed in the `_angle_history`
|
||||
variable. Default: False
|
||||
:type logangle: bool
|
||||
"""
|
||||
self.serial = serial.Serial(port=dev, baudrate=baudrate, timeout=timeout)
|
||||
logger.setLevel([logging.DEBUG,logging.INFO,logging.WARNING][loglevel])
|
||||
self.serial.readlines() # empty serial buffer
|
||||
self.current_angle = 0.0
|
||||
self._angle_history = []
|
||||
self.initialise()
|
||||
self.return_to_origin = return_to_origin
|
||||
self.logangel = logangle
|
||||
|
||||
def __del__(self):
|
||||
if self.return_to_origin:
|
||||
logging.info("Return to origin")
|
||||
self._send("g1")
|
||||
self._wait()
|
||||
self.serial.close()
|
||||
|
||||
def _send(self, string_to_send):
|
||||
formatted_string = "%s>\r\n"%string_to_send
|
||||
logging.debug("send: %s"%(repr(formatted_string)))
|
||||
self.serial.write(formatted_string)
|
||||
|
||||
def _recv(self):
|
||||
retstr = self.serial.readline().strip().replace("\x00","")
|
||||
search_result = re.search(r"<(\d+)>", retstr)
|
||||
if search_result != None:
|
||||
angle = float(search_result.group(1))/36.0
|
||||
self.current_angle = angle
|
||||
if self.logangle:
|
||||
self._angle_history.append(angle)
|
||||
logging.debug("%.2f"%angle)
|
||||
return angle
|
||||
else:
|
||||
return None
|
||||
|
||||
def _wait(self):
|
||||
logging.debug("Wait until rotation finnished (current: %.2f)"%(self.current_angle))
|
||||
time.sleep(4)
|
||||
while True:
|
||||
retstr = self._recv()
|
||||
if not retstr:
|
||||
logging.debug("Rotation finnished (current: %.2f)"%(self.current_angle))
|
||||
break
|
||||
|
||||
def initialise(self):
|
||||
logging.info("Initialize goniometer")
|
||||
self._send("R000")
|
||||
self.current_angle = 0.0
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops the current movement, not possible while doing :func:`step` and :func:`angle`
|
||||
"""
|
||||
logging.info("Stop goniometer")
|
||||
self._send("S456")
|
||||
|
||||
def step(self, sample_rotation_degree=1.0):
|
||||
"""
|
||||
How many degrees should we step further. Negative values are not allowed, the stepper would return to 0.
|
||||
A ValueError exception is raised in this case.
|
||||
:param sample_rotation_degree: How many degrees to rotate. Default: 1
|
||||
:type sample_rotation_degree: float
|
||||
"""
|
||||
if sample_rotation_degree <= 0:
|
||||
raise ValueError("This does not what you expect, would move to the start position whatever the value")
|
||||
logging.info("Step goniometer: %.2f"%sample_rotation_degree)
|
||||
direction = "g" if (sample_rotation_degree < 0) else "G"
|
||||
sample_rotation_degree = -1*sample_rotation_degree if sample_rotation_degree < 0 else sample_rotation_degree
|
||||
steps = int(sample_rotation_degree%360)
|
||||
self._send("%s%i"%(direction, steps ))
|
||||
self._wait()
|
||||
|
||||
def angle(self, angle_degree):
|
||||
"""
|
||||
To what angle, in degrees, should we rotate. Mod 360 is calculated for `angle_degree`.
|
||||
If angle is smaller than current angle an exception will be raised.
|
||||
(From the underlying :func:`step` function)
|
||||
|
||||
TODO: rotate either back or over to the wanted position.
|
||||
|
||||
:param angle_degree: position in degree
|
||||
:type angle_degree: float
|
||||
"""
|
||||
angle_degree %= 360
|
||||
delta_degree = angle_degree - self.current_angle
|
||||
logging.info("Rotate tp %.2f (from %.2f, i.e. delta=%.2f)"%(angle_degree, self.current_angle, delta_degree))
|
||||
self.step(sample_rotation_degree=delta_degree)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import numpy as N
|
||||
import sys
|
||||
if sys.version_info > (2,6,0):
|
||||
import numbers
|
||||
else:
|
||||
pass
|
||||
|
||||
if sys.version_info > (2,6,0):
|
||||
def lin_range(start,stop,step):
|
||||
if isinstance(step, numbers.Integral):
|
||||
return N.linspace(start,stop,step)
|
||||
else:
|
||||
return N.arange(start,stop,step)
|
||||
else:
|
||||
def lin_range(start,stop,step):
|
||||
return N.arange(start,stop,step)
|
||||
|
||||
|
||||
|
||||
def log_range(start, stop, stepno):
|
||||
if (start<=0 or stop<=0 or stepno<1):
|
||||
raise ValueError("start, stop must be positive and stepno must be >=1")
|
||||
return N.logspace(N.log10(start),N.log10(stop), num=stepno)
|
||||
|
||||
|
||||
def staggered_range(some_range, size=3):
|
||||
m=0
|
||||
if isinstance(some_range, N.ndarray):
|
||||
is_numpy = True
|
||||
some_range = list(some_range)
|
||||
else:
|
||||
is_numpy = False
|
||||
new_list=[]
|
||||
for k in range(len(some_range)):
|
||||
for i in range(size):
|
||||
try:
|
||||
index = (m*size)
|
||||
new_list.append(some_range.pop(index))
|
||||
except IndexError:
|
||||
break
|
||||
m+=1
|
||||
if is_numpy:
|
||||
new_list = N.asarray(new_list+some_range)
|
||||
else:
|
||||
new_list+=some_range
|
||||
return new_list
|
||||
|
||||
|
||||
def combine_ranges(*ranges):
|
||||
new_list = []
|
||||
for r in ranges:
|
||||
new_list.extend(r)
|
||||
return new_list
|
||||
|
||||
combined_ranges=combine_ranges
|
||||
|
||||
def interleaved_range(some_list, left_out):
|
||||
"""
|
||||
in first run, do every n-th, then do n-1-th of the remaining values and so on...
|
||||
"""
|
||||
m=0
|
||||
new_list = []
|
||||
for j in range(left_out):
|
||||
for i in range(len(some_list)):
|
||||
if (i*left_out+m) < len(some_list):
|
||||
new_list.append(some_list[i*left_out+m])
|
||||
else:
|
||||
m+=1
|
||||
break
|
||||
if isinstance(some_list, N.ndarray):
|
||||
new_list = N.array(new_list)
|
||||
return new_list
|
||||
|
||||
|
||||
# These are the generators
|
||||
def lin_range_iter(start,stop, step):
|
||||
this_one=float(start)+0.0
|
||||
if step>0:
|
||||
while (this_one<=float(stop)):
|
||||
yield this_one
|
||||
this_one+=float(step)
|
||||
else:
|
||||
while (this_one>=float(stop)):
|
||||
yield this_one
|
||||
this_one+=float(step)
|
||||
|
||||
|
||||
def log_range_iter(start, stop, stepno):
|
||||
if (start<=0 or stop<=0 or stepno<1):
|
||||
raise ValueError("start, stop must be positive and stepno must be >=1")
|
||||
if int(stepno)==1:
|
||||
factor=1.0
|
||||
else:
|
||||
factor=(stop/start)**(1.0/int(stepno-1))
|
||||
for i in range(int(stepno)):
|
||||
yield start*(factor**i)
|
||||
|
||||
def staggered_range_iter(some_range, size = 1):
|
||||
"""
|
||||
size=1: do one, drop one, ....
|
||||
size=n: do 1 ... n, drop n+1 ... 2*n
|
||||
in a second run the dropped values were done
|
||||
"""
|
||||
left_out=[]
|
||||
try:
|
||||
while True:
|
||||
for i in range(size):
|
||||
yield next(some_range)
|
||||
for i in range(size):
|
||||
left_out.append(next(some_range))
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
# now do the droped ones
|
||||
for i in left_out:
|
||||
yield i
|
||||
|
||||
def combined_ranges_iter(*ranges):
|
||||
"""
|
||||
iterate over one range after the other
|
||||
"""
|
||||
for r in ranges:
|
||||
for i in r:
|
||||
yield i
|
||||
|
||||
combine_ranges_iter=combined_ranges_iter
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import math
|
||||
|
||||
__all__ = ['rotate_signal']
|
||||
|
||||
|
||||
def rotate_signal(timesignal, angle):
|
||||
"Rotate <timesignal> by <angle> degrees"
|
||||
# implicit change to float arrays!
|
||||
if timesignal.get_number_of_channels()!=2:
|
||||
raise Exception("rotation defined only for 2 channels")
|
||||
# simple case 0, 90, 180, 270 degree
|
||||
reduced_angle=divmod(angle, 90)
|
||||
if abs(reduced_angle[1])<1e-6:
|
||||
reduced_angle=reduced_angle[0]%4
|
||||
if reduced_angle==0:
|
||||
return
|
||||
elif reduced_angle==1:
|
||||
timesignal.y[1]*=-1
|
||||
timesignal.y=[timesignal.y[1],timesignal.y[0]]
|
||||
elif reduced_angle==2:
|
||||
timesignal.y[0]*=-1
|
||||
timesignal.y[1]*=-1
|
||||
elif reduced_angle==3:
|
||||
timesignal.y[0]*=-1
|
||||
timesignal.y=[timesignal.y[1],timesignal.y[0]]
|
||||
else:
|
||||
sin_angle=math.sin(angle/180.0*math.pi)
|
||||
cos_angle=math.cos(angle/180.0*math.pi)
|
||||
timesignal.y=[cos_angle*timesignal.y[0]-sin_angle*timesignal.y[1],
|
||||
sin_angle*timesignal.y[0]+cos_angle*timesignal.y[1]]
|
||||
Reference in New Issue
Block a user