Salinity unit calculator

minagos

New Member
View Badges
Joined
May 13, 2017
Messages
16
Reaction score
13
Rating - 0%
0   0   0
Hi Everyone,

Small background of myself so you can understand why I am asking for help.

I am electronic technician by trade. Over the years I have worked with robotics and vacuum control chamber for semiconductor field.
Presently I am supervisor of a WWTP, we treat around 6 mgd.

I have reef tank with around 240 gallons of total volume.
My system is heavy automated with Siemens PLC. I have single axis valves, VFD pumps and various controllers (pH,Temperature, Conductivity) .

Now my question. I would like to convert conductivity (ms/cm) to ppt and specific gravity.
I would like to display those values on my HMI screens. I can handle the PLC side, if I had working formulas.
My goal is making something like this that works in the background.
HTML:
https://reefapp.net/en/maintenance/calculator/unitconversion

I went to the reference pages that website uses, but the math is not adding up and I cannot get specific gravity to work.

My friend and I modify that program from that page to test the math, but ppt is not calculating like the web page does.
HTML:
http://www.code10.info/index.php%3Foption%3Dcom_content%26view%3Darticle%26id%3D65:conversion-between-conductivity-and-pss-78-salinity%26catid%3D54:cat_coding_algorithms_seawater%26Itemid%3D79

Can anyone here double check the math, I am missing something and this over anything I have done.
Thank you so much if anyone can help.

