com.rstar.mobile.thermocouple.functions.Fn.java Source code

Java tutorial

Introduction

Here is the source code for com.rstar.mobile.thermocouple.functions.Fn.java

Source

/*
 * Copyright (c) 2015 Annie Hui @ RStar Technology Solutions
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.rstar.mobile.thermocouple.functions;

import android.graphics.PointF;

import com.rstar.mobile.thermocouple.AppSettings;
import com.rstar.mobile.thermocouple.Savelog;

import org.json.JSONArray;
import org.json.JSONObject;

public class Fn {
    private static final String TAG = Fn.class.getSimpleName() + "_class";
    private static final boolean debug = AppSettings.defaultDebug;

    public static final int InternalPtsPerSegmentForE = 8; // choose 3*n+2 for E
    public static final int InternalPtsPerSegmentForS = 30; // choose 3*n for S use 9
    private static final int BadIndex = -1;

    private String name = "";
    private String equation[] = null;
    private String coefficientType = "";
    private String unitT = "";
    private String unitEMF = "";

    private Polynomial[] polynomials = null;
    private Exponential exponential = null;

    public Fn(String data) {
        try {
            load(data);
        } catch (Exception e) {
            clear();
        }
    }

    private void clear() {
        name = "";
        equation = new String[0];
        coefficientType = "";
        unitT = "";
        unitEMF = "";
        polynomials = new Polynomial[0];
        exponential = null;
    }

    public double getTmin() {
        double Tmin;
        if (polynomials == null || polynomials.length == 0)
            return 0.0;
        Tmin = polynomials[0].Tmin;
        for (int index = 1; index < polynomials.length; index++) {
            if (Tmin > polynomials[index].Tmin)
                Tmin = polynomials[index].Tmin;
        }
        return Tmin;
    }

    public double getTmax() {
        double Tmax;
        if (polynomials == null || polynomials.length == 0)
            return 0.0;
        Tmax = polynomials[0].Tmax;
        for (int index = 1; index < polynomials.length; index++) {
            if (Tmax < polynomials[index].Tmax)
                Tmax = polynomials[index].Tmax;
        }
        return Tmax;
    }

    // NOTE: This is only an estimate without doing any thorough search.
    // E is NOT monotonously increasing with respect to Temperature, especially in the case of Type B.
    // However, the overall trend between T and E is approximately linear.
    // In this project, this function is used only for finding the scope of E for graphing purpose.
    // For such a purpose, an approximation of Emin and Emax is good enough.
    public double getApproxEmin() {
        try {
            return computeE(getTmin());
        } catch (Exception e) {
            return 0x0.0p0;
        }
    }

    // NOTE: This is only an estimate without doing any thorough search.
    // E is NOT monotonously increasing with respect to Temperature, especially in the case of Type B.
    // However, the overall trend between T and E is approximately linear.
    // In this project, this function is used only for finding the scope of E for graphing purpose.
    // For such a purpose, an approximation of Emin and Emax is good enough.
    public double getApproxEmax() {
        try {
            return computeE(getTmax());
        } catch (Exception e) {
            return 0x0.0p0;
        }
    }

    public double computeE(double temperature) throws Exception {
        // Throw an exception if temperature is out of range
        int index = findPolynomial(temperature);
        if (index != BadIndex) {
            double data = polynomials[index].compute(temperature);

            double correction = 0.0;
            if (exponential != null && temperature > 0) {
                // according to the function definition from NIST,
                // the exponential term is available only for type K when temperature > 0
                // Reference http://srdata.nist.gov/its90/download/download.html
                correction = exponential.compute(temperature);
            }
            return data + correction;
        } else {
            throw new Exception(getInputOutOrRangeMessage(temperature));
        }
    }

    public void reportTRange(double temperature) {
        Savelog.d(TAG, debug, "Type" + name);
        for (int j = 0; j < polynomials.length; j++) {
            Savelog.d(TAG, debug, "P" + j + ": [" + polynomials[j].Tmin + "," + polynomials[j].Tmax);
        }
        Savelog.d(TAG, debug, "T input = " + temperature + " not found");
    }

    public Result computeDetails(double temperature) throws Exception {

        int index = findPolynomial(temperature);
        if (index != BadIndex) {
            Result result = new Result();
            result.Tinput = temperature;

            double data = polynomials[index].compute(temperature);

            double correction = 0.0;
            if (exponential != null && temperature > 0) {
                // according to the function definition from NIST,
                // the exponential term is available only for type K when temperature > 0
                // Reference http://srdata.nist.gov/its90/download/download.html
                correction = exponential.compute(temperature);
                result.exponential = exponential;
            }
            result.polynomial = polynomials[index];
            result.E = data + correction;
            result.Epoly = data;
            result.correction = correction;
            return result;
        } else {
            throw new Exception(getInputOutOrRangeMessage(temperature));
        }
    }

    public double compute_dEdT(double temperature) throws Exception {
        // Throw an exception if temperature is out of range
        int index = findPolynomial(temperature);
        if (index != BadIndex) {
            double data = polynomials[index].compute_dEdT(temperature);

            double correction = 0.0;
            if (exponential != null && temperature > 0) {
                // according to the function definition from NIST,
                // the exponential term is available only for type K when temperature > 0
                // Reference http://srdata.nist.gov/its90/download/download.html
                correction = exponential.compute_dEdT(temperature);
            }
            return data + correction;
        } else {
            throw new Exception(getInputOutOrRangeMessage(temperature));
        }
    }

    private String getInputOutOrRangeMessage(double temperature) {
        return "Type " + name + " input T=" + temperature + " out of range";
    }

    public boolean isInRange(double temperature) {
        return (findPolynomial(temperature) != BadIndex);
    }

    // For Fn, the segments are highly continuous,
    // the difference between two polynomials at any junction is practically 0
    // So just find the first polynomial that fits
    private int findPolynomial(double temperature) {
        if (polynomials == null || polynomials.length == 0)
            return BadIndex;
        for (int index = 0; index < polynomials.length; index++) {
            if (polynomials[index].isInRange(temperature))
                return index;
        }
        return BadIndex;
    }

    // To handle cases where a point is at the boundary
    private int findSecondPolynomial(double temperature) {
        int firstIndex = -1;
        if (polynomials == null || polynomials.length == 0)
            return BadIndex;
        for (int index = 0; index < polynomials.length; index++) {
            if (polynomials[index].isInRange(temperature)) {
                if (firstIndex == -1)
                    firstIndex = index; // no first index
                else
                    return index; // First index exists. So this must be the second.
            }
        }
        return BadIndex;
    }

    private double[] getControlTemperaturesForEMF(int internalPtsPerSegment) {
        if (polynomials == null || polynomials.length == 0)
            return null;
        int numberOfSegments = polynomials.length;

        // Minimum number of control points must be located
        // at the boundaries of the segments
        int endPoints = numberOfSegments + 1;

        // Note: for forward function, the range of temperature is 0-degree continuous

        if (internalPtsPerSegment < 0)
            internalPtsPerSegment = 0;

        double[] point = new double[endPoints + numberOfSegments * internalPtsPerSegment];

        int count = 0;
        for (int index = 0; index < numberOfSegments; index++) {
            double Tmin = polynomials[index].Tmin;
            double Tmax = polynomials[index].Tmax;
            double Tinterval = (Tmax - Tmin) / (internalPtsPerSegment + 1); // number of intervals = number of internal points+1
            point[count] = Tmin; // starting point of the segment
            count++;
            for (int j = 1; j <= internalPtsPerSegment; j++) {
                point[count] = Tmin + Tinterval * j;
                count++;
            }
        }
        // last control point
        int last = numberOfSegments - 1;
        point[count] = polynomials[last].Tmax;
        count++;

        Savelog.d(TAG, debug, "control point count=" + count);
        return point;
    }

    public PointF[] getEMFCurveControlPoints(int internalPtsPerSegment) {
        double[] controlTemperature = getControlTemperaturesForEMF(internalPtsPerSegment);
        if (controlTemperature == null || controlTemperature.length == 0)
            return null;

        try {
            int count = controlTemperature.length;
            double[] voltage = new double[count];
            for (int index = 0; index < count; index++) {
                voltage[index] = computeE(controlTemperature[index]);
            }
            PointF[] pointF = new PointF[count];
            for (int index = 0; index < count; index++) {
                pointF[index] = new PointF((float) controlTemperature[index], (float) voltage[index]);
            }
            return pointF;
        } catch (Exception e) {
            return null;
        }
    }

    private double[] getControlTemperaturesFor_dE() {
        if (polynomials == null || polynomials.length == 0)
            return null;
        int numberOfSegments = polynomials.length;

        // Since the E curve is not guaranteed to be smooth in order 1,
        // DO NOT use the end points of the segments as control points!
        // But for completeness's sake, include the start point and the end point of the whole curve

        // Add start and end points
        double[] point = new double[numberOfSegments * InternalPtsPerSegmentForS + 2];

        int count = 0;
        point[count] = getTmin();
        count++;

        for (int index = 0; index < numberOfSegments; index++) {
            double Tmin = polynomials[index].Tmin;
            double Tmax = polynomials[index].Tmax;
            double Tinterval = (Tmax - Tmin) / (InternalPtsPerSegmentForS); // number of intervals = number of internal points

            // Start the first point at half of an interval into the segment
            for (int j = 0; j < InternalPtsPerSegmentForS; j++) {
                point[count] = Tinterval / 2 + Tmin + Tinterval * j;
                count++;
            }
        }

        point[count] = getTmax();
        count++;

        Savelog.d(TAG, debug, "control point count=" + count);
        return point;
    }

    public PointF[] getSeebeckCurveControlPoints() {
        double[] controlTemperature = getControlTemperaturesFor_dE();
        if (controlTemperature == null || controlTemperature.length == 0)
            return null;

        try {
            int count = controlTemperature.length;
            double[] dEdT = new double[count];
            for (int index = 0; index < count; index++) {
                dEdT[index] = compute_dEdT(controlTemperature[index]);
            }
            PointF[] pointF = new PointF[count];
            for (int index = 0; index < count; index++) {
                pointF[index] = new PointF((float) controlTemperature[index], (float) dEdT[index]);
            }
            return pointF;
        } catch (Exception e) {
            return null;
        }
    }

    public String getUnitT() {
        return unitT;
    }

    public String getUnitEMF() {
        return unitEMF;
    }

    // voltage as a function of temperature
    private static final String JSON_type = "thermocouple type";
    private static final String JSON_equation = "equation";
    private static final String JSON_Tlo = "Tlo";
    private static final String JSON_Thi = "Thi";
    private static final String JSON_expo = "exponential";
    private static final String JSON_expo_a1 = "a1";
    private static final String JSON_expo_a2 = "a2";
    private static final String JSON_expo_a0 = "a0";
    private static final String JSON_data = "data";
    private static final String JSON_poly_order = "order(n)";
    private static final String JSON_poly_Tmax = "Tmax";
    private static final String JSON_poly_Tmin = "Tmin";
    private static final String JSON_poly_coeffs = "Coefficients";
    private static final String JSON_coeff_type = "coefficient type";
    private static final String JSON_units = "units";
    private static final String JSON_unit_T = "T";
    private static final String JSON_unit_EMF = "EMF";

    public void load(String data) throws Exception {
        try {
            // data may be null or bad

            JSONObject json;
            json = new JSONObject(data);

            name = json.getString(JSON_type);
            if (name == null)
                name = "";

            Savelog.d(TAG, debug, "name=" + name);

            // For type k, there are 2 equations, for others, only one
            if (name.equals("K")) {
                Savelog.d(TAG, debug, "type K has 2 equations");
                equation = new String[2];
                JSONObject equationJSON = json.getJSONObject(JSON_equation);
                equation[0] = equationJSON.getString(JSON_Tlo);
                equation[1] = equationJSON.getString(JSON_Thi);
                if (equation[0] == null)
                    equation[0] = "";
                if (equation[1] == null)
                    equation[1] = "";
                Savelog.d(TAG, debug, "equation1=" + equation[0] + " equation2=" + equation[1]);
            } else { // all other types have just one equation
                equation = new String[1];
                equation[0] = json.getString(JSON_equation);
                if (equation[0] == null)
                    equation[0] = "";
                Savelog.d(TAG, debug, "equation=" + equation[0]);
            }

            exponential = null;
            // exponential term is optional
            try {
                double[] aTerm = null;
                JSONObject exponentsJSON = json.getJSONObject(JSON_expo);
                aTerm = new double[3];
                aTerm[0] = exponentsJSON.getDouble(JSON_expo_a0);
                aTerm[1] = exponentsJSON.getDouble(JSON_expo_a1);
                aTerm[2] = exponentsJSON.getDouble(JSON_expo_a2);
                exponential = new Exponential(aTerm);

                Savelog.d(TAG, debug, "exponential=" + exponential.toString());
            } catch (Exception e) {
            } // leave aTerm as null

            JSONArray dataJSONArray = json.getJSONArray(JSON_data);
            polynomials = new Polynomial[dataJSONArray.length()];

            for (int index = 0; index < polynomials.length; index++) {

                JSONObject polyJSON = dataJSONArray.getJSONObject(index);

                int order = polyJSON.getInt(JSON_poly_order);
                double Tmin = polyJSON.getDouble(JSON_poly_Tmin);
                double Tmax = polyJSON.getDouble(JSON_poly_Tmax);

                JSONArray coeffsJSONArray = polyJSON.getJSONArray(JSON_poly_coeffs);
                double[] coeffs = new double[coeffsJSONArray.length()];
                for (int j = 0; j < coeffs.length; j++) {
                    coeffs[j] = coeffsJSONArray.getDouble(j);
                }

                polynomials[index] = new Polynomial(order, Tmin, Tmax, coeffs);

                Savelog.d(TAG, debug, "polynomials: " + polynomials[index].toString());
            }
            if (polynomials == null)
                polynomials = new Polynomial[0];

            coefficientType = json.getString(JSON_coeff_type);
            if (coefficientType == null)
                coefficientType = "";

            Savelog.d(TAG, debug, "coefficientType=" + coefficientType);

            JSONObject unitsJSON = json.getJSONObject(JSON_units);

            unitT = unitsJSON.getString(JSON_unit_T);
            if (unitT == null)
                unitT = "";
            Savelog.d(TAG, debug, "unitT=" + unitT);

            unitEMF = unitsJSON.getString(JSON_unit_EMF);
            if (unitEMF == null)
                unitEMF = "";
            Savelog.d(TAG, debug, "unitEMF=" + unitEMF);

        } catch (Exception e) {
            Savelog.e(TAG, "Problem loading JSON ", e);
            throw e;
        }
    }

    @Override
    public String toString() {
        String data = "";
        data += JSON_type + ": " + name + "\n";
        data += JSON_equation + ": " + "\n";
        for (int index = 0; index < equation.length; index++) {
            data += "  " + equation[index] + "\n";
        }
        data += JSON_coeff_type + ": " + coefficientType + "\n";
        data += JSON_unit_T + ": " + unitT + "\n";
        data += JSON_unit_EMF + ": " + unitEMF + "\n";
        data += "Polynomials:\n";
        if (polynomials != null) {
            for (int index = 0; index < polynomials.length; index++)
                data += polynomials[index].toString();
        }
        if (exponential != null) {
            data += "Exponential:\n";
            data += exponential.toString();
        }
        return data;
    }

    public static class Result {
        public Polynomial polynomial;
        public double Tinput;
        public double Epoly;
        public Exponential exponential;
        public double correction;
        public double E;
    }
}