示例#1
0
        // -------------------------------------------------------------------------------------
        //                              !!! PRIVATE METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// Adds a new measurement, taken at time t, to the lists.
        /// </summary>
        /// <param name="t">simulation time in days</param>
        /// <param name="value">an array of physical values measured at that time</param>
        private void addMeasurement(double t, physValue[] value)
        {
            double last_t = 0;

            if (time.Count > 0)
            {
                last_t = time[time.Count - 1];
            }

            physValue[] last_signals;

            if (values.Count > 0)
            {
                last_signals = values[values.Count - 1];
            }
            else // init with 0 elements, needed below in if of getNoisyMeasurement
            {
                last_signals = new physValue[0];
            }

            values.Add(value);                    // just add value to list

            // add noisy value to list
            values_noise.Add(sensor_config.getNoisyMeasurement(t, last_t, value, last_signals, myConfigs));

            time.Add(t); // add current time to time vector
        }
示例#2
0
        // diese überladung dürfte nicht benötigt werden, da in sensor dies überladung existiert
        // ruft die methode unten für noisy= false auf
        ///// <summary>
        ///// Get value at time t of measured variable with the id: param
        ///// </summary>
        ///// <param name="param">id of the variable, the correct values of the
        ///// ids are defined inside this function
        ///// ids are: H2_%, CH4_%, CO2_%, and biogas_m3_d</param>
        ///// <param name="t">some simulation time [days]</param>
        ///// <returns>measured values at time t for given param</returns>
        ///// <exception cref="exception">Unknown param</exception>
        //override public physValue getMeasurementAt(string param, double t)
        //{
        //  return getMeasurementAt(param, t, false);
        //}
        /// <summary>
        /// Get value at time t of measured variable with the id: param
        /// </summary>
        /// <param name="param">id of the variable, the correct values of the
        /// ids are defined inside this function
        /// ids are: H2_%, CH4_%, CO2_%, and biogas_m3_d</param>
        /// <param name="t">some simulation time [days]</param>
        /// <param name="noisy">if true, then noisy measurement values are returned.
        /// they are only noisy if the parameter apply_real_sensor was true before and during
        /// the simulation</param>
        /// <returns>measured values at time t for given param</returns>
        /// <exception cref="exception">Unknown param</exception>
        override public physValue getMeasurementAt(string param, double t, bool noisy)
        {
            switch (param)
            {
            // TODO : überarbeiten!!!
            case "H2_%":
                return(getMeasurementAt((int)BioGas.n_gases + BioGas.pos_h2 - 1, t, noisy));

            case "CH4_%":
                return(getMeasurementAt((int)BioGas.n_gases + BioGas.pos_ch4 - 1, t, noisy));

            case "CO2_%":
                return(getMeasurementAt((int)BioGas.n_gases + BioGas.pos_co2 - 1, t, noisy));

            case "biogas_m3_d":
                physValue[] values = getMeasurementVectorAt(t, noisy);

                physValue myValue = values[0];

                for (int igas = 0; igas < (int)BioGas.n_gases; igas++)
                {
                    myValue = myValue + values[igas];
                }

                myValue.Symbol = "biogas";

                return(myValue);

            default:
                throw new exception(String.Format("biogas_sensor: Unknown param: {0}!", param));
            }
        }
示例#3
0
        /// <summary>
        /// type 7
        ///
        /// called in ADMstate_stoichiometry.cs -> measure_type7
        /// </summary>
        /// <param name="x">ADM state vector - not used</param>
        /// <param name="myPlant"></param>
        /// <param name="mySubstrates">not yet used</param>
        /// <param name="mySensors">used to get TS inside digester</param>
        /// <param name="Q">not used</param>
        /// <param name="par">not used</param>
        /// <returns>measured values</returns>
        override protected physValue[] doMeasurement(double[] x, biogas.plant myPlant,
                                                     biogas.substrates mySubstrates,
                                                     biogas.sensors mySensors,
                                                     double[] Q, params double[] par)
        {
            // 1st Pel in kWh/d for mixing digester
            // 2nd Pdissipated in kWh/d for mixing digester, dissipated in digester
            physValue[] values = new physValue[dimension];

            //

            digester myDigester = myPlant.getDigesterByID(id_suffix);

            // calc stirrer(s) power for digester in kWh/d
            values[0] = myDigester.calcStirrerPower(mySensors);

            // calc stirrer(s) power dissipated to digester in kWh/d
            values[1] = myDigester.calcStirrerDissipation(mySensors);

            values[0].Label = "electrical energy of stirrer";
            values[1].Label = "thermal energy dissipated by stirrer";

            //

            return(values);
        }
