Some thoughts on DIVA file format parameters.

Fri, 15 Dec 2017 12:58:20 +0200

author
Iannis <ulalume3@yahoo.com>
date
Fri, 15 Dec 2017 12:58:20 +0200
changeset 112
07bb7a219314
parent 111
16b58fb6d5c0
child 113
b5bbfee2a898

Some thoughts on DIVA file format parameters.

atmospheric_lidar/diva.py file | annotate | diff | comparison | revisions
atmospheric_lidar/systems/rali/rali_diva_parameters.yaml file | annotate | diff | comparison | revisions
--- a/atmospheric_lidar/diva.py	Fri Dec 15 08:50:40 2017 +0200
+++ b/atmospheric_lidar/diva.py	Fri Dec 15 12:58:20 2017 +0200
@@ -20,6 +20,7 @@
             parameters = pyyaml.load(f)
 
         global_parameters = parameters['global_parameters']  # Shortcut
+        channels = parameters['channels']
 
         iso_date = datetime.datetime.utcnow().isoformat()
         python_file_name = os.path.basename(__file__)
@@ -39,6 +40,10 @@
             f.history = global_parameters['history'].format(date=iso_date, file=python_file_name)
             f.featureType = "timeSeriesProfile"
 
+            # Top level dimensions
+            f.createDimension('name_strlen', size=40)
+            f.createDimension('nv', size=2)
+
             # Top level variables
             latitude = f.createVariable('latitude', datatype='f4')
             latitude.standard_name = 'latitude'
@@ -55,117 +60,160 @@
             laser_angle.long_name = 'zenith angle of emitted laser'
             laser_angle.units = 'degree'
 
-            laser_angle = f.createVariable('laser_zenith_angle', datatype='f4')
-            laser_angle.long_name = 'zenith angle of emitted laser'
-            laser_angle.units = 'degrees'
+            laser_azimuth = f.createVariable('laser_azimuth_angle', datatype='f4')
+            laser_azimuth.standard_name = 'sensor_azimuth_angle'
+            laser_azimuth.long_name = 'azimuth angle of emitted laser'
+            laser_azimuth.units = 'degree'
+            laser_azimuth.comment = 'Based on North. Optional'
 
             altitude = f.createVariable('altitude', datatype='f4')
             altitude.standard_name = 'altitude'
             altitude.long_name = 'system altitude'
             altitude.units = 'm'
 
+            for channel_name, channel_parameters in channels.iteritems():
 
-            # Create a separate group for each channel
-            f = f.createGroup("channel_532nmP")  # This should be changed to a meaningful channel name
-            f.data_type = self.data_type
+                # Create a separate group for each channel
+                group_name = "channel_{0}".format(channel_name)  # Give channels groups a standard name
+                g = f.createGroup(group_name)
+                g.long_name = channel_parameters['long_name']
+                g.detector_manufacturer = channel_parameters['long_name']    # Optional
+                g.detector_model = channel_parameters['detector_model']
+                g.daq_manufacturer = channel_parameters['daq_manufacturer']
+                g.daq_model = channel_parameters['daq_model']
 
-            f.createDimension('profile', len(self.time))
-            f.createDimension('range', len(self.range))
+                # Dimensions
+                g.createDimension('profile', size=None)  # Infinite dimension
+                g.createDimension('range', len(self.range))
 
-            id = f.createVariable('channel_id', 'i4')
-            id.cf_role = "trajectory_id"
+                # Variables
+                name = g.createVariable('channel_id', dimensions=('name_strlen',))
+                name.cf_role = 'timeseries_id'
+                name.long_name = 'channel identification'
 
-            latitude = f.createVariable('latitude', datatype='f8', dimensions=('profile',), zlib=True)
-            latitude.long_name = 'aircraft GPS latitude'
-            latitude.units = 'degrees_north'
-            latitude.standard_name = 'latitude'
+                laser_rep_rate = g.createVariable('laser_repetition_rate')
+                laser_rep_rate.long_name = 'nominal laser repetition rate'
+                laser_rep_rate.units = 'Hz'
 