This code will work in Microsoft Visual Studio.

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LuisProject
{
    class Program
    {
        static void Main(string[] args)
        {
            double sal;

            Luis luisclass= new Luis();
            bool exit = false;


           while (!exit)
                {
                    double salinity;
                    double conductivity, temperature;
                    Console.Write("Please enter cond in ms/sec-1 : ");
                    conductivity = Convert.ToDouble(Console.ReadLine());
                    Console.Write("Please enter temperature in C : ");
                    temperature = Convert.ToDouble(Console.ReadLine());

                    salinity = luisclass.Sal78(conductivity / 42.914, temperature, 10000, 0);
                    Console.WriteLine("Salinity = " + salinity);
                    Console.WriteLine("");
                    Console.Write("Do you want to exit Y/N? ");
                    string response = Console.ReadLine();
                    if ((response== "Y")|| (response=="y"))
                    { exit = true; }



                }
                }
    }

    class Luis
    {
        public double Sal78(double CND, double T, double P, int Ma)
        {
            // THE CONDUCTIVITY RATIO (CND)=1.0000000 FOR SALINITY=35 PSS-78
            // TEMPERATURE=15.0 DEG. CELSIUS AND ATMOSPHERIC PRESSURE.
            // FUNCTION TO CONVERT CONDUCTIVITY RATIO TO SALINITY (M=0)
            // SALINITY TO CONDUCTIVITY RATIO (M=1, CND BECOMES INPUT SALINITY)
            // REFERENCES: ALSO LOCATED IN UNESCO REPORT NO. 37 1981
            // PRACTICAL SALINITY SCALE 1978: E.L. LEWIS IEEE OCEAN ENG. JAN. 1980
            // ----------------------------------------------------------
            // UNITS:
            //   PRESSURE      P      DECIBARS
            //   TEMPERATURE   T      DEG CELSIUS IPTS-68
            //   CONDUCTIVITY  CND    RATIO                (M=0)
            //   SALINITY      SAL78  PSS-78               (M=0)
            // ----------------------------------------------------------
            // CHECKVALUES:
            //   1.) SAL78=1.888091 for CND=40.0000, T=40 DEG C, P=10000 DECIBARS:   M=1
            //   2.) SAL78=40.00000 for CND=1.888091, T=40 DEG C, P=10000 DECIBARS:  M=0
            // ----------------------------------------------------------
            // SAL78 RATIO: RETURNS ZERO FOR CONDUCTIVITY RATIO: < 0.0005
            // SAL78: RETURNS ZERO FOR SALINITY: < 0.02
            // ----------------------------------------------------------
            // Original fortran code is found in:
            //   UNESCO technical papers in marine science 44 (1983) -
            //   'Algorithms for computation of fundamental properties of seawater'
            // ----------------------------------------------------------
            // Translated to object pascal by:
            //   Dr. Jan Schulz, 19. May 2008, www.code10.info

            double DT;
            double Res;
            double RT;
            double SI;
            int N;
            double DELS;
            double RTT;
            double AT;
            double BT;
            double CP;



            // ZERO SALINITY/CONDUCTIVITY TRAP
            if (((Ma == 0) && (CND <= 5e-4)) || ((Ma == 1) && (CND <= 0.2)))
            { return 0; }

            DT = T - 15;

            // SELECT BRANCH FOR SALINITY (M=0) OR CONDUCTIVITY (M=1)
            if (Ma == 0) {


                // CONVERT CONDUCTIVITY TO SALINITY
                Res = CND;
                RT = Res / (RT35(T) * (1.0 + C(P) / (B(T) + A(T) * Res)));
                RT = Math.Sqrt(Math.Abs(RT));
                return SAL(RT, DT);

            }

            if (Ma == 1)
            {
                // INVERT SALINITY TO CONDUCTIVITY BY THE
                // NEWTON-RAPHSON ITERATIVE METHOD
                // FIRST APPROXIMATION

                RT = Math.Sqrt(CND / 35);
                SI = SAL(RT, DT);
                N = 0;
                DELS = 1;
                // ITERATION LOOP BEGINS HERE WITH A MAXIMUM OF 10 CYCLES
                while ((N < 10) && DELS > 1e-4)
                {
                    RT = RT + (CND - SI) / DSAL(RT, DT);
                    SI = SAL(RT, DT);
                    N = N + 1;
                    DELS = Math.Abs(SI - CND);
                }
                //IF((DELS.GT.1.0E-4).AND.(N.LT.10)) GO TO 15

                //Until not ((DELS > 1.0E-4) AND (N <10));

                //COMPUTE CONDUCTIVITY RATIO
                RTT = RT35(T) * RT * RT;
                AT = A(T);
                BT = B(T);
                CP = C(P);
                CP = RTT * (CP + BT);
                BT = BT - RTT * AT;

                // SOLVE QUADRATIC EQUATION FOR R: R=RT35*RT*(1+C/AR+B)
                //    R  := SQRT (ABS (BT * BT + 4.0 * AT * CP)) - BT;
                Res = Math.Sqrt(Math.Abs(BT * BT + 4 * AT * CP)) - BT;

                // CONDUCTIVITY RETURN
                return 0.5 * Res / AT;
            }
            return 0;
        }
        double SAL(double XR, double XT)
        // PRACTICAL SALINITY SCALE 1978 DEFINITION WITH TEMPERATURE
        // CORRECTION;XT :=T-15.0; XR:=SQRT(RT);
        {
            double tempSAL;
            tempSAL = ((((2.7081 * XR - 7.0261) * XR + 14.0941) * XR + 25.3851) * XR
                    - 0.1692) * XR + 0.0080
                    + (XT / (1.0 + 0.0162 * XT)) * (((((-0.0144 * XR
                    + 0.0636) * XR - 0.0375) * XR - 0.0066) * XR - 0.0056) * XR + 0.0005);
            return tempSAL;
        }

        double DSAL(double XR, double XT)
        // FUNCTION FOR DERIVATIVE OF SAL(XR,XT) WITH XR
        {
            double tempDSAL;
            tempDSAL = ((((13.5405 * XR - 28.1044) * XR + 42.2823) * XR + 50.7702) * XR
                     - 0.1692) + (XT / (1.0 + 0.0162 * XT)) * ((((-0.0720 * XR + 0.2544)
                     * XR - 0.1125) * XR - 0.0132) * XR - 0.0056);
            return tempDSAL;
        }

        double RT35(double XT)
        // FUNCTION RT35: C(35,T,0)/C(35,15,0) VARIATION WITH TEMPERATURE
        {
            double tempRT35;
            tempRT35 = (((1.0031E-9 * XT - 6.9698E-7) * XT + 1.104259E-4) * XT
               + 2.00564E-2) * XT + 0.6766097;
            return tempRT35;
        }


        double C(double XP)
        // C(XP) POLYNOMIAL CORRESPONDS TO A1-A3 CONSTANTS: LEWIS 1980
        {
            return ((3.989E-15 * XP - 6.370E-10) * XP + 2.070E-5) * XP;
        }

        double B(double XT)
        {
            return (4.464E-4 * XT + 3.426E-2) * XT + 1.0;
        }

        double A(double XT)
        //A(XT) POLYNOMIAL CORRESPONDS TO B3 AND B4 CONSTANTS: LEWIS 1980
        {
            return -3.107E-3 * XT + 0.4215;
        }



    }
        //The function Cond2Sal78 converts conductivity to salinity.Required input parameters are aConductivity in S* m-1, Temp in °C and Press in decibars.In contrast to the function Sal78 it returns the salinity value as a parameter, while the return value of the function is a boolean.The function returns TRUE, if the passed conductivity value is >0.2 and the result of the conversion is between 2 and 40 PSS-78. In other cases FALSE is returned, indicating that the result might be unreliable (see above: Equation).
        class Luis2
        {
        public bool Cond2Sal78(double aConductivity, double Temp, double Press, out double aSalinity)
        //// Function Cond2Sal converts a conductivity value of seawater to a value
        //// of the pratical-salinity-scale 1978 (PSS-78) for given values of
        //// conductivity, temperature and pressure. Result is returned as
        //// parameter in aSalinity. A returned boolean result TRUE of the
        //// function indicates that the result is reliable.
        //// UNITS:
        ////   PRESSURE      Press          DECIBARS
        ////   TEMPERATURE   Temp           DEG CELSIUS IPTS-68
        ////   CONDUCTIVITY  aConductivity  S/m
        ////   SALINITY      aSalinity      PSS-78
        //// ----------------------------------------------------------
        //// CHECKVALUES:
        ////   2.) aSalinity=40.00000 for CND=1.888091, T=40 DEG C, P=10000 DECIBARS
        //// ----------------------------------------------------------
        //// SAL78 RATIO: RETURNS ZERO FOR CONDUCTIVITY RATIO: < 0.0005
        //// ----------------------------------------------------------
        //// This source code is based on the original fortran code in:
        ////   UNESCO technical papers in marine science 44 (1983) -
        ////   'Algorithms for computation of fundamental properties of seawater'
        //// ----------------------------------------------------------
        //// Written in object pascal by:
        ////   Dr. Jan Schulz, 26. May 2008, www.code10.info
        {


            double DT;
            double RT;

            //  // we expect the best
            //  Cond2Sal78 := True;
            aSalinity = 0;

            // equation is not defined for conductivity values below 5e-4
            if (aConductivity <= 0.2)
            {
                return false;
            }

            // start conversion
            DT = Temp - 15;
            aSalinity = aConductivity / 4.2914;
            RT = aSalinity / (RT35(Temp) * (1.0 + C(Press) / (B(Temp) + A(Temp) * aSalinity)));
            RT = Math.Sqrt(Math.Abs(RT));
            aSalinity= SAL(RT, DT);

            // control, whether result is in the validity range of PSS-78
            if ((aSalinity < 2) || (aSalinity > 42))
            {
                return false;
            }
            return true;
           }

        double SAL(double XR, double XT)
        // PRACTICAL SALINITY SCALE 1978 DEFINITION WITH TEMPERATURE
        // CORRECTION;XT :=T-15.0; XR:=SQRT(RT);
        {
            double tempSAL;
            tempSAL = ((((2.7081 * XR - 7.0261) * XR + 14.0941) * XR + 25.3851) * XR
                    - 0.1692) * XR + 0.0080
                    + (XT / (1.0 + 0.0162 * XT)) * (((((-0.0144 * XR
                    + 0.0636) * XR - 0.0375) * XR - 0.0066) * XR - 0.0056) * XR + 0.0005);
            return tempSAL;
        }
        double RT35(double XT)
        // FUNCTION RT35: C(35,T,0)/C(35,15,0) VARIATION WITH TEMPERATURE
        {
            double tempRT35;
            tempRT35 = (((1.0031E-9 * XT - 6.9698E-7) * XT + 1.104259E-4) * XT
               + 2.00564E-2) * XT + 0.6766097;
            return tempRT35;
        }


        double C(double XP)
        // C(XP) POLYNOMIAL CORRESPONDS TO A1-A3 CONSTANTS: LEWIS 1980
        {
            return ((3.989E-15 * XP - 6.370E-10) * XP + 2.070E-5) * XP;
        }

        double B(double XT)
        {
            return (4.464E-4 * XT + 3.426E-2) * XT + 1.0;
        }

        double A(double XT)
        //A(XT) POLYNOMIAL CORRESPONDS TO B3 AND B4 CONSTANTS: LEWIS 1980
        {
            return -3.107E-3 * XT + 0.4215;
        }

        
        
    }
    
}
 

