piel.experimental
=================

.. py:module:: piel.experimental


Submodules
----------

.. toctree::
   :maxdepth: 1

   /autoapi/piel/experimental/analysis/index
   /autoapi/piel/experimental/configuration/index
   /autoapi/piel/experimental/devices/index
   /autoapi/piel/experimental/file_system/index
   /autoapi/piel/experimental/measurements/index
   /autoapi/piel/experimental/models/index
   /autoapi/piel/experimental/report/index
   /autoapi/piel/experimental/text/index
   /autoapi/piel/experimental/types/index


Attributes
----------

.. autoapisummary::

   piel.experimental.configuration_to_measurement_map
   piel.experimental.measurement_composition_method_mapping


Functions
---------

.. autoapisummary::

   piel.experimental.create_experiment_data_collection_from_unique_parameters
   piel.experimental.experiment_data_from_parameter_subset
   piel.experimental.compose_xarray_dataset_from_experiment_data
   piel.experimental.construct_experiment_directories
   piel.experimental.construct_experiment_structure
   piel.experimental.construct_multimeter_sweep_signal_from_csv
   piel.experimental.construct_sourcemeter_sweep_signal_from_csv
   piel.experimental.construct_multimeter_sweep_signal_from_dataframe
   piel.experimental.construct_sourcemeter_sweep_signal_from_dataframe
   piel.experimental.extract_signal_data_from_csv
   piel.experimental.extract_signal_data_from_dataframe
   piel.experimental.extract_dc_sweeps_from_operating_point_csv
   piel.experimental.extract_dc_sweep_experiment_data_from_csv
   piel.experimental.extract_dc_metrics_from_experiment_data
   piel.experimental.extract_electro_optic_dc_path_transmission_from_csv
   piel.experimental.extract_electro_optic_dc_network_from_measurement_collection
   piel.experimental.extract_propagation_delay_data_from_measurement
   piel.experimental.extract_s_parameter_data_from_vna_measurement
   piel.experimental.extract_power_sweep_data_from_vna_measurement
   piel.experimental.extract_power_sweep_s2p_to_network_transmission
   piel.experimental.extract_power_sweep_s2p_to_dataframe
   piel.experimental.convert_row_to_sdict
   piel.experimental.extract_data_from_measurement_collection
   piel.experimental.extract_data_from_experiment
   piel.experimental.load_experiment_data_from_directory
   piel.experimental.compose_measurement_from_experiment_instance
   piel.experimental.compose_measurement_collection_from_experiment
   piel.experimental.compose_vna_s_parameter_measurement
   piel.experimental.compose_propagation_delay_measurement
   piel.experimental.compose_oscilloscope_measurement
   piel.experimental.create_report
   piel.experimental.create_report_from_experiment_directory
   piel.experimental.create_plots_from_experiment_data
   piel.experimental.create_plots_from_experiment_directory
   piel.experimental.write_schema_markdown
   piel.experimental.write_experiment_top_markdown


Package Contents
----------------

.. py:function:: create_experiment_data_collection_from_unique_parameters(experiment_data: piel.types.experimental.ExperimentData) -> piel.types.experimental.ExperimentDataCollection

   Each individual raw ``ExperimentData`` can contain multiple operating points or unique parameters which are being
   tested. It can be handy to create subsets of ``ExperimentData`` -> multiple ``ExperimentData``s
   that correspond to relevant operating points stored with the relevant parameters both internally and in an
   ``ExperimentDataCollection``. As such, it is easier to understand the collection of data
   measurements based on this and perform plotting accordingly in a more relevant implementation. Likewise,
   the corresponding operating point metadata is encoded in the generated ``ExperimentData`` sets.

   First, we will need to extract the operating points from the ``ExperimentData.experiment.parameters``.
   This can be done by identifying the unique elements from the pandas DataFrame.
   Then, we will need to create a new ``ExperimentData`` for each of the operating points.
   Finally, we will need to create a new ``ExperimentDataCollection`` with the new ``ExperimentData``.