-            longitude = f.createVariable('longitude', datatype='f8', dimensions=('profile',), zlib=True)
-            longitude.long_name = 'aircraft GPS longitude'
-            longitude.units = 'degrees_east'
-            longitude.standard_name = 'longitude'
+                emission_energy = g.createVariable('emission_energy', datatype='f8', dimensions=('profile',))
+                emission_energy.long_name = 'emission energy per pulse'
+                emission_energy.units = 'mJ'
+                emission_energy.standard_name = 'radiation_wavelength'
+                emission_energy.comment = "could be scalar, if value is nominal."
 
-            altitude = f.createVariable('altitude', datatype='f4', dimensions=('profile',), zlib=True)
-            altitude.long_name = 'aircraft GPS altitude'
-            altitude.units = 'm'
-            altitude.standard_name = 'altitude'
+                emission_pol = g.createVariable('emission_polarization', datatype='b')
+                emission_pol.long_name = 'nominal emission poalrization'
+                emission_pol.flag_values = '0b 1b 2b'
+                emission_pol.flag_meanings = 'linear circular none'
 
-            time = f.createVariable('time', datatype='f8', dimensions=('profile',),
-                                    zlib=True)
-            time.long_name = 'starting time of record'
-            time.units = "seconds since 1970-01-01 00:00:00"
-            time.standard_name = "time"
+                fov = g.createVariable('fov', datatype='f4')
+                fov.long_name = 'channel field of view full angle'
+                fov.units = 'mrad'
+                fov.comment = 'simulated'
+
+                detector_type = g.createVariable('detector_type', datatype='b')
+                detector_type.long_name = 'detector type'
+                detector_type.flag_values = '0b 1b'
+                detector_type.flag_meanings = 'PMT APD'
 
-            bin_range = f.createVariable('range', datatype='f4', dimensions=('range',),
-                                         zlib=True)  # Use name 'bin_range' to avoid conflict with built-in range
-            bin_range.long_name = 'range from instrument'
-            bin_range.units = "m"
-            bin_range.positive = "down"
-            bin_range.axis = 'Z'  # This is strictly not correct, as it does not correspond to geophysical variable. Still it can be usefull for quick plotting.
+                detection_mode = g.createVariable('detection_mode', datatype='b')
+                detection_mode.long_name = 'detection mode'
+                detection_mode.flag_values = '0b 1b'
+                detection_mode.flag_meanings = 'analog photon_counting'
+
+                detection_cw = g.createVariable('detection_wavelength', datatype='f8')
+                detection_cw.long_name = 'center wavelength of detection filters'
+                detection_cw.units = 'nm'
+                detection_cw.standard_name = 'sensor_band_central_radiation_wavelength'
 
-            pitch = f.createVariable('pitch', datatype='f4', dimensions=('profile',), zlib=True)
-            pitch.long_name = 'aircraft pitch'
-            pitch.units = 'degree'
-            pitch.standard_name = 'platform_pitch_angle'
-            pitch.coordinates = "time longitude latitude"
+                detection_fwhm = g.createVariable('detection_fwhm', datatype='f8')
+                detection_fwhm.long_name = 'FWHM of detection filters'
+                detection_fwhm.units = 'nm'
 
-            roll = f.createVariable('roll', datatype='f4', dimensions=('profile',), zlib=True)
-            roll.long_name = 'aircraft roll'
-            roll.units = 'degree'
-            roll.standard_name = 'platform_roll_angle'
-            roll.coordinates = "time longitude latitude"
+                detection_pol = g.createVariable('detection_polarization', datatype='b')
+                detection_pol.long_name = 'nominal detection poalrization'
+                detection_pol.flag_values = '0b 1b 2b'
+                detection_pol.flag_meanings = 'linear circular none'
+
+                polarizer_angle = g.createVariable('polarizer_angle', datatype='f4', dimensions=('profile', ), zlib=True)
+                polarizer_angle.long_name = 'polarizer angle in respect to laser plane of polarization'
+                polarizer_angle.units = 'degree'
+                polarizer_angle.comments = 'Optional'
 