Martin Kuhn

Active Member
View Badges
Joined
Sep 21, 2016
Messages
229
Reaction score
108
Rating - 0%
0   0   0
Hello Minagos
this are the procedures AquaCalculator uses for the salinity conversions. They are derived from the UNESCO Equation state of seawater.
Code language is Embarcadero Delphi. It should be easy to convert in any other language

Code:
Function TForm1.s_Rt(t, Rt: Real): Real;
var
  Rt5, t15, dels, sal: Real;
begin
  Rt5  := sqrt(Rt);
  t15  := t - 15;
  dels := t15 / (1 + 0.0162 * t15);
  sal  := (14.0941 + dels * -0.0375) + Rt5 * ((-7.0261 + dels * 0.0636) + Rt5 * ((2.7081 + dels * -0.0144)));
  sal  := (0.008 + dels * 0.0005) + Rt5 * ((-0.1692 + dels * -0.0056) + Rt5 * ((25.3851 + dels * -0.0066) + Rt5 * sal));

  Result := sal;
end;




// Compute salinity (psu) from conductivity, temperature and pressure
function TForm1.Cond2Salinity(Conductivity, temp, pressure: Real): Real;
var
  R, rt_, Rp, Rt, I, J, K: Real;
begin
  R    := Conductivity / 4.29140 / 10;
  rt_  := 0.6766097 + temp * (0.0200564 + temp * (1.104259E-04 + temp * (-6.9698E-07 + temp * 1.0031E-09)));
  I    := 0.4215 - 0.003107 * temp;
  J    := 1 + temp * (0.03426 + temp * 0.0004464);
  K    := pressure * (2.07E-5 + pressure * (-6.37E-10 + pressure * 3.989E-15));
  Rp   := 1 + K / (J + I * R);
  Rt   := R / rt_ / Rp;

  Result := s_Rt(temp, Rt);
end;

// Compute conductivity from salinity, temperature and pressure
Function TForm1.Sal2Conductivity(salinity, temp, pressure: Real): Real;
var
  R, Rt, rt_, A, B, C, sNew, Rtlo, Rthi, err: Real;
  I, limit: Integer;
begin
  Rtlo := 0.0;
  Rthi := 10.0;
  err := 1.0;
  I := 0;
  limit := 10000;
  Rt := 0;
  if (salinity < 0.01)
    then begin
           Result := 0.0;
           exit
         end;
  // ----------
  while ((abs(err) > 0.00001) AND (I < limit)) do
  begin
    Rt := (Rthi + Rtlo) / 2.0;
    sNew := s_Rt(temp, Rt);
    err := (sNew - salinity) / salinity;
    if (err > 0.0)
      then Rthi := Rt
      else Rtlo := Rt;
    Inc(I);
  end;

  if (I >= limit) then
  begin
    Result := -99999;
    exit;
  end;

  rt_ := 0.6766097 + temp * (0.0200564 + temp * (1.104259E-04 + temp * (-6.9698E-07 + temp * 1.0031E-09)));
  A := 0.4215 - 0.003107 * temp;
  B := 1 + temp * (0.03426 + temp * 0.0004464);
  C := pressure * (2.07E-5 + pressure * (-6.37E-10 + pressure * 3.989E-15));
  R := (sqrt((A * rt_ * Rt - B) * (A * rt_ * Rt - B) + 4 * rt_ * Rt * A * (B + C)) + (A * rt_ * Rt - B)) / (2 * A);
  Result := R * 4.29140 * 10;
end;

function TForm1.Salinity2Density(Temp, sal: Real): Real;
Var
  dens: Real;