.. py:function:: experiment_data_from_parameter_subset(experiment_data: piel.types.ExperimentData, subset: pandas.DataFrame) -> piel.types.ExperimentData

   Filters the given ExperimentData based on a subset of parameters.

   :param experiment_data: The original experiment data.
   :type experiment_data: ExperimentData
   :param subset: The subset of parameters to filter by.
   :type subset: pd.DataFrame

   :returns: A new ExperimentData instance containing only the filtered data.
   :rtype: ExperimentData


.. py:function:: compose_xarray_dataset_from_experiment_data(experiment_data: piel.types.ExperimentData)

   Composes an xarray.Dataset from an ExperimentData instance, using all experiment parameters as coordinates.

   :param experiment_data: The experiment data containing parameters and measurements.
   :type experiment_data: ExperimentData

   :returns: An xarray Dataset containing the measurements indexed by all parameters and metric name.
   :rtype: xr.Dataset

   :raises ValueError: If the number of parameters does not match the number of measurement data entries.
   :raises AttributeError: If any measurement data entry lacks the `measurements` attribute.


.. py:function:: construct_experiment_directories(experiment: piel.types.experimental.Experiment, parent_directory: piel.types.PathTypes, construct_directory: bool = True, write_schema_markdown: bool = False) -> piel.types.PathTypes

   This function constructs the directories of the experiment configuration. It iterates through the experiment
   instances. It checks that each of these instances is unique. Each experiment.experiment_instance should have a
   unique name. This directory name is an enumerated integer. This enumerated integer is the index of the experiment
   instance in the experiment.experiment_instances tuple. This function should be able to create a new experiment
   configuration from scratch.

   A parent directory is defined in which to create the experiment directories. The experiment directory is created
   in the parent directory. The experiment directory contains the experiment.json file. The experiment.json file
   contains the experiment configuration. Note that the experiment.json file should be recursive.
   The experiment directory also contains the experiment instances. The
   experiment instances are directories. Each experiment instance directory contains the instance.json file. The
   instance.json file contains the experiment instance configuration. This is as flat as the directory structure gets.

   The instance directory will contain the data files alongside all of this metadata information.
    The data files are at the top level of the instance directory, and should not have subdirectories.

   The data files are manually generated from the corresponding measurements specified in the instance.json file.
   These will be added after wards from this directory structure creation.

   This schema is used to generate a README file for the experiment configuration if `write_markdown_schema` is true. This README file should contain
   all the information about the experiment configuration. This includes the experiment instances and their
   corresponding configurations.

   :param experiment: The experiment configuration to create the directories for.
   :type experiment: Experiment
   :param parent_directory: The parent directory to create the experiment directory in.
   :type parent_directory: PathTypes
   :param write_markdown_schema: Writes the json schema into markdown if true. Defaults to false.
   :type write_markdown_schema: bool

   :returns: The path to the experiment directory.
   :rtype: PathTypes


.. py:function:: construct_experiment_structure(experiment: piel.types.experimental.Experiment, parent_directory: piel.types.PathTypes)

   The goal of this function is to construct both the directories and the json file which defines both the experiment
   and all the experiment instances. It should be able to create a new experiment configuration from scratch.



.. py:function:: construct_multimeter_sweep_signal_from_csv(file_path: piel.types.PathTypes, signal_name: str, unit: piel.types.Unit = V, **kwargs) -> piel.types.SignalDC

   Construct a multimeter sweep signal from a CSV file.

   :param file_path: The path to the CSV file.
   :type file_path: PathTypes
   :param signal_name: The name of the signal.
   :type signal_name: str
   :param unit: Determines type of signal.
   :type unit: Unit
   :param \*\*kwargs:

   :returns: *
             * *SignalDC* -- The multimeter sweep signal


.. py:function:: construct_sourcemeter_sweep_signal_from_csv(file_path: piel.types.PathTypes, voltage_signal_name: str, current_signal_name: str, **kwargs) -> piel.types.SignalDC

