atmospheric_lidar/licel_depol.py

Thu, 02 Mar 2017 10:20:58 +0200

author
Iannis <ulalume3@yahoo.com>
date
Thu, 02 Mar 2017 10:20:58 +0200
changeset 69
e5e561439b27
parent 63
ed4ae866a95a
child 70
c667d81dd268
permissions
-rw-r--r--

Use id.

binietoglou@38 1 import datetime
binietoglou@38 2
binietoglou@38 3 import numpy as np
binietoglou@38 4
binietoglou@38 5 from licel import LicelLidarMeasurement
binietoglou@38 6
binietoglou@38 7
binietoglou@38 8 class LicelCalibrationMeasurement(LicelLidarMeasurement):
binietoglou@38 9
ulalume3@69 10 def __init__(self, plus45_files=None, minus45_files=None, use_id_as_name=False):
binietoglou@38 11 # Setup the empty class
ulalume3@69 12 super(LicelCalibrationMeasurement, self).__init__(use_id_as_name=use_id_as_name)
binietoglou@38 13
binietoglou@38 14 self.plus45_files = plus45_files
binietoglou@38 15 self.minus45_files = minus45_files
binietoglou@38 16
ulalume3@69 17 if plus45_files and minus45_files:
binietoglou@38 18 self.check_equal_length()
binietoglou@38 19
binietoglou@38 20 self.read_channel_data()
binietoglou@38 21 self.update()
binietoglou@38 22
binietoglou@38 23 def update(self):
binietoglou@38 24 """ Correct timescales after each update.
binietoglou@38 25 """
binietoglou@38 26 super(LicelCalibrationMeasurement, self).update()
binietoglou@38 27 self.correct_timescales()
binietoglou@38 28
binietoglou@38 29 def check_equal_length(self):
binietoglou@38 30 """
binietoglou@38 31 Check if input time series have equal lengths.
binietoglou@38 32 """
binietoglou@38 33 len_plus = len(self.plus45_files)
binietoglou@38 34 len_minus = len(self.minus45_files)
binietoglou@38 35 if len_plus != len_minus:
binietoglou@38 36 raise self.UnequalMeasurementLengthError(
binietoglou@38 37 "Input timeseries have different length: %s vs %s." % (len_plus, len_minus))
binietoglou@38 38
binietoglou@38 39 def read_channel_data(self):
binietoglou@38 40
binietoglou@38 41 # Read plus and minus 45 measurements
binietoglou@38 42 self.plus45_measurement = LicelLidarMeasurement(self.plus45_files)
binietoglou@38 43 self.plus45_measurement.rename_channel(suffix='_p45')
binietoglou@38 44
binietoglou@38 45 self.minus45_measurement = LicelLidarMeasurement(self.minus45_files)
binietoglou@38 46 self.minus45_measurement.rename_channel(suffix='_m45')
binietoglou@38 47
binietoglou@38 48 # Combine them in this object
binietoglou@38 49 self.channels = {}
binietoglou@38 50 self.channels.update(self.plus45_measurement.channels)
binietoglou@38 51 self.channels.update(self.minus45_measurement.channels)
binietoglou@38 52
binietoglou@38 53 def correct_timescales(self):
binietoglou@38 54 self.check_timescales_are_two()
binietoglou@38 55 self.combine_scales()
binietoglou@38 56
binietoglou@38 57 def check_timescales_are_two(self):
binietoglou@38 58 no_timescales = len(self.variables['Raw_Data_Start_Time'])
binietoglou@38 59 if no_timescales != 2:
binietoglou@38 60 raise self.WrongNumberOfTimescalesError("Wrong number of timescales: %s instead of 2." % no_timescales)
binietoglou@38 61
binietoglou@38 62 def combine_scales(self):
binietoglou@38 63 start_times, end_times = self.get_ordered_timescales()
binietoglou@38 64 new_start_time = start_times[0]
binietoglou@38 65 new_stop_time = end_times[1]
binietoglou@38 66 self.variables['Raw_Data_Start_Time'] = [new_start_time, ]
binietoglou@38 67 self.variables['Raw_Data_Stop_Time'] = [new_stop_time, ]
binietoglou@38 68 self.reset_timescale_id()
binietoglou@38 69
binietoglou@38 70 def reset_timescale_id(self):
binietoglou@38 71 """
binietoglou@38 72 Set all timescales to 0
binietoglou@38 73 :return:
binietoglou@38 74 """
binietoglou@38 75 timescale_dict = self.variables['id_timescale']
binietoglou@38 76 self.variables['id_timescale'] = dict.fromkeys(timescale_dict, 0)
binietoglou@38 77
binietoglou@38 78 def get_ordered_timescales(self):
binietoglou@38 79 scale_start_1, scale_start_2 = self.variables['Raw_Data_Start_Time']
binietoglou@38 80 scale_end_1, scale_end_2 = self.variables['Raw_Data_Stop_Time']
binietoglou@38 81
binietoglou@38 82 if scale_start_1[0] > scale_start_2[0]:
binietoglou@38 83 scale_start_1, scale_start_2 = scale_start_2, scale_start_1
binietoglou@38 84
binietoglou@38 85 if scale_end_1[0] > scale_end_2[0]:
binietoglou@38 86 scale_end_1, scale_end_2 = scale_end_2, scale_end_1
binietoglou@38 87
binietoglou@38 88 return (scale_start_1, scale_start_2), (scale_end_1, scale_end_2)
binietoglou@38 89
binietoglou@38 90 def add_fake_measurements(self, no_profiles, variation=0.1):
binietoglou@38 91 """
binietoglou@38 92 Add a number of fake measurements. This is done to allow testing with single analog profiles.
binietoglou@38 93
binietoglou@38 94 Adds a predefined variation in each new profile.
binietoglou@38 95 """
binietoglou@38 96 duration = self.info['duration']
binietoglou@38 97 for channel_name, channel in self.channels.items():
binietoglou@38 98 base_time = channel.data.keys()[0]
binietoglou@38 99 base_data = channel.data[base_time]
binietoglou@38 100
binietoglou@38 101 for n in range(no_profiles):
binietoglou@38 102 random_variation = base_data * (np.random.rand(len(base_data)) * 2 - 1) * variation
binietoglou@38 103
binietoglou@38 104 new_time = base_time + n * duration
binietoglou@38 105 new_data = channel.data[base_time].copy() + random_variation
binietoglou@38 106 if 'ph' in channel_name:
binietoglou@38 107 new_data = new_data.astype('int')
binietoglou@38 108 channel.data[new_time] = new_data
binietoglou@38 109
binietoglou@38 110 self.update()
binietoglou@38 111
binietoglou@38 112 def subset_photoncounting(self):
binietoglou@38 113 """
binietoglou@38 114 Subset photoncounting channels.
binietoglou@38 115 """
binietoglou@38 116 ph_channels = [channel for channel in self.channels.keys() if 'ph' in channel]
binietoglou@38 117 new_measurement = self.subset_by_channels(ph_channels)
binietoglou@38 118 return new_measurement
binietoglou@38 119
binietoglou@43 120 def _get_scc_channel_variables(self):
binietoglou@43 121 """
binietoglou@43 122 Get a list of variables to put in the SCC.
binietoglou@43 123
binietoglou@43 124 It can be overridden e.g. in the depolarization product class.
binietoglou@43 125
binietoglou@43 126 Returns
binietoglou@43 127 -------
binietoglou@43 128
binietoglou@43 129 channel_variables: dict
binietoglou@43 130 A dictionary with channel variable specifications.
binietoglou@43 131 """
binietoglou@43 132 channel_variables = \
binietoglou@43 133 {'channel_ID': (('channels',), 'i'),
binietoglou@43 134 'Background_Low': (('channels',), 'd'),
binietoglou@43 135 'Background_High': (('channels',), 'd'),
binietoglou@43 136 'LR_Input': (('channels',), 'i'),
binietoglou@43 137 'DAQ_Range': (('channels',), 'd'),
binietoglou@43 138 'Pol_Calib_Range_Min': (('channels',), 'd'),
binietoglou@43 139 'Pol_Calib_Range_Max': (('channels',), 'd'),
binietoglou@43 140 }
binietoglou@43 141 return channel_variables
binietoglou@43 142
binietoglou@38 143 class UnequalMeasurementLengthError(RuntimeError):
binietoglou@38 144 """ Raised when the plus and minus files have different length.
binietoglou@38 145 """
binietoglou@38 146 pass
binietoglou@38 147
binietoglou@38 148 class WrongNumberOfTimescalesError(RuntimeError):
binietoglou@38 149 """ Raised when timescales are not two.
binietoglou@38 150 """
binietoglou@38 151 pass

mercurial