示例#4
0
        /// <summary>
        /// Calculates the extended buswell equation for the given molecule.
        /// Calculates CH4, CO2, NH3 and H2S in "mol gas / mol molecule"
        /// </summary>
        /// <param name="c">mol C / mol molecule</param>
        /// <param name="h">mol H / mol molecule</param>
        /// <param name="o">mol O / mol molecule</param>
        /// <param name="n">mol N / mol molecule</param>
        /// <param name="s">mol S / mol molecule</param>
        /// <param name="ch4">CH4 in "mol gas / mol molecule"</param>
        /// <param name="co2">CO2 in "mol gas / mol molecule"</param>
        /// <param name="nh3">NH3 in "mol gas / mol molecule"</param>
        /// <param name="h2s">H2S in "mol gas / mol molecule"</param>
        public static void buswell_extended(physValue c, physValue h, physValue o,
                                            physValue n, physValue s,
                                            out physValue ch4, out physValue co2,
                                            out physValue nh3, out physValue h2s)
        {
            ch4 = c / 2 + h / 8 - o / 4 - 3 * n / 8 - s / 4;

            ch4.Symbol = "ch4";
            ch4.Label  = String.Format("mol CH4 / mol C{0}H{1}O{2}N{3}S{4} (fermentation)",
                                       c.Value, h.Value, o.Value, n.Value, s.Value);

            co2 = c / 2 - h / 8 + o / 4 + 3 * n / 8 + s / 4;

            co2.Symbol = "co2";
            co2.Label  = String.Format("mol CO2 / mol C{0}H{1}O{2}N{3}S{4} (fermentation)",
                                       c.Value, h.Value, o.Value, n.Value, s.Value);

            nh3 = n;

            nh3.Symbol = "nh3";
            nh3.Label  = String.Format("mol NH3 / mol C{0}H{1}O{2}N{3}S{4} (fermentation)",
                                       c.Value, h.Value, o.Value, n.Value, s.Value);

            h2s = s;

            h2s.Symbol = "h2s";
            h2s.Label  = String.Format("mol H2S / mol C{0}H{1}O{2}N{3}S{4} (fermentation)",
                                       c.Value, h.Value, o.Value, n.Value, s.Value);
        }
        /// <summary>
        /// Calculates the organic loading rate of the digester.
        /// Assumption that Q and Qsum is measured in m^3/d.
        ///
        /// As a reference see:
        ///
        /// Handreichung Biogasgewinnung und -nutzung: Grundlagen der anaeroben
        /// Fermentation, S. 29.
        ///
        /// </summary>
        /// <param name="x">digester state vector</param>
        /// <param name="mySubstrates">
        /// substrates or sludge but not both!!! Because TS content is calculated
        /// out of COD in digester. If there is a mixture of substrate and sludge going
        /// into the digester, then the COD is aleardy decreased by the sludge, so no need
        /// to account for the lower TS of the sludge here.
        /// TODO: hier sollten es beide sein!
        /// </param>
        /// <param name="Q">
        /// Q of the substrates or sludge, but not both!
        /// TODO: hier sollten es beide sein!
        /// </param>
        /// <param name="Qsum">
        /// if there is sludge and substrate going into the digester, then Qsum will be
        /// bigger then math.sum(Q). Qsum is needed to account for full volumeflow
        /// going into the digester no matter if substrate or sludge.
        /// TODO: nach Änderung, dass Q alle feed enthält, ist Qsum= sum(Q)
        /// kann also als Parameter entfernt werden
        /// </param>
        /// <returns></returns>
        public physValue calcOLR(double[] x, substrates mySubstrates, double[] Q, double Qsum)
        {
            physValue Vliq = this.Vliq;

            physValue TS;

            // TODO
            // was mache ich hier!!!! ???????????????????
            // warum nehme ich nicht einfach VS aus den Substraten???
            physValue VS;//= calcVS(x, mySubstrates, Q, out TS);

            mySubstrates.get_weighted_mean_of(Q, "VS", out VS);
            mySubstrates.get_weighted_mean_of(Q, "TS", out TS);

            VS = biogas.substrate.convertFrom_TS_To_FM(VS, TS);
            VS = VS.convertUnit("100 %");

            physValue rho;

            mySubstrates.get_weighted_mean_of(Q, "rho", out rho);

            // hier wird die Annahme gemacht, dass rho von schlamm gleich ist
            // wie rho der substrate, aber egal (TODO)
            // evtl. wäre es besser gemessenes rho aus density_sensor zu nehmen
            // das ist dichte des inputs in den fermenter (Gemisch aus substrate und rezischlamm)
            physValue OLR = new physValue(Qsum, "m^3/d") * rho * VS / Vliq;

            OLR.Symbol = "OLR";

            return(OLR);
        }
        /// <summary>
        /// Returns C, H, O and N content of molecule. mol / molecule
        /// </summary>
        /// <param name="molecule">string of molecule</param>
        /// <param name="C">mol C / mol molecule</param>
        /// <param name="H">mol H / mol molecule</param>
        /// <param name="O">mol O / mol molecule</param>
        /// <param name="N">mol N / mol molecule</param>
        /// <exception cref="exception">Unknown molecule</exception>
        public static void get_CHON_of(string molecule, out physValue C, out physValue H,
                                       out physValue O, out physValue N)
        {
            physValue S;

            get_CHONS_of(molecule, out C, out H, out O, out N, out S);
        }
示例#7
0
        /// <summary>
        /// Set two physValues to the given value. Only the Value of the given values is
        /// set, so you must make sure that the unit and the rest is ok
        /// </summary>
        /// <param name="sym1">1st parameter to be set</param>
        /// <param name="val1">value of 1st parameter to be set</param>
        /// <param name="sym2">2nd parameter to be set</param>
        /// <param name="val2">value of 2nd parameter to be set</param>
        /// <exception cref="exception">Unknown parameter</exception>
        public void set_params_of(string sym1, physValue val1,
                                  string sym2, physValue val2)
        {
            object[] values = { sym1, val1.Value, sym2, val2.Value };

            this.set_params_of(values);
        }
示例#8
0
        /// <summary>
        /// Calculates energy flow needed to get the thermal power pP_loss
        /// from the heating.
        /// </summary>
        /// <param name="pP_loss">thermal power loss</param>
        /// <param name="P_loss_kW">thermal or electrical power</param>
        /// <param name="P_loss_kWh_d">thermal or electrical energy per day</param>
        /// <exception cref="exception">efficiency is zero, division by zero</exception>
        /// <exception cref="exception">heating failed</exception>
        public void compensateHeatLoss(physValue pP_loss,
                                       out physValue P_loss_kW, out physValue P_loss_kWh_d)
        {
            if (eta == 0)
            {
                throw new exception("electrical/thermal degree of efficiency of the heating: eta == 0");
            }

            try
            {
                if (status)
                {
                    physValue P_loss = pP_loss / eta;

                    P_loss.Symbol = "Ploss";

                    P_loss_kW = P_loss.convertUnit("kW");
                }
                else
                {
                    P_loss_kW = new physValue("Ploss", 0, "kW");
                }

                P_loss_kWh_d = P_loss_kW.convertUnit("kWh/d");
            }
            catch (exception e)
            {
                Console.WriteLine(e.Message);
                throw new exception("compensateHeatLoss: heating failed!");
            }
        }