.. py:function:: construct_multimeter_sweep_signal_from_dataframe(dataframe: pandas.DataFrame, signal_name: str, signal_kwargs: dict = None, **kwargs) -> piel.types.SignalDC

   Construct a multimeter sweep signal from a dataframe.

   :param dataframe: The dataframe containing the multimeter sweep signal data.
   :type dataframe: pd.DataFrame
   :param signal_name: The name of the signal.
   :type signal_name: str
   :param signal_kwargs: Additional keyword arguments.
   :type signal_kwargs: dict
   :param \*\*kwargs:

   :returns: *
             * *SignalDC* -- The multimeter sweep signal


.. py:function:: construct_sourcemeter_sweep_signal_from_dataframe(dataframe: pandas.DataFrame, voltage_signal_name: str, current_signal_name: str, signal_kwargs: dict = None, **kwargs) -> piel.types.SignalDC

.. py:function:: extract_signal_data_from_csv(file_path: piel.types.PathTypes, input_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], output_signal_name_list: list[str], power_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], **kwargs) -> piel.types.SignalDCCollection

   Extract DC sweep data from a CSV file.

   :param file_path: The path to the CSV file.
   :type file_path: PathTypes
   :param input_signal_name_list: The pairs of sourcemeter voltage and current signal names.
   :type input_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param output_signal_name_list: The multimeter signals.
   :type output_signal_name_list: list[str]
   :param power_signal_name_list: The pairs of sourcemeter voltage and current signal names relating to power lines.
   :type power_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param \*\*kwargs: Additional keyword arguments.

   :returns: *
             * *SignalDCCollection* -- The DC sweep data.


.. py:function:: extract_signal_data_from_dataframe(dataframe: pandas.DataFrame, input_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], output_signal_name_list: list[str], power_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], **kwargs) -> piel.types.SignalDCCollection

   Extract DC sweep data from a dataframe.

   :param dataframe: The dataframe containing the DC sweep data.
   :type dataframe: pd.DataFrame
   :param input_signal_name_list: The pairs of sourcemeter voltage and current signal names.
   :type input_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param output_signal_name_list: The multimeter signals.
   :type output_signal_name_list: list[str]
   :param power_signal_name_list: The pairs of sourcemeter voltage and current signal names.
   :type power_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param \*\*kwargs: Additional keyword arguments.

   :returns: *
             * *SignalDCCollection* -- The DC sweep data.


.. py:function:: extract_dc_sweeps_from_operating_point_csv(file_path: piel.types.PathTypes, input_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], output_signal_name_list: list[str], power_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], unique_operating_point_columns: list[str], **kwargs) -> piel.types.DCSweepMeasurementDataCollection

   Extract DC sweep data from a full operating point CSV file. The operating point CSV file contains the DC sweep data
   for multiple operating points. The unique operating point columns are used to extract the unique operating points
   from the CSV file. The DC sweep data is then extracted for each unique operating point. The DC sweep data is
   returned as a DCMeasurementDataCollection. The DCMeasurementDataCollection is a list of DCMeasurementDataTypes.

   :param file_path: The path to the operating point CSV file.
   :type file_path: PathTypes
   :param input_signal_name_list: The pairs of sourcemeter voltage and current signal names.
   :type input_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param output_signal_name_list: The multimeter signals.
   :type output_signal_name_list: list[str]
   :param power_signal_name_list: The pairs of sourcemeter voltage and current signal names relating to power lines.
   :type power_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param unique_operating_point_columns: The unique operating point columns.
   :type unique_operating_point_columns: list[str]
   :param \*\*kwargs: Additional keyword arguments.

   :returns: The DC sweep data collection.
   :rtype: DCMeasurementDataCollection


