Skip to content

Commit

Permalink
Add support for internal temperature out of calibration range calibra…
Browse files Browse the repository at this point in the history
…tion

   + Accelerate interpolation by using 2d interpolation from scipy
  • Loading branch information
doizuc committed Jul 24, 2020
1 parent daf56f0 commit a60c1c0
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 28 deletions.
2 changes: 1 addition & 1 deletion pyACS/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

__all__ = ['acs']
__version__ = '0.0.1'
__version__ = '0.0.2'
35 changes: 29 additions & 6 deletions pyACS/acs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
from struct import unpack, unpack_from, calcsize
import csv
from sys import version_info, exit
try:
from scipy import interpolate
except ImportError:
SCIPY_IMPORTED = False
else:
SCIPY_IMPORTED = True

# Check Python version running script
if version_info.major != 3:
Expand Down Expand Up @@ -177,7 +183,7 @@ class ACS:

def __init__(self, device_filename=None):
# Meta data
self.serial_number = None
self.serial_number = None # and Meter Type
self.structure_version_number = None
self.baudrate = 115200
self.output_wavelength = None
Expand All @@ -201,6 +207,8 @@ def __init__(self, device_filename=None):
self.t = None
self.delta_t_c = None
self.delta_t_a = None
self.f_delta_t_c = None
self.f_delta_t_a = None

# Unpack frame format
self.frame_core_format = None
Expand Down Expand Up @@ -271,7 +279,13 @@ def read_device_file(self, filename):
self.delta_t_a[iwl, :] = np.array(foo[2].split('\t'))
iwl += 1
# skip lines "ACS Meter", "tcal[...]", and "maxANoise maxCNoise[...]"
# TODO: Add test
if SCIPY_IMPORTED:
# Build 2D interpolation function for speed
self.f_delta_t_c = interpolate.interp1d(self.t, self.delta_t_c, axis=1, assume_sorted=True, copy=False,
bounds_error=False, fill_value=(self.delta_t_c[:,1], self.delta_t_c[:,-1]))
self.f_delta_t_a = interpolate.interp1d(self.t, self.delta_t_a, axis=1, assume_sorted=True, copy=False,
bounds_error=False, fill_value=(self.delta_t_a[:,1], self.delta_t_a[:,-1]))
#TODO: Add test

def set_output_wavelength(self, output_wavelength):
# Change number of wavelength of object
Expand Down Expand Up @@ -396,15 +410,24 @@ def calibrate_frame(self, frame, get_auxiliaries=False):

# Process
internal_temperature_su = compute_internal_temperature(frame.t_int)
delta_t_c = [np.interp(internal_temperature_su, self.t, v) for v in self.delta_t_c]
delta_t_a = [np.interp(internal_temperature_su, self.t, v) for v in self.delta_t_a]
if internal_temperature_su < self.t[0] or self.t[-1] < internal_temperature_su:
flag_outside_T_cal_range = True
else:
flag_outside_T_cal_range = False
if SCIPY_IMPORTED:
delta_t_c = self.f_delta_t_c(internal_temperature_su)
delta_t_a = self.f_delta_t_a(internal_temperature_su)
else:
# Use numpy for interpolation (slower as do every wavelength one by one)
delta_t_c = [np.interp(internal_temperature_su, self.t, v) for v in self.delta_t_c]
delta_t_a = [np.interp(internal_temperature_su, self.t, v) for v in self.delta_t_a]
c = (self.offset_c - (1 / self.x) * np.log(frame.c_sig / frame.c_ref)) - delta_t_c
a = (self.offset_a - (1 / self.x) * np.log(frame.a_sig / frame.a_ref)) - delta_t_a
if get_auxiliaries:
external_temperature_su = compute_external_temperature(frame.t_ext)
return c, a, internal_temperature_su, external_temperature_su
return c, a, internal_temperature_su, external_temperature_su, flag_outside_T_cal_range
else:
return c, a
return c, a, flag_outside_T_cal_range

# if __name__ == '__main__':

Expand Down
58 changes: 37 additions & 21 deletions pyACS/test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unittest
from struct import unpack
import numpy as np
from scipy import interpolate