示例#9
0
        // -------------------------------------------------------------------------------------
        //                            !!! PROTECTED METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// Calculates faecal bacteria removal capacity of the digester, measured in %
        ///
        /// type 0 aktuell type 1
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="par">HRT of the digester in m^3, temperature inside the digester in °C</param>
        /// <returns>measured faecal bacteria removal capacity in %</returns>
        override protected physValue[] doMeasurement(double[] x, params double[] par)
        {
            physValue[] values = new physValue[dimension];

            if (par.Length != 2)
            {
                throw new exception(String.Format(
                                        "Length of params is != 2: {0}!", par.Length));
            }

            double HRT = par[0];
            double T   = par[1];

            if (HRT == 0)
            {
                throw new exception("HRT == 0");
            }

            // intestinal enterococci
            values[0] = new physValue("eta_IE", 98.29 - 2.2 * Math.Pow(1 / HRT, 2) + 0.031 * T, "%");
            // faecal coliforms
            values[1] = new physValue("eta_FC", 98.29 - 1.0 * Math.Pow(1 / HRT, 2) + 0.031 * T, "%");

            return(values);
        }
示例#10
0
        // -------------------------------------------------------------------------------------
        //                              !!! CONSTRUCTOR METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// Standard Constructor sets default values of ADM parameters
        /// </summary>
        /// <param name="T">digester temperature in °C</param>
        public ADM(physValue T)
        {
            T = T.convertUnit("°C");

            // set default parameter values
            setDefaultParams(T.Value);
        }