.. py:function:: extract_dc_sweep_experiment_data_from_csv(file_path: piel.types.PathTypes, input_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], output_signal_name_list: list[str], power_signal_name_list: list[piel.types.VoltageCurrentSignalNamePair], unique_operating_point_columns: list[str], **kwargs) -> piel.types.ExperimentData

   Extract DC sweep data experiment data from a full operating point CSV file. The operating point CSV file contains the DC sweep data
   for multiple operating points. The unique operating point columns are used to extract the unique operating points
   from the CSV file. The DC sweep data is then extracted for each unique operating point. The DC sweep data is returned as a ExperimentData with the unique_operating_point_columns as part of the parameter_list definition, and the sweep data as part of the collection DCSweepMeasurementDataCollection.

   :param file_path: The path to the operating point CSV file.
   :type file_path: PathTypes
   :param input_signal_name_list: The pairs of sourcemeter voltage and current signal names.
   :type input_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param output_signal_name_list: The multimeter signals.
   :type output_signal_name_list: list[str]
   :param power_signal_name_list: The pairs of sourcemeter voltage and current signal names of the power lines.
   :type power_signal_name_list: list[VoltageCurrentSignalNamePair]
   :param unique_operating_point_columns: The unique operating point columns.
   :type unique_operating_point_columns: list[str]
   :param \*\*kwargs: Additional keyword arguments.

   :returns: A collection of experiment and metadata to represent a DC sweep analysis.
   :rtype: ExperimentData


.. py:function:: extract_dc_metrics_from_experiment_data(experiment_data: piel.types.ExperimentData, parameter_column: str = 'driver_b_v_set', label_column_name='ID', **kwargs)

.. py:function:: extract_electro_optic_dc_path_transmission_from_csv(file: str, port_map: piel.types.ConnectionTypes, dc_voltage_column: str = 'bias_v', dc_current_column: str = 'bias_current', optical_power_column: str = 'pm_out') -> piel.types.ElectroOpticDCPathTransmission

   Converts a CSV file into an ElectroOpticDCPathTransmission instance.

   This function ensures that the output power (`pm_out`) aligns with the DC voltage (`bias_v`) and
   current (`bias_current`) data by inserting `np.nan` where `pm_out` data is missing.

   Parameters:
   - file (str): Path to the CSV file.
   - connection (ConnectionTypes): The port mapping information.
   - dc_voltage_column (str): The name of the DC voltage column in the CSV.
   - dc_current_column (str): The name of the DC current column in the CSV.
   - optical_power_column (str): The name of the optical power column in the CSV.

   Returns:
   - ElectroOpticDCPathTransmission: The mapped ElectroOpticDCPathTransmission instance.


.. py:function:: extract_electro_optic_dc_network_from_measurement_collection(measurement_collection: piel.types.ElectroOpticDCMeasurementCollection, dc_voltage_column: str = 'bias_v', dc_current_column: str = 'bias_current', optical_power_column: str = 'pm_out') -> piel.types.ElectroOpticDCNetworkTransmission

   Converts an ElectroOpticDCMeasurementCollection into an ElectroOpticDCNetworkTransmission instance.

   Parameters:
   - measurement_collection (ElectroOpticDCMeasurementCollection): The collection of measurements.
   - dc_voltage_column (str): Column name for DC voltage in the CSV files.
   - dc_current_column (str): Column name for DC current in the CSV files.
   - optical_power_column (str): Column name for optical power in the CSV files.

   Returns:
   - ElectroOpticDCNetworkTransmission: The compiled network transmission instance.


.. py:function:: extract_propagation_delay_data_from_measurement(measurement: piel.types.experimental.PropagationDelayMeasurement) -> piel.types.experimental.PropagationDelayMeasurementData

.. py:function:: extract_s_parameter_data_from_vna_measurement(measurement: piel.types.experimental.VNASParameterMeasurement, **kwargs) -> piel.types.experimental.VNASParameterMeasurementData

.. py:function:: extract_power_sweep_data_from_vna_measurement(measurement: piel.types.VNAPowerSweepMeasurement, **kwargs) -> piel.types.VNAPowerSweepMeasurementData

