.. _pt1000_processing:

PT1000 Temperature Value Processing
===================================

The PT1000 temperature sensor is the sensing element used for determining the Reflow Oven Temperature.

The PT1000 value processing is enabled by default and not intended to be turned off.

PT1000 Value Sampling
---------------------

The following block diagram shows the processing chain of the temperature signal.

.. blockdiag::
	:desctable:
	
	blockdiag {
		orientation = portrait;
		
		FRONTEND[description=":ref:`hw_analog_fe`", label="Frontend"];
		ADC[description="`Analog to Digital Converter <ADC_>`_"];
		WATCHDOG [label = "WDT", shape=endpoint, description="`Hardware Value Watchdog <Watchdog_>`_"];
		PREFILTER [label=Prefilter, description="`Prefiltering and Downsampling <Prefilter_>`_"];
		ADC2RES [label= "Val -> Ohm", description="`Conversion from ADC value to resistance in Ohms <ADC Value to Ohm_>`_"]		
		MAVG [label="MAVG Filter", description="`Exponential Moving Average Filter`_"];
		RAW_HF [label="HF", shape = endpoint, description="High Frequency raw value reading"];
		PT1000 [label = "LF", shape = endpoint, description="Low Frequency PT1000 resistance value (see: `MAVG Filter <Exponential Moving Average Filter_>`_)"]
		RAW_STREAM [label = "Stream", shape = endpoint, description="Raw value streaming"];

		FRONTEND -> ADC -> WATCHDOG;
		ADC -> PREFILTER [label="1 kHz"];
		PREFILTER -> ADC2RES [label="1/6 kHz"];
		ADC2RES -> MAVG;
		MAVG -> PT1000 [label="1/6 kHz"];
		PREFILTER -> RAW_HF [label="1/6 kHz"];
		PREFILTER -> RAW_STREAM [label="1/6 kHz"];		
	}

ADC
~~~

The internal ADC of the STM32F407 controller is used to sample the analog signal from the :ref:`hw_analog_fe`. The ADC is triggered by the hardware Timer *TIM2* each millisecond, which results in a sampling frequency of
1 kHz. The ADC module provides an analog value `watchdog <Watchdog_>`_, which is used to detect wirebreaks and other hardware errors that result in a wrong resistance measurement.

The sample frequency is controlled by

.. doxygendefine:: ADC_PT1000_SAMPLE_CNT_DELAY

whereas the ADC Peripheral module is defined by

.. doxygendefine:: ADC_PT1000_PERIPH

Prefilter
~~~~~~~~~

The analog value prefilter is used to filter outliers. It is triggered after a certain amount ``n`` of values have been sampled by the `ADC`_.
The filter then removes the two most extreme values and computes the average of the remaining ``n - 2`` values. By default ``n`` is configured to:

.. doxygendefine:: ADC_PT1000_DMA_AVG_SAMPLES

Therefore, by default, the resulting datastream has a sampling rate of 1/6 kHz. This depends on the :c:macro:`ADC_PT1000_SAMPLE_CNT_DELAY` and ``n``


.. _firmware_meas_adc_watchdog:

Watchdog
~~~~~~~~

The analog watchdog supervises the measured value of the `ADC`_. It is configured by the following defines:

.. doxygendefine:: ADC_PT1000_LOWER_WATCHDOG

.. doxygendefine:: ADC_PT1000_UPPER_WATCHDOG

.. doxygendefine:: ADC_PT1000_WATCHDOG_SAMPLE_COUNT

The watchdog will set the :ref:`safety_flags_adc_watchdog` error flag.

ADC Value to Ohm
~~~~~~~~~~~~~~~~

This block converts the analog value to an Ohm resistance value.
The formula is:

.. math::
	R(V) = \frac{V}{4096} \cdot 2500~\Omega

The equation is implemented in 

.. doxygendefine:: ADC_TO_RES

and applied during the `Exponential Moving Average Filter`_.

.. _firmware_meas_adc_filter:

Exponential Moving Average Filter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The external moving average filter filters the measured resistance value. It's equation is:

.. math::
	y[n] = (1-\alpha) y[n-1] + \alpha x[n]

The filter constant *alpha* defaults to the define

.. doxygendefine:: ADC_PT1000_FILTER_WEIGHT

and can be changed in code using

.. doxygenfunction:: adc_pt1000_set_moving_average_filter_param

After initial startup and after each change of the filter constant, the filter will set the :ref:`safety_flags_adc_unstable` flag for a defined sample count of:

.. doxygendefine:: ADC_FILTER_STARTUP_CYCLES

The moving average filter's output signal is the Low Frequency (LF) PT1000 resistance signal used for internal PT1000 measurements.

Reading and Converting the PT1000 Value
---------------------------------------

Calibration
~~~~~~~~~~~

The functions

.. doxygenfunction:: adc_pt1000_set_resistance_calibration
	:outline:

and

.. doxygenfunction:: adc_pt1000_get_resistance_calibration
	:outline:

are used to set the resistance calibration internally. For a guide on how to calibrate the deivce, see the corresponding :ref:`usage_calibration` usage page.

The calibration is calculated the following way:

.. blockdiag::
	:desctable:
	
	blockdiag {
		orientation = portrait;
		
		LF [label="LF", shape=beginpoint, description="Low Frequency PT1000 Value"];
		SENS [label="Sens", description="Sensitivity Correction :math:`\sigma`"];
		OFFSET [label="Offset", description="Offset Correction :math:`O`"];
		OUT [shape=endpoint, description="Corrected Value"];

		LF -> OFFSET -> SENS -> OUT
	}

The final calibrated PT1000 resistance is calculated as:

.. math::
	R_{PT1000_{corr}} = (R_{PT1000_{LF}} - O) \cdot (1 + \sigma)

The default values, if no calibration is loaded / executed, are:

============== =========
:math:`\sigma` :math:`O`
============== =========
      0            0
============== =========

Get Calibration Corrected Value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The PT1000 value is available through the following function.
If a calibration is set, it is applied.

.. doxygenfunction:: adc_pt1000_get_current_resistance

Converting the Value
~~~~~~~~~~~~~~~~~~~~

The valid range for conversion is between

.. doxygendefine:: TEMP_CONVERSION_MIN_RES
	:outline:

and 

.. doxygendefine:: TEMP_CONVERSION_MAX_RES
	:outline:

By default, the valid range is:

.. math::
	1000~\Omega \le R_{PT1000} \le 2200~\Omega

.. doxygenfunction:: temp_converter_convert_resistance_to_temp

The cvonversion function is based on a lookup table with linear interpolation between the data points.
The lookuptable is stored as a header file and can, if necessary, be recreated using the ``create-temp-lookup-table.py`` script.
	