示例#11
0
        // -------------------------------------------------------------------------------------
        //                              !!! PUBLIC METHODS !!!
        // -------------------------------------------------------------------------------------

        ///// <summary>
        ///// Calculates energy flow needed to heat the substrate flows Q
        ///// up to the temperature Tend. The volumeflows Q are assumed to
        ///// be measured in m^3/d
        ///// </summary>
        ///// <param name="Q">array of volumeflows of the substrates in [m³/d]</param>
        ///// <param name="mySubstrates"></param>
        ///// <param name="Tend"></param>
        ///// <param name="Pel_kWh_d">thermal or electrical energy per day</param>
        ///// <param name="Pel_kW">thermal or electrical power</param>
        ///// <exception cref="exception">Q.Length != mySubstrates.Count</exception>
        ///// <exception cref="exception">efficiency is zero, division by zero</exception>
        //public void heatSubstrates(double[] Q, substrates mySubstrates,
        //                           physValue Tend, out physValue Pel_kWh_d,
        //                                           out physValue Pel_kW)
        //{
        //  physValue[] pQ= new physValue[Q.Length];

        //  for (int iel= 0; iel < Q.Length; iel++)
        //    pQ[iel]= new physValue("Q", Q[iel], "m^3/d");

        //  heatSubstrates(pQ, mySubstrates, Tend, out Pel_kWh_d, out Pel_kW);
        //}
        ///// <summary>
        ///// Calculates energy flow needed to heat the substrate flows Q
        ///// up to the temperature Tend. The volumeflows Q are assumed to
        ///// be measured in m^3/d
        ///// </summary>
        ///// <param name="Q">array of volumeflows of the substrates in [m³/d]</param>
        ///// <param name="mySubstrates"></param>
        ///// <param name="Tend"></param>
        ///// <param name="Pel_kWh_d">thermal or electrical energy per day</param>
        ///// <exception cref="exception">Q.Length != mySubstrates.Count</exception>
        ///// <exception cref="exception">efficiency is zero, division by zero</exception>
        //public void heatSubstrates(double[] Q, substrates mySubstrates,
        //                           physValue Tend, out physValue Pel_kWh_d)
        //{
        //  physValue[] pQ = new physValue[Q.Length];

        //  for (int iel = 0; iel < Q.Length; iel++)
        //    pQ[iel] = new physValue("Q", Q[iel], "m^3/d");

        //  heatSubstrates(pQ, mySubstrates, Tend, out Pel_kWh_d);
        //}
        ///// <summary>
        ///// Calculates energy flow needed to heat the substrate flows Q
        ///// up to the temperature Tend.
        ///// </summary>
        ///// <param name="Q"></param>
        ///// <param name="mySubstrates"></param>
        ///// <param name="Tend"></param>
        ///// <param name="Pel_kWh_d">thermal or electrical energy per day</param>
        ///// <param name="Pel_kW">thermal or electrical power</param>
        ///// <exception cref="exception">Q.Length != mySubstrates.Count</exception>
        ///// <exception cref="exception">efficiency is zero, division by zero</exception>
        //public void heatSubstrates(physValue[] Q, substrates mySubstrates,
        //                           physValue Tend, out physValue Pel_kWh_d,
        //                                           out physValue Pel_kW)
        //{
        //  physValue Qtherm_day=
        //            mySubstrates.calcSumQuantityOfHeatPerDay(Q, Tend);

        //  heatSubstrate(Qtherm_day, out Pel_kWh_d, out Pel_kW);
        //}
        ///// <summary>
        ///// Calculates energy flow needed to heat the substrate flows Q
        ///// up to the temperature Tend.
        ///// </summary>
        ///// <param name="Q"></param>
        ///// <param name="mySubstrates"></param>
        ///// <param name="Tend"></param>
        ///// <param name="Pel_kWh_d">thermal or electrical energy per day</param>
        ///// <exception cref="exception">Q.Length != mySubstrates.Count</exception>
        ///// <exception cref="exception">efficiency is zero, division by zero</exception>
        //public void heatSubstrates(physValue[] Q, substrates mySubstrates,
        //                           physValue Tend, out physValue Pel_kWh_d)
        //{
        //  physValue Qtherm_day =
        //            mySubstrates.calcSumQuantityOfHeatPerDay(Q, Tend);

        //  heatSubstrate(Qtherm_day, out Pel_kWh_d);
        //}

        ///// <summary>
        ///// Calculates energy flow needed to get the thermal energy/day pQtherm_day
        ///// from the heating.
        ///// </summary>
        ///// <param name="pQtherm_day"></param>
        ///// <param name="Pel_kWh_d">thermal or electrical energy per day</param>
        ///// <param name="Pel_kW">thermal or electrical power</param>
        ///// <exception cref="exception">efficiency is zero, division by zero</exception>
        //public void heatSubstrate(physValue pQtherm_day, out physValue Pel_kWh_d,
        //                                                 out physValue Pel_kW)
        //{
        //  heatSubstrate(pQtherm_day, out Pel_kWh_d);

        //  Pel_kW = Pel_kWh_d.convertUnit("kW");
        //}

        ///// <summary>
        ///// Calculates energy flow needed to get the thermal energy/day pQtherm_day
        ///// from the heating.
        ///// </summary>
        ///// <param name="pQtherm_day"></param>
        ///// <param name="Pel_kWh_d">thermal or electrical energy per day</param>
        ///// <exception cref="exception">efficiency is zero, division by zero</exception>
        //public void heatSubstrate(physValue pQtherm_day, out physValue Pel_kWh_d)
        //{
        //  if (status)
        //  {
        //    physValue Qtherm_day= pQtherm_day.convertUnit("kWh/d");

        //    if (eta != 0)
        //    {
        //      Pel_kWh_d= Qtherm_day / eta;
        //      Pel_kWh_d.Symbol= "Pel_sub";
        //    }
        //    else
        //      throw new exception("electrical degree of efficiency of the heating: eta == 0");
        //  }
        //  else
        //  {
        //    Pel_kWh_d= new physValue("Pel", 0, "kWh/d");
        //  }
        //}

        ///// <summary>
        ///// Calculates energy flow needed to get the thermal power pP_radiation_loss
        ///// from the heating.
        ///// </summary>
        ///// <param name="pP_radiation_loss"></param>
        ///// <param name="P_radiation_loss_kW">thermal or electrical power</param>
        ///// <param name="P_radiation_loss_kWh_d">thermal or electrical energy per day</param>
        ///// <exception cref="exception">efficiency is zero, division by zero</exception>
        //public void compensateHeatLossDueToRadiation(physValue pP_radiation_loss,
        //                                             out physValue P_radiation_loss_kW,
        //                                             out physValue P_radiation_loss_kWh_d)
        //{
        //  if (eta == 0)
        //    throw new exception("electrical degree of efficiency of the heating: eta == 0");

        //  if (status)
        //  {
        //    physValue P_radiation_loss= pP_radiation_loss / eta;

        //    P_radiation_loss.Symbol= "Pel_rad";

        //    P_radiation_loss_kW= P_radiation_loss.convertUnit("kW");
        //  }
        //  else
        //  {
        //    P_radiation_loss_kW= new physValue("Pel", 0, "kW");
        //  }

        //  P_radiation_loss_kWh_d= P_radiation_loss_kW.convertUnit("kWh/d");
        //}

        /// <summary>
        /// Calculates costs for heating the digester in €/d. in case of a thermal heating
        /// costs are lost gain which we had if we sell the thermal energy. In case
        /// of an electrical heating it is the cost producing the electrical energy.
        /// </summary>
        /// <param name="pP_loss">thermal power loss</param>
        /// <param name="sell_heat">€/kWh for selling thermal energy, this is a virtual price here
        /// missed gain, needed for a thermal heating</param>
        /// <param name="cost_elEnergy">costs for electricity in €/kWh, needed if we have a electrical
        /// heating</param>
        /// <param name="P_loss_kW">thermal or electrical power</param>
        /// <param name="P_loss_kWh_d">thermal or electrical energy per day</param>
        /// <returns>costs in €/d</returns>
        /// <exception cref="exception">efficiency is zero, division by zero</exception>
        public double calcCostsForHeating(physValue pP_loss, double sell_heat, double cost_elEnergy,
                                          out physValue P_loss_kW, out physValue P_loss_kWh_d)
        {
            compensateHeatLoss(pP_loss, out P_loss_kW, out P_loss_kWh_d);

            // falls im fermenter th. energie produziert wird, mehr als verbraucht, dann
            // sind kosten == 0, man kann diese thermische energie nicht verkaufen, also kein
            // gewinn machen
            if (pP_loss.Value < 0)
            {
                return(0);
            }

            switch (type)
            {
            case 0:                                         // electrical heating
                return(P_loss_kWh_d.Value * cost_elEnergy); // €

            case 1:                                         // thermal heating
                return(P_loss_kWh_d.Value * sell_heat);     // €

            default:
                throw new exception(String.Format("Unknown heating type: {0}", type));
            }
        }