.. py:function:: extract_power_sweep_s2p_to_network_transmission(file_path: piel.types.PathTypes, input_frequency_Hz: float = 0, **kwargs) -> piel.types.NetworkTransmission

   Extracts power sweep data from an S2P file and converts it into a NetworkTransmission object.

   This function combines the functionalities of extracting data from an S2P file into a pandas DataFrame
   and then converting that DataFrame into a NetworkTransmission instance. It serves as a
   convenient single-step process for obtaining structured transmission state data from an S2P file.

   Parameters:
   -----------
   file_path : PathTypes
       The path to the S2P file to be processed. Can be a string or a Path-like object.

   input_frequency_Hz : float, optional (default=0)
       The input frequency in Hertz to be added to the DataFrame before conversion.

   **kwargs :
       Additional keyword arguments to pass to the `extract_power_sweep_s2p_to_dataframe` function.

   Returns:
   --------
   :
   NetworkTransmission
       An instance of NetworkTransmission populated with the extracted and converted data.

   Example:
   --------
   >>> state = extract_power_sweep_s2p_to_network_transmission('path_to_file.s2p',input_frequency_Hz=1e9)
   >>> print(state)
   NetworkTransmission(p_in_dbm=[-10.0, -9.9977, ...], s_11_db=[-8.311036, -8.307557, ...], ...)

   Notes:
   ------
   - This function internally calls `extract_power_sweep_s2p_to_dataframe` and
     `convert_power_sweep_s2p_to_frequency_array_state`.
   - Ensure that the NetworkTransmission class is properly defined and accessible in your environment.


.. py:function:: extract_power_sweep_s2p_to_dataframe(file_path: piel.types.PathTypes, input_frequency_Hz: float = 0, **kwargs)

   Extracts numerical data from an S2P (Touchstone) file and returns it as a pandas DataFrame.

   This function reads an S2P file, parses its numerical data, and organizes it into a structured
   pandas DataFrame. It skips comment lines and ensures that each data line contains the expected
   number of columns. If discrepancies are found, warnings are printed, and those lines are skipped.

   Parameters:
   -----------
   file_path : PathTypes
       The path to the S2P file to be processed. Can be a string or a Path-like object.

   input_frequency_Hz : float, optional (default=0)
       The input frequency in Hertz to be added as a column in the resulting DataFrame.

   **kwargs :
       Additional keyword arguments to pass to the pandas DataFrame constructor.

   Returns:
   --------
   :
   pd.DataFrame
       A DataFrame containing the extracted data with the following columns:
       - `p_in_dbm` : Input power in dBm.
       - `s_11_db` : S-parameter S11 in dB.
       - `s_11_deg` : S-parameter S11 in degrees.
       - `s_21_db` : S-parameter S21 in dB.
       - `s_21_deg` : S-parameter S21 in degrees.
       - `s_12_db` : S-parameter S12 in dB.
       - `s_12_deg` : S-parameter S12 in degrees.
       - `s_22_db` : S-parameter S22 in dB.
       - `s_22_deg` : S-parameter S22 in degrees.
       - `input_frequency_Hz` : The input frequency provided as a parameter.

   Example:
   --------
   >>> df = extract_power_sweep_s2p_to_dataframe('path_to_file.s2p', input_frequency_Hz=1e9)
   >>> print(df.head())
      p_in_dbm  s_11_db  s_11_deg  s_21_db  s_21_deg  s_12_db  s_12_deg  s_22_db  s_22_deg  input_frequency_Hz
   0   -10.0000 -8.311036  90.38824 -11.35558  137.4781 -55.67513   54.62733  -8.564775 -164.7370         1000000000.0
   1    -9.9977 -8.307557  90.38396 -11.34543  137.4497 -55.04230   53.47807  -8.555398 -164.7173         1000000000.0
   2    -9.9953 -8.309752  90.35067 -11.35137  137.4250 -55.01111    48.11482  -8.562661 -164.6533         1000000000.0
   3    -9.9930 -8.310988  90.35760 -11.34326  137.3693 -56.74514    39.34027  -8.559170 -164.7386         1000000000.0

   Notes:
   ------
   - Lines in the S2P file starting with '!' or '#' are treated as comments or headers and are skipped.
   - Each valid data line is expected to have exactly 9 numerical values corresponding to the defined columns.
   - If a line does not have 9 values or contains non-numeric data, a warning or error is printed, and the line is skipped.


