diff --git a/wetb/flex/__init__.py b/wetb/flex/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4d88eaf1e090114e4fe440c509ee4f83e9605c60 --- /dev/null +++ b/wetb/flex/__init__.py @@ -0,0 +1,6 @@ +from ._io import load, read_sensor_info +from wetb import gtsdf + +class Dataset(gtsdf.Dataset): + def __init__(self, filename): + self.time, self.data, self.info = load(filename) \ No newline at end of file diff --git a/wetb/flex/_io.py b/wetb/flex/_io.py new file mode 100644 index 0000000000000000000000000000000000000000..d3e4e3ea71cdd16bbc8b5b4e1fa990899de4d7eb --- /dev/null +++ b/wetb/flex/_io.py @@ -0,0 +1,159 @@ +''' +Created on 11. apr. 2017 + +@author: mmpe +''' +import struct +import numpy as np +import os + +def load(filename, dtype=np.float): + if isinstance(filename, str): + fid = open(filename,'rb') + elif hasattr(filename, "name"): + fid = filename + filename = fid.name + try: + _ = struct.unpack('i', fid.read(4)) + _ = struct.unpack('i', fid.read(4)) + title = fid.read(60).strip() + + _ = struct.unpack('i', fid.read(4)) + _ = struct.unpack('i', fid.read(4)) + no_sensors = struct.unpack('i', fid.read(4))[0] + + sensor_numbers = [struct.unpack('i', fid.read(4))[0] for _ in range(no_sensors)] + _ = struct.unpack('i', fid.read(4)) + _ = struct.unpack('i', fid.read(4)) + time_start = struct.unpack('f', fid.read(4))[0] + time_step = struct.unpack('f', fid.read(4))[0] + scale_factors = np.array([struct.unpack('f', fid.read(4))[0] for _ in range(no_sensors)], dtype=np.double) + data = np.fromstring(fid.read(), 'int16').astype(dtype) + finally: + fid.close() + +# if title.isalnum(): +# self.set_info(title, "", self.filename) +# else: +# self.set_info(os.path.basename(self.name), "", self.name) + try: + data = data.reshape(len(data) // no_sensors, no_sensors) + except ValueError: + raise ValueError("The number of data values (%d) is not divisible by the number of sensors (%d)" % (len(data), no_sensors)) + + for i in range(data.shape[1]): + data[:, i] *= scale_factors[i] + no_scans = data.shape[0] + + + # Load sensor file if exists + + + sensor_filename = os.path.join(os.path.dirname(filename), "sensor") + sensor_info = {info[0]:info[1:] for info in read_sensor_info(sensor_filename) } + + # set gain and offset for "Time" + gains = [] + offsets = [] + names, units, descriptions = [], [], [] + + for sensor_nr in sensor_numbers: + + name, unit, description, gain, offset = sensor_info.get(sensor_nr, ["Attribute %d"%sensor_nr, '-','',1,0]) + if sensor_nr==1 and name=="Time" and unit=="s": + data = data[:,1:] + continue + names.append(name) + units.append(unit) + descriptions.append(description) + gains.append(gain) + offsets.append(offset) + + time = np.arange(time_start, time_start + data.shape[0] * time_step, time_step).reshape((no_scans, 1)) + #data = np.concatenate((time, data), axis=1) + #gains = np.r_[1,gains] + #offsets = np.r_[0,offsets] + # self[:]*=self.gains + # self[:]+=self.offsets + info = {"name": title, + "description": filename, + "attribute_names": names, + "attribute_units": units, + "attribute_descriptions": descriptions} + return time, data, info + + +def read_sensor_info(sensor_file): + + if hasattr(sensor_file, 'readlines'): + sensor_info_lines = sensor_file.readlines()[2:] + else: + with open(sensor_file, encoding="utf-8") as fid: + sensor_info_lines = fid.readlines()[2:] + sensor_info = [] + for line in sensor_info_lines: + # while " " in line: + # line = line.replace(" "," ") + line = line.strip().split() + nr = int(line[0]) + gain = float(line[1]) + offset = float(line[2]) + unit = line[5] + name_desc = " ".join(line[6:]) + name = name_desc[:8].split()[0] + description = name_desc[8:] +# name = line[6] +# description = " ".join(line[7:]) + + + sensor_info.append((nr, name, unit, description, gain, offset)) + return sensor_info + +# def save(dataset, filename): +# ds = dataset +# # Write int data file +# f = open(filename, 'wb') +# time_att = ds.basis_attribute() +# sensors = [s for s in ds.attributes() if s is not time_att] +# +# if isinstance(ds, FLEX4Dataset): +# data = ds[:] # (ds[:]-ds.offsets)/ds.gains +# else: +# data = ds[:] +# if time_att.index != -1: # time_att may be "Index" with index=-1 if "Time" not exists +# data = np.delete(data, time_att.index, axis=1) +# f.write(struct.pack('ii', 0, 0)) # 2x empty int +# title = ("%-60s" % str(ds.name)).encode() +# f.write(struct.pack('60s', title)) # title +# f.write(struct.pack('ii', 0, 0)) # 2x empty int +# ns = len(sensors) +# f.write(struct.pack('i', ns)) +# f.write(struct.pack('i' * ns, *range(1, ns + 1))) # sensor number +# f.write(struct.pack('ii', 0, 0)) # 2x empty int +# time = ds.basis_attribute() +# f.write(struct.pack('ff', time[0], time[1] - time[0])) # start time and time step +# +# scale_factors = np.max(np.abs(data), 0) / 32000 +# f.write(struct.pack('f' * len(scale_factors), *scale_factors)) +# # avoid dividing by zero +# not0 = np.where(scale_factors != 0) +# data[:, not0] /= scale_factors[not0] +# #flatten and round +# data = np.round(data.flatten()).astype(np.int16) +# f.write(struct.pack('h' * len(data), *data.tolist())) +# f.close() +# +# # write sensor file +# f = open(os.path.join(os.path.dirname(filename), 'sensor'), 'w') +# f.write("Sensor list for %s\n" % filename) +# f.write(" No forst offset korr. c Volt Unit Navn Beskrivelse------------\n") +# sensorlineformat = "%3s %.3f %.3f 1.00 0.00 %7s %-8s %s\n" +# +# if isinstance(ds, FLEX4Dataset): +# gains = np.r_[ds.gains[1:], np.ones(ds.shape[1] - len(ds.gains))] +# offsets = np.r_[ds.offsets[1:], np.zeros(ds.shape[1] - len(ds.offsets))] +# sensorlines = [sensorlineformat % ((nr + 1), gain, offset, att.unit[:7], att.name.replace(" ", "_")[:8], att.description[:512]) for nr, att, gain, offset in zip(range(ns), sensors, gains, offsets)] +# else: +# sensorlines = [sensorlineformat % ((nr + 1), 1, 0, att.unit[:7], att.name.replace(" ", "_")[:8], att.description[:512]) for nr, att in enumerate(sensors)] +# f.writelines(sensorlines) +# f.close() \ No newline at end of file diff --git a/wetb/flex/tests/__init__.py b/wetb/flex/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/wetb/flex/tests/test_files/test1/sensor b/wetb/flex/tests/test_files/test1/sensor new file mode 100644 index 0000000000000000000000000000000000000000..88e89f63990b9e53bef2ba37ebcd5abef5083e88 --- /dev/null +++ b/wetb/flex/tests/test_files/test1/sensor @@ -0,0 +1,9 @@ +Sensor list for C:/mmpe/programming/python/WindEnergyToolbox/wetb/flex/tests/test_files/test1/test.int + No forst offset korr. c Volt Unit Navn Beskrivelse------------ + 1 1.000 0.000 1.00 0.00 m/s WSP_gl._ Free wind speed Vy, gl. coo, of gl. pos 0.75, 0.00, -40.75 + 2 1.000 0.000 1.00 0.00 m/s WSP_gl._ Free wind speed Vy, gl. coo, of gl. pos 1.00, 0.00, -39.00 + 3 1.000 0.000 1.00 0.00 m/s WSP_gl._ Free wind speed Vy, gl. coo, of gl. pos 7.00, 0.00, -33.00 + 4 1.000 0.000 1.00 0.00 rad/s Omega Rotor speed + 5 1.000 0.000 1.00 0.00 m Ae_pos_x Aero position x of blade 1 at radius 20.50, global coo. + 6 1.000 0.000 1.00 0.00 m Ae_pos_y Aero position y of blade 1 at radius 20.50, global coo. + 7 1.000 0.000 1.00 0.00 m Ae_pos_z Aero position z of blade 1 at radius 20.50, global coo. diff --git a/wetb/flex/tests/test_files/test1/test.int b/wetb/flex/tests/test_files/test1/test.int new file mode 100644 index 0000000000000000000000000000000000000000..5df18a5d5b28c9b45ec0b48786925a5fb7d9a306 Binary files /dev/null and b/wetb/flex/tests/test_files/test1/test.int differ diff --git a/wetb/flex/tests/test_files/test_sensor_info/sensor b/wetb/flex/tests/test_files/test_sensor_info/sensor new file mode 100644 index 0000000000000000000000000000000000000000..593044b9a59183b02162c7acc03652b2fa20f864 --- /dev/null +++ b/wetb/flex/tests/test_files/test_sensor_info/sensor @@ -0,0 +1,69 @@ + Version ID : HAWC2MB 12.3 (beta -rev_TJ6) + No forst offset korr. c Volt Unit Navn Beskrivelse--------------- + 1 1.0 0.0 0.00 1.0 s Time Time + 2 1.0 0.0 0.00 1.0 deg bea1 an shaft_rot angle + 3 1.0 0.0 0.00 1.0 rpm bea1 an shaft_rot angle speed + 4 1.0 0.0 0.00 1.0 deg bea2 an pitch1 angle + 5 1.0 0.0 0.00 1.0 deg/s bea2 an pitch1 angle speed + 6 1.0 0.0 0.00 1.0 deg bea2 an pitch2 angle + 7 1.0 0.0 0.00 1.0 deg/s bea2 an pitch2 angle speed + 8 1.0 0.0 0.00 1.0 deg bea2 an pitch3 angle + 9 1.0 0.0 0.00 1.0 deg/s bea2 an pitch3 angle speed + 10 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:towertop nodenr: 1 coo: tower tower top -1: below top mass + 11 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:towertop nodenr: 1 coo: tower tower top -1: below top mass + 12 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:towertop nodenr: 1 coo: tower tower top -1: below top mass + 13 1.0 0.0 0.00 1.0 kN Fx coo: Force Fx Mbdy:towertop nodenr: 1 coo: tower tower top -1: below top mass + 14 1.0 0.0 0.00 1.0 kN Fy coo: Force Fy Mbdy:towertop nodenr: 1 coo: tower tower top -1: below top mass + 15 1.0 0.0 0.00 1.0 kN Fz coo: Force Fz Mbdy:towertop nodenr: 1 coo: tower tower top -1: below top mass + 16 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:tower nodenr: 1 coo: tower tower base flange + 17 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:tower nodenr: 1 coo: tower tower base flange + 18 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:tower nodenr: 1 coo: tower tower base flange + 19 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:towertop nodenr: 2 coo: towertop yaw bearing + 20 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:towertop nodenr: 2 coo: towertop yaw bearing + 21 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:towertop nodenr: 2 coo: towertop yaw bearing + 22 1.0 0.0 0.00 1.0 kN Fx coo: Force Fx Mbdy:towertop nodenr: 2 coo: towertop yaw bering + 23 1.0 0.0 0.00 1.0 kN Fy coo: Force Fy Mbdy:towertop nodenr: 2 coo: towertop yaw bering + 24 1.0 0.0 0.00 1.0 kN Fz coo: Force Fz Mbdy:towertop nodenr: 2 coo: towertop yaw bering + 25 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:shaft nodenr: 4 coo: shaft main bearing + 26 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:shaft nodenr: 4 coo: shaft main bearing + 27 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:shaft nodenr: 4 coo: shaft main bearing + 28 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:blade1 nodenr: 3 coo: blade1 blade 1 root + 29 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:blade1 nodenr: 3 coo: blade1 blade 1 root + 30 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:blade1 nodenr: 3 coo: blade1 blade 1 root + 31 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:blade1 nodenr: 10 coo: local blade 1 50% local e coo + 32 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:blade1 nodenr: 10 coo: local blade 1 50% local e coo + 33 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:blade1 nodenr: 10 coo: local blade 1 50% local e coo + 34 1.0 0.0 0.00 1.0 kN Fx coo: Force Fx Mbdy:blade1 nodenr: 1 coo: blade1 blade 1 root + 35 1.0 0.0 0.00 1.0 kN Fy coo: Force Fy Mbdy:blade1 nodenr: 1 coo: blade1 blade 1 root + 36 1.0 0.0 0.00 1.0 kN Fz coo: Force Fz Mbdy:blade1 nodenr: 1 coo: blade1 blade 1 root + 37 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:blade2 nodenr: 1 coo: blade2 blade 2 root + 38 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:blade2 nodenr: 1 coo: blade2 blade 2 root + 39 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:blade2 nodenr: 1 coo: blade2 blade 2 root + 40 1.0 0.0 0.00 1.0 kNm Mx coo: MomentMx Mbdy:blade3 nodenr: 1 coo: blade3 blade 3 root + 41 1.0 0.0 0.00 1.0 kNm My coo: MomentMy Mbdy:blade3 nodenr: 1 coo: blade3 blade 3 root + 42 1.0 0.0 0.00 1.0 kNm Mz coo: MomentMz Mbdy:blade3 nodenr: 1 coo: blade3 blade 3 root + 43 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:towertop E-nr: 1 Z-rel:1.00 coo: global tower top flange position + 44 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:towertop E-nr: 1 Z-rel:1.00 coo: global tower top flange position + 45 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:towertop E-nr: 1 Z-rel:1.00 coo: global tower top flange position + 46 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: blade1 blade 1 tip pos + 47 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: blade1 blade 1 tip pos + 48 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: blade1 blade 1 tip pos + 49 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:blade2 E-nr: 18 Z-rel:1.00 coo: blade2 blade 2 tip pos + 50 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:blade2 E-nr: 18 Z-rel:1.00 coo: blade2 blade 2 tip pos + 51 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:blade2 E-nr: 18 Z-rel:1.00 coo: blade2 blade 2 tip pos + 52 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:blade3 E-nr: 18 Z-rel:1.00 coo: blade3 blade 3 tip pos + 53 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:blade3 E-nr: 18 Z-rel:1.00 coo: blade3 blade 3 tip pos + 54 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:blade3 E-nr: 18 Z-rel:1.00 coo: blade3 blade 3 tip pos + 55 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: global blade 1 tip pos + 56 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: global blade 1 tip pos + 57 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: global blade 1 tip pos + 58 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: hub1 blade 1 tip pos hub coo + 59 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: hub1 blade 1 tip pos hub coo + 60 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:blade1 E-nr: 18 Z-rel:1.00 coo: hub1 blade 1 tip pos hub coo + 61 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:blade2 E-nr: 18 Z-rel:1.00 coo: hub2 blade 2 tip pos hub coo + 62 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:blade2 E-nr: 18 Z-rel:1.00 coo: hub2 blade 2 tip pos hub coo + 63 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:blade2 E-nr: 18 Z-rel:1.00 coo: hub2 blade 2 tip pos hub coo + 64 1.0 0.0 0.00 1.0 m State p State pos x Mbdy:blade3 E-nr: 18 Z-rel:1.00 coo: hub3 blade 3 tip pos hub coo + 65 1.0 0.0 0.00 1.0 m State p State pos y Mbdy:blade3 E-nr: 18 Z-rel:1.00 coo: hub3 blade 3 tip pos hub coo + 66 1.0 0.0 0.00 1.0 m State p State pos z Mbdy:blade3 E-nr: 18 Z-rel:1.00 coo: hub3 blade 3 tip pos hub coo + 67 1.0 0.0 0.00 1.0 rad/s omega t State_rot omega tz Mbdy:shaft E-nr: 4 Z-rel:1.00 coo: shaft diff --git a/wetb/flex/tests/test_flex_io.py b/wetb/flex/tests/test_flex_io.py new file mode 100644 index 0000000000000000000000000000000000000000..85aff6126a61a23cf19457d96c8eb54473f68012 --- /dev/null +++ b/wetb/flex/tests/test_flex_io.py @@ -0,0 +1,27 @@ +''' +Created on 11. apr. 2017 + +@author: mmpe +''' +import os +import unittest +from wetb import flex + + +tfp = os.path.join(os.path.dirname(__file__), 'test_files/') # test file path +class Test(unittest.TestCase): + + + def test_load(self): + time, data, info = flex.load(tfp+"test1/test.int") + self.assertEqual(data.shape, (800,7)) + self.assertEqual(info['attribute_names'][1], "WSP_gl._") + self.assertEqual(info['attribute_units'][1], "m/s") + self.assertEqual(info['attribute_descriptions'][1], " Free wind speed Vy, gl. coo, of gl. pos 0.75, 0.00, -40.75") + + self.assertAlmostEqual(data[0, 1], 12.037,3) + + +if __name__ == "__main__": + #import sys;sys.argv = ['', 'Test.testName'] + unittest.main() \ No newline at end of file diff --git a/wetb/flex/tests/test_sensor.py b/wetb/flex/tests/test_sensor.py new file mode 100644 index 0000000000000000000000000000000000000000..3a88479b1d1d014cdd89b48bf4f1f48b444c4a36 --- /dev/null +++ b/wetb/flex/tests/test_sensor.py @@ -0,0 +1,26 @@ +''' +Created on 9. sep. 2016 + +@author: mmpe +''' +import os +import unittest +from wetb.flex import read_sensor_info + + +tfp = os.path.join(os.path.dirname(__file__), 'test_files/') # test file path +class Test(unittest.TestCase): + + + def test_sensor_load(self): + sensor_info = read_sensor_info(tfp + "test_sensor_info/sensor") + nr, name, unit, description, _, _ = sensor_info[17] + self.assertEqual(nr, 18) + self.assertEqual(name, "Mz coo: ") + self.assertEqual(unit, "kNm") + self.assertEqual(description, "MomentMz Mbdy:tower nodenr: 1 coo: tower tower base flange") + + +if __name__ == "__main__": + #import sys;sys.argv = ['', 'Test.test_sensor_load'] + unittest.main()