示例#12
0
        /// <summary>
        /// Calculates the f-Factor: fXI_Xc, defining the fraction of particulate inerts in
        /// composites Xc
        /// </summary>
        /// <param name="pADL">ADL</param>
        /// <param name="pNDF">NDF</param>
        /// <param name="pVS">VS</param>
        /// <param name="pD_VS">degradation level</param>
        /// <returns>fXI_Xc</returns>
        /// <exception cref="exception">value out of bounds</exception>
        public static double calcfXI_Xc(physValue pADL, physValue pNDF,
                                        physValue pVS, physValue pD_VS)
        {
            physValue ADL  = pADL.convertUnit("% TS");
            physValue NDF  = pNDF.convertUnit("% TS");
            physValue VS   = pVS.convertUnit("% TS");
            physValue D_VS = pD_VS.convertUnit("100 %");

            double d = calc_d(ADL, NDF, D_VS, VS);

            physValue pfXI_Xc;

            if (VS.Value > 0)
            {
                pfXI_Xc = (ADL + (1 - d) * (NDF - ADL)) / VS;
            }
            else
            {
                pfXI_Xc = new physValue(0, "-");
            }

            // 0.8 ist Test, noch nicht in thesis, s.u. fSI_XC, da steht 0.2f
            double fXI_Xc = pfXI_Xc.Value;// *0.6f;

            if (fXI_Xc < 0 || fXI_Xc > 1)
            {
                throw new exception(String.Format("fXI_Xc is out of bounds [0,1]: {0}!",
                                                  fXI_Xc));
            }

            return(fXI_Xc);
        }
示例#13
0
        /// <summary>
        /// Calculates the f-Factor: fPr_Xc, defining the fraction of proteins in
        /// composites Xc
        /// </summary>
        /// <param name="pRP">RP</param>
        /// <param name="pVS">VS</param>
        /// <returns>fPr_Xc</returns>
        /// <exception cref="exception">value out of bounds</exception>
        public static double calcfPr_Xc(physValue pRP, physValue pVS)
        {
            physValue RP = pRP.convertUnit("% TS");
            physValue VS = pVS.convertUnit("% TS");

            physValue pfPr_Xc;

            if (VS.Value > 0)
            {
                pfPr_Xc = RP / VS;
            }
            else
            {
                pfPr_Xc = new physValue(0, "-");
            }

            double fPr_Xc = pfPr_Xc.Value;

            if (fPr_Xc < 0 || fPr_Xc > 1)
            {
                throw new exception(String.Format("fPr_Xc is out of bounds [0,1]: {0}!",
                                                  fPr_Xc));
            }

            return(fPr_Xc);
        }
示例#14
0
        /// <summary>
        /// Calculates the f-Factor: fCh_Xc, defining the fraction of carbohydrates in
        /// composites Xc
        /// The values given are converted to the correct unit, thus the units
        /// of the given values are not important.
        /// </summary>
        /// <param name="pRF">raw fiber</param>
        /// <param name="pNfE">nitrogen free extracts</param>
        /// <param name="pADL">acid detergent lignin</param>
        /// <param name="pNDF">neutral detergent fiber</param>
        /// <param name="pVS">volatile solids</param>
        /// <param name="pD_VS">degradation level</param>
        /// <returns>fCh_Xc</returns>
        /// <exception cref="exception">value out of bounds</exception>
        public static double calcfCh_Xc(physValue pRF, physValue pNfE, physValue pADL,
                                        physValue pNDF, physValue pVS, physValue pD_VS)
        {
            physValue RF   = pRF.convertUnit("% TS");
            physValue NfE  = pNfE.convertUnit("% TS");
            physValue ADL  = pADL.convertUnit("% TS");
            physValue NDF  = pNDF.convertUnit("% TS");
            physValue VS   = pVS.convertUnit("% TS");
            physValue D_VS = pD_VS.convertUnit("100 %");

            double d = calc_d(ADL, NDF, D_VS, VS);

            physValue pfCh_Xc;

            if (VS.Value > 0)
            {
                pfCh_Xc = (calcNFC(RF, NfE, NDF) + d * (NDF - ADL)) / VS;
            }
            else
            {
                pfCh_Xc = new physValue(0, "-");
            }

            double fCh_Xc = pfCh_Xc.Value;

            if (fCh_Xc < 0 || fCh_Xc > 1)
            {
                throw new exception(String.Format("fCh_Xc is out of bounds [0,1]: {0}!",
                                                  fCh_Xc));
            }

            return(fCh_Xc);
        }
        /// <summary>
        /// Returns O content of molecule. mol O / molecule
        /// </summary>
        /// <param name="molecule">string of molecule</param>
        /// <param name="O">mol O / mol molecule</param>
        /// <exception cref="exception">Unknown molecule</exception>
        public static void get_O_of(string molecule, out physValue O)
        {
            physValue H;
            physValue C;

            get_CHO_of(molecule, out C, out H, out O);
        }
        /// <summary>
        /// Combusts the chemical formula C_cH_hO_oN_n.
        /// Calculates O2, CO2, H2O and NH3 in mol/mol
        /// </summary>
        /// <param name="c">mol C in molecule</param>
        /// <param name="h">mol H in molecule</param>
        /// <param name="o">mol O in molecule</param>
        /// <param name="n">mol N in molecule</param>
        /// <param name="o2">mol O2 oxydized in the reaction</param>
        /// <param name="co2">mol CO2 created during combustion</param>
        /// <param name="h2o">mol H2O created during combustion</param>
        /// <param name="nh3">mol NH3 created during combustion</param>
        public static void combust(physValue c, physValue h, physValue o, physValue n,
                                   out physValue o2, out physValue co2, out physValue h2o,
                                   out physValue nh3)
        {
            // in meinem PDF steht hier fehlerhaft + o/2, muss - o/2 sein, sonst geht O Bilanz nicht auf
            o2 = c + h / 4f - o / 2f - 3f * n / 4f;

            co2 = c;

            h2o = h / 2f - 3f * n / 2f;

            nh3 = n;

            o2.Symbol = "o2";
            o2.Label  = String.Format("mol molecular oxygen / mol C{0}H{1}O{2}N{3} (combustion)",
                                      c.Value, h.Value, o.Value, n.Value);

            co2.Symbol = "co2";
            co2.Label  = String.Format("mol carbon dioxide / mol C{0}H{1}O{2}N{3} (combustion)",
                                       c.Value, h.Value, o.Value, n.Value);

            h2o.Symbol = "o2";
            h2o.Label  = String.Format("mol water / mol C{0}H{1}O{2}N{3} (combustion)",
                                       c.Value, h.Value, o.Value, n.Value);

            nh3.Symbol = "nh3";
            nh3.Label  = String.Format("mol ammonia / mol C{0}H{1}O{2}N{3} (combustion)",
                                       c.Value, h.Value, o.Value, n.Value);
        }
        /// <summary>
        /// Returns C, H and O content of molecule. mol / molecule
        /// </summary>
        /// <param name="molecule">string of molecule</param>
        /// <param name="C">mol C / mol molecule</param>
        /// <param name="H">mol H / mol molecule</param>
        /// <param name="O">mol O / mol molecule</param>
        /// <exception cref="exception">Unknown molecule</exception>
        public static void get_CHO_of(string molecule, out physValue C, out physValue H,
                                      out physValue O)
        {
            physValue N;

            get_CHON_of(molecule, out C, out H, out O, out N);
        }
        // -------------------------------------------------------------------------------------
        //                              !!! PUBLIC METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// Combusts the chemical formula C_cH_hO_oN_n.
        /// Calculates O2 in mol/mol
        /// </summary>
        /// <param name="c">mol C in molecule</param>
        /// <param name="h">mol H in molecule</param>
        /// <param name="o">mol O in molecule</param>
        /// <param name="n">mol N in molecule</param>
        /// <param name="o2">mol O2 oxydized in the reaction</param>
        public static void combust(physValue c, physValue h, physValue o, physValue n,
                                   out physValue o2)
        {
            physValue co2;

            combust(c, h, o, n, out o2, out co2);
        }