begin
  If (sal < 20) or (sal > 50) or (Temp < 2) or (Temp > 90) then
  begin
    Result := 0;
    exit;
  end;
  dens := -0.157406 + Temp * (6.793952E-2 - Temp * (9.095290E-3 - Temp * (1.001685E-4 - Temp * (1.120083E-6 - Temp * 6.536332E-9)))) + sal * (8.24493E-1 - Temp * (4.0899E-3 - Temp * (7.6438E-5 - Temp * (8.2467E-7 - Temp * 5.3875E-9))) - sqrt(sal) *   (5.72466E-3 - Temp * (1.0227E-4 - Temp * 1.6546E-6)) + sal * 4.8314E-4);
  dens := dens + 1000;
  dens := dens / 1000;

  Result := dens;
end;

function TForm1.Density2Salinity(temp, density: Real): Real;
Var
  densNew: Real;
  salinity: Real;
  limit: Real;
  salmin: Real;
  salmax: Real;
  fehler: Real;
  I: Integer;

begin
  limit    := 10000;
  salmin   := 0.0;
  salmax   := 100.0;
  fehler   := 1.0;
  I        := 0;
  salinity := 0;

  density := density * 1000 - 999.96;
  while (abs(fehler) > 0.00001) AND (I < limit) do
  begin
    salinity := (salmin + salmax) / 2.0;
    densNew := -0.157406 + temp * (6.793952E-2 - temp * (9.095290E-3 - temp * (1.001685E-4 - temp * (1.120083E-6 - temp * 6.536332E-9)))) + salinity * (8.24493E-1 - temp * (4.0899E-3 - temp * (7.6438E-5 - temp * (8.2467E-7 - temp * 5.3875E-9))) - sqrt(salinity) * (5.72466E-3 - temp * (1.0227E-4 - temp * 1.6546E-6)) + salinity * 4.8314E-4);
    fehler := (densNew - density) / density;
    if (fehler > 0.0)
      then salmax := salinity
      else salmin := salinity;
    Inc(I);
  end;

  if (I >= limit)
    then Result := -99999
    else Result := salinity;
end;


Conversion From/to "specific density" (RelDensity) is a bit more tricky.
here you need an additional procedure with H2Os density parameters behind ("DensityH2O") and an additional parameter that specifies the reference temperature of the specific density measurement tool (RelDensTemp.)

Call the function like this : RelDensity := Density/ DensityH2O (RelDensTemp);

Code:
Function TForm1.CalcH2ODens(MyTemperature: Integer): Real;
begin
  case MyTemperature of
    0: Result := 0.9998;
    1 .. 3:Result := 0.9999;
    4 .. 6:Result := 1.0000;
    7 .. 9:Result := 0.9999;
    10 .. 11:Result := 0.9997;
    12:Result := 0.9996;
    13:Result := 0.9994;
    14:Result := 0.9993;
    15:Result := 0.9992;
    16:Result := 0.9990;
    17:Result := 0.9988;
    18:Result := 0.9987;
    19:Result := 0.9985;
    20:Result := 0.9983;
    21:Result := 0.9981;
    22:Result := 0.9978;
    23:Result := 0.9976;
    24:Result := 0.9974;
    25:Result := 0.9971;
    26:Result := 0.9968;
    27:Result := 0.9966;
    28:Result := 0.9963;
    29:Result := 0.9960;
    30:Result := 0.9957;
    31:Result := 0.9954;
    32:Result := 0.9951;
    33:Result := 0.9947;
    34:Result := 0.9944;
    35:Result := 0.9940;
    40:Result := 0.9923;
    45:Result := 0.9902;
    50:Result := 0.9880;
    51 .. 55:Result := 0.9857;
    56 .. 60:Result := 0.9832;
    61 .. 65:Result := 0.9805;
    66 .. 70:Result := 0.9777;
    71 .. 75:Result := 0.9748;
    76 .. 80:Result := 0.9716;
    81 .. 85:Result := 0.9684;                         nm mb
    86 .. 90:Result := 0.9652;
    91 .. 95:Result := 0.9616;
    96 .. 100:Result := 0.9581;
  else
    Result := -9999;
  end;
end;

// Density Water
Function TForm1.DensityH2O(MyTemperature: Real): Real;
Var
  FullNr, hundreth, MyPos: Integer;
  MyNrStr: String;
  Res, Diff: Real;

begin
  MyNrStr := FloatToStrF(MyTemperature, ffFixed, 10, 2);
  MyPos := point of sale(',', MyNrStr);

  If (MyPos = 0) then
    FullNr := Round(MyTemperature)
  else
    FullNr := StrToInt(Copy(MyNrStr, 1, MyPos - 1));

  If (MyPos = 0) then
    hundreth := 0
  else
    hundreth := StrToInt(Copy(MyNrStr, MyPos + 1, 2));

  Res := CalcH2ODens(FullNr);
  Diff := CalcH2ODens(FullNr + 1) - CalcH2ODens(FullNr);

  Result := Res + (hundreth / 100 * Diff)
end;

Function TForm1.s_Rt(t, Rt: Real): Real;
var
  Rt5, t15, dels, sal: Real;
begin
  Rt5  := sqrt(Rt);
  t15  := t - 15;
  dels := t15 / (1 + 0.0162 * t15);
  sal  := (14.0941 + dels * -0.0375) + Rt5 * ((-7.0261 + dels * 0.0636) + Rt5 * ((2.7081 + dels * -0.0144)));
  sal  := (0.008 + dels * 0.0005) + Rt5 * ((-0.1692 + dels * -0.0056) + Rt5 * ((25.3851 + dels * -0.0066) + Rt5 * sal));

  Result := sal;
end;


i hope this helps
Martin
 

Martin Kuhn

