Files
DP44/DataPRO/Modules/PreviousDBVersions/Version57/DatabaseExport/DASConcepts/LinearizationFormula.cs
2026-04-17 14:55:32 -04:00

703 lines
33 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
namespace DatabaseExport
{
public class LinearizationFormula
{
private bool _bIsValid;
public bool IsValid() { return _bIsValid; }
public void MarkValid(bool bValid)
{
_bIsValid = bValid;
}
public enum Styles
{
IRTraccManual,
IRTraccDiagnosticsZero,
IRTraccZeroMMmV,
IRTraccAverageOverTime,
Polynomial,
IRTraccCalFactor
}
// public enum SLICEWareStyles
// {
// Manual,
// DiagnosticZeroMMmV,
// ZeroMMmV,
// AverageOverTime,
// Polynomial
// }
// // Translation
// public SLICEWareStyles SLICEWareStyle
// {
// get { return (SLICEWareStyles)_style; }
// set { _style = (Styles)value; }
// }
public Styles Style { get; set; } = Styles.IRTraccDiagnosticsZero;
public double PolynomialSensitivity { get; set; } = 1D;
public double LinearizationExponent { get; set; } = 1D;
// THIS IS MM/V, (UI has already been updated, we need to update the variable name)
public double MMPerV { get; set; }
public double MVAt0MM { get; set; }
public double Slope { get; set; }
public double Intercept { get; set; }
public double CalibrationFactor { get; set; }
public double ZeroPositionIntercept { get; set; }
public LinearizationFormula()
{
ZeroPositionIntercept = 0D;
CalibrationFactor = 0D;
Intercept = 0D;
_coefficients = new List<double>(new double[] { 0, 0, 0, 0 });
_exponents = new List<double>(new double[] { 0, 1, 2, 3 });
}
public LinearizationFormula(LinearizationFormula copy)
{
UsemVOverVForPolys = copy.UsemVOverVForPolys;
_bIsValid = copy._bIsValid;
_coefficients = new List<double>(copy._coefficients.ToArray());
_exponents = new List<double>(copy._exponents.ToArray());
Intercept = copy.Intercept;
LinearizationExponent = copy.LinearizationExponent;
MMPerV = copy.MMPerV;
MVAt0MM = copy.MVAt0MM;
Slope = copy.Slope;
Style = copy.Style;
_coefficients = new List<double>(copy._coefficients);
_exponents = new List<double>(copy._exponents);
PolynomialSensitivity = copy.PolynomialSensitivity;
ZeroPositionIntercept = copy.ZeroPositionIntercept;
CalibrationFactor = copy.CalibrationFactor;
}
// public double GetCoefficient(double exponent)
// {
// for (int i = 0; i < _exponents.Count && i < _coefficients.Count; i++)
// {
// if (_exponents[i] == exponent) { return _coefficients[i]; }
// }
// return 0;
// }
// public void SetCoefficient(double exponent, double coefficient)
// {
// for (int i = 0; i < _exponents.Count && i < _coefficients.Count; i++)
// {
// if (_exponents[i] == exponent) { _coefficients[i] = coefficient; return; }
// }
// }
// public double GetLinearizedValue(double input, double excitation)
// {
// if (Style != Styles.Polynomial && input <= 0)
// {
// //ir-tracc should never be < 0, however we may get readings less than zero due to
// //noise and other factors, treat these as positive near to zero
// input = .001;
// }
// //first linearize
// input /= 1000D;//assume input is in mV and we want it in Volts
// input = Math.Pow(input, LinearizationExponent);
// switch (Style)
// {
// case Styles.IRTraccDiagnosticsZero:
// return GetEUDiagnosticsZero(input);
// case Styles.IRTraccManual:
// return GetEUIRTraccManual(input);
// case Styles.IRTraccZeroMMmV:
// return GetEUZeroMMmV(input);
// case Styles.IRTraccAverageOverTime:
// return GetEUAverageOverTime(input);
// case Styles.Polynomial:
// return GetEUPolynomial(input, excitation);
// case Styles.IRTraccCalFactor:
// return GetEUIRTraccCalFactor(input);
// default:
// throw new NotSupportedException("unknown format: " + Style.ToString());
// }
// }
// private double GetEUIRTraccCalFactor(double volts)
// {
// return volts * CalibrationFactor + ZeroPositionIntercept;
// }
// private double GetEUIRTraccManual(double volts)
// {
// return (volts - Intercept) / Slope;
// }
public bool UsemVOverVForPolys { get; set; } = true;
// private double GetEUZeroMMmV(double volts)
// {
// double input = MVAt0MM / 1000D;
// input = Math.Pow(input, LinearizationExponent);
// if (double.IsNaN(input) || double.IsNegativeInfinity(input) || double.IsPositiveInfinity(input))
// {
// return volts * MMPerV;
// }
// else { return (volts * MMPerV - MMPerV * input); }
// }
private List<double> _coefficients = new List<double>();
private List<double> _exponents = new List<double>();
// private double GetEUPolynomial(double volts, double excitation)
// {
// //per J2517
// //3.4 Use of the Calibration Coefficients
// //The potentiometer assembly should be re-installed in the dummy without any mechanical adjustment of the
// //potentiometer. Prior to a crash test, the original zero offset level must be preserved by either not zeroing the
// //potentiometer (by signal conditioning or post-processing) or the amount that was zeroed must be added during postprocessing.
// //During the test the absolute voltage output time history should be recorded. This voltage signal is then
// //converted to engineering units by:
// //1. Convert voltage signal to mV/V at the sensor. This is the sensor reading S.
// //2. Convert the sensor reading S to displacement D by using the equation:
// //D = A*S^3 + B*S^2 + C*S + M (Eq. 2)
// //where:
// //D is the displacement relative to the thorax design position in mm
// //S is the sensor output reading in mV/V
// //A, B, C, and M are the calibration coefficients
// //NOTE: Make sure to use sufficient significant digits on all coefficients to assure accuracy of the conversion to
// //engineering units. It is recommended to use 5 significant digits (example 0.000012345).
// //double mV = volts * 1000D;
// //double gain = 1D;
// //mV = mV / (gain * excitation);
// //if (0 != PolynomialSensitivity && 1!= PolynomialSensitivity) { mV /= PolynomialSensitivity; }
// //double eu = 0D;
// //for (int i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
// //{
// // eu += _coefficients[i] * Math.Pow(mV, _exponents[i]);
// //}
// //return eu;
// //CHANGED FOR GM TESTING
// if (0 != PolynomialSensitivity && 1 != PolynomialSensitivity)
// {
// volts /= PolynomialSensitivity;
// }
// double voltsOverV = 0D;
// if (UsemVOverVForPolys)
// {
// //convert to mV first
// voltsOverV = (volts * 1000D) / excitation;
// }
// else
// {
// //used by GM
// voltsOverV = volts / excitation;
// }
// double eu = 0;
// for (int i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
// {
// if (_exponents[i] != 0)
// {
// eu += _coefficients[i] * Math.Pow(voltsOverV, _exponents[i]);
// }
// else
// {
// eu += _coefficients[i];
// }
// }
// return eu;
// }
// /// <summary>
// /// MvAt0MM set at diagnostics
// /// </summary>
// /// <param name="volts"></param>
// /// <returns></returns>
// private double GetEUDiagnosticsZero(double volts)
// {
// //double input = MVAt0MM/1000D;
// //input = System.Math.Pow(input,LinearizationExponent);
// double input = double.NaN;
// if (double.IsNaN(input) || double.IsPositiveInfinity(input) || double.IsNegativeInfinity(input))
// {
// return volts * MMPerV;
// }
// else
// {
// return volts * MMPerV - MMPerV * input;
// }
// }
// /// <summary>
// /// MVAt0MM set by diagnostics and then later on at
// /// Average Over Time
// /// </summary>
// /// <param name="volts"></param>
// /// <returns></returns>
// private double GetEUAverageOverTime(double volts)
// {
// //double input = MVAt0MM / 1000D;
// //input = System.Math.Pow(input, LinearizationExponent);
// double input = double.NaN;
// if (double.IsNaN(input) || double.IsNegativeInfinity(input) || double.IsPositiveInfinity(input))
// {
// return volts * MMPerV;
// }
// else
// {
// return volts * MMPerV - MMPerV * input;
// }
// }
// public string ToSLICEWareSerializeString()
// {
// if (!_bIsValid) { return ""; }
// StringBuilder sb = new StringBuilder();
// sb.AppendFormat("{0}_", Style.ToString());
// switch (Style)
// {
// case Styles.IRTraccDiagnosticsZero:
// sb.Append(ToIRTraccDiagnosticZeroString());
// break;
// case Styles.IRTraccManual:
// sb.Append(ToIRTraccManualString());
// break;
// case Styles.IRTraccZeroMMmV:
// sb.Append(ToIRTraccZeroMMmVString());
// break;
// case Styles.IRTraccAverageOverTime:
// sb.Append(ToIRTraccAverageOverTimeString());
// break;
// case Styles.Polynomial:
// sb.Append(ToSLICEWarePolynomialString());
// break;
// case Styles.IRTraccCalFactor:
// throw new NotSupportedException("CalFactor not supported in SLICEWare");
// default:
// throw new NotSupportedException("unknown type: " + Style.ToString());
// }
// return sb.ToString();
// }
/// <summary>
/// serializes to a string of the format "c0xe0 c1xe1...cnxen"
/// this will allow us arbitrary length polynomials and fractional exponents.
/// </summary>
/// <returns></returns>
public string ToSerializeString()
{
if (!_bIsValid) { return ""; }
var sb = new StringBuilder();
sb.AppendFormat("{0}_", Style.ToString());
switch (Style)
{
case Styles.IRTraccDiagnosticsZero:
sb.Append(ToIRTraccDiagnosticZeroString());
break;
case Styles.IRTraccManual:
sb.Append(ToIRTraccManualString());
break;
case Styles.IRTraccZeroMMmV:
sb.Append(ToIRTraccZeroMMmVString());
break;
case Styles.IRTraccAverageOverTime:
sb.Append(ToIRTraccAverageOverTimeString());
break;
case Styles.Polynomial:
sb.Append(ToPolynomialString());
break;
case Styles.IRTraccCalFactor:
sb.Append(ToIRTraccCalFactorString());
break;
default:
throw new NotSupportedException("unknown type: " + Style.ToString());
}
return sb.ToString();
}
public string ToIRTraccDiagnosticZeroString()
{
return string.Format("{0}x{1}", MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture), LinearizationExponent
.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
public string ToIRTraccCalFactorString()
{
return string.Format("{0}x{1}x{2}", CalibrationFactor.ToString(System.Globalization.CultureInfo.InvariantCulture), LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture),
ZeroPositionIntercept.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
public void FromIRTraccCalFactorString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid CalFactor format: " + s); }
CalibrationFactor = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
ZeroPositionIntercept = double.Parse(tokens[2], culture);
}
public void FromIRTraccDiagnosticZeroString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 2) { throw new NotSupportedException("Invalid DiagnosticsZero format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
}
public string ToIRTraccManualString()
{
return string.Format("{0}x{1}x{2}", Slope.ToString(System.Globalization.CultureInfo.InvariantCulture), Intercept.ToString
(System.Globalization.CultureInfo.InvariantCulture), LinearizationExponent.ToString(
System.Globalization.CultureInfo.InvariantCulture));
}
public void FromIRTraccManualString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid IRTraccManual format: " + s); }
Slope = double.Parse(tokens[0], culture);
Intercept = double.Parse(tokens[1], culture);
LinearizationExponent = double.Parse(tokens[2], culture);
}
public string ToIRTraccZeroMMmVString()
{
return string.Format("{0}x{1}x{2}", MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture),
MVAt0MM.ToString(System.Globalization.CultureInfo.InvariantCulture),
LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
// public string ToSLICEWarePolynomialString()
// {
// //SLICEWare is the reverse order of our DataPRO Database
// StringBuilder sb = new StringBuilder();
// for (int i = _exponents.Count - 1; i >= 0; i--)
// {
// if (i != _exponents.Count - 1) { sb.Append(","); }
// sb.AppendFormat("{0}x{1}", _coefficients[i].ToString(System.Globalization.CultureInfo.InvariantCulture),
// _exponents[i].ToString(System.Globalization.CultureInfo.InvariantCulture));
// }
// sb.AppendFormat(",S={0}", PolynomialSensitivity.ToString(System.Globalization.CultureInfo.InvariantCulture));
// return sb.ToString();
// }
public string ToPolynomialString()
{
var sb = new StringBuilder();
for (var i = 0; i < _coefficients.Count && i < _exponents.Count; i++)
{
if (i > 0) { sb.Append(","); }
sb.AppendFormat("{0}x{1}", _coefficients[i].ToString(System.Globalization.CultureInfo.InvariantCulture),
_exponents[i].ToString(System.Globalization.CultureInfo.InvariantCulture));
}
sb.AppendFormat(",S={0},mV={1}",
PolynomialSensitivity.ToString(System.Globalization.CultureInfo.InvariantCulture),
UsemVOverVForPolys.ToString(System.Globalization.CultureInfo.InvariantCulture));
return sb.ToString();
}
// public double[] PolynomialCoefficients
// {
// get { return _coefficients.ToArray(); }
// set { _coefficients = new List<double>(value); }
// }
// public double[] PolynomialExponents
// {
// get { return _exponents.ToArray(); }
// set { _exponents = new List<double>(value); }
// }
public string ToIRTraccAverageOverTimeString()
{
return string.Format("{0}x{1}", MMPerV.ToString(System.Globalization.CultureInfo.InvariantCulture),
LinearizationExponent.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
public void FromIRTraccAverageOverTimeString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 2) { throw new NotSupportedException("Invalid IRTRaccAverageOverTime format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
LinearizationExponent = double.Parse(tokens[1], culture);
}
public void FromIRTraccZeroMMmVString(string s, System.Globalization.CultureInfo culture)
{
var tokens = s.Split('x');
if (tokens.Length < 3) { throw new NotSupportedException("Invalid IRTraccZeroMMmV format: " + s); }
MMPerV = double.Parse(tokens[0], culture);
MVAt0MM = double.Parse(tokens[1], culture);
LinearizationExponent = double.Parse(tokens[2], culture);
}
public void FromPolynomialString(string s, System.Globalization.CultureInfo culture)
{
_coefficients.Clear();
_exponents.Clear();
var tokens = s.Split(',');
foreach (var t in tokens)
{
var subtokens = t.Split('x');
if (2 == subtokens.Length)
{
double d;
if (double.TryParse(subtokens[0], System.Globalization.NumberStyles.Float, culture, out d))
{
_coefficients.Add(d);
_exponents.Add(double.Parse(subtokens[1], culture));
}
else
{
PolynomialSensitivity = double.Parse(subtokens[1], culture);
}
}
else
{
subtokens = t.Split('=');
if (subtokens.Length == 2)
{
switch (subtokens[0])
{
case "S":
PolynomialSensitivity = double.Parse(subtokens[1], culture);
break;
case "mV":
UsemVOverVForPolys = Convert.ToBoolean(subtokens[1], culture);
break;
}
}
}
}
}
public void FromSerializeString(string s, System.Globalization.CultureInfo culture)
{
if (string.IsNullOrEmpty(s)) { _bIsValid = false; return; }
if (s.Equals("1") || s.Equals("0") || s.Equals("1 ")) { _bIsValid = false; return; }
var tokens = s.Split('_');
if (tokens.Length < 2) { throw new NotSupportedException("unsupported Linearization Formula Format"); }
var style = (Styles)Enum.Parse(typeof(Styles), tokens[0], true);
Style = style;
switch (Style)
{
case Styles.IRTraccDiagnosticsZero:
FromIRTraccDiagnosticZeroString(tokens[1], culture);
_bIsValid = true;
break;
case Styles.IRTraccManual:
FromIRTraccManualString(tokens[1], culture);
_bIsValid = true;
break;
case Styles.IRTraccZeroMMmV:
FromIRTraccZeroMMmVString(tokens[1], culture);
_bIsValid = true;
break;
case Styles.Polynomial:
FromPolynomialString(tokens[1], culture);
_bIsValid = true;
break;
case Styles.IRTraccAverageOverTime:
FromIRTraccAverageOverTimeString(tokens[1], culture);
_bIsValid = true;
break;
case Styles.IRTraccCalFactor:
FromIRTraccCalFactorString(tokens[1], culture);
_bIsValid = true;
break;
default:
throw new NotSupportedException("Unknown format: " + Style.ToString());
}
}
public void FromSerializeString(string s)
{
FromSerializeString(s, System.Globalization.CultureInfo.InvariantCulture);
}
// public void FromTDCSerializeString()
// {
// _bIsValid = true;
// }
// /// <summary>
// /// Will return a display string for a nonlinear calibration based on N4 formating
// /// </summary>
// public string ToDisplayString()
// {
// return ToDisplayString("N4");
// }
// /// <summary>
// /// Will return a display string for a nonlinear calibration based on 1st paramater formating string
// /// </summary>
// /// <param name="nonlinearFormat"></param>
// /// <returns></returns>
// public string ToDisplayString(string nonlinearFormat)
// {
// if (string.IsNullOrEmpty(nonlinearFormat)) { nonlinearFormat = "N4"; }
// switch (Style)
// {
// case Styles.Polynomial:
// {
// return ToPolynomial(nonlinearFormat);
// }
// case Styles.IRTraccZeroMMmV:
// {
// return string.Format("mV = {0:n4}, {1:n4}*(V^{2})", MVAt0MM, MMPerV, ToSuperScript(LinearizationExponent.ToString(nonlinearFormat)));
// }
// case Styles.IRTraccManual:
// {
// return string.Format("((V^{0})-{1:n4})/{2:n4}", ToSuperScript(LinearizationExponent.ToString(nonlinearFormat)), Intercept, Slope);
// }
// case Styles.IRTraccDiagnosticsZero:
// {
// return string.Format("{0:n4}*(V^{1})", MMPerV, ToSuperScript(LinearizationExponent.ToString(nonlinearFormat)));
// }
// case Styles.IRTraccAverageOverTime:
// {
// return string.Format("{0:n4}*(V^{1})", MMPerV, ToSuperScript(LinearizationExponent.ToString(nonlinearFormat)));
// }
// case Styles.IRTraccCalFactor:
// {
// return string.Format("{2:n4}+{1:n4}*(V^{0})", ToSuperScript(LinearizationExponent.ToString(nonlinearFormat)), CalibrationFactor, ZeroPositionIntercept);
// }
// default:
// return string.Empty;
// }
// }
// private string ToPolynomial(string nonlinearFormat)
// {
// if (string.IsNullOrEmpty(nonlinearFormat)) { nonlinearFormat = "N4"; }
// StringBuilder sb = new StringBuilder();
// int termNumber = PolynomialCoefficients.Length - 1;
// foreach (var x in PolynomialCoefficients)
// {
// if (PolynomialCoefficients[termNumber] != 0)
// {
// double coeff = PolynomialCoefficients[termNumber];
// // Let the appended math symbol handle sign unless we're the first term.
// if (termNumber != PolynomialCoefficients.Length - 1)
// {
// coeff = Math.Abs(coeff);
// }
// sb.Append(coeff.ToString(nonlinearFormat));
// if (PolynomialExponents[termNumber] != 0)
// {
// sb.Append("x");
// if (PolynomialExponents[termNumber] != 1)
// {
// sb.Append(ToSuperScript(PolynomialExponents[termNumber].ToString("N0")));
// }
// }
// if (termNumber > 0)
// {
// // Coerricients are Displayed in absolute value. We need to combine the sign with the addition symbol
// sb.Append(PolynomialCoefficients[termNumber - 1] > 0 ? " + " : " - ");
// }
// }
// termNumber--;
// }
// return sb.ToString();
// }
// private string ToSuperScript(string source)
// {
// StringBuilder superScript = new StringBuilder();
// foreach (char c in source)
// {
// switch (c)
// {
// case '-':
// superScript.Append('\u207B');
// break;
// case '.':
// superScript.Append('\u00B7');
// break;
// case '1':
// superScript.Append('\u00B9');
// break;
// case '2':
// superScript.Append('\u00B2');
// break;
// case '3':
// superScript.Append('\u00B3');
// break;
// case '4':
// superScript.Append('\u2074');
// break;
// case '5':
// superScript.Append('\u2075');
// break;
// case '6':
// superScript.Append('\u2076');
// break;
// case '7':
// superScript.Append('\u2077');
// break;
// case '8':
// superScript.Append('\u2078');
// break;
// case '9':
// superScript.Append('\u2079');
// break;
// case '0':
// superScript.Append('\u2070');
// break;
// case '\'':
// superScript.Append('\u02C8');
// break;
// case ',':
// superScript.Append('\u22C5'); // there is no unicode superscript comma. this comes close
// break;
// case '\u00A0':
// superScript.Append('\u2009'); // unicode 'thin' space
// break;
// default:
// superScript.Append('\u207F');
// break;
// }
// }
// return superScript.ToString();
// }
// /*
// * we are given an equation in the form of y = ax^1 + b, except x and y are backwards for us (y=V where we'd prefer X was voltage, so we switch it)
// * y/a - b/a = x, and then switch y and x, (1/a)x^1 -(b/a)x^0 = y
// * now we want to get the coefficient of the first equation, which is "a", we get this by taking the inverse
// * we get b on the other hand by taking -1 * (b/a)*a. if we have the "coefficient", we have a
// */
// /*
// public double GetIRTraccCoefficient()
// {
// foreach (Factor f in Factors)
// {
// if (f.Exponent == 1D) { return System.Math.Pow(f.Coefficient, -1); }
// }
// return 1D; //0 doesn't make sense for ir
// }
// public double GetIRTraccConstant()
// {
// foreach (Factor f in Factors)
// {
// if (f.Exponent == 0D) { return -1D * GetIRTraccCoefficient() * f.Coefficient; }
// }
// return 0D;
// }
// public void SetIRTraccFactor(double coefficient, double constant)
// {
// if (0 == coefficient)
// {
// //well this doesn't make any sense ...
// coefficient = 1;
// }
// Factors = new Factor[]
// {
// new Factor(1/coefficient,1),
// new Factor(-constant/coefficient,0),
// };
// }*/
}
}