示例#19
0
        /// <summary>
        /// aktuell type 4
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="u">Qin in m³/d</param>
        /// <param name="par">
        /// par[0] is the density of the substrate in kg/m^3
        /// </param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant,
                                                     double u, params double[] par)
        {
            //
            physValue[] values = new physValue[1];

            // 1. komponente ist rho als double, unten in density def. dann anstatt
            // 1000 einsetzen
            if (par.Length != 1) // 2, da rho auch übergeben werden muss
            {
                throw new exception(String.Format(
                                        "Length of par is != 1: {0}!", par.Length));
            }

            transportation myTransportations = myPlant.myTransportation;

            // get pump from transportation class using id
            biogas.substrate_transport mySubsTransport = myTransportations.getSubstrateTransportByID(id_suffix);

            // is the energy_per_ton [kWh/t]
            double energy_per_ton = mySubsTransport.energy_per_ton;

            // calc energy consumption in kWh/d
            // hier muss man schon rho der zu fördernden menge kennen
            values[0] = new physValue("Pel_trans", u * par[0] / 1000 * energy_per_ton, "kWh/d",
                                      "transport energy");

            return(values);
        }
        /// <summary>
        /// Combusts the chemical formula C_cH_hO_oN_n.
        /// Calculates O2 and CO2 in mol/mol
        /// </summary>
        /// <param name="c">mol C in molecule</param>
        /// <param name="h">mol H in molecule</param>
        /// <param name="o">mol O in molecule</param>
        /// <param name="n">mol N in molecule</param>
        /// <param name="o2">mol O2 oxydized in the reaction</param>
        /// <param name="co2">mol CO2 created during combustion</param>
        /// <param name="h2o">mol H2O created during combustion</param>
        public static void combust(physValue c, physValue h, physValue o, physValue n,
                                   out physValue o2, out physValue co2, out physValue h2o)
        {
            physValue nh3;

            combust(c, h, o, n, out o2, out co2, out h2o, out nh3);
        }
示例#21
0
        /// <summary>
        /// Calculates costs for heating the digester. in case of a thermal heating
        /// costs are lost gain which we had if we sell the thermal energy. In case
        /// of an electrical heating it is the cost producing the electrical energy.
        /// </summary>
        /// <param name="pP_loss">thermal power loss</param>
        /// <param name="sell_heat">€/kWh for selling thermal energy, this is a virtual price here
        /// missed gain, needed for a thermal heating</param>
        /// <param name="cost_elEnergy">costs for electricity in €/kWh, needed if we have a electrical
        /// heating</param>
        /// <returns>costs in €/d</returns>
        /// <exception cref="exception">efficiency is zero, division by zero</exception>
        public double calcCostsForHeating(physValue pP_loss, double sell_heat, double cost_elEnergy)
        {
            physValue P_loss_kW, P_loss_kWh_d;

            return(heating.calcCostsForHeating(pP_loss, sell_heat, cost_elEnergy,
                                               out P_loss_kW, out P_loss_kWh_d));
        }
示例#22
0
        ///// <summary>
        ///// Calculate thermal power needed to compensate heat loss due ot radiation
        ///// through the digesters surface.
        ///// </summary>
        ///// <param name="digester_id"></param>
        ///// <param name="T_ambient"></param>
        ///// <param name="P_radiation_loss_kW"></param>
        ///// <param name="P_radiation_loss_kWh_d"></param>
        //public void compensateHeatLossDueToRadiation(string digester_id,
        //                                             physValue T_ambient,
        //                                             out physValue P_radiation_loss_kW,
        //                                             out physValue P_radiation_loss_kWh_d)
        //{
        //  digester myDigester= get(digester_id);

        //  myDigester.compensateHeatLossDueToRadiation(T_ambient, out P_radiation_loss_kW,
        //                                                         out P_radiation_loss_kWh_d);
        //}

        /// <summary>
        /// Calculates costs for heating the digester. in case of a thermal heating
        /// costs are lost gain which we had if we sell the thermal energy. In case
        /// of an electrical heating it is the cost producing the electrical energy.
        /// </summary>
        /// <param name="digester_id">digester id</param>
        /// <param name="pP_loss">thermal power loss</param>
        /// <param name="sell_heat">€/kWh for selling thermal energy, this is a virtual price here
        /// missed gain, needed for a thermal heating</param>
        /// <param name="cost_elEnergy">costs for electricity in €/kWh, needed if we have a electrical
        /// heating</param>
        /// <returns>costs in €/d</returns>
        /// <exception cref="exception">Unknown digester id</exception>
        /// <exception cref="exception">efficiency is zero, division by zero</exception>
        public double calcCostsForHeating(string digester_id, physValue pP_loss, double sell_heat,
                                          double cost_elEnergy)
        {
            digester myDigester = get(digester_id);

            return(myDigester.calcCostsForHeating(pP_loss, sell_heat, cost_elEnergy));
        }
