Files
2026-08-24 10:03:24 +08:00

328 lines
9.2 KiB
C++

/*
* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description: c++ file
*/
#define LOG_TAG "SystemControl"
#define LOG_TV_TAG "GammaOperation"
#include <math.h>
#include "GammaOperation.h"
GammaOperation::GammaOperation()
{
}
GammaOperation::~GammaOperation()
{
}
//============================gamma Power Convert Start=======================================
int GammaOperation::GammaOperation_BaseGammaConvert(unsigned short *gamma_value, double basePower , double targetPower, int NodeNum)
{
int ret = -1;
std::vector<double> xData, yData;
if (basePower == targetPower) {
return 0;
}
if (gamma_value == NULL) {
return -1;
}
for (int j = 0; j < NodeNum; ++j)
{
xData.push_back(((double)j)/(double)(NodeNum - 1));
yData.push_back((double)gamma_value[j]);
}
tk::spline continuousLine;
continuousLine.set_points(xData, yData);
std::vector<int> returnCurve;
for (int j = 0; j < NodeNum; ++j)
{
returnCurve.push_back(continuousLine(pow(((double)j) / (double)(NodeNum - 1) , targetPower / basePower )));
gamma_value[j] = returnCurve[j];
}
ret = 0;
return ret;
}
//============================gamma Power Convert End=======================================
//=========================whiteBalan ceconvert start=======================================
interpolation_info_t* GammaOperation::nat_cubic_spline(int num_points, interpolation_info_t* output_fun) {
float x_delta[num_points-1]; /* x differences */
float y_delta[num_points-1]; /* y differences */
float A[num_points][NUMBER_POINTS]; /* matrix for solving for c */
float h[num_points]; /* vector for solving for c */
/* Goal: create interpolating functions of the form:
S_j(x) = a_j(x) + b_j(x - x_j) + c_j(x - x_j)^2 + d_j(x - x_j)^3
where 0 < j < num_points
*/
/* First, want to solve: Ac = h where A is a matrix and c and h are
vectors
*/
int i; /* loop index */
/* If there aren't enough points to interpolate, bail */
if (num_points < 3) {
return NULL;
}
/* Assign parameters to our S struct */
output_fun->num_points = num_points;
/* Build x diff and y diff */
for (i = 1; i < num_points; i++) {
x_delta[i-1] = output_fun->x[i] - output_fun->x[i-1];
y_delta[i-1] = output_fun->y[i] - output_fun->y[i-1];
}
/* Build "a" vector (just y) */
for (i = 0; i < num_points; i++) {
output_fun->a[i] = output_fun->y[i];
}
/* Build A matrix */
build_A_matrix(x_delta, num_points, A);
/* Build h vector */
build_h_vector(h, x_delta, output_fun->a, num_points);
/* Solve matrix equation for c vector (Ac = h) */
solve_matrix(output_fun->c, h, num_points, A);
/* Build b vector */
build_b_vector(output_fun->b, x_delta, y_delta, output_fun->c, num_points);
/* Build d vector */
build_d_vector(output_fun->d, x_delta, output_fun->c, num_points);
/* Return S struct containing all the coeffs and init vals */
return output_fun;
}
void GammaOperation::build_A_matrix(float *x_delta, int num_points,
float A[][NUMBER_POINTS]) {
int i;
/* Set top and bottom corners */
A[0][0] = 1;
A[num_points-1][num_points-1] = 1;
/* Fill in the matrix by natural cubic spline algorithm */
for (i = 1; i < num_points-1; i++) {
A[i][i-1] = x_delta[i-1];
A[i][i] = 2*(x_delta[i-1]+x_delta[i]);
A[i][i+1] = x_delta[i];
}
}
float* GammaOperation::build_h_vector(float *h, float *x_delta, float *a, int num_points) {
int i;
/* Set top and bottom */
h[0] = 0.;
h[num_points-1] = 0.;
/* Fill in the vector by natural cubic spline algorithm */
for (i = 1; i < num_points-1; i++) {
h[i] = 3.*((a[i+1]-a[i]) / x_delta[i] - (a[i]-a[i-1]) / x_delta[i-1]);
}
return h;
}
float* GammaOperation::solve_matrix(float *x, float *h, int num_points,
float A[][NUMBER_POINTS]) {
/* Solves tridiagonal matrix equation Ax = h
for tridiagonal matrix A using Thomas' algorithm.
This requires the matrix to be diagonally dominant or symmetric
positive definite. This should always be the case for our spline.
*/
float a[num_points]; /* values to the left of diagonal of A */
float b[num_points]; /* values on the diagonal of A */
float c[num_points]; /* values to the right of diagonal of A */
int i; /* loop index */
float w[num_points]; /* used as a temp variable */
/* Set end points */
b[0] = 1.;
c[0] = 0.;
a[num_points-1] = 0.;
b[num_points-1] = 1.;
/* Build a, b, c */
for (i = 1; i < num_points-1; i++) {
a[i] = A[i][i-1];
b[i] = A[i][i];
c[i] = A[i][i+1];
}
/* Apply Thomas' algorithm */
for (i = 1; i < num_points; i++) {
w[i] = a[i] / b[i-1];
b[i] = b[i] - w[i]*c[i-1];
h[i] = h[i] - w[i]*h[i-1];
}
/* Back substitute x */
x[num_points-1] = h[num_points-1] / b[num_points-1];
for (i = num_points-2; i >= 0; i--) {
x[i] = (h[i] - c[i] * x[i+1]) / b[i];
}
return x;
}
float* GammaOperation::build_b_vector(float *b, float *x_delta, float *y_delta, float *c,
int num_points) {
int i; /* loop index */
/* Build b by natural cubic spline */
for (i = 0; i < num_points-1; i++) {
b[i] = y_delta[i] / x_delta[i] - x_delta[i] / 3 * (2 * c[i] + c[i+1]);
}
return b;
}
float* GammaOperation::build_d_vector(float *d, float *x_delta, float *c, int num_points) {
int i; /* loop index */
/* Build d by natural cubic spline */
for (i = 0; i < num_points-1; i++) {
d[i] = (c[i+1] - c[i]) / (3 * x_delta[i]);
}
return d;
}
int GammaOperation::evaluate(interpolation_info_t *function, float val, float *result) {
/* Use the interpolation to evaluate a val, answer stored in
result
*/
int i; /* loop index */
/* if the val is less than the smallest value, outside of range,
bail.
*/
if (val < function->x[0]) {
/* -1 represents too small of a val ... not sure how errno is used
in arduino so I'm using return values to set error types.
*/
return -1;
}
/* If the val is greater than the largest value, outside of range,
bail.
*/
else if (val > function->x[function->num_points-1]) {
/* Set error val */
return -2;
}
for (i = 0; i < function->num_points-1; i++) {
/* If val equals an element in my x array, just return the
corresponding y val
*/
if (almost_equals(val, function->x[i])) {
*result = function->y[i];
/* return val of 0 means no errors */
return 0;
}
/* Check the next element also, since I use the range next */
else if (almost_equals(val, function->x[i+1])) {
*result = function->y[i+1];
return 0;
}
else if (val > function->x[i] && val < function->x[i+1]) {
/* If the val falls between 2 initial x values, find the value the
interpolation gives.
*/
*result = spline_func(function, val, i);
return 0;
}
}
/* Something has gone horribly wrong */
return -3;
}
float GammaOperation::spline_func(interpolation_info_t *function, float val, int i) {
/* This function selects the appropriate spline function and evaluates
that function at val.
*/
/* Each p is a different term in the polynomial (number after p is the
power)
*/
float p0;
float p1;
float p2;
float p3;
/* It's useful to copy and paste the functional form of our spline from
above:
S_i(x) = a_i(x) + b_i(x - x_i) + c_i(x - x_i)^2 + d_i(x - x_i)^3
where 0 < i < num_points.
We take the ith element from the a, b, c, d, and x arrays for the
{letter}_i terms. The x term is val in this function. S_i(x) is the
returned value from the interpolation.
*/
p0 = function->a[i];
p1 = function->b[i] * (val - function->x[i]);
p2 = function->c[i] * (val - function->x[i])*(val - function->x[i]);
p3 = function->d[i] * (val -
function->x[i]) * (val - function->x[i]) * (val - function->x[i]);
return p0 + p1 + p2 + p3;
}
bool GammaOperation::almost_equals(float a, float b) {
/* Comparing floats for exact equality is shady, they won't ever be
exactly the same, so use this function to test if they're close enough.
*/
float c = a - b; /* c is the difference */
/* Make sure c is positive */
if (c < 0) {
c = -1*c;
}
/* If the difference is sufficiently small, return true */
if (c < 0.00000001) {
return true;
}
/* Otherwise, return false */
else {
return false;
}
}
//===========================whiteBalan ceconvert end===================================
GammaOperation *GammaOperation::mInstance = NULL;
GammaOperation *GammaOperation::GetInstance()
{
if (NULL == mInstance) {
mInstance = new GammaOperation();
}
return mInstance;
}