.. py:function:: convert_row_to_sdict(row)

   Converts a single DataFrame row containing S-parameter data into an SDict.

   Parameters:
   -----------
   row : pd.Series
       A pandas Series containing S-parameter data with the following indices:
       - p_in_dbm
       - s_11_db
       - s_11_deg
       - s_21_db
       - s_21_deg
       - s_12_db
       - s_12_deg
       - s_22_db
       - s_22_deg

   Returns:
   --------
   :
   SDict
       A dictionary mapping PortCombination tuples to complex S-parameter arrays.

   Example:
   --------
   >>> sdict = convert_row_to_sdict(df.iloc[0])
   >>> print(sdict)
   {
       ('in0', 'in0'): DeviceArray(-0.03295842+0.0313j, dtype=float32),
       ('in0', 'out0'): DeviceArray(-0.03361994+0.0325j, dtype=float32),
       ('out0', 'in0'): DeviceArray(0.03118884+0.0477j, dtype=float32),
       ('out0', 'out0'): DeviceArray(-0.03206138-0.0143j, dtype=float32)
   }


.. py:function:: extract_data_from_measurement_collection(measurement_collection: piel.types.experimental.MeasurementCollectionTypes, measurement_to_data_map: dict = measurement_to_data_map, measurement_to_data_method_map: dict = measurement_to_data_method_map, skip_missing: bool = False, **kwargs) -> piel.types.experimental.MeasurementDataCollectionTypes

   The goal of this function is to compose the data from a collection of measurement references.
   Based on each type of measurement, it will apply an extraction function based on the data mapping accordingly.
   It will return a collection of data measurement which is inherent to the type of the measurement collection provided.


.. py:function:: extract_data_from_experiment(experiment: piel.types.experimental.Experiment, experiment_directory: piel.types.PathTypes, composition_kwargs: dict = None, extraction_kwargs: dict = None, **kwargs) -> piel.types.experimental.ExperimentData

   This function must be run after data has already been written within the ``Experiment`` directories
   and the metadata has been created accordingly. This will extract all the corresponding measurements collection,
   and also extract the corresponding data from each setup accordingly. It will create a `ExperimentData` that collects
   both the metadata and measurement data.

   :param experiment: The experiment object that contains the metadata of the experiment.
   :type experiment: Experiment
   :param experiment_directory: The directory where the experiment is located.
   :type experiment_directory: PathTypes
   :param \*\*kwargs: Extra keyword arguments passed to the class instantiation.

   :returns: *
             * *ExperimentData* -- The data extracted from the experiment.


.. py:function:: load_experiment_data_from_directory(experiment_directory: piel.types.PathTypes, **kwargs) -> piel.types.experimental.ExperimentData

   This function will load an `Experiment` from the metadata stored in the `experiment.json` directory.


.. py:function:: compose_measurement_from_experiment_instance(experiment_instance: piel.types.experimental.ExperimentInstance, instance_directory: piel.types.PathTypes, configuration_measurement_map: dict = configuration_to_measurement_map, measurement_composition_method_mapping: dict = measurement_composition_method_mapping, composition_methods_kwargs: dict = None, **kwargs) -> piel.types.experimental.MeasurementTypes

   This function is meant to be run after the measurements have been collected and the data exists within the measurement directories.
   Each experiment instance should correspond to a list of measurement configurations, ie the specific set of measurements
    that are required at each directory generated for the measurement instance. Hence, for this function to work properly,
    it is required to have a mapping between experiment configuration measurement and measurement classes accordingly.
    The mapping will be between a given ``MeasurementConfiguration`` type and a ``Measurement`` class which has the references
    of the data containers accordingly.