Active Member
View Badges
Joined
Sep 21, 2016
Messages
229
Reaction score
108
Rating - 0%
0   0   0
Hello
here you go with the SourceCode is use within AquaCalculator for salinity conversions in all directions.
They are derived from the Unesco ocalculation for seawater and are coded in Embarcadero Delphi.
All temperatures in °C (not °F)

=========================================
1.) Conversions salinity <-> Density <-> Conductivity
Code:
Function TForm1.s_Rt(t, Rt: Real): Real;
var
  Rt5, t15, dels, sal: Real;
begin
  Rt5  := sqrt(Rt);
  t15  := t - 15;
  dels := t15 / (1 + 0.0162 * t15);
  sal  := (14.0941 + dels * -0.0375) + Rt5 * ((-7.0261 + dels * 0.0636) + Rt5 * ((2.7081 + dels * -0.0144)));
  sal  := (0.008 + dels * 0.0005) + Rt5 * ((-0.1692 + dels * -0.0056) + Rt5 * ((25.3851 + dels * -0.0066) + Rt5 * sal));

  Result := sal;
end;




// Compute salinity (psu) from conductivity, temperature and pressure
function TForm1.Cond2Salinity(Conductivity, temp, pressure: Real): Real;
var
  R, rt_, Rp, Rt, I, J, K: Real;
begin
  R    := Conductivity / 4.29140 / 10;
  rt_  := 0.6766097 + temp * (0.0200564 + temp * (1.104259E-04 + temp * (-6.9698E-07 + temp * 1.0031E-09)));
  I    := 0.4215 - 0.003107 * temp;
  J    := 1 + temp * (0.03426 + temp * 0.0004464);
  K    := pressure * (2.07E-5 + pressure * (-6.37E-10 + pressure * 3.989E-15));
  Rp   := 1 + K / (J + I * R);
  Rt   := R / rt_ / Rp;

  Result := s_Rt(temp, Rt);
end;

// Compute conductivity from salinity, temperature and pressure
Function TForm1.Sal2Conductivity(salinity, temp, pressure: Real): Real;
var
  R, Rt, rt_, A, B, C, sNew, Rtlo, Rthi, err: Real;
  I, limit: Integer;
begin
  Rtlo := 0.0;
  Rthi := 10.0;
  err := 1.0;
  I := 0;
  limit := 10000;
  Rt := 0;
  if (salinity < 0.01)
    then begin
           Result := 0.0;
           exit
         end;
  // ----------
  while ((abs(err) > 0.00001) AND (I < limit)) do
  begin
    Rt := (Rthi + Rtlo) / 2.0;
    sNew := s_Rt(temp, Rt);
    err := (sNew - salinity) / salinity;
    if (err > 0.0)
      then Rthi := Rt
      else Rtlo := Rt;
    Inc(I);
  end;

  if (I >= limit) then
  begin
    Result := -99999;
    exit;
  end;

  rt_ := 0.6766097 + temp * (0.0200564 + temp * (1.104259E-04 + temp * (-6.9698E-07 + temp * 1.0031E-09)));
  A := 0.4215 - 0.003107 * temp;
  B := 1 + temp * (0.03426 + temp * 0.0004464);
  C := pressure * (2.07E-5 + pressure * (-6.37E-10 + pressure * 3.989E-15));
  R := (sqrt((A * rt_ * Rt - B) * (A * rt_ * Rt - B) + 4 * rt_ * Rt * A * (B + C)) + (A * rt_ * Rt - B)) / (2 * A);
  Result := R * 4.29140 * 10;
end;

function TForm1.Salinity2Density(Temp, sal: Real): Real;
Var
  dens: Real;
begin
  If (sal < 20) or (sal > 50) or (Temp < 2) or (Temp > 90) then
  begin
    Result := 0;
    exit;
  end;
  dens := -0.157406 + Temp * (6.793952E-2 - Temp * (9.095290E-3 - Temp * (1.001685E-4 - Temp * (1.120083E-6 - Temp * 6.536332E-9)))) + sal * (8.24493E-1 - Temp * (4.0899E-3 - Temp * (7.6438E-5 - Temp * (8.2467E-7 - Temp * 5.3875E-9))) - sqrt(sal) *   (5.72466E-3 - Temp * (1.0227E-4 - Temp * 1.6546E-6)) + sal * 4.8314E-4);
  dens := dens + 1000;
  dens := dens / 1000;

  Result := dens;
end;

function TForm1.Density2Salinity(temp, density: Real): Real;
Var
  densNew: Real;
  salinity: Real;
  limit: Real;
  salmin: Real;
  salmax: Real;
  fehler: Real;
  I: Integer;

begin
  limit    := 10000;
  salmin   := 0.0;
  salmax   := 100.0;
  fehler   := 1.0;
  I        := 0;
  salinity := 0;

  density := density * 1000 - 999.96;
  while (abs(fehler) > 0.00001) AND (I < limit) do
  begin
    salinity := (salmin + salmax) / 2.0;
    densNew := -0.157406 + temp * (6.793952E-2 - temp * (9.095290E-3 - temp * (1.001685E-4 - temp * (1.120083E-6 - temp * 6.536332E-9)))) + salinity * (8.24493E-1 - temp * (4.0899E-3 - temp * (7.6438E-5 - temp * (8.2467E-7 - temp * 5.3875E-9))) - sqrt(salinity) * (5.72466E-3 - temp * (1.0227E-4 - temp * 1.6546E-6)) + salinity * 4.8314E-4);
    fehler := (densNew - density) / density;
    if (fehler > 0.0)
      then salmax := salinity
      else salmin := salinity;
    Inc(I);
  end;

  if (I >= limit)
    then Result := -99999
    else Result := salinity;
end;

=================================================================
2.) Specific gravity is a bit special as it also regards waters density at specific temperatures

