Creating a simulated LIDAR signal#
This page documents SignalCreation.Lidar.Lidar.create_simulated_lidar(), which generates a
theoretical raw LIDAR signal per channel and a slope (log-derivative of PR²) used for diagnostics
and comparison with measurements.
The simulated signal is calibrated on a reference altitude and computed using the currently loaded atmospheric density, ozone climatology, and cross-sections.
Overview#
###########################
# Lidar Signal Simulation #
###########################
lidar.create_simulated_lidar()
This method loops over all LIDAR channels with Signal_Type in [100, 119], collects their
laser and received wavelengths (if available), and builds a simulated raw signal per channel.
Each simulated signal is then calibrated to match the real signal at a given reference altitude.
Finally, a slope is computed by filtering and differentiating \(\ln(P\,R^2)\) (PR²) for the
simulated signals.
Prerequisites#
Raw data imported → Importing LIDAR raw data
Atmospheric fields (density, etc.) imported → Importing atmospheric data
Ozone climatology and ozone/air cross-sections imported → Importing other atmospheric components
Method signature#
def create_simulated_lidar(self) -> None:
"""Create per-channel simulated raw LIDAR signals and their PR² slopes."""
What it does (step by step)#
Select channels with
Signal_Typein the interval 100–119 (uncertainty channels excluded).Read wavelengths from channel attributes (
WAVELENGTH_LASER,WAVELENGTH_RECEIVED) when present.Pick reference altitude (
Simulated_signal/altitude_ref) from XML per Signal_Type.If not provided, it is set automatically and written back to XML:
Elastic (Rayleigh) channels (laser == received): 40 km
Inelastic (Raman / DIAL off-on) channels (laser != received): 25 km
Build simulator (
CreateLidarSignal) using: - altitude grid, ozone number density, ozone cross-sections, - atmospheric density, molecular cross-sections, - the measured channel as calibration reference and the reference altitude.Store outputs: - One ``simulated_raw_lidar_data`` variable per channel (same
Signal_Typein attrs).Compute slopes: - Apply
SignalCreation.Lidar.Lidar.filtering()on simulated signals withuse_pr2=Trueanduse_log=Trueto get ``Simulated_Slope`` variables.
XML configuration#
Reference altitude per channel (optional, recommended):
<Dial>
<Simulated_signal>
<!-- Example: set per-channel reference altitude (km) -->
<altitude_ref units="km" condition_key="Read/Lidar_files/Signal_type" condition_value="100">40</altitude_ref>
<altitude_ref units="km" condition_key="Read/Lidar_files/Signal_type" condition_value="101">25</altitude_ref>
</Simulated_signal>
</Dial>
If not provided, defaults are applied (40 km elastic, 25 km inelastic) and saved back to the XML under the same conditional key/value.
Derivative filtering (used to compute the PR² slope of the simulated signals): the method calls
filtering(..., name_param_tag="Derivative_Filtering", use_pr2=True, use_log=True).
Provide suitable parameters in XML (schema analogous to your filtering config):
<Dial>
<Derivative_Filtering>
<parameters>
<filter_name>Savitzky-Golay</filter_name>
<mode>dial poly</mode>
<ncan1>3,3,4,4,5,5</ncan1>
<ican1>120,120,120,120,60,60</ican1>
<ncan2>35,35,30,30,40,40</ncan2>
<ican2>300,300,300,300,200,200</ican2>
<alt_unit>km</alt_unit>
</parameters>
<resolution_methodology options="df,ir,origin" multiple_option="True">df, ir, origin</resolution_methodology>
</Derivative_Filtering>
</Dial>
Outputs in _lidar (xarray.Dataset)#
For each processed channel:
simulated_raw_lidar_data_*Simulated raw photon-count signal matching the channel, with attributeSignal_Typecopied from the source channel.Simulated_Slope_*Slope of \(\ln(P\,R^2)\) after derivative filtering, used as a diagnostic curve.
Note
The internal dataset ``_lidar`` is an xarray.Dataset.
You can list and plot the simulated variables exactly as for measured ones.
Example usage#
from SignalCreation.Lidar import Lidar
lidar = Lidar("Configuration_files/Parameters/example_station.xml", "2024-03-28")
lidar.import_lidar_data()
lidar.import_atmospheric_component()
lidar.import_other_atmospheric_component("ozone")
# Create simulated signals and slopes
lidar.create_simulated_lidar()
# Inspect a simulated variable
print([v for v in lidar._lidar.data_vars if "simulated_raw_lidar_data" in v])
print([v for v in lidar._lidar.data_vars if "Simulated_Slope" in v])
Notes & best practices#
Signal types: ensure each channel has a valid
Signal_Typein [100–119]. See Signal types (Signal_Type) for definitions.Wavelength metadata: set
WAVELENGTH_LASER/WAVELENGTH_RECEIVEDon channels whenever possible; defaults are handled but explicit metadata improve fidelity.Reference altitude: choose a clean, aerosol-poor layer for calibration. Too low a reference (overlap region) may bias the simulation.
Consistency: the simulator depends on the previously loaded density, ozone, and cross-sections. Make sure these are present and on the same altitude grid.