|
@@ -0,0 +1,465 @@
|
|
|
+package com.gyee.power.fitting.common.alg;
|
|
|
+
|
|
|
+//package easyexcel;
|
|
|
+
|
|
|
+import com.alibaba.excel.EasyExcel;
|
|
|
+import com.alibaba.excel.context.AnalysisContext;
|
|
|
+import com.alibaba.excel.event.AnalysisEventListener;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.LinkedList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+//绘制曲线需要
|
|
|
+import java.awt.*;
|
|
|
+import javax.swing.*;
|
|
|
+import java.awt.geom.GeneralPath;
|
|
|
+
|
|
|
+
|
|
|
+import com.gyee.power.fitting.model.custom.LineCurveFitting;
|
|
|
+import com.gyee.power.fitting.model.custom.PointVo;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+
|
|
|
+import org.apache.commons.math3.fitting.PolynomialCurveFitter;
|
|
|
+import org.apache.commons.math3.fitting.WeightedObservedPoints;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * I-V曲线拟合算法
|
|
|
+ * 最小二乘法
|
|
|
+ */
|
|
|
+public class MpptFittingAlg {
|
|
|
+
|
|
|
+
|
|
|
+ public static List<PointVo> BuildLine_IV_LSC(double[] arrX, double[] arrY, int length, int dimension, double scale){
|
|
|
+
|
|
|
+ List<PointVo> points = new ArrayList<>();
|
|
|
+
|
|
|
+ if(arrX.length != arrY.length || arrX.length < 3){
|
|
|
+ return points;
|
|
|
+ }
|
|
|
+
|
|
|
+ double minValue = arrY[arrY.length - 1];
|
|
|
+ double maxValue = arrY[0];
|
|
|
+
|
|
|
+ double min = 0;
|
|
|
+ double max = 0;
|
|
|
+
|
|
|
+ double[] coefficient = MultiLine(arrX, arrY, length, dimension);
|
|
|
+
|
|
|
+ for (double i = arrX[arrX.length - 1]; i > arrX[0]; i -= scale) {
|
|
|
+ PointVo point = new PointVo();
|
|
|
+ point.setX(i);
|
|
|
+
|
|
|
+ for (int j = 0; j < coefficient.length; j++) {
|
|
|
+ if (j == 0) {
|
|
|
+ point.setY(coefficient[j] * Math.pow(point.getX(), j));
|
|
|
+ } else {
|
|
|
+ double temp = coefficient[j] *Math.pow(point.getX(), j);
|
|
|
+ point.setY(point.getY() + temp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (point.getY() < minValue) {
|
|
|
+ point.setY(minValue);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ if (point.getY() > maxValue) {
|
|
|
+ point.setY(maxValue);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (point.getY() < min) {
|
|
|
+ min = point.getY();
|
|
|
+ }
|
|
|
+ if (point.getY() > max) {
|
|
|
+ max = point.getY();
|
|
|
+ }
|
|
|
+
|
|
|
+ points.add(point);
|
|
|
+ }
|
|
|
+ Builder(points, min, max);
|
|
|
+ System.out.print("X轴数据\n");
|
|
|
+ int len = points.size();
|
|
|
+ double[] aX = new double[len];
|
|
|
+ for (int i = len-1; i >0; i --){
|
|
|
+ aX[i] = points.get(i).getX();
|
|
|
+ System.out.print(aX[i]+",");
|
|
|
+ System.out.print("\n");
|
|
|
+ }
|
|
|
+ System.out.print("\n");
|
|
|
+ System.out.print("Y轴数据\n");
|
|
|
+
|
|
|
+ double[] aY = new double[len];
|
|
|
+ for(int i = len-1;i >0; i--){
|
|
|
+ aY[i] = points.get(i).getY();
|
|
|
+ System.out.print(aY[i]+",");
|
|
|
+ System.out.print("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ return points;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * P-V曲线拟合算法
|
|
|
+ * 最小二乘法
|
|
|
+ */
|
|
|
+ public static List<PointVo> BuildLine_PV_LSC(double[] arrX, double[] arrY, int length, int dimension, double scale){
|
|
|
+
|
|
|
+ List<PointVo> points = new ArrayList<>();
|
|
|
+
|
|
|
+ if(arrX.length != arrY.length || arrX.length < 3){
|
|
|
+ return points;
|
|
|
+ }
|
|
|
+
|
|
|
+ double minValue = arrY[0];
|
|
|
+ double maxValue = 0;
|
|
|
+ for(int i = 0 ;i < arrY.length; i++){
|
|
|
+ double val = arrY[i];
|
|
|
+ if(val > maxValue){
|
|
|
+ maxValue = val;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ double min = 0;
|
|
|
+ double max = 0;
|
|
|
+
|
|
|
+ double[] coefficient = MultiLine(arrX, arrY, length, dimension);
|
|
|
+
|
|
|
+ for (double i = arrX[arrX.length - 1]; i > arrX[0]; i -= scale) {
|
|
|
+ PointVo point = new PointVo();
|
|
|
+ point.setX(i);
|
|
|
+
|
|
|
+ for (int j = 0; j < coefficient.length; j++) {
|
|
|
+ if (j == 0) {
|
|
|
+ point.setY(coefficient[j] * Math.pow(point.getX(), j));
|
|
|
+ } else {
|
|
|
+ double temp = coefficient[j] *Math.pow(point.getX(), j);
|
|
|
+ point.setY(point.getY() + temp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (point.getY() < minValue) {
|
|
|
+ point.setY(minValue);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ if (point.getY() > maxValue) {
|
|
|
+ point.setY(maxValue);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (point.getY() < min) {
|
|
|
+ min = point.getY();
|
|
|
+ }
|
|
|
+ if (point.getY() > max) {
|
|
|
+ max = point.getY();
|
|
|
+ }
|
|
|
+
|
|
|
+ points.add(point);
|
|
|
+ }
|
|
|
+ Builder(points, min, max);
|
|
|
+ System.out.print("X轴数据\n");
|
|
|
+ int len = points.size();
|
|
|
+ double[] aX = new double[len];
|
|
|
+ for (int i = len-1; i >0; i --){
|
|
|
+ aX[i] = points.get(i).getX();
|
|
|
+ System.out.print(aX[i]+",");
|
|
|
+ System.out.print("\n");
|
|
|
+ }
|
|
|
+ System.out.print("\n");
|
|
|
+ System.out.print("Y轴数据\n");
|
|
|
+
|
|
|
+ double[] aY = new double[len];
|
|
|
+ for (int i = len-1;i >0; i--){
|
|
|
+ aY[i] = points.get(i).getY();
|
|
|
+ System.out.print(aY[i]+",");
|
|
|
+ System.out.print("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ return points;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void Builder(List<PointVo> points, double min, double max) {
|
|
|
+ boolean b = false;
|
|
|
+ for (int i = 0; i < points.size(); i++) {
|
|
|
+ if (b) {
|
|
|
+ points.get(i).setY(max);
|
|
|
+ } else {
|
|
|
+ if (max == points.get(i).getY()) {
|
|
|
+ b = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ for (int i = points.size() - 1; i > -1; i--) {
|
|
|
+ if (!b) {
|
|
|
+ points.get(i).setY(min);
|
|
|
+ } else {
|
|
|
+ if (min == points.get(i).getY()) {
|
|
|
+ b = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double[] MultiLine(double[] arrX, double[] arrY, int length,int dimension)
|
|
|
+ {
|
|
|
+ int n = dimension + 1; //dimension次方程需要求 dimension+1个 系数
|
|
|
+ double[][] Guass = new double[n][n + 1]; //高斯矩阵 例如:y=a0+a1*x+a2*x*x
|
|
|
+ for (int i = 0; i < n; i++) {
|
|
|
+ int j;
|
|
|
+ for (j = 0; j < n; j++) {
|
|
|
+ Guass[i][j] = SumArr(arrX, j + i, length);
|
|
|
+ }
|
|
|
+ Guass[i][j] = SumArr(arrX, i, arrY, 1, length);
|
|
|
+ }
|
|
|
+ return ComputGauss(Guass, n);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double SumArr(double[] arr, int n, int length) //求数组的元素的n次方的和
|
|
|
+ {
|
|
|
+ double s = 0;
|
|
|
+ for (int i = 0; i < length; i++) {
|
|
|
+ if (arr[i] != 0 || n != 0)
|
|
|
+ s = s + Math.pow(arr[i], n);
|
|
|
+ else
|
|
|
+ s = s + 1;
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double SumArr(double[] arr1, int n1, double[] arr2, int n2, int length) {
|
|
|
+ double s = 0;
|
|
|
+ for (int i = 0; i < length; i++) {
|
|
|
+ if ((arr1[i] != 0 || n1 != 0) && (arr2[i] != 0 || n2 != 0))
|
|
|
+ s = s + Math.pow(arr1[i], n1) * Math.pow(arr2[i], n2);
|
|
|
+ else
|
|
|
+ s = s + 1;
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double[] ComputGauss(double[][] Guass, int n) {
|
|
|
+ int i, j;
|
|
|
+ int k, m;
|
|
|
+ double temp;
|
|
|
+ double max;
|
|
|
+ double s;
|
|
|
+ double[] x = new double[n];
|
|
|
+ for (i = 0; i < n; i++) x[i] = 0.0;//初始化
|
|
|
+
|
|
|
+ for (j = 0; j < n; j++) {
|
|
|
+ max = 0;
|
|
|
+ k = j;
|
|
|
+ for (i = j; i < n; i++) {
|
|
|
+ if (Math.abs(Guass[i][j]) > max) {
|
|
|
+ max = Guass[i][j];
|
|
|
+ k = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (k != j) {
|
|
|
+ for (m = j; m < n + 1; m++) {
|
|
|
+ temp = Guass[j][m];
|
|
|
+ Guass[j][m] = Guass[k][m];
|
|
|
+ Guass[k][m] = temp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (0 == max) {
|
|
|
+ // "此线性方程为奇异线性方程"
|
|
|
+ return x;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = j + 1; i < n; i++) {
|
|
|
+ s = Guass[i][j];
|
|
|
+ for (m = j; m < n + 1; m++) {
|
|
|
+ Guass[i][m] = Guass[i][m] - Guass[j][m] * s / (Guass[j][j]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }//结束for (j=0;j<n;j++)
|
|
|
+
|
|
|
+ for (i = n - 1; i >= 0; i--) {
|
|
|
+ s = 0;
|
|
|
+ for (j = i + 1; j < n; j++) {
|
|
|
+ s = s + Guass[i][j] * x[j];
|
|
|
+ }
|
|
|
+ x[i] = (Guass[i][n] - s) / Guass[i][i];
|
|
|
+ }
|
|
|
+ return x;
|
|
|
+ }//返回值是函数的系数
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * P-V曲线拟合算法
|
|
|
+ * 多项式曲线拟合
|
|
|
+ * @param arrX --功率(P)值
|
|
|
+ * @param arrY --电流(I)值
|
|
|
+ * @param order 进行拟合的阶数
|
|
|
+ */
|
|
|
+
|
|
|
+ public static List<PointVo> BuildLine_PV_Poly(double[] arrX, double[] arrY, int order) {
|
|
|
+
|
|
|
+ double[] aX = new double[10];
|
|
|
+
|
|
|
+ double maxValue = 0;
|
|
|
+ for(int i = 0 ;i < arrX.length; i++){
|
|
|
+ double val = arrX[i];
|
|
|
+ if(val > maxValue){
|
|
|
+ maxValue = val;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ double scale = 0.1;
|
|
|
+ int ylen = (int)(maxValue/scale);
|
|
|
+
|
|
|
+ double[] aY = new double[ylen];
|
|
|
+ for(int i = 0; i< arrX.length; i++){
|
|
|
+ aX[i] = arrX[i];
|
|
|
+ }
|
|
|
+ PointVo point = new PointVo();
|
|
|
+ List<PointVo> points = new ArrayList<>();
|
|
|
+
|
|
|
+ // N阶多项式会有N+1个系数,其中之一为常数项
|
|
|
+ double[] factor = new double[order + 1];
|
|
|
+ for(int index = 0; index < factor.length; index++) {
|
|
|
+ factor[index] = index + 1;
|
|
|
+ }
|
|
|
+ for(int index = 0; index < arrY.length; index++) {
|
|
|
+ arrX[index] = index * 0.00001;
|
|
|
+ arrY[index] = calcPoly(arrX[index], factor); // y = sum(x[n) * fact[n])
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //调用将arrX和arrY序列中的数据逐个添加到观察点序列对象中
|
|
|
+ WeightedObservedPoints point1 = new WeightedObservedPoints();
|
|
|
+ for(int index = 0; index < arrX.length; index++) {
|
|
|
+ point1.add(arrX[index], arrY[index]);
|
|
|
+ }
|
|
|
+ // 创建PolynomialCurveFitter对象,需指定拟合多项式的阶数
|
|
|
+ PolynomialCurveFitter fitter = PolynomialCurveFitter.create(order);
|
|
|
+
|
|
|
+ List<Object> params = new ArrayList<Object>();
|
|
|
+ params.add(point1);
|
|
|
+ // 调用PolynomialCurveFitter的fit方法进行多项式曲线拟合
|
|
|
+ WeightedObservedPoints point2 = (WeightedObservedPoints)params.get(0);
|
|
|
+ // 拟合结果通过一个double数组返回,按元素顺序依次是常数项、一次项、二次项、……。
|
|
|
+ double[] result = fitter.fit(point2.toList());//例如 3,4,2,6 y=3*x^3+4*x^2+2*x+6
|
|
|
+
|
|
|
+ // String y = printPoly(result);
|
|
|
+ int k = result.length - 1;
|
|
|
+ System.out.print("X轴数据\n");
|
|
|
+ for(int i = 0;i < aX.length; i++){
|
|
|
+ System.out.print(aX[i]+",");
|
|
|
+ System.out.print("\n");
|
|
|
+ }
|
|
|
+ System.out.print("Y轴数据\n");
|
|
|
+
|
|
|
+ int q = 0;
|
|
|
+
|
|
|
+ for (double i = aX[aX.length - 1]; i > aX[0]; i -= scale) {
|
|
|
+
|
|
|
+ for (int j = 0; j < result.length; j++) {
|
|
|
+ if (j == 0) {
|
|
|
+ aY[q] = result[k];
|
|
|
+ } else {
|
|
|
+ aY[q] += Math.pow(arrX[q], j) * result[k - j];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ System.out.print(aY[q]+",");
|
|
|
+ System.out.print("\n");
|
|
|
+ q++;
|
|
|
+ }
|
|
|
+ return points;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * P-V曲线拟合算法
|
|
|
+ * 多项式曲线拟合
|
|
|
+ *
|
|
|
+ * @param arrX --电压(V)值
|
|
|
+ * @param arrY --电流(I)值
|
|
|
+ * @param order 进行拟合的阶数
|
|
|
+ */
|
|
|
+
|
|
|
+ public static List<PointVo> BuildLine_IV_Poly(double[] arrX, double[] arrY, int order) {
|
|
|
+
|
|
|
+ PointVo point = new PointVo();
|
|
|
+ List<PointVo> points = new ArrayList<>();
|
|
|
+
|
|
|
+ // N阶多项式会有N+1个系数,其中之一为常数项
|
|
|
+ double[] factor = new double[order + 1];
|
|
|
+ for(int index = 0; index < factor.length; index++)
|
|
|
+ {
|
|
|
+ factor[index] = index + 1;
|
|
|
+ }
|
|
|
+ for(int index = 0; index < arrY.length; index++)
|
|
|
+ {
|
|
|
+ arrX[index] = index * 0.00001;
|
|
|
+ arrY[index] = calcPoly(arrX[index], factor); // y = sum(x[n) * fact[n])
|
|
|
+ }
|
|
|
+ //调用将arrX和arrY序列中的数据逐个添加到观察点序列对象中
|
|
|
+ WeightedObservedPoints point1 = new WeightedObservedPoints();
|
|
|
+ for(int index = 0; index < arrX.length; index++)
|
|
|
+ {
|
|
|
+ point1.add(arrX[index], arrY[index]);
|
|
|
+ }
|
|
|
+ // 创建PolynomialCurveFitter对象,需指定拟合多项式的阶数
|
|
|
+ PolynomialCurveFitter fitter = PolynomialCurveFitter.create(order);
|
|
|
+
|
|
|
+ List<Object> params = new ArrayList<Object>();
|
|
|
+ params.add(point1);
|
|
|
+ // 调用PolynomialCurveFitter的fit方法进行多项式曲线拟合
|
|
|
+ WeightedObservedPoints point2 = (WeightedObservedPoints)params.get(0);
|
|
|
+ // 拟合结果通过一个double数组返回,按元素顺序依次是常数项、一次项、二次项、……。
|
|
|
+ double[] result = fitter.fit(point2.toList());//例如 3,4,2,6 y=3*x^3+4*x^2+2*x+6
|
|
|
+
|
|
|
+ int k = result.length - 1;
|
|
|
+ for (int i = 0 ; i <= arrX[arrX.length - 1]; i++) {
|
|
|
+ for (int j = 0; j < result.length; j++) {
|
|
|
+ if (j == 0) {
|
|
|
+ arrY[i] = result[k];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ arrY[i] += Math.pow(arrX[i], j) * result[k - j];
|
|
|
+ }
|
|
|
+ point.setX(arrX[i]);
|
|
|
+ point.setX(arrY[i]);
|
|
|
+ points.add(point);
|
|
|
+ }
|
|
|
+
|
|
|
+ return points;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static double calcPoly(double x, double[] factor)
|
|
|
+ {
|
|
|
+ double y = 0;
|
|
|
+ for(int deg = 0; deg < factor.length; deg++)
|
|
|
+ {
|
|
|
+ y += Math.pow(x, deg) * factor[deg];
|
|
|
+ }
|
|
|
+ return y;
|
|
|
+ }
|
|
|
+ public static String printPoly(double[] result) {
|
|
|
+
|
|
|
+ String polynomialString = "";
|
|
|
+ for (int i = 0; i < result.length; i++) {
|
|
|
+ if (i == 0) {
|
|
|
+ polynomialString += result[i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ polynomialString += result[i] + "x^" + i + " ";
|
|
|
+ }
|
|
|
+ return polynomialString;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|