示例#23
0
        /// <summary>
        /// converts double biogas stream u, given in ppm, % and % to
        /// corresponding physValues
        /// </summary>
        /// <param name="u_rel">n_gases dim vector of h2 in ppm,
        /// ch4 in % and co2 in %</param>
        /// <returns>u as physValue vector measured in % and ppm resp.</returns>
        /// <exception cref="exception">u_rel.Length &lt; _n_gases</exception>
        public static physValue[] convert(double[] u_rel)
        {
            if (u_rel.Length < _n_gases)
            {
                throw new exception(String.Format(
                                        "The gas stream u has not the right dimension ({0}). Must be >= {1}!",
                                        u_rel.Length, _n_gases));
            }

            physValue[] values = new physValue[u_rel.Length];

            //

            for (int igas = 0; igas < u_rel.Length; igas++)
            {
                if (igas == pos_h2 - 1)
                {
                    values[igas] = new physValue(symGases[igas] + "_t", u_rel[igas], "ppm", labelGases[igas]);
                }
                else
                {
                    values[igas] = new physValue(symGases[igas] + "_t", u_rel[igas], "%", labelGases[igas]);
                }
            }

            return(values);
        }
示例#24
0
        /// <summary>
        /// Calculate thermal/electrical power needed by heating to compensate heat loss in digester.
        /// </summary>
        /// <param name="digester_id">digester id</param>
        /// <param name="Q">substrate feed measured in m^3/d</param>
        /// <param name="mySubstrates"></param>
        /// <param name="T_ambient">ambient temperature</param>
        /// <param name="mySensors"></param>
        /// <returns>thermal/electrical energy needed by heating in kWh/d</returns>
        /// <exception cref="exception">Unknown digester id</exception>
        /// <exception cref="exception">Q.Length != mySubstrates.Count</exception>
        /// <exception cref="exception">efficiency is zero, division by zero</exception>
        public double calcHeatPower(string digester_id, double[] Q, substrates mySubstrates,
                                    physValue T_ambient, sensors mySensors)
        {
            digester myDigester = get(digester_id);

            return(myDigester.calcHeatPower(Q, mySubstrates, T_ambient, mySensors));
        }
示例#25
0
        /// <summary>
        /// calc methane yield [m^3 CH4 / kgVS]
        ///
        /// http://www.bioconverter.com/technology/primer.htm#Methane%20Yield%20%28m3%20CH4%20/%20kg%20VS%20added%29
        ///
        /// if methane yield is high, everything is ok, if it is too low
        /// maybe decrease substrate feed, digester could be overburdened
        ///
        /// </summary>
        /// <param name="x">ADM state vector</param>
        /// <param name="pQ">Q   : m^3/d  : total feed into the digester</param>
        /// <param name="pVS">VS  : % TS   : volatile solids content of feed</param>
        /// <param name="pTS">TS  : % FM   : total solids content of feed</param>
        /// <param name="prho">rho : kg/m^3 : density of feed</param>
        /// <returns></returns>
        public physValue calcCH4Yield(double[] x, physValue pQ, physValue pVS,
                                      physValue pTS, physValue prho)
        {
            physValue Qgas_h2, Qgas_ch4;

            ADMstate.calcBiogasOfADMstate(x, Vliq, T, out Qgas_h2, out Qgas_ch4);

            physValue Q   = pQ.convertUnit("m^3/d");
            physValue VS  = pVS.convertUnit("% TS");
            physValue TS  = pTS.convertUnit("% FM");
            physValue rho = prho.convertUnit("kg/m^3");

            VS = substrate.convertFrom_TS_To_FM(VS, TS);

            // VS [% FM] * [100 % / % FM] * m^3/d * kg/m^3 = VS kg/d
            physValue VS_kg = VS.convertUnit("100 %") * Q * rho;

            if (VS_kg.Value == 0)
            {
                return(new physValue(0, "m^3/kg"));
            }

            // m^3/d / kgVS/d= m^3/kgVS
            // Einheit ist: m^3/kg
            physValue CH4Yield = Qgas_ch4 / VS_kg;

            return(CH4Yield);
        }
        /// <summary>
        /// Returns the current measurement vector in the list, so the values last saved
        /// in the list. If list is empty a zero vector with dimension dimension is returned.
        /// </summary>
        /// <param name="noisy">if true, then noisy measurement values are returned.
        /// they are only noisy if the parameter apply_real_sensor was true before and during
        /// the simulation</param>
        /// <returns>current measurement vector</returns>
        public physValue[] getCurrentMeasurementVector(bool noisy)
        {
            if (values.Count > 0)
            {
                if (noisy)
                {
                    return(values_noise[values_noise.Count - 1]); // return noisy values
                }
                else
                {
                    return(values[values.Count - 1]); // return normal values
                }
            }
            else
            {
                physValue[] myValues = new physValue[dimension];

                for (int ivalue = 0; ivalue < dimension; ivalue++)
                {
                    myValues[ivalue] = new physValue();
                }

                return(myValues);
            }
        }
