[libcamera-devel,2/4] libipa: camera_sensor_helper: Implement exponential gain model
diff mbox series

Message ID 20220328120336.10834-3-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • IPA sensor helpers for IMX290 and IMX296
Related show

Commit Message

Laurent Pinchart March 28, 2022, 12:03 p.m. UTC
The CameraSensorHelper specifies two gain models, linear and an
exponential. They are modelled after the MIPI CCS specification. Only
the linear model has been implemented, the exponential model was left
for later.

We now need to support sensors that configure their gain in a hardware
register with a value expressed in dB. This has similarities with the
MIPI CCS exponential gain model, but is only has an exponential factor,
while CCS also allows sensors to support a configurable linear factor.

The full CCS exponential model needs two values (for the linear and
exponential factors) to express a gain, while IPAs use a single linear
gain value internally. However, the exponential gain model example in
the CCS specification has a fixed linear factor, which may indicate that
it could be common for sensors that implement the exponential gain model
to only use the exponential factor. For this reason, implement the
exponential gain model with a fixed linear factor, but with a
sensor-specific coefficient for the exponential factor that allows
expressing the gain in dB (or other logarithmical units) instead of
limiting it to powers of 2 as in the MIPI CCS specification.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/ipa/libipa/camera_sensor_helper.cpp | 82 ++++++++++++++++++-------
 src/ipa/libipa/camera_sensor_helper.h   |  6 ++
 2 files changed, 67 insertions(+), 21 deletions(-)

Comments

Jacopo Mondi March 28, 2022, 1:37 p.m. UTC | #1
Hi Laurent,

On Mon, Mar 28, 2022 at 03:03:34PM +0300, Laurent Pinchart via libcamera-devel wrote:
> The CameraSensorHelper specifies two gain models, linear and an

s/an //

> exponential. They are modelled after the MIPI CCS specification. Only
> the linear model has been implemented, the exponential model was left
> for later.
>
> We now need to support sensors that configure their gain in a hardware
> register with a value expressed in dB. This has similarities with the
> MIPI CCS exponential gain model, but is only has an exponential factor,
> while CCS also allows sensors to support a configurable linear factor.
>
> The full CCS exponential model needs two values (for the linear and
> exponential factors) to express a gain, while IPAs use a single linear
> gain value internally. However, the exponential gain model example in
> the CCS specification has a fixed linear factor, which may indicate that
> it could be common for sensors that implement the exponential gain model
> to only use the exponential factor. For this reason, implement the
> exponential gain model with a fixed linear factor, but with a

Isn't the linear factor k.exp.a not fixed ?

        return k.exp.a * std::exp2(k.exp.m * gain);

Reading this I would have expected k.exp.a to be fixed to 1