-            heading = f.createVariable('heading', datatype='f4', dimensions=('profile',), zlib=True)
-            heading.long_name = 'aircraft heading'
-            heading.units = 'degree'
-            heading.standard_name = 'platform_course'
-            heading.coordinates = "time longitude latitude"
+                dead_time_model = g.createVariable('dead_time_model', datatype='b')
+                dead_time_model.long_name = 'optimal dead time model of detection system'
+                dead_time_model.flag_values = '0b 1b 2b'
+                dead_time_model.flag_meanings = 'paralyzable non_paralyzable other'
 
-            hv = f.createVariable('hv', datatype='f4', dimensions=('profile',), zlib=True)
-            hv.long_name = 'detector high voltage'
-            hv.units = 'V'
-            hv.coordinates = "time longitude latitude"
+                dead_time = g.createVariable('dead_time', datatype='f8')
+                dead_time.long_name = 'dead time value'
+                dead_time.units = 'ns'
+                dead_time.comment = "Manufacturer. Source of the value."
+
+                bin_length = g.createVariable('bin_length', datatype='f4')
+                bin_length.long_name = "time duration of each bin"
+                bin_length.units = 'ns'
+
+                detector_voltage = g.createVariable('detector_voltage', datatype='f4', dimensions=('profile',), zlib=True)
+                detector_voltage.long_name = 'detector voltage'
+                detector_voltage.units = 'V'
+                detector_voltage.coordinates = "time"
 
-            averaging_time = f.createVariable('averaging_time', datatype='f4', dimensions=('profile',), zlib=True)
-            averaging_time.long_name = 'averaging time'
-            averaging_time.units = 's'
-            averaging_time.coordinates = "time longitude latitude"
+                discriminator = g.createVariable('discriminator', datatype='f8', dimensions=('profiles',))
+                discriminator.long_name = 'discriminator level'
+                discriminator.units = ''
+
+                adc_range = g.createVariable('adc_range', datatype='f4', dimensions=('profile',),
+                                                    zlib=True)
+                adc_range.long_name = 'analog-to-digital converter range'
+                adc_range.units = 'mV'
+                adc_range.coordinates = "time"
 
-            emission_wl = f.createVariable('emission_wavelength', datatype='f8', dimensions=('profile',),
-                                           zlib=True)
-            emission_wl.long_name = 'emission wavelength in vacuum'
-            emission_wl.units = 'nm'
-            emission_wl.standard_name = 'radiation_wavelength'
-            emission_wl.coordinates = "time longitude latitude"
+                adc_bits = g.createVariable('adc_bits', datatype='i4', dimensions=('profile',),
+                                             zlib=True)
+                adc_bits.long_name = 'analog-to-digital converter bits'
+                adc_bits.coordinates = "time"
+
+                pulses = g.createVariable('pulses', datatype='i4', dimensions=('profile',),
+                                          zlib=True)
+                pulses.long_name = 'accumulated laser pulses per record'
+                pulses.coordinates = "time"
 
-            pulses = f.createVariable('pulses', datatype='i4', dimensions=('profile',),
-                                      zlib=True)
-            pulses.long_name = 'laser pulses per record'
-            pulses.coordinates = "time longitude latitude"
+                nd_filter = g.createVariable('nd_filter_od', datatype='f8', dimensions=('profile',))
+                nd_filter.long_name = "neutral density filter optical depth "
+                nd_filter.coordinates = "time"
 
-            signal = f.createVariable('signal', datatype='i4', dimensions=('profile', 'range'),
-                                      zlib=True)
-            signal.long_name = 'signal'
-            signal.units = "counts"
-            signal.missing_value = -1
-            signal.coordinates = "time longitude latitude range"
+                emission_delay = g.createVariable('emission_delay', datatype='f4')
+                emission_delay.long_name = "pulse emission difference from channel trigger"
+                emission_delay.units = 'ns'
+                emission_delay.comments = 'Positive values for pre-trigger systems. Negative for trigger delay.'
 