.. py:function:: compose_measurement_collection_from_experiment(experiment: piel.types.experimental.Experiment, experiment_directory: piel.types.PathTypes = None, **kwargs) -> piel.types.experimental.MeasurementCollectionTypes

   This function takes a defined experiment and returns a measurement collection from them.
   Note that the complexity of this is verifying that the experiment is composed of the same type of measurements accordingly.
   TODO this should be validated in the Experiment composition accordingly.


.. py:function:: compose_vna_s_parameter_measurement(instance_directory: piel.types.PathTypes, skip_missing: bool = False, **kwargs) -> piel.types.experimental.VNASParameterMeasurement

   There should only be one .s2p s-parameter file in this directory. If there are more than one, it will read the first one.
   This function will iterate through the instance directory and find the .s2p file. It will return a measurement accordingly.


.. py:data:: configuration_to_measurement_map

.. py:data:: measurement_composition_method_mapping

.. py:function:: compose_propagation_delay_measurement(instance_directory: piel.types.PathTypes, dut_file_prefix: str = 'Ch1', reference_file_prefix: str = 'Ch2', measurement_file_prefix: str = '', skip_missing: bool = False, **kwargs) -> piel.types.experimental.PropagationDelayMeasurement

   This function will iterate through the instance directory and find the files that correspond to the propagation delay measurement.
   The files are expected to be in the form of:
   - {dut_file_prefix}_waveform.csv
   - {reference_file_prefix}_waveform.csv
   - {measurement_file_prefix}_measurements.csv


.. py:function:: compose_oscilloscope_measurement(instance_directory: piel.types.PathTypes, skip_missing: bool = False, **kwargs) -> piel.types.experimental.OscilloscopeMeasurement

   This function composes an OscilloscopeMeasurement from a given directory. The OscilloscopeMeasurement.waveform_file_list
   will be a collection of files that end with a suffix ``Ch*.csv``. This function will compose the list of files in the order
   of the channel number. The OscilloscopeMeasurement.measurements_file will be a file that ends without a suffix ``Ch*.csv``.


.. py:function:: create_report()

   This functionality is used to create a report of a given directory containing the `ExperimentCollection`
   and the `Experiments` themselves.

   This uses the metadata of the `Experiment`s and the corresponding `ExperimentData`
   to generate the corresponding images.


.. py:function:: create_report_from_experiment_directory(experiment_directory: piel.types.PathTypes, plot_output_directory: piel.types.PathTypes = None, report_readme_path: piel.types.PathTypes = None, load_data_kwargs: dict = None, plot_kwargs: dict = None, **kwargs)

   First we need to extract the `ExperimentData` from the directory.
   Then we can generate the report from the `ExperimentData`.



.. py:function:: create_plots_from_experiment_data(experiment_data: piel.types.experimental.ExperimentData, plot_output_directory: piel.types.PathTypes = None, experiment_directory: piel.types.PathTypes = None, parametric: bool = False, erase_plot_output_path: bool = False, **kwargs) -> list[list[tuple], piel.types.PathTypes]

   This function iterates through all the saved measurement data and generates the corresponding plots
   for the type of data provided using a method as specified.

   Returns a list of (Figures,Axes), and a reference list of paths where the image has been saved.


.. py:function:: create_plots_from_experiment_directory(experiment_directory: piel.types.PathTypes, plot_output_directory: piel.types.PathTypes = None, **kwargs) -> list[tuple]

   This function will create the plots from the given experiment directory. It will first extract the `ExperimentData`
    from the directory and then generate the plots based on that.


.. py:function:: write_schema_markdown(schema_json_file: piel.types.PathTypes, target_markdown_file: piel.types.PathTypes)

   This function writes the schema markdown file for the experiment configuration. This schema markdown file should
   contain all the required information to understand the experiment configuration. This should include all the
   experiment instances and their corresponding configurations.



.. py:function:: write_experiment_top_markdown(experiment: piel.types.experimental.Experiment, experiment_directory: piel.types.PathTypes, target_markdown_file: piel.types.PathTypes = None)