> sensor-specific coefficient for the exponential factor that allows
> expressing the gain in dB (or other logarithmical units) instead of
> limiting it to powers of 2 as in the MIPI CCS specification.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/ipa/libipa/camera_sensor_helper.cpp | 82 ++++++++++++++++++-------
>  src/ipa/libipa/camera_sensor_helper.h   |  6 ++
>  2 files changed, 67 insertions(+), 21 deletions(-)
>
> diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
> index 714cd86f039f..7bb999e19102 100644
> --- a/src/ipa/libipa/camera_sensor_helper.cpp
> +++ b/src/ipa/libipa/camera_sensor_helper.cpp
> @@ -7,6 +7,8 @@
>   */
>  #include "camera_sensor_helper.h"
>
> +#include <cmath>
> +
>  #include <libcamera/base/log.h>
>
>  /**
> @@ -51,20 +53,28 @@ namespace ipa {
>   * This function aims to abstract the calculation of the gain letting the IPA
>   * use the real gain for its estimations.
>   *
> - * The parameters come from the MIPI Alliance Camera Specification for
> - * Camera Command Set (CCS).
> - *
>   * \return The gain code to pass to V4L2
>   */
>  uint32_t CameraSensorHelper::gainCode(double gain) const
>  {
>  	const AnalogueGainConstants &k = gainConstants_;
>
> -	ASSERT(gainType_ == AnalogueGainLinear);
> -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> +	switch (gainType_) {
> +	case AnalogueGainLinear:
> +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
>
> -	return (k.linear.c0 - k.linear.c1 * gain) /
> -	       (k.linear.m1 * gain - k.linear.m0);
> +		return (k.linear.c0 - k.linear.c1 * gain) /
> +		       (k.linear.m1 * gain - k.linear.m0);
> +
> +	case AnalogueGainExponential:
> +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> +
> +		return std::log2(gain / k.exp.a) / k.exp.m;
> +
> +	default:
> +		ASSERT(false);
> +		return 0;
> +	}
>  }
>
>  /**
> @@ -75,20 +85,29 @@ uint32_t CameraSensorHelper::gainCode(double gain) const
>   * use the real gain for its estimations. It is the counterpart of the function
>   * CameraSensorHelper::gainCode.
>   *
> - * The parameters come from the MIPI Alliance Camera Specification for
> - * Camera Command Set (CCS).
> - *
>   * \return The real gain
>   */
>  double CameraSensorHelper::gain(uint32_t gainCode) const
>  {
>  	const AnalogueGainConstants &k = gainConstants_;
> +	double gain = static_cast<double>(gainCode);
>
> -	ASSERT(gainType_ == AnalogueGainLinear);
> -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> +	switch (gainType_) {
> +	case AnalogueGainLinear:
> +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
>
> -	return (k.linear.m0 * static_cast<double>(gainCode) + k.linear.c0) /
> -	       (k.linear.m1 * static_cast<double>(gainCode) + k.linear.c1);
> +		return (k.linear.m0 * gain + k.linear.c0) /
> +		       (k.linear.m1 * gain + k.linear.c1);
> +
> +	case AnalogueGainExponential:
> +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> +
> +		return k.exp.a * std::exp2(k.exp.m * gain);
> +
> +	default:
> +		ASSERT(false);
> +		return 0.0;
> +	}
>  }
>
>  /**
> @@ -120,15 +139,22 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>
>  /**
>   * \var CameraSensorHelper::AnalogueGainExponential
> - * \brief Gain is computed using exponential gain estimation
> - * (introduced in CCS v1.1)
> + * \brief Gain is expressed using an exponential model
>   *
> - * Starting with CCS v1.1, Alternate Global Analogue Gain is also available.
> - * If the image sensor supports it, then the global analogue gain can be
> - * controlled by linear and exponential gain formula:
> + * The relationship between the integer gain parameter and the resulting gain
> + * multiplier is given by the following equation:
>   *
> - * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal}\f$
> - * \todo not implemented in libipa
> + * \f$gain = a \cdot 2^{m \cdot x}\f$
> + *
> + * Where 'x' is the gain control parameter, and 'a' and 'm' are image
> + * sensor-specific constants.
> + *
> + * This is a subset of the MIPI CCS exponential gain model with the linear
> + * factor 'a' being a constant, but with the exponent being configurable
> + * through the 'm' coefficient.

So I don't really get what 'constant' means, as this seems to match
the CCS spec (apart from the 'm' paramter)

> + *
> + * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
> + * \f$log_{2}{10^{frac{1}{20}}}\f$.
>   */
>
>  /**
> @@ -152,6 +178,17 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   * \brief Constant used in the linear gain coding/decoding
>   */
>
> +/**
> + * \struct CameraSensorHelper::AnalogueGainExpConstants
> + * \brief Analogue gain constants for the exponential gain model
> + *
> + * \var CameraSensorHelper::AnalogueGainExpConstants::a
> + * \brief Constant used in the exponential gain coding/decoding
> + *
> + * \var CameraSensorHelper::AnalogueGainExpConstants::m
> + * \brief Constant used in the exponential gain coding/decoding
> + */
> +
>  /**
>   * \struct CameraSensorHelper::AnalogueGainConstants
>   * \brief Analogue gain model constants
> @@ -161,6 +198,9 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   *
>   * \var CameraSensorHelper::AnalogueGainConstants::linear
>   * \brief Constants for the linear gain model
> + *
> + * \var CameraSensorHelper::AnalogueGainConstants::exp
> + * \brief Constants for the exponential gain model
>   */
>
>  /**
> diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
> index 6b96520ba601..7351fc7c2928 100644
> --- a/src/ipa/libipa/camera_sensor_helper.h
> +++ b/src/ipa/libipa/camera_sensor_helper.h
> @@ -41,8 +41,14 @@ protected:
>  		int16_t c1;
>  	};
>
> +	struct AnalogueGainExpConstants {
> +		double a;
> +		double m;
> +	};
> +
>  	union AnalogueGainConstants {
>  		AnalogueGainLinearConstants linear;
> +		AnalogueGainExpConstants exp;
>  	};

With my confusion about what 'constant' means clarified:

Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>


>
>  	AnalogueGainType gainType_;
> --
> Regards,
>
> Laurent Pinchart
>
Laurent Pinchart March 28, 2022, 4:10 p.m. UTC | #2
Hi Jacopo,

On Mon, Mar 28, 2022 at 03:37:49PM +0200, Jacopo Mondi wrote:
> On Mon, Mar 28, 2022 at 03:03:34PM +0300, Laurent Pinchart via libcamera-devel wrote:
> > The CameraSensorHelper specifies two gain models, linear and an
> 
> s/an //
> 
> > exponential. They are modelled after the MIPI CCS specification. Only
> > the linear model has been implemented, the exponential model was left
> > for later.
> >
> > We now need to support sensors that configure their gain in a hardware
> > register with a value expressed in dB. This has similarities with the
> > MIPI CCS exponential gain model, but is only has an exponential factor,
> > while CCS also allows sensors to support a configurable linear factor.
> >
> > The full CCS exponential model needs two values (for the linear and
> > exponential factors) to express a gain, while IPAs use a single linear
> > gain value internally. However, the exponential gain model example in
> > the CCS specification has a fixed linear factor, which may indicate that
> > it could be common for sensors that implement the exponential gain model
> > to only use the exponential factor. For this reason, implement the
> > exponential gain model with a fixed linear factor, but with a
> 
> Isn't the linear factor k.exp.a not fixed ?
> 
>         return k.exp.a * std::exp2(k.exp.m * gain);
> 
> Reading this I would have expected k.exp.a to be fixed to 1

By fixed, I meant that it doesn't vary at runtime, but it can be
sensor-specific. The CCS exponential model has two parameters than can
vary at runtime:

gain = gain_{lin} * 2^{gain_{exp}}

with both gain_{lin} and gain_{exp} being programmable in two different
sensor registers.

> > sensor-specific coefficient for the exponential factor that allows
> > expressing the gain in dB (or other logarithmical units) instead of
> > limiting it to powers of 2 as in the MIPI CCS specification.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  src/ipa/libipa/camera_sensor_helper.cpp | 82 ++++++++++++++++++-------
> >  src/ipa/libipa/camera_sensor_helper.h   |  6 ++
> >  2 files changed, 67 insertions(+), 21 deletions(-)
> >
> > diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
> > index 714cd86f039f..7bb999e19102 100644
> > --- a/src/ipa/libipa/camera_sensor_helper.cpp
> > +++ b/src/ipa/libipa/camera_sensor_helper.cpp
> > @@ -7,6 +7,8 @@
> >   */
> >  #include "camera_sensor_helper.h"
> >
> > +#include <cmath>
> > +
> >  #include <libcamera/base/log.h>
> >
> >  /**
> > @@ -51,20 +53,28 @@ namespace ipa {
> >   * This function aims to abstract the calculation of the gain letting the IPA
> >   * use the real gain for its estimations.
> >   *
> > - * The parameters come from the MIPI Alliance Camera Specification for
> > - * Camera Command Set (CCS).
> > - *
> >   * \return The gain code to pass to V4L2
> >   */
> >  uint32_t CameraSensorHelper::gainCode(double gain) const
> >  {
> >  	const AnalogueGainConstants &k = gainConstants_;
> >
> > -	ASSERT(gainType_ == AnalogueGainLinear);
> > -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> > +	switch (gainType_) {
> > +	case AnalogueGainLinear:
> > +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> >
> > -	return (k.linear.c0 - k.linear.c1 * gain) /
> > -	       (k.linear.m1 * gain - k.linear.m0);
> > +		return (k.linear.c0 - k.linear.c1 * gain) /
> > +		       (k.linear.m1 * gain - k.linear.m0);
> > +
> > +	case AnalogueGainExponential:
> > +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> > +
> > +		return std::log2(gain / k.exp.a) / k.exp.m;
> > +
> > +	default:
> > +		ASSERT(false);
> > +		return 0;
> > +	}
> >  }
> >
> >  /**
> > @@ -75,20 +85,29 @@ uint32_t CameraSensorHelper::gainCode(double gain) const
> >   * use the real gain for its estimations. It is the counterpart of the function
> >   * CameraSensorHelper::gainCode.
> >   *
> > - * The parameters come from the MIPI Alliance Camera Specification for
> > - * Camera Command Set (CCS).
> > - *
> >   * \return The real gain
> >   */
> >  double CameraSensorHelper::gain(uint32_t gainCode) const
> >  {
> >  	const AnalogueGainConstants &k = gainConstants_;
> > +	double gain = static_cast<double>(gainCode);
> >
> > -	ASSERT(gainType_ == AnalogueGainLinear);
> > -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> > +	switch (gainType_) {
> > +	case AnalogueGainLinear:
> > +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> >
> > -	return (k.linear.m0 * static_cast<double>(gainCode) + k.linear.c0) /
> > -	       (k.linear.m1 * static_cast<double>(gainCode) + k.linear.c1);
> > +		return (k.linear.m0 * gain + k.linear.c0) /
> > +		       (k.linear.m1 * gain + k.linear.c1);
> > +
> > +	case AnalogueGainExponential:
> > +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> > +
> > +		return k.exp.a * std::exp2(k.exp.m * gain);
> > +
> > +	default:
> > +		ASSERT(false);
> > +		return 0.0;
> > +	}
> >  }
> >
> >  /**
> > @@ -120,15 +139,22 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
> >
> >  /**
> >   * \var CameraSensorHelper::AnalogueGainExponential
> > - * \brief Gain is computed using exponential gain estimation
> > - * (introduced in CCS v1.1)
> > + * \brief Gain is expressed using an exponential model
> >   *
> > - * Starting with CCS v1.1, Alternate Global Analogue Gain is also available.
> > - * If the image sensor supports it, then the global analogue gain can be
> > - * controlled by linear and exponential gain formula:
> > + * The relationship between the integer gain parameter and the resulting gain
> > + * multiplier is given by the following equation:
> >   *
> > - * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal}\f$
> > - * \todo not implemented in libipa
> > + * \f$gain = a \cdot 2^{m \cdot x}\f$
> > + *
> > + * Where 'x' is the gain control parameter, and 'a' and 'm' are image
> > + * sensor-specific constants.
> > + *
> > + * This is a subset of the MIPI CCS exponential gain model with the linear
> > + * factor 'a' being a constant, but with the exponent being configurable
> > + * through the 'm' coefficient.
> 
> So I don't really get what 'constant' means, as this seems to match
> the CCS spec (apart from the 'm' paramter)
> 
> > + *
> > + * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
> > + * \f$log_{2}{10^{frac{1}{20}}}\f$.
> >   */
> >
> >  /**
> > @@ -152,6 +178,17 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
> >   * \brief Constant used in the linear gain coding/decoding
> >   */
> >
> > +/**
> > + * \struct CameraSensorHelper::AnalogueGainExpConstants
> > + * \brief Analogue gain constants for the exponential gain model
> > + *
> > + * \var CameraSensorHelper::AnalogueGainExpConstants::a
> > + * \brief Constant used in the exponential gain coding/decoding
> > + *
> > + * \var CameraSensorHelper::AnalogueGainExpConstants::m
> > + * \brief Constant used in the exponential gain coding/decoding
> > + */
> > +
> >  /**
> >   * \struct CameraSensorHelper::AnalogueGainConstants
> >   * \brief Analogue gain model constants
> > @@ -161,6 +198,9 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
> >   *
> >   * \var CameraSensorHelper::AnalogueGainConstants::linear
> >   * \brief Constants for the linear gain model
> > + *
> > + * \var CameraSensorHelper::AnalogueGainConstants::exp
> > + * \brief Constants for the exponential gain model
> >   */
> >
> >  /**
> > diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
> > index 6b96520ba601..7351fc7c2928 100644
> > --- a/src/ipa/libipa/camera_sensor_helper.h
> > +++ b/src/ipa/libipa/camera_sensor_helper.h
> > @@ -41,8 +41,14 @@ protected:
> >  		int16_t c1;
> >  	};
> >
> > +	struct AnalogueGainExpConstants {
> > +		double a;
> > +		double m;
> > +	};
> > +
> >  	union AnalogueGainConstants {
> >  		AnalogueGainLinearConstants linear;
> > +		AnalogueGainExpConstants exp;
> >  	};
> 
> With my confusion about what 'constant' means clarified:
> 
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> 
> >
> >  	AnalogueGainType gainType_;
Umang Jain March 30, 2022, 8:41 a.m. UTC | #3
Hi Laurent,

Thank you for the patch.

On 3/28/22 17:33, Laurent Pinchart via libcamera-devel wrote:
> The CameraSensorHelper specifies two gain models, linear and an
> exponential. They are modelled after the MIPI CCS specification. Only
> the linear model has been implemented, the exponential model was left
> for later.
>
> We now need to support sensors that configure their gain in a hardware
> register with a value expressed in dB. This has similarities with the
> MIPI CCS exponential gain model, but is only has an exponential factor,
> while CCS also allows sensors to support a configurable linear factor.
>
> The full CCS exponential model needs two values (for the linear and
> exponential factors) to express a gain, while IPAs use a single linear
> gain value internally. However, the exponential gain model example in
> the CCS specification has a fixed linear factor, which may indicate that
> it could be common for sensors that implement the exponential gain model
> to only use the exponential factor. For this reason, implement the
> exponential gain model with a fixed linear factor, but with a
> sensor-specific coefficient for the exponential factor that allows
> expressing the gain in dB (or other logarithmical units) instead of
> limiting it to powers of 2 as in the MIPI CCS specification.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>


Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
> ---
>   src/ipa/libipa/camera_sensor_helper.cpp | 82 ++++++++++++++++++-------
>   src/ipa/libipa/camera_sensor_helper.h   |  6 ++
>   2 files changed, 67 insertions(+), 21 deletions(-)
>
> diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
> index 714cd86f039f..7bb999e19102 100644
> --- a/src/ipa/libipa/camera_sensor_helper.cpp
> +++ b/src/ipa/libipa/camera_sensor_helper.cpp
> @@ -7,6 +7,8 @@
>    */
>   #include "camera_sensor_helper.h"
>   
> +#include <cmath>
> +
>   #include <libcamera/base/log.h>
>   
>   /**
> @@ -51,20 +53,28 @@ namespace ipa {
>    * This function aims to abstract the calculation of the gain letting the IPA
>    * use the real gain for its estimations.
>    *
> - * The parameters come from the MIPI Alliance Camera Specification for
> - * Camera Command Set (CCS).
> - *
>    * \return The gain code to pass to V4L2
>    */
>   uint32_t CameraSensorHelper::gainCode(double gain) const
>   {
>   	const AnalogueGainConstants &k = gainConstants_;
>   
> -	ASSERT(gainType_ == AnalogueGainLinear);
> -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> +	switch (gainType_) {
> +	case AnalogueGainLinear:
> +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
>   
> -	return (k.linear.c0 - k.linear.c1 * gain) /
> -	       (k.linear.m1 * gain - k.linear.m0);
> +		return (k.linear.c0 - k.linear.c1 * gain) /
> +		       (k.linear.m1 * gain - k.linear.m0);
> +
> +	case AnalogueGainExponential:
> +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> +
> +		return std::log2(gain / k.exp.a) / k.exp.m;
> +
> +	default:
> +		ASSERT(false);
> +		return 0;
> +	}
>   }
>   
>   /**
> @@ -75,20 +85,29 @@ uint32_t CameraSensorHelper::gainCode(double gain) const
>    * use the real gain for its estimations. It is the counterpart of the function
>    * CameraSensorHelper::gainCode.
>    *
> - * The parameters come from the MIPI Alliance Camera Specification for
> - * Camera Command Set (CCS).
> - *
>    * \return The real gain
>    */
>   double CameraSensorHelper::gain(uint32_t gainCode) const
>   {
>   	const AnalogueGainConstants &k = gainConstants_;
> +	double gain = static_cast<double>(gainCode);
>   
> -	ASSERT(gainType_ == AnalogueGainLinear);
> -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> +	switch (gainType_) {
> +	case AnalogueGainLinear:
> +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
>   
> -	return (k.linear.m0 * static_cast<double>(gainCode) + k.linear.c0) /
> -	       (k.linear.m1 * static_cast<double>(gainCode) + k.linear.c1);
> +		return (k.linear.m0 * gain + k.linear.c0) /
> +		       (k.linear.m1 * gain + k.linear.c1);
> +
> +	case AnalogueGainExponential:
> +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> +
> +		return k.exp.a * std::exp2(k.exp.m * gain);
> +
> +	default:
> +		ASSERT(false);
> +		return 0.0;
> +	}
>   }
>   
>   /**
> @@ -120,15 +139,22 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   
>   /**
>    * \var CameraSensorHelper::AnalogueGainExponential
> - * \brief Gain is computed using exponential gain estimation
> - * (introduced in CCS v1.1)
> + * \brief Gain is expressed using an exponential model
>    *
> - * Starting with CCS v1.1, Alternate Global Analogue Gain is also available.
> - * If the image sensor supports it, then the global analogue gain can be
> - * controlled by linear and exponential gain formula:
> + * The relationship between the integer gain parameter and the resulting gain
> + * multiplier is given by the following equation:
>    *
> - * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal}\f$
> - * \todo not implemented in libipa
> + * \f$gain = a \cdot 2^{m \cdot x}\f$
> + *
> + * Where 'x' is the gain control parameter, and 'a' and 'm' are image
> + * sensor-specific constants.
> + *
> + * This is a subset of the MIPI CCS exponential gain model with the linear
> + * factor 'a' being a constant, but with the exponent being configurable
> + * through the 'm' coefficient.
> + *
> + * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
> + * \f$log_{2}{10^{frac{1}{20}}}\f$.
>    */
>   
>   /**
> @@ -152,6 +178,17 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>    * \brief Constant used in the linear gain coding/decoding
>    */
>   
> +/**
> + * \struct CameraSensorHelper::AnalogueGainExpConstants
> + * \brief Analogue gain constants for the exponential gain model
> + *
> + * \var CameraSensorHelper::AnalogueGainExpConstants::a
> + * \brief Constant used in the exponential gain coding/decoding
> + *
> + * \var CameraSensorHelper::AnalogueGainExpConstants::m
> + * \brief Constant used in the exponential gain coding/decoding
> + */
> +
>   /**
>    * \struct CameraSensorHelper::AnalogueGainConstants
>    * \brief Analogue gain model constants
> @@ -161,6 +198,9 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>    *
>    * \var CameraSensorHelper::AnalogueGainConstants::linear
>    * \brief Constants for the linear gain model
> + *
> + * \var CameraSensorHelper::AnalogueGainConstants::exp
> + * \brief Constants for the exponential gain model
>    */
>   
>   /**
> diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
> index 6b96520ba601..7351fc7c2928 100644
> --- a/src/ipa/libipa/camera_sensor_helper.h
> +++ b/src/ipa/libipa/camera_sensor_helper.h
> @@ -41,8 +41,14 @@ protected:
>   		int16_t c1;
>   	};
>   
> +	struct AnalogueGainExpConstants {
> +		double a;
> +		double m;
> +	};
> +
>   	union AnalogueGainConstants {
>   		AnalogueGainLinearConstants linear;
> +		AnalogueGainExpConstants exp;
>   	};
>   
>   	AnalogueGainType gainType_;
Nicolas Dufresne via libcamera-devel March 30, 2022, 8:45 a.m. UTC | #4
Hi Laurent,

On Mon, Mar 28, 2022 at 03:03:34PM +0300, Laurent Pinchart via libcamera-devel wrote:
> The CameraSensorHelper specifies two gain models, linear and an

s/an//

> exponential. They are modelled after the MIPI CCS specification. Only
> the linear model has been implemented, the exponential model was left
> for later.
> 
> We now need to support sensors that configure their gain in a hardware
> register with a value expressed in dB. This has similarities with the
> MIPI CCS exponential gain model, but is only has an exponential factor,
> while CCS also allows sensors to support a configurable linear factor.
> 
> The full CCS exponential model needs two values (for the linear and
> exponential factors) to express a gain, while IPAs use a single linear
> gain value internally. However, the exponential gain model example in
> the CCS specification has a fixed linear factor, which may indicate that
> it could be common for sensors that implement the exponential gain model
> to only use the exponential factor. For this reason, implement the
> exponential gain model with a fixed linear factor, but with a
> sensor-specific coefficient for the exponential factor that allows
> expressing the gain in dB (or other logarithmical units) instead of
> limiting it to powers of 2 as in the MIPI CCS specification.

Makes sense to me.

> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>

> ---
>  src/ipa/libipa/camera_sensor_helper.cpp | 82 ++++++++++++++++++-------
>  src/ipa/libipa/camera_sensor_helper.h   |  6 ++
>  2 files changed, 67 insertions(+), 21 deletions(-)
> 
> diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
> index 714cd86f039f..7bb999e19102 100644
> --- a/src/ipa/libipa/camera_sensor_helper.cpp
> +++ b/src/ipa/libipa/camera_sensor_helper.cpp
> @@ -7,6 +7,8 @@
>   */
>  #include "camera_sensor_helper.h"
>  
> +#include <cmath>
> +
>  #include <libcamera/base/log.h>
>  
>  /**
> @@ -51,20 +53,28 @@ namespace ipa {
>   * This function aims to abstract the calculation of the gain letting the IPA
>   * use the real gain for its estimations.
>   *
> - * The parameters come from the MIPI Alliance Camera Specification for
> - * Camera Command Set (CCS).
> - *
>   * \return The gain code to pass to V4L2
>   */
>  uint32_t CameraSensorHelper::gainCode(double gain) const
>  {
>  	const AnalogueGainConstants &k = gainConstants_;
>  
> -	ASSERT(gainType_ == AnalogueGainLinear);
> -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> +	switch (gainType_) {
> +	case AnalogueGainLinear:
> +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
>  
> -	return (k.linear.c0 - k.linear.c1 * gain) /
> -	       (k.linear.m1 * gain - k.linear.m0);
> +		return (k.linear.c0 - k.linear.c1 * gain) /
> +		       (k.linear.m1 * gain - k.linear.m0);
> +
> +	case AnalogueGainExponential:
> +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> +
> +		return std::log2(gain / k.exp.a) / k.exp.m;
> +
> +	default:
> +		ASSERT(false);
> +		return 0;
> +	}
>  }
>  
>  /**
> @@ -75,20 +85,29 @@ uint32_t CameraSensorHelper::gainCode(double gain) const
>   * use the real gain for its estimations. It is the counterpart of the function
>   * CameraSensorHelper::gainCode.
>   *
> - * The parameters come from the MIPI Alliance Camera Specification for
> - * Camera Command Set (CCS).
> - *
>   * \return The real gain
>   */
>  double CameraSensorHelper::gain(uint32_t gainCode) const
>  {
>  	const AnalogueGainConstants &k = gainConstants_;
> +	double gain = static_cast<double>(gainCode);
>  
> -	ASSERT(gainType_ == AnalogueGainLinear);
> -	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> +	switch (gainType_) {
> +	case AnalogueGainLinear:
> +		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
>  
> -	return (k.linear.m0 * static_cast<double>(gainCode) + k.linear.c0) /
> -	       (k.linear.m1 * static_cast<double>(gainCode) + k.linear.c1);
> +		return (k.linear.m0 * gain + k.linear.c0) /
> +		       (k.linear.m1 * gain + k.linear.c1);
> +
> +	case AnalogueGainExponential:
> +		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> +
> +		return k.exp.a * std::exp2(k.exp.m * gain);
> +
> +	default:
> +		ASSERT(false);
> +		return 0.0;
> +	}
>  }
>  
>  /**
> @@ -120,15 +139,22 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>  
>  /**
>   * \var CameraSensorHelper::AnalogueGainExponential
> - * \brief Gain is computed using exponential gain estimation
> - * (introduced in CCS v1.1)
> + * \brief Gain is expressed using an exponential model
>   *
> - * Starting with CCS v1.1, Alternate Global Analogue Gain is also available.
> - * If the image sensor supports it, then the global analogue gain can be
> - * controlled by linear and exponential gain formula:
> + * The relationship between the integer gain parameter and the resulting gain
> + * multiplier is given by the following equation:
>   *
> - * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal}\f$
> - * \todo not implemented in libipa
> + * \f$gain = a \cdot 2^{m \cdot x}\f$
> + *
> + * Where 'x' is the gain control parameter, and 'a' and 'm' are image
> + * sensor-specific constants.
> + *
> + * This is a subset of the MIPI CCS exponential gain model with the linear
> + * factor 'a' being a constant, but with the exponent being configurable
> + * through the 'm' coefficient.
> + *
> + * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
> + * \f$log_{2}{10^{frac{1}{20}}}\f$.
>   */
>  
>  /**
> @@ -152,6 +178,17 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   * \brief Constant used in the linear gain coding/decoding
>   */
>  
> +/**
> + * \struct CameraSensorHelper::AnalogueGainExpConstants
> + * \brief Analogue gain constants for the exponential gain model
> + *
> + * \var CameraSensorHelper::AnalogueGainExpConstants::a
> + * \brief Constant used in the exponential gain coding/decoding
> + *
> + * \var CameraSensorHelper::AnalogueGainExpConstants::m
> + * \brief Constant used in the exponential gain coding/decoding
> + */
> +
>  /**
>   * \struct CameraSensorHelper::AnalogueGainConstants
>   * \brief Analogue gain model constants
> @@ -161,6 +198,9 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   *
>   * \var CameraSensorHelper::AnalogueGainConstants::linear
>   * \brief Constants for the linear gain model
> + *
> + * \var CameraSensorHelper::AnalogueGainConstants::exp
> + * \brief Constants for the exponential gain model
>   */
>  
>  /**
> diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
> index 6b96520ba601..7351fc7c2928 100644
> --- a/src/ipa/libipa/camera_sensor_helper.h
> +++ b/src/ipa/libipa/camera_sensor_helper.h
> @@ -41,8 +41,14 @@ protected:
>  		int16_t c1;
>  	};
>  
> +	struct AnalogueGainExpConstants {
> +		double a;
> +		double m;
> +	};
> +
>  	union AnalogueGainConstants {
>  		AnalogueGainLinearConstants linear;
> +		AnalogueGainExpConstants exp;
>  	};
>  
>  	AnalogueGainType gainType_;

Patch
diff mbox series

diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
index 714cd86f039f..7bb999e19102 100644
--- a/src/ipa/libipa/camera_sensor_helper.cpp
+++ b/src/ipa/libipa/camera_sensor_helper.cpp
@@ -7,6 +7,8 @@ 
  */
 #include "camera_sensor_helper.h"
 