call the function like this: RelDensity := Density / DensityH2O (RelDensTemp);
with "RelDensTemp" is the reference temp the measurement is calibratetd to (typically 4°C)

Code:
Function TForm1.CalcH2ODens(MyTemperature: Integer): Real;
begin
  case MyTemperature of
    0: Result := 0.9998;
    1 .. 3:Result := 0.9999;
    4 .. 6:Result := 1.0000;
    7 .. 9:Result := 0.9999;
    10 .. 11:Result := 0.9997;
    12:Result := 0.9996;
    13:Result := 0.9994;
    14:Result := 0.9993;
    15:Result := 0.9992;
    16:Result := 0.9990;
    17:Result := 0.9988;
    18:Result := 0.9987;
    19:Result := 0.9985;
    20:Result := 0.9983;
    21:Result := 0.9981;
    22:Result := 0.9978;
    23:Result := 0.9976;
    24:Result := 0.9974;
    25:Result := 0.9971;
    26:Result := 0.9968;
    27:Result := 0.9966;
    28:Result := 0.9963;
    29:Result := 0.9960;
    30:Result := 0.9957;
    31:Result := 0.9954;
    32:Result := 0.9951;
    33:Result := 0.9947;
    34:Result := 0.9944;
    35:Result := 0.9940;
    40:Result := 0.9923;
    45:Result := 0.9902;
    50:Result := 0.9880;
    51 .. 55:Result := 0.9857;
    56 .. 60:Result := 0.9832;
    61 .. 65:Result := 0.9805;
    66 .. 70:Result := 0.9777;
    71 .. 75:Result := 0.9748;
    76 .. 80:Result := 0.9716;
    81 .. 85:Result := 0.9684;                         nm mb
    86 .. 90:Result := 0.9652;
    91 .. 95:Result := 0.9616;
    96 .. 100:Result := 0.9581;
  else
    Result := -9999;
  end;
end;

// Density Water
Function TForm1.DensityH2O(MyTemperature: Real): Real;
Var
  FullNr, hundreth, MyPos: Integer;
  MyNrStr: String;
  Res, Diff: Real;

begin
  MyNrStr := FloatToStrF(MyTemperature, ffFixed, 10, 2);
  MyPos := point of sale(',', MyNrStr);

  If (MyPos = 0) then
    FullNr := Round(MyTemperature)
  else
    FullNr := StrToInt(Copy(MyNrStr, 1, MyPos - 1));

  If (MyPos = 0) then
    hundreth := 0
  else
    hundreth := StrToInt(Copy(MyNrStr, MyPos + 1, 2));

  Res := CalcH2ODens(FullNr);
  Diff := CalcH2ODens(FullNr + 1) - CalcH2ODens(FullNr);

  Result := Res + (hundreth / 100 * Diff)
end;

enjoy
Martin
 
OP
OP
M

minagos

New Member
View Badges
Joined
May 13, 2017
Messages
16
Reaction score
13
Rating - 0%
0   0   0
Thank you so much.
I will be able to play with it tomorrow, my day off. : )

I will post something with my setup.
 
OP
OP
M

minagos

New Member
View Badges
Joined
May 13, 2017
Messages
16
Reaction score
13
Rating - 0%
0   0   0
My very smart friend, figure out the problem. We were not calculating pressure. New code reflects this now. It will ask for that input.

