Updates to raymetrics reading routines.

Mon, 26 Feb 2018 18:08:00 +0200

author
Iannis <i.binietoglou@impworks.gr>
date
Mon, 26 Feb 2018 18:08:00 +0200
changeset 129
6f902a45b83d
parent 128
168da625489b
child 130
24e450fdd25c

Updates to raymetrics reading routines.

atmospheric_lidar/generic.py file | annotate | diff | comparison | revisions
atmospheric_lidar/licel.py file | annotate | diff | comparison | revisions
atmospheric_lidar/raymetrics.py file | annotate | diff | comparison | revisions
--- a/atmospheric_lidar/generic.py	Fri Feb 23 14:45:36 2018 +0200
+++ b/atmospheric_lidar/generic.py	Mon Feb 26 18:08:00 2018 +0200
@@ -651,7 +651,7 @@
         return []
 
 
-class LidarChannel:
+class LidarChannel(object):
     """ 
     This class represents a general measurement channel, independent of the input files.
 
--- a/atmospheric_lidar/licel.py	Fri Feb 23 14:45:36 2018 +0200
+++ b/atmospheric_lidar/licel.py	Mon Feb 26 18:08:00 2018 +0200
@@ -36,21 +36,21 @@
         self.duration = duration
         self.use_id_as_name = use_id_as_name
         self.adcbits = int(raw_info['ADCbits'])
-        self.active = int(raw_info['Active'])
-        self.analog_photon = raw_info['AnalogPhoton']
-        self.bin_width = float(raw_info['BinW'])
-        self.data_points = int(raw_info['DataPoints'])
+        self.active = int(raw_info['active'])
+        self.analog_photon = raw_info['analog_photon']
+        self.bin_width = float(raw_info['bin_width'])
+        self.data_points = int(raw_info['number_of_datapoints'])
 
         self.hv = float(raw_info['HV'])
         self.id = raw_info['ID']
-        self.laser_user = int(raw_info['LaserUsed'])
-        self.number_of_shots = int(raw_info['NShots'])
-        self.wavelength_str = raw_info['Wavelength']
+        self.laser_used = int(raw_info['laser_used'])
+        self.number_of_shots = int(raw_info['number_of_shots'])
+        self.wavelength_str = raw_info['wavelength']
 
         if self.is_analog:
-            self.discriminator = float(raw_info['Discriminator']) * 1000  # Analog range in mV
+            self.discriminator = float(raw_info['discriminator']) * 1000  # Analog range in mV
         else:
-            self.discriminator = float(raw_info['Discriminator'])
+            self.discriminator = float(raw_info['discriminator'])
 
     @property
     def wavelength(self):
@@ -112,9 +112,9 @@
         data = self.raw_data
 
         norm = data / float(self.number_of_shots)
-        dz = float(self.raw_info['BinW'])
+        dz = self.bin_width
 
-        if self.raw_info['AnalogPhoton'] == '0':
+        if self.is_analog:
             # If the channel is in analog mode
             ADCrange = self.discriminator  # Discriminator value already in mV
             channel_data = norm * ADCrange / ((2 ** self.adcbits) - 1)  # TODO: Check this. Agrees with Licel docs, but differs from their LabView code.
@@ -142,14 +142,14 @@
         return self.analog_photon == '0'
 
 
-class LicelFile:
+class LicelFile(object):
     """ A class representing a single binary Licel file. """
 
-    licel_file_header_format = ['Filename',
-                                'StartDate StartTime EndDate EndTime Altitude Longtitude Latitude ZenithAngle',
+    licel_file_header_format = ['filename',
+                                'start_date start_time end_date end_time altitude longitude latitude zenith_angle',
                                 # Appart from Site that is read manually
-                                'LS1 Rate1 LS2 Rate2 DataSets', ]
-    licel_file_channel_format = 'Active AnalogPhoton LaserUsed DataPoints 1 HV BinW Wavelength d1 d2 d3 d4 ADCbits NShots Discriminator ID'
+                                'LS1 rate_1 LS2 rate_2 number_of_datasets', ]
+    licel_file_channel_format = 'active analog_photon laser_used number_of_datapoints 1 HV bin_width wavelength d1 d2 d3 d4 ADCbits number_of_shots discriminator ID'
 
     file_channel_class = LicelFileChannel
 
@@ -182,7 +182,7 @@
             channel.calculate_physical()
 
     def _import_file(self, file_path):
-        """ Read the content of the Licel file.
+        """ Read the header info and data of the Licel file.
 
         Parameters
         ----------
@@ -200,7 +200,7 @@
 
             # Import the data
             for current_channel_info in self.channel_info:
-                raw_data = np.fromfile(f, 'i4', int(current_channel_info['DataPoints']))
+                raw_data = np.fromfile(f, 'i4', int(current_channel_info['number_of_datapoints']))
                 a = np.fromfile(f, 'b', 1)
                 b = np.fromfile(f, 'b', 1)
 
@@ -239,8 +239,8 @@
         raw_info.update(self._read_rest_of_header(f))
 
         # Update the object properties based on the raw info
-        start_string = '%s %s' % (raw_info['StartDate'], raw_info['StartTime'])
-        stop_string = '%s %s' % (raw_info['EndDate'], raw_info['EndTime'])
+        start_string = '%s %s' % (raw_info['start_date'], raw_info['start_time'])
+        stop_string = '%s %s' % (raw_info['end_date'], raw_info['end_time'])
         date_format = '%d/%m/%Y %H:%M:%S'
 
         try:
@@ -257,16 +257,26 @@
         self.start_time = local_start_time.astimezone(pytz.utc)
         self.stop_time = local_stop_time.astimezone(pytz.utc)
 
-        self.latitude = float(raw_info['Latitude'])
-        self.longitude = float(raw_info['Longtitude'])
+        self.latitude = float(raw_info['latitude'])
+        self.longitude = float(raw_info['longitude'])
 
         # Read the rest of the header.
-        for c1 in range(int(raw_info['DataSets'])):
+        for c1 in range(int(raw_info['number_of_datasets'])):
             channel_info.append(self.match_lines(f.readline(), self.licel_file_channel_format))
 
         self.raw_info = raw_info
         self.channel_info = channel_info
 
+        self._assign_properties()
+
+    def _assign_properties(self):
+        """ Assign properties from the raw_info dictionary. """
+        self.number_of_datasets = int(self.raw_info['number_of_datasets'])
+        self.altitude = float(self.raw_info['altitude'])
+        self.longitude = float(self.raw_info['longitude'])
+        self.latitude = float(self.raw_info['latitude'])
+        self.zenith_angle = float(self.raw_info['zenith_angle'])
+
     def _read_second_header_line(self, f):
         """ Read the second line of a licel file. """
         raw_info = {}
@@ -280,7 +290,7 @@
 
         site_name = second_line.split('/')[0][:-2]
         clean_site_name = site_name.strip()
-        raw_info['Site'] = clean_site_name
+        raw_info['site'] = clean_site_name
 
         raw_info.update(self.match_lines(second_line[len(clean_site_name) + 1:], self.licel_file_header_format[1]))
         return raw_info
@@ -309,9 +319,10 @@
         list2 = f2.split()
 
         if len(list1) != len(list2):
-            logging.debug("Channel parameter list has different length from licel specifications.")
+            logging.debug("Channel parameter list has different length from LICEL specifications.")
             logging.debug("List 1: %s" % list1)
             logging.debug("List 2: %s" % list2)
+
         combined = zip(list2, list1)
         combined = dict(combined)
         return combined
@@ -358,8 +369,7 @@
         self._assign_unique_property('points', file_channel.data_points)
         self._assign_unique_property('adcbits', file_channel.adcbits)
         self._assign_unique_property('active', file_channel.active)
-        self._assign_unique_property('laser_user', file_channel.laser_user)
-        self._assign_unique_property('adcbints', file_channel.adcbits)
+        self._assign_unique_property('laser_used', file_channel.laser_used)
         self._assign_unique_property('analog_photon_string', file_channel.analog_photon_string)
 
     def _assign_unique_property(self, property_name, value):
--- a/atmospheric_lidar/raymetrics.py	Fri Feb 23 14:45:36 2018 +0200
+++ b/atmospheric_lidar/raymetrics.py	Mon Feb 26 18:08:00 2018 +0200
@@ -2,6 +2,7 @@
 import datetime
 import logging
 
+import numpy as np
 import pytz
 
 from .licel import LicelFile, LicelLidarMeasurement, LicelChannel
@@ -31,12 +32,12 @@
 
 
 class ScanningFile(LicelFile):
-    licel_file_header_format = ['Filename',
-                                'StartDate StartTime EndDate EndTime Altitude Longtitude Latitude ZenithAngle Temperature Pressure', # Appart from Site that is read manually
-                                'azimuth_start azimuth_finish azimuth_step zenith_start zenith_finish zenith_step azimuth_offset',
-                                'LS1 Rate1 LS2 Rate2 DataSets', ]
-    licel_file_channel_format = 'Active AnalogPhoton LaserUsed DataPoints 1 HV BinW Wavelength d1 d2 d3 d4 ADCbits NShots Discriminator ID'
-
+    licel_file_header_format = ['filename',
+                                'start_date start_time end_date end_time altitude longitude latitude zenith_angle azimuth_angle temperature pressure',
+                                # Appart from Site that is read manually
+                                'azimuth_start azimuth_stop azimuth_step zenith_start zenith_finish zenith_step azimuth_offset',
+                                'LS1 rate_1 LS2 rate_2 number_of_datasets', ]
+    licel_file_channel_format = 'active analog_photon laser_used number_of_datapoints 1 HV bin_width wavelength d1 d2 d3 d4 ADCbits number_of_shots discriminator ID'
 
     def _read_rest_of_header(self, f):
         """ Read the rest of the header lines, after line 2. """
@@ -49,6 +50,33 @@
         raw_info.update(self.match_lines(fourth_line, self.licel_file_header_format[3]))
         return raw_info
 
+    def _assign_properties(self):
+        super(ScanningFile, self)._assign_properties()
+        self.azimuth_angle = float(self.raw_info['altitude'])
+        self.temperature = float(self.raw_info['temperature'])
+        self.pressure = float(self.raw_info['pressure'])
+        self.azimuth_start = float(self.raw_info['azimuth_start'])
+        self.azimuth_stop = float(self.raw_info['azimuth_stop'])
+        self.azimuth_step = float(self.raw_info['azimuth_step'])
+        self.zenith_start = float(self.raw_info['zenith_start'])
+        self.zenith_finish = float(self.raw_info['zenith_finish'])
+        self.zenith_step = float(self.raw_info['zenith_step'])
+        self.azimuth_offset = float(self.raw_info['azimuth_offset'])
+
+
+class ScanningChannel(LicelChannel):
+
+    def __init__(self):
+        self.azimuth_start = None
+        self.azimuth_stop = None
+        self.azimuth_step = None
+        self.zenith_start = None
+        self.zenith_finish = None
+        self.zenith_step = None
+        self.azimuth_offset = None
+        super(ScanningChannel, self).__init__()
+
+
 
 class ScanningLidarMeasurement(RaymetricsLidarMeasurement):
     file_class = ScanningFile
@@ -64,6 +92,36 @@
         self._assign_unique_property('wavelength', file_channel.wavelength)
         self._assign_unique_property('adcbits', file_channel.adcbits)
         self._assign_unique_property('active', file_channel.active)
-        self._assign_unique_property('laser_user', file_channel.laser_user)
-        self._assign_unique_property('adcbints', file_channel.adcbits)
-        self._assign_unique_property('analog_photon_string', file_channel.analog_photon_string)
\ No newline at end of file
+        self._assign_unique_property('laser_used', file_channel.laser_used)
+        self._assign_unique_property('adcbits', file_channel.adcbits)
+        self._assign_unique_property('analog_photon_string', file_channel.analog_photon_string)
+
+    # def calculate_physical(self):
+    #     """ Calculate physically-meaningful data from photodiode channels:
+    #
+    #     * In case of analog signals, the data are converted to mV.
+    #     * In case of photon counting signals, data are stored as number of photons.
+    #
+    #     In addition, some ancillary variables are also calculated (z, dz, number_of_bins).
+    #     """
+    #     data = self.raw_data
+    #
+    #     norm = data / float(self.number_of_shots)
+    #     dz = self.bin_width
+    #
+    #     if self.is_analog:
+    #         # If the channel is in analog mode
+    #         ADCrange = self.discriminator  # Discriminator value already in mV
+    #         if self.adcbits == 0:
+    #             logger.warning("Changing adcbits to 1. This is a bug in current licel format.")
+    #             channel_data = norm * ADCrange / ((2 ** self.adcbits) )
+    #         else:
+    #             channel_data = norm * ADCrange / ((2 ** self.adcbits) - 1)
+    #
+    #     else:
+    #         channel_data = norm * self.number_of_shots
+    #
+    #     # Calculate Z
+    #     self.z = np.array([dz * bin_number + dz / 2.0 for bin_number in range(self.data_points)])
+    #     self.dz = dz
+    #     self.data = channel_data
\ No newline at end of file

mercurial