+#include <cmath>
+
 #include <libcamera/base/log.h>
 
 /**
@@ -51,20 +53,28 @@  namespace ipa {
  * This function aims to abstract the calculation of the gain letting the IPA
  * use the real gain for its estimations.
  *
- * The parameters come from the MIPI Alliance Camera Specification for
- * Camera Command Set (CCS).
- *
  * \return The gain code to pass to V4L2
  */
 uint32_t CameraSensorHelper::gainCode(double gain) const
 {
 	const AnalogueGainConstants &k = gainConstants_;
 
-	ASSERT(gainType_ == AnalogueGainLinear);
-	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
+	switch (gainType_) {
+	case AnalogueGainLinear:
+		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
 
-	return (k.linear.c0 - k.linear.c1 * gain) /
-	       (k.linear.m1 * gain - k.linear.m0);
+		return (k.linear.c0 - k.linear.c1 * gain) /
+		       (k.linear.m1 * gain - k.linear.m0);
+
+	case AnalogueGainExponential:
+		ASSERT(k.exp.a != 0 && k.exp.m != 0);
+
+		return std::log2(gain / k.exp.a) / k.exp.m;
+
+	default:
+		ASSERT(false);
+		return 0;
+	}
 }
 
 /**
@@ -75,20 +85,29 @@  uint32_t CameraSensorHelper::gainCode(double gain) const
  * use the real gain for its estimations. It is the counterpart of the function
  * CameraSensorHelper::gainCode.
  *
- * The parameters come from the MIPI Alliance Camera Specification for
- * Camera Command Set (CCS).
- *
  * \return The real gain
  */
 double CameraSensorHelper::gain(uint32_t gainCode) const
 {
 	const AnalogueGainConstants &k = gainConstants_;
+	double gain = static_cast<double>(gainCode);
 
-	ASSERT(gainType_ == AnalogueGainLinear);
-	ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
+	switch (gainType_) {
+	case AnalogueGainLinear:
+		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
 
-	return (k.linear.m0 * static_cast<double>(gainCode) + k.linear.c0) /
-	       (k.linear.m1 * static_cast<double>(gainCode) + k.linear.c1);
+		return (k.linear.m0 * gain + k.linear.c0) /
+		       (k.linear.m1 * gain + k.linear.c1);
+
+	case AnalogueGainExponential:
+		ASSERT(k.exp.a != 0 && k.exp.m != 0);
+
+		return k.exp.a * std::exp2(k.exp.m * gain);
+
+	default:
+		ASSERT(false);
+		return 0.0;
+	}
 }
 
 /**
@@ -120,15 +139,22 @@  double CameraSensorHelper::gain(uint32_t gainCode) const
 
 /**
  * \var CameraSensorHelper::AnalogueGainExponential
- * \brief Gain is computed using exponential gain estimation
- * (introduced in CCS v1.1)
+ * \brief Gain is expressed using an exponential model
  *
- * Starting with CCS v1.1, Alternate Global Analogue Gain is also available.
- * If the image sensor supports it, then the global analogue gain can be
- * controlled by linear and exponential gain formula:
+ * The relationship between the integer gain parameter and the resulting gain
+ * multiplier is given by the following equation:
  *
- * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal}\f$
- * \todo not implemented in libipa
+ * \f$gain = a \cdot 2^{m \cdot x}\f$
+ *
+ * Where 'x' is the gain control parameter, and 'a' and 'm' are image
+ * sensor-specific constants.
+ *
+ * This is a subset of the MIPI CCS exponential gain model with the linear
+ * factor 'a' being a constant, but with the exponent being configurable
+ * through the 'm' coefficient.
+ *
+ * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
+ * \f$log_{2}{10^{frac{1}{20}}}\f$.
  */
 
 /**
@@ -152,6 +178,17 @@  double CameraSensorHelper::gain(uint32_t gainCode) const
  * \brief Constant used in the linear gain coding/decoding
  */
 