Thank you all.

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LuisProject
{
    class Program
    {
        static void Main(string[] args)
        {
            double sal;

            Luis luisclass = new Luis();
            bool exit = false;


            while (!exit)
            {
                double salinity, density, standarddensity, sg;
                double conductivity, temperature, pressure;
                Console.Write("Please cond in ms/sec-1 : ");
                conductivity = Convert.ToDouble(Console.ReadLine());
                Console.Write("Please enter pressure in decibars: ");
                pressure = Convert.ToDouble(Console.ReadLine());
                Console.Write("Pleaser temperature in C : ");
                temperature = Convert.ToDouble(Console.ReadLine());

                salinity = luisclass.Sal78(conductivity / 42.914, temperature, pressure, 0);
                density = luisclass.PsuToDensity(salinity, temperature);
                standarddensity = luisclass.PsuToDensity(0, temperature);
                sg = density / standarddensity;
                Console.WriteLine("Salinity = " + salinity);
                Console.WriteLine("Density = " + density);
                Console.WriteLine("Specific Gravity = " + sg);
                Console.WriteLine("");
                Console.Write("Dowant to exit Y/N? ");
                string response = Console.ReadLine();
                if ((response == "Y") || (response == "y"))
                { exit = true; }



            }
        }
    }

    class Luis
    {
        public double Sal78(double CND, double T, double P, int Ma)
        {
            // THE CONDUCTIVITY RATIO (CND)=1.0000000 FOR SALINITY=35 PSS-78
            // TEMPERATURE=15.0 DEG. CELSIUS AND ATMOSPHERIC PRESSURE.
            // FUNCTION TO CONVERT CONDUCTIVITY RATIO TO SALINITY (M=0)
            // SALINITY TO CONDUCTIVITY RATIO (M=1, CND BECOMES INPUT SALINITY)
            // REFERENCES: ALSO LOCATED IN UNESCO REPORT NO. 37 1981
            // PRACTICAL SALINITY SCALE 1978: E.L. LEWIS IEEE OCEAN ENG. JAN. 1980
            // ----------------------------------------------------------
            // UNITS:
            //   PRESSURE      P      DECIBARS
            //   TEMPERATURE   T      DEG CELSIUS IPTS-68
            //   CONDUCTIVITY  CND    RATIO                (M=0)
            //   SALINITY      SAL78  PSS-78               (M=0)
            // ----------------------------------------------------------
            // CHECKVALUES:
            //   1.) SAL78=1.888091 for CND=40.0000, T=40 DEG C, P=10000 DECIBARS:   M=1
            //   2.) SAL78=40.00000 for CND=1.888091, T=40 DEG C, P=10000 DECIBARS:  M=0
            // ----------------------------------------------------------
            // SAL78 RATIO: RETURNS ZERO FOR CONDUCTIVITY RATIO: < 0.0005
            // SAL78: RETURNS ZERO FOR SALINITY: < 0.02
            // ----------------------------------------------------------
            // Original fortran code is found in:
            //   UNESCO technical papers in marine science 44 (1983) -
            //   'Algorithms for computation of fundamental properties of seawater'
            // ----------------------------------------------------------
            // Translated to object pascal by:
            //   Dr. Jan Schulz, 19. May 2008, www.code10.info

            double DT;
            double Res;
            double RT;
            double SI;
            int N;
            double DELS;
            double RTT;
            double AT;
            double BT;
            double CP;



            // ZERO SALINITY/CONDUCTIVITY TRAP
            if (((Ma == 0) && (CND <= 5e-4)) || ((Ma == 1) && (CND <= 0.2)))
            { return 0; }

            DT = T - 15;

            // SELECT BRANCH FOR SALINITY (M=0) OR CONDUCTIVITY (M=1)
            if (Ma == 0)
            {


                // CONVERT CONDUCTIVITY TO SALINITY
                Res = CND;
                RT = Res / (RT35(T) * (1.0 + C(P) / (B(T) + A(T) * Res)));
                RT = Math.Sqrt(Math.Abs(RT));
                return SAL(RT, DT);

            }

            if (Ma == 1)
            {
                // INVERT SALINITY TO CONDUCTIVITY BY THE
                // NEWTON-RAPHSON ITERATIVE METHOD
                // FIRST APPROXIMATION

                RT = Math.Sqrt(CND / 35);
                SI = SAL(RT, DT);
                N = 0;
                DELS = 1;
                // ITERATION LOOP BEGINS HERE WITH A MAXIMUM OF 10 CYCLES
                while ((N < 10) && DELS > 1e-4)
                {
                    RT = RT + (CND - SI) / DSAL(RT, DT);
                    SI = SAL(RT, DT);
                    N = N + 1;
                    DELS = Math.Abs(SI - CND);
                }
                //IF((DELS.GT.1.0E-4).AND.(N.LT.10)) GO TO 15

                //Until not ((DELS > 1.0E-4) AND (N <10));

                //COMPUTE CONDUCTIVITY RATIO
                RTT = RT35(T) * RT * RT;
                AT = A(T);
                BT = B(T);
                CP = C(P);
                CP = RTT * (CP + BT);
                BT = BT - RTT * AT;

                // SOLVE QUADRATIC EQUATION FOR R: R=RT35*RT*(1+C/AR+B)
                //    R  := SQRT (ABS (BT * BT + 4.0 * AT * CP)) - BT;
                Res = Math.Sqrt(Math.Abs(BT * BT + 4 * AT * CP)) - BT;

                // CONDUCTIVITY RETURN
                return 0.5 * Res / AT;
            }
            return 0;
        }
        double SAL(double XR, double XT)
        // PRACTICAL SALINITY SCALE 1978 DEFINITION WITH TEMPERATURE
        // CORRECTION;XT :=T-15.0; XR:=SQRT(RT);
        {
            double tempSAL;
            tempSAL = ((((2.7081 * XR - 7.0261) * XR + 14.0941) * XR + 25.3851) * XR
                    - 0.1692) * XR + 0.0080
                    + (XT / (1.0 + 0.0162 * XT)) * (((((-0.0144 * XR
                    + 0.0636) * XR - 0.0375) * XR - 0.0066) * XR - 0.0056) * XR + 0.0005);
            return tempSAL;
        }

        double DSAL(double XR, double XT)
        // FUNCTION FOR DERIVATIVE OF SAL(XR,XT) WITH XR
        {
            double tempDSAL;
            tempDSAL = ((((13.5405 * XR - 28.1044) * XR + 42.2823) * XR + 50.7702) * XR
                     - 0.1692) + (XT / (1.0 + 0.0162 * XT)) * ((((-0.0720 * XR + 0.2544)
                     * XR - 0.1125) * XR - 0.0132) * XR - 0.0056);
            return tempDSAL;
        }

        double RT35(double XT)
        // FUNCTION RT35: C(35,T,0)/C(35,15,0) VARIATION WITH TEMPERATURE
        {
            double tempRT35;
            tempRT35 = (((1.0031E-9 * XT - 6.9698E-7) * XT + 1.104259E-4) * XT
               + 2.00564E-2) * XT + 0.6766097;
            return tempRT35;
        }


        double C(double XP)
        // C(XP) POLYNOMIAL CORRESPONDS TO A1-A3 CONSTANTS: LEWIS 1980
        {
            return ((3.989E-15 * XP - 6.370E-10) * XP + 2.070E-5) * XP;
        }

        double B(double XT)
        {
            return (4.464E-4 * XT + 3.426E-2) * XT + 1.0;
        }

        double A(double XT)
        //A(XT) POLYNOMIAL CORRESPONDS TO B3 AND B4 CONSTANTS: LEWIS 1980
        {
            return -3.107E-3 * XT + 0.4215;
        }

        public  double PsuToDensity(double psu, double  temp)
        {
            // http://www.niot.res.in/COAT/coat_pdf/CHAP%20III%20-%20Equation%20of%20State.pdf
            double density;
            density = 999.842594 + temp * (0.06793952 + temp * (-0.00909529 + temp * (0.0001001685 + temp * (-1.120083e-6 + temp * 6.536332e-9)))) + psu * (0.824493 + temp * (-0.0040899 + temp * (0.000076438 + temp * (-8.2467e-7 + temp * 5.3875e-9))) + (-0.00572466 + temp * (0.00010227 - temp * 0.0000016546)) * Math.Sqrt(psu) + 0.00048314 * psu);

            return density;
        }
        


    }
    //The function Cond2Sal78 converts conductivity to salinity.Required input parameters are aConductivity in S* m-1, Temp in °C and Press in decibars.In contrast to the function Sal78 it returns the salinity value as a parameter, while the return value of the function is a boolean.The function returns TRUE, if the passed conductivity value is >0.2 and the result of the conversion is between 2 and 40 PSS-78. In other cases FALSE is returned, indicating that the result might be unreliable (see above: Equation).
    class Luis2
    {
        public bool Cond2Sal78(double aConductivity, double Temp, double Press, out double aSalinity)
        //// Function Cond2Sal converts a conductivity value of seawater to a value
        //// of the pratical-salinity-scale 1978 (PSS-78) for given values of
        //// conductivity, temperature and pressure. Result is returned as
        //// parameter in aSalinity. A returned boolean result TRUE of the
        //// function indicates that the result is reliable.
        //// UNITS:
        ////   PRESSURE      Press          DECIBARS
        ////   TEMPERATURE   Temp           DEG CELSIUS IPTS-68
        ////   CONDUCTIVITY  aConductivity  S/m
        ////   SALINITY      aSalinity      PSS-78
        //// ----------------------------------------------------------
        //// CHECKVALUES:
        ////   2.) aSalinity=40.00000 for CND=1.888091, T=40 DEG C, P=10000 DECIBARS
        //// ----------------------------------------------------------
        //// SAL78 RATIO: RETURNS ZERO FOR CONDUCTIVITY RATIO: < 0.0005
        //// ----------------------------------------------------------
        //// This source code is based on the original fortran code in:
        ////   UNESCO technical papers in marine science 44 (1983) -
        ////   'Algorithms for computation of fundamental properties of seawater'
        //// ----------------------------------------------------------
        //// Written in object pascal by:
        ////   Dr. Jan Schulz, 26. May 2008, www.code10.info
        {


            double DT;
            double RT;

            //  // we expect the best
            //  Cond2Sal78 := True;
            aSalinity = 0;

            // equation is not defined for conductivity values below 5e-4
            if (aConductivity <= 0.2)
            {
                return false;
            }

            // start conversion
            DT = Temp - 15;
            aSalinity = aConductivity / 4.2914;
            RT = aSalinity / (RT35(Temp) * (1.0 + C(Press) / (B(Temp) + A(Temp) * aSalinity)));
            RT = Math.Sqrt(Math.Abs(RT));
            aSalinity = SAL(RT, DT);

            // control, whether result is in the validity range of PSS-78
            if ((aSalinity < 2) || (aSalinity > 42))
            {
                return false;
            }
            return true;
        }

        double SAL(double XR, double XT)
        // PRACTICAL SALINITY SCALE 1978 DEFINITION WITH TEMPERATURE
        // CORRECTION;XT :=T-15.0; XR:=SQRT(RT);
        {
            double tempSAL;
            tempSAL = ((((2.7081 * XR - 7.0261) * XR + 14.0941) * XR + 25.3851) * XR
                    - 0.1692) * XR + 0.0080
                    + (XT / (1.0 + 0.0162 * XT)) * (((((-0.0144 * XR
                    + 0.0636) * XR - 0.0375) * XR - 0.0066) * XR - 0.0056) * XR + 0.0005);
            return tempSAL;
        }
        double RT35(double XT)
        // FUNCTION RT35: C(35,T,0)/C(35,15,0) VARIATION WITH TEMPERATURE
        {
            double tempRT35;
            tempRT35 = (((1.0031E-9 * XT - 6.9698E-7) * XT + 1.104259E-4) * XT
               + 2.00564E-2) * XT + 0.6766097;
            return tempRT35;
        }


        double C(double XP)
        // C(XP) POLYNOMIAL CORRESPONDS TO A1-A3 CONSTANTS: LEWIS 1980
        {
            return ((3.989E-15 * XP - 6.370E-10) * XP + 2.070E-5) * XP;
        }

        double B(double XT)
        {
            return (4.464E-4 * XT + 3.426E-2) * XT + 1.0;
        }

        double A(double XT)
       //A(XT) POLYNOMIAL CORRESPONDS TO B3 AND B4 CONSTANTS: LEWIS 1980
        {
            return -3.107E-3 * XT + 0.4215;
        }



    }

}
 
OP
OP
M

minagos

New Member
View Badges
Joined
May 13, 2017
Messages
16
Reaction score
13
Rating - 0%
0   0   0
Hey guys, just wanted to update my progress. I was able to update my HMI screen with the new salinity conversions. Hope you like my screen.
I will do a build thread soon.

HMI.png
 

Just grow it: Have you ever added CO2 to your reef tank?

  • I currently use a CO2 with my reef tank.

    Votes: 8 5.4%
  • I don’t currently use CO2 with my reef tank, but I have in the past.

    Votes: 5 3.4%
  • I have never used CO2 with my reef tank, but I plan to in the future.

    Votes: 8 5.4%
  • I have never used CO2 with my reef tank and have no plans to in the future.

    Votes: 120 81.6%
  • Other.

    Votes: 6 4.1%
Back
Top