TEST_FRAME = b'\x53\xd0\x03\x01\x53\x00\x00\x02\x4e\x1e\x01\xba\x21\x29\x35\xff\
\x00\xff\x00\x02\xd0\x05\x01\x53\x00\x00\x02\x4e\x1a\x01\xba\x02\
Expand Down Expand Up @@ -129,29 +130,29 @@ def test_acs_calibrate_math(self):

def test_acs_calibrate_frame(self):
# Same as method test_acs_calibrate_math but use acs.calibrate_frame with 3 wavelength
from pyACS.acs import ACS, FrameContainer
from pyACS import acs as pa
# Define Frame
counts = unpack('!HHHH', b'\x04\x05\x03\x63\x04\xf4\x03\x10')
frame = FrameContainer(serial_number='0x5300012A', # acs 298
output_wavelength=3,
# t_int=unpack('!H', b'\xb9\xd7')[0], # 17.91 Issue with temperature in wetview doc
t_int=42969, # 42969=27.931 ou 42970=27.929
c_ref=counts[0],
a_ref=np.array([counts[1],counts[1],counts[1]], dtype=np.uint16),
c_sig=counts[2],
a_sig=np.array([counts[3],counts[3],counts[3]], dtype=np.uint16),
frame_len=np.NaN, # packet length
frame_type=np.NaN, # Packet type identifier
a_ref_dark=np.NaN, # A reference dark counts (for diagnostic purpose)
p=np.NaN, # A/D counts from the pressure sensor circuitry
a_sig_dark=np.NaN, # A signal dark counts (for diagnostic purpose)
t_ext=np.NaN, # External temperature voltage counts
c_ref_dark=np.NaN, # C reference dark counts
c_sig_dark=np.NaN, # C signal dark counts
time_stamp=np.NaN # unsigned integer: Time stamp (ms)
)
frame = pa.FrameContainer(serial_number='0x5300012A', # acs 298
output_wavelength=3,
# t_int=unpack('!H', b'\xb9\xd7')[0], # 17.91 Issue with temperature in wetview doc
t_int=42969, # 42969=27.931 ou 42970=27.929
c_ref=counts[0],
a_ref=np.array([counts[1],counts[1],counts[1]], dtype=np.uint16),
c_sig=counts[2],
a_sig=np.array([counts[3],counts[3],counts[3]], dtype=np.uint16),
frame_len=np.NaN, # packet length
frame_type=np.NaN, # Packet type identifier
a_ref_dark=np.NaN, # A reference dark counts (for diagnostic purpose)
p=np.NaN, # A/D counts from the pressure sensor circuitry
a_sig_dark=np.NaN, # A signal dark counts (for diagnostic purpose)
t_ext=np.NaN, # External temperature voltage counts
c_ref_dark=np.NaN, # C reference dark counts
c_sig_dark=np.NaN, # C signal dark counts
time_stamp=np.NaN # unsigned integer: Time stamp (ms)
)
# Define ACS
acs = ACS()
acs = pa.ACS()
acs.serial_number = '0x5300012A'
acs.output_wavelength = 3
acs.t = np.array([27.75, 28.2625])
Expand All @@ -164,7 +165,22 @@ def test_acs_calibrate_frame(self):
acs.offset_a = np.array([-0.431,-0.431,-0.431])
acs.x = 0.25

_, a = acs.calibrate_frame(frame)
# Finish init for SciPy runs
acs.f_delta_t_c = interpolate.interp1d(acs.t, acs.delta_t_c, axis=1)
acs.f_delta_t_a = interpolate.interp1d(acs.t, acs.delta_t_a, axis=1)

# Test with SciPy
pa.__dict__['SCIPY_IMPORTED'] = True
_, a, flag_outside_temperature_calibration_range = acs.calibrate_frame(frame)
self.assertEqual(flag_outside_temperature_calibration_range, False)
for i in range(3):
self.assertEqual(a[0], a[i])
self.assertAlmostEqual(float(a[i]), -0.0409, 2)

# Test with numPy
pa.__dict__['SCIPY_IMPORTED'] = False
_, a, flag_outside_temperature_calibration_range = acs.calibrate_frame(frame)
self.assertEqual(flag_outside_temperature_calibration_range, False)
for i in range(3):
self.assertEqual(a[0], a[i])
self.assertAlmostEqual(float(a[i]), -0.0409, 2)
Expand Down

0 comments on commit a60c1c0

Please sign in to comment.