+/**
+ * \struct CameraSensorHelper::AnalogueGainExpConstants
+ * \brief Analogue gain constants for the exponential gain model
+ *
+ * \var CameraSensorHelper::AnalogueGainExpConstants::a
+ * \brief Constant used in the exponential gain coding/decoding
+ *
+ * \var CameraSensorHelper::AnalogueGainExpConstants::m
+ * \brief Constant used in the exponential gain coding/decoding
+ */
+
 /**
  * \struct CameraSensorHelper::AnalogueGainConstants
  * \brief Analogue gain model constants
@@ -161,6 +198,9 @@  double CameraSensorHelper::gain(uint32_t gainCode) const
  *
  * \var CameraSensorHelper::AnalogueGainConstants::linear
  * \brief Constants for the linear gain model
+ *
+ * \var CameraSensorHelper::AnalogueGainConstants::exp
+ * \brief Constants for the exponential gain model
  */
 
 /**
diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
index 6b96520ba601..7351fc7c2928 100644
--- a/src/ipa/libipa/camera_sensor_helper.h
+++ b/src/ipa/libipa/camera_sensor_helper.h
@@ -41,8 +41,14 @@  protected:
 		int16_t c1;
 	};
 
+	struct AnalogueGainExpConstants {
+		double a;
+		double m;
+	};
+
 	union AnalogueGainConstants {
 		AnalogueGainLinearConstants linear;
+		AnalogueGainExpConstants exp;
 	};
 
 	AnalogueGainType gainType_;