/// <summary> /// Call measure of all type 8 sensors /// /// type 8 /// /// used by fitness sensors /// </summary> /// <param name="time">current simulation time in days</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="par"></param> public void measure_type8(double time, //double deltatime, biogas.plant myPlant, biooptim.fitness_params myFitnessParams, double par) { double value; foreach (string id in ids_type8) { measure(time, id, myPlant, myFitnessParams, par, out value); } }
// ------------------------------------------------------------------------------------- // !!! PRIVATE METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Calc loss in €/d due to in excess produced biogas /// </summary> /// <param name="biogas_v">measured biogas vector gotten out of sensors</param> /// <param name="substrate_costs">costs for substrates in [€/d]</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="biogasExcess">in excess produced biogas [m^3/d]</param> /// <returns></returns> private static double calcLossDueToBiogasExcess(physValue[] biogas_v, double substrate_costs, biogas.plant myPlant, biooptim.fitness_params myFitnessParams, out double biogasExcess) { double H2Concentration = biogas_v[1].Value; // ppm double methaneConcentration = biogas_v[2].Value; // % double CO2Concentration = biogas_v[3].Value; // % // in excess produced biogas in [m^3/d] biogasExcess = biogas_v[biogas_v.Length - 1].Value; // double[] u = new double[3]; // biogas excess in m³/d u[0] = biogasExcess * H2Concentration / 1000000; u[1] = biogasExcess * methaneConcentration / 100; u[2] = biogasExcess * CO2Concentration / 100; // €/d : get monetary value of in excess produced biogas. which amount of // money would we earn when we had sell the energy produced by the in excess // produced biogas? double valueMethaneExcess = calcValueOfMethaneExcess(u, myPlant, myFitnessParams); // m³/d : total biogas production double total_biogas_prod = biogas_v[0].Value; // costs of substrates needed to produce the excess methane amount in €/d double substrateCostsMethaneExcess = calcSubstrateCostsForMethaneExcess(biogasExcess, methaneConcentration, substrate_costs, total_biogas_prod); // since complete substrate costs are already included in fitness function. // therefore we only may add the difference of the value of the methane and // the substrate costs needed to produce it. this value is always positive, // because methane is more worse then the substates needed to produce it. double lossBiogasExcess = valueMethaneExcess - substrateCostsMethaneExcess; // if (lossBiogasExcess < 0) { // TODO - throw error //error('loss: %f < 0, value: %f, costs: %f', ... //lossBiogasExcess, valueMethaneExcess, substrateCostsMethaneExcess); //throw new toolbox.exception(String.Format("lossBiogasExcess < 0: {0}", lossBiogasExcess)); } return(lossBiogasExcess); }
/// <summary> /// ... /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">not used</param> /// <returns></returns> override protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values = new physValue[1]; // fitness > 0 if pH value under or over boundaries double pHvalue_fitness = getpHvalue_fitness(mySensors, myPlant, myFitnessParams); values[0] = new physValue("pH_fitness", pHvalue_fitness, "-"); return(values); }
/// <summary> /// ... /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">not used</param> /// <returns></returns> override protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values = new physValue[1]; // this is the fitness of the VS_COD in the digester double VS_COD_degradationRate; double VS_COD_fitness = getVS_COD_fitness(mySensors, out VS_COD_degradationRate); values[0] = new physValue("VS_COD_fitness", VS_COD_fitness, "-"); return(values); }
/// <summary> /// ... /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">not used</param> /// <returns></returns> override protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values = new physValue[1]; // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein double VFA_TAC_fitness = sensors.calcFitnessDigester_min_max(myPlant, mySensors, "VFA_TAC", "min_max", myFitnessParams, "_3", true); values[0] = new physValue("VFA_TAC_fitness", VFA_TAC_fitness, "-"); return(values); }
/// <summary> /// ... /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">not used</param> /// <returns></returns> override protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values = new physValue[1]; // this is the fitness of the CH4 in the digester // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein double CH4_fitness; getBiogas_fitness(mySensors, out CH4_fitness); values[0] = new physValue("CH4_fitness", CH4_fitness, "-"); return(values); }
// ------------------------------------------------------------------------------------- // !!! PUBLIC METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Sell produced electrical and thermal energy. /// returns money we make by selling the energy in [€/d] /// </summary> /// <param name="energyProduction">electrical energy production in kWh/d</param> /// <param name="energyThermProduction">thermal energy production in kWh/d</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <returns></returns> public static double sellEnergy(double energyProduction, double energyThermProduction, biogas.plant myPlant, biooptim.fitness_params myFitnessParams) { // how much is paid for electrical energy production in €/kWh // sellCurrent measured in €/kWh double sellCurrent = myPlant.getVerguetung(energyProduction / 24, myFitnessParams.manurebonus); // energyProduction : produced electrical energy (power) [kWh/d] // energyThermProduction : produced thermal energy (power) [kWh/d] // // moneyEnergy is the money you get by selling electrical and thermal power // €/d = kWh/d * €/kWh double moneyEnergy = energyProduction * sellCurrent + energyThermProduction * myPlant.myFinances.revenueTherm.Value; return(moneyEnergy); }
// ------------------------------------------------------------------------------------- // !!! PRIVATE METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// Calculates sum of setpoint control errors /// </summary> /// <param name="mySensors">sensors object with all measurements</param> /// <param name="myPlant">plant object</param> /// <param name="myFitnessParams">fitness params</param> /// <param name="noisy">if true then noisy measurements are used</param> /// <returns></returns> private static double calc_setpoint_errors(sensors mySensors, plant myPlant, biooptim.fitness_params myFitnessParams, bool noisy) { double diff_setpoints = 0; // to be returned value: control setpoint error double[] sim_t = mySensors.getTimeStream(); double t = mySensors.getCurrentTime(); double sim_val, ref_val; // last simulated value and reference value at time t // if (sim_t.Length > 3) { foreach (biooptim.setpoint mySetpoint in myFitnessParams.mySetpoints) { if (mySetpoint.s_operator == "") // then compare measurement of one sensor { string sensor_id = mySetpoint.sensor_id + "_" + mySetpoint.location; // get reference values always not noisy ref_val = mySensors.getMeasurementDAt(String.Format("ref_{0}_{1}", sensor_id, mySetpoint.index), "", t, 0, false); sim_val = mySensors.getCurrentMeasurementDind(sensor_id, mySetpoint.index, noisy); } else // compare measurement of a group of sensors, energy of all chps, gas of all digesters, ... { string s_operator = mySetpoint.location + "_" + mySetpoint.s_operator; // get reference values always not noisy ref_val = mySensors.getMeasurementDAt( String.Format("ref_{0}_{1}", mySetpoint.sensor_id, mySetpoint.index), "", t, 0, false); sim_val = mySensors.getCurrentMeasurementDind(myPlant, mySetpoint.sensor_id, s_operator, mySetpoint.index, noisy); } diff_setpoints += mySetpoint.scalefac * Math.Pow(ref_val - sim_val, 2); } } return(diff_setpoints); }
// ------------------------------------------------------------------------------------- // !!! PRIVATE METHODS !!! // ------------------------------------------------------------------------------------- /// <summary> /// returns a value between 0 and 1. if the pH value is lower or upper /// some constraints, then the value is greater 0, else 0. /// /// TODO: diese methode überdenken /// </summary> /// <param name="mySensors"></param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <returns></returns> private static double getpHvalue_fitness(biogas.sensors mySensors, biogas.plant myPlant, biooptim.fitness_params myFitnessParams) { double pH_Punishment = 0; double pH_value; int n_digester = myPlant.getNumDigesters(); for (int idigester = 0; idigester < n_digester; idigester++) { string digester_id = myPlant.getDigesterID(idigester + 1); mySensors.getCurrentMeasurementD("pH_" + digester_id + "_3", out pH_value); // punish values bigger than 8 or smaller than 7 // Der Faktor gibt die Steilheit der Strafe an, bei max. 2, dann ist // schon bei 8 bzw. 7 der Ausdruck ( 2.0 .* (pH(ifermenter,1) - 7.5) ) // == 1 // TODO - maybe use tukey function here instead // macht es überhaupt sinn mit optimal values zu arbeiten? // oder einfacher die calcFitnessDigester_min_max() methode nutzen double pH_punish_digester = Math.Min(1 / (10 ^ 4) * ( Math.Pow(1.8 * (pH_value - myFitnessParams.get_param_of("pH_optimum", idigester)), 12)), Math.Abs(pH_value - myFitnessParams.get_param_of("pH_optimum", idigester))); pH_punish_digester = Math.Max(pH_punish_digester, Convert.ToDouble(pH_value < myFitnessParams.get_param_of("pH_min", idigester))); pH_punish_digester = Math.Max(pH_punish_digester, Convert.ToDouble(pH_value > myFitnessParams.get_param_of("pH_max", idigester))); // diese zeile begrenzt pH Strafe zwischen 0 und 1 pH_Punishment = pH_Punishment + Math.Min(pH_punish_digester, 1); } if (n_digester > 0) { pH_Punishment = pH_Punishment / n_digester; } // values between 0 and 1, can be hard constraints return(pH_Punishment); }
/// <summary> /// Do measurements which depend on fitness_params. /// /// 8th type /// /// example sensor: /// used by all fitness sensors /// </summary> /// <param name="time">current simulation time [days]</param> /// <param name="deltatime">sample time of the sensor [days]</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">some doubles</param> /// <returns>measured values</returns> public physValue[] measure(double time, double deltatime, biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values; if (time - getCurrentTime() >= deltatime) { values = doMeasurement(myPlant, myFitnessParams, mySensors, par); addMeasurement(time, values); } else { values = getCurrentMeasurementVector(); } return(values); }
/// <summary> /// Calc monetary value of in excess produced methane in €/d /// </summary> /// <param name="u">u - 3dim vector of in excess produced biogas in m³/d /// h2, ch4, co2</param> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <returns></returns> private static double calcValueOfMethaneExcess(double[] u, biogas.plant myPlant, biooptim.fitness_params myFitnessParams) { string bhkw_id = myPlant.getCHPID(1); // electrical and thermal energy produced by in excess produced biogas // measured in kWh/d double Pel_kWh_d, Ptherm_kWh_d; myPlant.burnBiogas(bhkw_id, u, out Pel_kWh_d, out Ptherm_kWh_d); // // €/d : get money that we would get by selling produced energy double valueMethaneExcess = sellEnergy(Pel_kWh_d, Ptherm_kWh_d, myPlant, myFitnessParams); return(valueMethaneExcess); }
/// <summary> /// ... /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">not used</param> /// <returns></returns> override protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values = new physValue[1]; // TODO - was muss ich hier machen, damit sensor daten noisy aufzeichnet??? bool noisy = false; // calc setpoint control error - errors of setpoint controls double diff_setpoints = calc_setpoint_errors(mySensors, myPlant, myFitnessParams, noisy); // wende tukey biweight an diff_setpoints = math.tukeybiweight(diff_setpoints); values[0] = new physValue("diff_setpoints", diff_setpoints, "-"); return(values); }
/// <summary> /// ... /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">not used</param> /// <returns></returns> override protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values = new physValue[1]; // Grenzwerte, welche ich mal auf einer Konferenz (vermutlich VDI Tagung) aufgeschnappt habe // // TAC < 50 mmol/l gefährlich // 50 < TAC < 100 mmol/l gering Warnung // 100 < TAC < 250 mmol/l OK // da mit tukey gearbeitet wird, kann der term auch etwas größer als 1 sein double TAC_fitness = sensors.calcFitnessDigester_min_max(myPlant, mySensors, "TAC", "min", myFitnessParams, "_3", true); values[0] = new physValue("TAC_fitness", TAC_fitness, "-"); return(values); }
/// <summary> /// ... /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">not used</param> /// <returns></returns> override protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { physValue[] values = new physValue[1]; // // <param name="biogasExcess_fitness">lost money due to biogas excess [1000 €/d]</param> // <param name="biogasExcess">in excess produced biogas [m^3/d]</param> // <param name="lossBiogasExcess">lost money due to biogas excess [€/d]</param> physValue[] biogas_v = mySensors.getCurrentMeasurementVector("total_biogas_"); // // excess biogas in [m^3/d] double biogasExcess;// = biogas_v[biogas_v.Length - 1].Value; // // Calculation of costs of substrate inflow // € / d double substrate_costs; mySensors.getCurrentMeasurementD("substrate_cost", out substrate_costs); // loss of excess methane prod. in €/d // if there is a loss, then positive value // if there is a gain, then negative value, should not be the case double lossBiogasExcess = calcLossDueToBiogasExcess(biogas_v, substrate_costs, myPlant, myFitnessParams, out biogasExcess); // tausend € / d double biogasExcess_fitness = lossBiogasExcess / 1000; // values[0] = new physValue("biogasExcess_fitness", biogasExcess_fitness, "-"); return(values); }
/// <summary> /// used by all fitness sensors /// /// type 8 /// </summary> /// <param name="myPlant"></param> /// <param name="myFitnessParams"></param> /// <param name="mySensors"></param> /// <param name="par">some doubles</param> /// <returns>measured values</returns> /// <exception cref="exception">Not implemented</exception> virtual protected physValue[] doMeasurement(biogas.plant myPlant, biooptim.fitness_params myFitnessParams, biogas.sensors mySensors, params double[] par) { throw new exception("Not implemented!"); }