示例#27
0
        // -------------------------------------------------------------------------------------
        //                            !!! PROTECTED METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// here it is defined what is measured in the sensor and in which position
        ///
        /// not type 0
        /// </summary>
        /// <param name="u">biogas stream: dimension: BioGas.n_gases</param>
        /// <param name="par">not used</param>
        /// <returns>
        /// measured biogas values
        /// first n_gases values are biogas in m^3/d
        /// next n_gases values are biogas concentrations in %
        /// </returns>
        /// <exception cref="exception">u.Length &lt; _n_gases</exception>
        /// <exception cref="exception">u is empty</exception>
        override protected physValue[] doMeasurement(double[] u, params double[] par)
        {
            physValue[] QgasP = new physValue[(int)BioGas.n_gases];

            // is already checked for in calcPercentualBiogasComposition
            //if (u.Length != (int)BioGas.n_gases)
            //  throw new exception(String.Format(
            //          "u is not of correct dimension: {0} != {1}!",
            //          u.Length, (int)BioGas.n_gases));

            BioGas.calcPercentualBiogasComposition(u, out QgasP);

            physValue[] values = new physValue[dimension];

            for (int ivalue = 0; ivalue < values.Length; ivalue++)
            {
                if (ivalue < (int)BioGas.n_gases)
                {
                    values[ivalue] = new physValue(BioGas.symGases[ivalue], u[ivalue], "m^3/d",
                                                   BioGas.labelGases[ivalue]);
                }
                else
                {
                    values[ivalue] = QgasP[ivalue - (int)BioGas.n_gases];
                }
            }

            return(values);
        }
        // -------------------------------------------------------------------------------------
        //                            !!! PROTECTED METHODS !!!
        // -------------------------------------------------------------------------------------

        /// <summary>
        /// measures ratio of acetoclastic to hydrogenotrophic methanogenesis of
        /// given digester
        /// </summary>
        /// <param name="intvars">ADM1 internal variables</param>
        /// <param name="par">2dim.
        /// 0: Yac
        /// 1: Yh2
        /// </param>
        /// <returns>ratio of acetoclastic to hydrogenotrophic methanogenesis
        /// inside digester</returns>
        override protected physValue[] doMeasurement(double[] intvars, params double[] par)
        {
            physValue[] values = new physValue[dimension];

            // Uptake of acetate
            double p_ac = intvars[48];
            // Uptake of hydrogen
            double p_h2 = intvars[49];

            double Yac = par[0]; // ADMparams.Get(46 - 1);
            double Yh2 = par[1]; // ADMparams.Get(47 - 1);

            double ch4_prod_ac = p_ac * (1 - Yac);
            double ch4_prod_h2 = p_h2 * (1 - Yh2);

            double aceto_ratio, hydro_ratio;

            if (ch4_prod_ac + ch4_prod_h2 != 0)
            {
                aceto_ratio = Math.Round(ch4_prod_ac / (ch4_prod_ac + ch4_prod_h2) * 100.0, 2);

                hydro_ratio = Math.Round(ch4_prod_h2 / (ch4_prod_ac + ch4_prod_h2) * 100.0, 2);
            }
            else
            {
                aceto_ratio = 0;
                hydro_ratio = 0;
            }

            values[0] = new physValue("aceto", aceto_ratio, "100 %", "acetoclastic methanogenesis");
            values[1] = new physValue("hydro", hydro_ratio, "100 %", "hydrogenotrophic methanogenesis");

            return(values);
        }
示例#29
0
        /// <summary>
        /// Calculate g C / kg substrate fresh matter
        /// </summary>
        /// <param name="mySubstrate">a substrate</param>
        /// <returns>g C / kg fresh matter</returns>
        private static physValue calcC(substrate mySubstrate)
        {
            physValue[] values = new physValue[6];

            try
            {
                mySubstrate.get_params_of(out values, "RF", "RP", "RL",
                                          "NfE", "ADL", "TS");
            }
            catch (exception e)
            {
                Console.WriteLine(e.Message);

                return(new physValue("error"));
            }

            physValue RF  = values[0];
            physValue RP  = values[1];
            physValue RL  = values[2];
            physValue NfE = values[3];
            physValue ADL = values[4];
            physValue TS  = values[5];

            return(calcC(RF, RP, RL, NfE, ADL, TS));
        }
示例#30
0
        /// <summary>
        /// Measure NH4 content inside a digester
        /// 1st measurement is Snh4 in g/l
        /// 2nd : Snh4 + NH4 in Xc in g/l
        ///
        /// type 5
        /// </summary>
        /// <param name="myPlant"></param>
        /// <param name="x">ADM state vector</param>
        /// <param name="param">not used - but OK</param>
        /// <param name="par">not used</param>
        /// <returns></returns>
        override protected physValue[] doMeasurement(biogas.plant myPlant, double[] x,
                                                     string param, params double[] par)
        {
            physValue[] values = new physValue[dimension];

            // hier wird umrechnungsfaktor 18 genutzt, deshalb nur ammonium und nicht
            // ammonium nitrogen
            values[0] = ADMstate.calcFromADMstate(x, "Snh4", "g/l");

            //
            // -2 wegen _2 bzw. _3
            string digester_id = id.Substring(("Snh4_").Length, id.Length - 2 - ("Snh4_").Length);

            // kmol N/m^3
            double NH4 = ADMstate.calcNH4(x, digester_id, myPlant);

            //
            // erstmal Snh4 nennen, damit convertUnit funktioniert
            // TODO - könnte es auch N nennen, dann wird allerdings nur mit 14 als
            // umrechnungsfaktor gerechnet und nicht wie jetzt mit 18. Vorsicht
            // bei vergleich mit Ntot, TKN und Norg, dort wird nur mit 14 gerechnet.
            // da ich die Größe ammonium nitrogen nenne, wird umrechnungsfaktor 14 genutzt
            values[1]        = new physValue("N", NH4, "mol/l", "total ammonium nitrogen");
            values[1]        = values[1].convertUnit("g/l");
            values[1].Symbol = "NH4";

            return(values);
        }