-            # Assign channel attributes
-            f.channel_name = 'L_532nmP'
+                time = g.createVariable('time', datatype='f8', dimensions=('profile',),
+                                        zlib=True)
+                time.long_name = 'profile start time '
+                time.units = "seconds since 1970-01-01 00:00:00"
+                time.standard_name = "time"
+                time.bounds = "time_bnds"
+                g.createVariable('time_bnds', datatype='f8', dimensions=('profile', 'nv'), zlib=True)
 
-            # Assign variables
-            id[:] = 1
-            latitude[:] = self.latitude[:]
-            longitude[:] = self.longitude[:]
-            altitude[:] = self.gps_altitude[:]
-            pitch[:] = self.pitch[:]
-            roll[:] = self.roll[:]
-            heading[:] = self.heading_angle[:]
-            hv[:] = self.high_voltage[:]
-            averaging_time[:] = self.averaging_time[:]
-            emission_wl[:] = self.emission_wavelength_vacuum[:]
-            pulses[:] = self.pulses[:]
-            time[:] = self.time[:]
-            bin_range[:] = self.range[:]
-            signal[:] = self.signal[:]
+                bin_time = g.createVariable('bin_time', datatype='f4', dimensions=('range',),
+                                             zlib=True)  # Use name 'bin_range' to avoid conflict with built-in range
+                bin_time.long_name = 'bin start time since trigger'
+                bin_time.units = "ns"
 
+                signal = g.createVariable('signal', datatype='i4', dimensions=('profile', 'range'),
+                                          zlib=True)
+                signal.long_name = 'signal'
+                signal.units = channel_parameters['signal_units']
+                signal.coordinates = "time"
+                signal.ancillary_variables = "signal_stddev"
+
+                # If measured
+                signal_stddev = g.createVariable('signal', datatype='i4', dimensions=('profile', 'range'),
+                                          zlib=True)
+                signal_stddev.long_name = 'signal standard deviation'
+                signal_stddev.units = channel_parameters['signal_units']
+                signal_stddev.coordinates = "time"
+
+                # Assign variables
+                # TBD
\ No newline at end of file
--- a/atmospheric_lidar/systems/rali/rali_diva_parameters.yaml	Fri Dec 15 08:50:40 2017 +0200
+++ b/atmospheric_lidar/systems/rali/rali_diva_parameters.yaml	Fri Dec 15 12:58:20 2017 +0200
@@ -4,10 +4,10 @@
   institution: INOE, Bucharest, Romania
   references: Nemuc, A. et al, Atmos. Meas. Tech. 6, 3243–3255, 2013.
   Conventions: CF-1.7
-  comment: "Test file"
+  comment: Test file
   location: Magurele, Bucharest, Romania
   data_version: 1.0
-  history: "{date} {file} Data file created\n"
+  history: "{date} {file} Data file created.\n"
 global_variables:
   laser_pointing_angle: 0
   latitude: 44.348
@@ -15,7 +15,26 @@
   system_altitude: 93.0
 channels:
   01064.o_an:
-    Laser_Shots: 3000
-    DAQ_Range: 100.0
-
-
+    long_name: elastic signal
+    detector_type: APD
+    detection_mode: analog              # analog or photon-counting
+    detector_manufacturer: Hamamatsu    # Optional
+    detector_model: ABC                 # Optional
+    daq_manufacturer: Licel             # Optional
+    daq_model: -                        # Optional
+    bin_length: 50                      # ns
+    pulse_delay: 5000                   # ns
+    laser_repetition_rate: 10           # Hz
+    signal_units: mV                    # counts or mV
+    emission_wavelength: 1064.01        # nm    
+    emission_polarization: linear       # linear, circular, or none
+    filter_cw: 1064.01                  # nm
+    filter_fwhm: 1.                     # nm
+    fov: 2.4                            # mrad full angle
+    detection_polarization: linear      # linear, circular, or none
+    polarizer_angle: 0.                 # polarization angle in case of linear polarization
+    dead_time_model: paralyzable        # paralyzable, non-paralyzable, or other
+    dead_time: 3.8                      # ns 
+  00532.p_ph:
+    discriminator: 10                   # discriminator level
+       

mercurial