From 099ac11693adb12d70f861a74ece0592372018b5 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Wed, 18 Aug 2021 16:13:01 -0400 Subject: [PATCH 01/24] Set battery variables --- src/Battery.int | 405 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 src/Battery.int diff --git a/src/Battery.int b/src/Battery.int new file mode 100644 index 0000000..3f1056f --- /dev/null +++ b/src/Battery.int @@ -0,0 +1,405 @@ +/*** + -------------------------------------------------------------------------------------------- + | | + | NASA Glenn Research Center | + | 21000 Brookpark Rd | + | Cleveland, OH 44135 | + | | + | File Name: Source.int | + | Author(s): George Thomas, Jeffrey Csank, David Sadey, Tom Lavelle, Brian Malone | + | Date(s): August 2021 | + | | + -------------------------------------------------------------------------------------------- +***/ + +#ifndef __SOURCE__ +#define __SOURCE__ +#include "PSL_math.fnc" + +int ESO_Id_ExceededEnergyDes = (10000 * 145) + (100 * 22) + 1; +ESOregCreate(ESO_Id_ExceededEnergyDes, 1, "Energy Constraint Exceeded"); + +class Battery extends ElectricElement { + + //---------------------------- + // ****** DOCUMENTATION ****** + //---------------------------- + + // title = ""; + + description = "The " + isA() + " serves as a voltage source with constant + impedance. It also contains simplified logic for calculating energy consumed + to be used with a MDP solver setup. This energy is used to compute mass via a + flat assumption for specific energy. Users can also specify specific power. + Mass is calculated as the larger of the two masses (design power/spc power) + and (design energy/spc energy)"; + + usageNotes = isA() + + " + +- The input design parameters that must be specified by the modeler when creating an instance +of this " + isA() + " component are mass specific power (SpecificPower), design efficiency +(effDes), frequency, and voltage (Vreal and Vimag). This component will produce electrical +power at the specified voltage and frequency, with losses according to its design efficiency. + +- When running ONDESIGN, this component will determine its output impedance, which is +calculated such that the component operates with the specified design efficiency value. +When running OFFDESIGN, the model will run with losses according to the impedance calculated +from the ONDESIGN run. + +- This component, being a source component, must have its electricPowerType specified, and +will propagate this power type information to components downstream of it when +findSourcesAndPropagate() is called. This component supports DC, single phase, and 3 phase AC. + +- This component produces power and includes a node. Being a component including a node, a +voltage must be specified at this component. However, being a source component, its voltage is +typically set to a fixed value (unless the modeler changes it to be otherwise), and it does +not need solver variables to operate (except when running in MDP mode). + +- Note that, as a component that contains a node and has its voltage known at the beginning +of the solverSequence, it uses its prePass() method to call the electrical port update +function to pass this voltage information to electrical components that it is connected to. +Note that in the current implementation of the NPSS Power System Library, these components +containing nodes do not know what currents are going through their ports at the beginning of +an iteration. Because of this, they must be connected to power transmission components (cables +and breakers), and these transmission components must be run before node-bearing +transformation components like this one, as the transmission components will calculate and +populate these current values. Note that this design is intended to be analogous to a common +approach taken in fluid networks within NPSS rocket models. + +- The battery block contains variables intended to be used in a multi-design-point (MDP) +simulation. This MDP logic is intended to consist of several different assemblies containing +systems including this source block; each one of these assemblies represents the same system +but running at a different design point (e.g. cruise, climb, and hover for an eVTOL concept). +To enable the solver variables that this component uses for MDP, set Option multiDes to true. +Then for each of the design point assemblies, set the appropriate value for segmentTime (how +long the mission segment is, in hours, that this assembly represents. Also select a segment +that represents the most important segment and give it an initial guess value for design +energy (energyDes). You will also need to disable autoSetup in ind_energyDes and dep_energyDes +or otherwise remove them from all assemblies other than the main MDP one. Finally, then set up +logic that copies energyDes from the main assembly to the other MDP assemblies before each of +them run, and set up a solver pair at the top level that varies the design energy for the main +mission segment, until the sum of the energies consumed in all of the segments is less than +the design energy. For an example on setting up this MDP logic, see baseline_all_elecMDP.run. + +- This component, like other power system components in the NPSS Power System Library, can +optionally include thermal models. An optional thermal model is enabled by setting +switchThermPort to TRUE, and plugging an EThermalMass subelement into the S_eThermMass socket. +Doing these will add a temperature state (existing within EThermalMass) and a thermal port to +the model. The thermal port is intended to connect this component to a second component that +represents the mechanism by which heat is extracted from this component. This second component +could represent a heat exchanger, cold plate, or just model heat transfer from the first +component to the surrounding environment. For more information, see EThermalMass. + +- The " + isA() + " component does not use solver variables, however it includes sizing logic. +this logic calculates mass as well as calculates the design torque and speed values. These +values are used by a performance map (if one is plugged into the S_map socket) to calculate +efficiency at the current operating point. For more information about performance maps for +this component, see MotorGeneratorMap.int"; + + //------------------------------ + // ****** SETUP VARIABLES ****** + //------------------------------ + + real actualSpecificPower { + value = 0; IOstatus = "output"; // [kw/kg] + description = "Specific power used during on-design."; + } + + real actualSpecificEnergy { + value = 0; IOstatus = "output"; // [wh/kg] + description = "Specific energy used during on-design."; + } + + real pfDes { + value = 0; IOstatus = "output"; units = "kW"; // [kilowatts] + description = "Design power factor at output of this source element."; + } + +// real effDes { +// value = 0.95; IOstatus = "input"; units = "none"; +// description = "Design efficiency of this source element."; +// } + + real pf { + value = 0; IOstatus = "output"; units = "kW"; // [kilowatts] + description = "Actual (calculated) power factor at output of this source element."; + } + + eff { + value = 0.95; IOstatus = "output"; units = "none"; + description = "Actual (calculated) efficiency of this source element."; + } + + real R { + value = .01; IOstatus = "output"; units = "ohm"; + } + + real L { + value = .0000796; IOstatus = "output"; units = "H"; // [henrys] + } + + real frequency { + value = 0; IOstatus = "input"; units = "Hz"; // [hertz] + description = "Output frequency"; + } + + Loss_r { + value = 0; IOstatus = "output"; units = "kW"; // [kilowatts] + description = "Real component of losses in this load."; + } + + Loss_j { + value = 0; IOstatus = "output"; units = "kW"; // [kilowatts] + description = "Imaginary component of losses in this load."; + } + + Q_heat { + value = 0; IOstatus = "output"; units = "Btu/sec"; // [BTUs / sec] + description = "Power dissipation in BTU/s at current time."; + } + + real energyDes { + value = 0; IOstatus = "output"; units = "none"; // [kW-h] + description = "Design energy for this source."; + } + + real energyConsumed { + value = 0; IOstatus = "output"; units = "none"; // [kW-h] + description = "Total energy consumed over mission, only use off-design."; + } + + real energy { + value = 0; IOstatus = "output"; units = "none"; // [kW-h] + description = "Energy consumed at the current operating point."; + } + + real powerDes { + value = 0; IOstatus = "output"; units = "none"; // [kW] + description = "Design power for this source."; + } + + real resistor_R0 { + value = 0; IOstatus = "output"; units = "none"; // [Ohm] + description = "Design upstream battery resistance."; + } + + real resistor_R1 { + value = 0; IOstatus = "output"; units = "none"; // [Ohm] + description = "Design downstream battery resistance."; + } + + real segmentTime { + value = 0.25; IOstatus = "output"; units = "hr"; // [h] + description = "Hours spent running at the current operating point."; + } + + real Vreal { + value = 1000.; IOstatus = "output"; units = "V"; // [volts] + description = "Real portion of output voltage."; + } + + real Vimag { + value = -1.; IOstatus = "output"; units = "V"; // [volts] + description = "Imaginary portion of output voltage."; + } + + real Voc { + value = -1.; IOstatus = "output"; units = "V"; // [volts] + description = "Real source voltage of equivalent battery circuit."; + } + + real SpecificPower { + value = 13; IOstatus = "input"; units = "none"; // [kW/kg] + description = "Power to weight ratio for the source."; + } + + real SpecificEnergy { + value = 130; IOstatus = "input"; units = "none"; // [W-h/kg] + description = "Energy to weight ratio for the source."; + } + + real C_rate { + value = 130; IOstatus = "input"; units = "none"; // [-] + description = "Computed on-design C-rate for the source."; + } + + Mass { + value = 1.; IOstatus = "output"; units = "kg"; // [kilograms] + description = "Computed on-design mass for the source."; + } + + //------------------------------------ + // ****** OPTION VARIABLE SETUP ****** + //------------------------------------ + + Option switchDes { + allowedValues = { "DESIGN", "OFFDESIGN" } + description = "Determines if the element is in design or off-design mode."; + rewritableValues = FALSE; + trigger = TRUE; + } + + Option switchThermPort { + allowedValues = { "TRUE", "FALSE" } + description = "Determines if component needs thermal port."; + rewritableValues = FALSE; // enables converter optimization + trigger = TRUE; + } + + Option switchTrackEnergy { + allowedValues = { "FALSE", "TRUE" } + description = "Determines if we should track energy or not when running off-design."; + rewritableValues = FALSE; // enables converter optimization + } + + Option multiDes { + allowedValues = { "FALSE", "TRUE" } + description = "Determines if component is undergoing multi-design point simulation."; + rewritableValues = FALSE; + trigger = TRUE; + } + + //---------------------------------------------------------- + // ****** SETUP PORTS, FLOW STATIONS, SOCKETS, TABLES ****** + //---------------------------------------------------------- + + /* ELECTRICAL PORTS */ + + ElectricOutputPort EP_O { + description = "Electric output port."; + } + + /* SOCKETS */ + + Socket S_eThermMass { + allowedValues = { "Q_heat", "Mass" } + description = "Thermal mass socket."; + socketType = "EThermalMass"; + } + + //----------------------------------------------------- + // ****** ADD SOLVER INDEPENDENTS & DEPENDENTS ****** + //----------------------------------------------------- + + // MDP variable + Independent ind_energyDes { + varName = "energyDes"; + description = "Varies design energy to match calculated energy at design condition."; + } + + // MDP variable + Dependent dep_energyDes { + eq_lhs = "energyDes"; + eq_rhs = "energy"; + } + + //------------------------------------------- + // ****** VARIABLE CHANGED METHODOLOGY ****** + //------------------------------------------- + + void variableChanged(string name, any oldVal) { + if (name == "switchThermPort") { + if (switchThermPort == "TRUE") { + create("", "ThermalInputPort", "Q_I"); + } + } + + if (name == "multiDes") { + if (switchDes == DESIGN) { + ind_energyDes.autoSetup = TRUE; + dep_energyDes.autoSetup = TRUE; + } + } + } + + //----------------------------------------------- + // ****** PERFORM ENGINEERING CALCULATIONS ****** + //----------------------------------------------- + + /** So this component expects you to set Vreal and Vimag. It will + * calculate (resistive only) impedance, power factor, etc. + */ + void calculate() { + + /** + * If we're on-design, we need to figure out the output impedance based + * on the design efficiency. Otherwise, calculate the loss and the + * efficiency based on the impedance (which is held constant). + */ + + pf = cos(EP_O.S.phase); + + if (switchDes == "DESIGN") { + pfDes = pf; + // eff = effDes; + + // internal power, before flowing through this component's output impedance + real PInternal = EP_O.S.r / eff**sign(EP_O.S.r); + Loss_r = PInternal - EP_O.S.r; + Loss_j = 0; + R = Loss_r / EP_O.I.mag**2; + L = 0; + + // Declare design point power. + powerDes = EP_O.S.r; + + // Energy consumed at this operating point. + energy = PInternal * segmentTime; + + // get design values + if (multiDes != "TRUE") { + energyDes = energy; + } + + real energyBasedMass = (energyDes*1000) / SpecificEnergy; // (kW-h/1000) / (W-h/kg) = kg + real powerBasedMass = EP_O.S.r / SpecificPower; + + if (energyBasedMass > powerBasedMass) { + Mass = energyBasedMass; // compute mass based on assumed specific energy + } else { + Mass = powerBasedMass; // compute mass based on assumed specific power + } + + actualSpecificEnergy = 1000 * energyDes/Mass; // [Wh/kg] + actualSpecificPower = powerDes/Mass; // [kW/kg] + + + C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) + + } else { + Loss_r = EP_O.I.mag**2 * R; + Loss_j = 0; + eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); + + // energy consumed at this operating point. + energy = (EP_O.S.r + Loss_r) * segmentTime; + } + + real KW_PER_BTU_PER_SEC = 1.05505585; + Q_heat = sqrt(Loss_r**2 + Loss_j**2); + Q_heat /= KW_PER_BTU_PER_SEC; + + if (switchThermPort == "TRUE") { + // run the thermal mass model. + if (!S_eThermMass.isEmpty()) { + S_eThermMass.execute(); + } + } + } + + void prePass() { + EP_O.frequency = frequency; + EP_O.setIVRMS(EP_O.I.r, EP_O.I.j, Vreal, Vimag); + } + + void trackEnergy() { + Source.energyConsumed += Source.energy; + if (Source.energyConsumed > Source.energyDes) { + ESOreport(ESO_Id_ExceededEnergyDes, + "Source component's energy consumed (" + toStr(Source.energyConsumed) + + ") exceeded design energy (" + toStr(Source.energyDes)+").", 1); + } + } +} +#endif From b787c7cc6d636f5a88e9f30cd8f1f300b6b6144b Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Thu, 19 Aug 2021 10:05:01 -0400 Subject: [PATCH 02/24] Added DC backflow battery files and set battery V/R/P constants/calculations --- model/DC_Backflow_batt.mdl | 91 ++++++++++++++++++++++++++++++++++++++ run/DC_Backflow_batt.run | 70 +++++++++++++++++++++++++++++ src/Battery.int | 23 ++++++---- 3 files changed, 175 insertions(+), 9 deletions(-) create mode 100644 model/DC_Backflow_batt.mdl create mode 100644 run/DC_Backflow_batt.run diff --git a/model/DC_Backflow_batt.mdl b/model/DC_Backflow_batt.mdl new file mode 100644 index 0000000..e7ddc5c --- /dev/null +++ b/model/DC_Backflow_batt.mdl @@ -0,0 +1,91 @@ +/*** + ------------------------------------------------------------------------------- + | | + | NASA Glenn Research Center | + | 21000 Brookpark Rd | + | Cleveland, OH 44135 | + | | + | File Name: SW13.mdl | + | Author(s): George Thomas, Brian Malone | + | Date(s): October 2020 | + | | + | Description: DC model with backflow | + | | + | | + ------------------------------------------------------------------------------- +***/ + +cout<<"======================================="< Date: Thu, 19 Aug 2021 11:58:17 -0400 Subject: [PATCH 03/24] Errors apart from convergence handled --- model/DC_Backflow_batt.mdl | 44 +++++++++++++++++++------------------- run/DC_Backflow_batt.run | 4 ++-- src/Battery.int | 11 +++++++--- src/ElectricPort.prt | 2 +- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/model/DC_Backflow_batt.mdl b/model/DC_Backflow_batt.mdl index e7ddc5c..347a0d8 100644 --- a/model/DC_Backflow_batt.mdl +++ b/model/DC_Backflow_batt.mdl @@ -30,31 +30,31 @@ cout<<"======================================="< Date: Thu, 19 Aug 2021 14:15:50 -0400 Subject: [PATCH 04/24] Preliminary converged model --- model/DC_Backflow_batt.mdl | 9 ++++++--- src/Battery.int | 32 ++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/model/DC_Backflow_batt.mdl b/model/DC_Backflow_batt.mdl index 347a0d8..0786474 100644 --- a/model/DC_Backflow_batt.mdl +++ b/model/DC_Backflow_batt.mdl @@ -79,13 +79,16 @@ solverSequence = { "Cable_Single", "Li_ion_cell", "CLoad" }; void BFPrintOutput() { - cout << " Case = " << CASE; - cout << " Battery voltage = " << Li_ion_cell.Vreal << endl; + cout << " Case = " << CASE << endl; + cout << " Battery output voltage = " << Li_ion_cell.Vreal << endl; + cout << " Battery input voltage = " << Li_ion_cell.Voc << endl; + cout << " Battery current = " << Li_ion_cell.Voc/Li_ion_cell.RTotal << endl; + cout << " PDirection = " << Li_ion_cell.PDirection << endl; cout << " Calculated load eff = " << CLoad.P/CLoad.EP_I.S.r << endl; cout << " Load eff = " << CLoad.eff << endl; } // Initial independent variable guesses are here. // DeltaDC.Voltage = 80; -CLoad.Vreal = 2; +CLoad.Vreal = 3; CLoad.Vimag = 0; diff --git a/src/Battery.int b/src/Battery.int index 59aef1f..8f0af05 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -179,6 +179,11 @@ this component, see MotorGeneratorMap.int"; description = "Design power for this source."; } + real PDirection { + value = 0; IOstatus = "output"; units = "none"; //- + description = "+1 for source to load power flow, -1 for load to source."; + } + real resistor_R0 { value = 0.6339; IOstatus = "output"; units = "none"; // [Ohm]; tR_0 in Python boring amprius_battery description = "Design upstream battery resistance."; @@ -200,8 +205,8 @@ this component, see MotorGeneratorMap.int"; } real Vreal { - value = 3.414; IOstatus = "output"; units = "V"; // [volts] - description = "Real portion of output voltage."; + value = 0; IOstatus = "output"; units = "V"; // [volts] + description = "Real portion of battery output voltage."; } real Vimag { @@ -210,7 +215,7 @@ this component, see MotorGeneratorMap.int"; } real Voc { - value = 0; IOstatus = "output"; units = "V"; // [volts] + value = 3.414; IOstatus = "output"; units = "V"; // [volts] description = "Real source voltage of equivalent battery circuit."; } @@ -336,10 +341,17 @@ this component, see MotorGeneratorMap.int"; pf = cos(EP_O.S.phase); if (switchDes == "DESIGN") { + PDirection = sign(EP_O.S.r); pfDes = pf; // eff = effDes; - RTotal = resistor_R0 + resistor_R_Th; - Voc = Vreal + (Vreal/RTotal) * RTotal; + RTotal = resistor_R0 + resistor_R_Th; + if (sign(EP_O.S.r) < 0){ + cout << "BPM: Hi! You made it." << endl; + Vreal = Voc; + Voc = Vreal - (Vreal/RTotal)*sign(EP_O.S.r) * resistor_R0; + } else { + Vreal = Voc - (Voc/RTotal)*sign(EP_O.S.r) * resistor_R_Th; + } // internal power, before flowing through this component's output impedance real PInternal = EP_O.S.r / eff**sign(EP_O.S.r); Loss_r = PInternal - EP_O.S.r; @@ -376,7 +388,15 @@ this component, see MotorGeneratorMap.int"; C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) } else { - RTotal = resistor_R0 + resistor_R_Th; + PDirection = sign(EP_O.S.r); + RTotal = resistor_R0 + resistor_R_Th; + if (sign(EP_O.S.r) < 0){ + cout << "BPM: Hi! You made it." << endl; + Vreal = Voc; + Voc = Vreal - (Vreal/RTotal)*sign(EP_O.S.r) * resistor_R0; + } else { + Vreal = Voc - (Voc/RTotal)*sign(EP_O.S.r) * resistor_R_Th; + } R = RTotal; Loss_r = EP_O.I.mag**2 * R; Loss_j = 0; From 03f70ca2b6d07d969e16f23607e0e2c80cb7c921 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Thu, 19 Aug 2021 14:52:13 -0400 Subject: [PATCH 05/24] Clarifying comments added --- run/DC_Backflow_batt.run | 13 +++++++++---- src/Battery.int | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/run/DC_Backflow_batt.run b/run/DC_Backflow_batt.run index 54c1389..02ab0cd 100644 --- a/run/DC_Backflow_batt.run +++ b/run/DC_Backflow_batt.run @@ -48,7 +48,9 @@ solver.maxIterations=500; solver.maxJacobians=500; cout << endl << solver.dependentNames << endl << solver.independentNames << endl; -run(); +// Constant power load 10 kW for Case 0 and 1 +run(); +BFPrintOutput(); CASE++; page.display(); // output data to out file @@ -59,12 +61,15 @@ Off design setOption("switchDes","OFFDESIGN"); autoSolverSetup(); -run(); CASE++; +run(); BFPrintOutput(); +CASE++; page.display(); CLoad.Pdemand = -10; //Backflow condition (current flowing "upstream" (load to source)) -run(); CASE++; -void BFPrintOutput(); +// Constant power load -10 kW for Case 2 +run(); +BFPrintOutput(); +CASE++; page.display(); diff --git a/src/Battery.int b/src/Battery.int index 8f0af05..d2d45f8 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -64,7 +64,8 @@ containing nodes do not know what currents are going through their ports at the an iteration. Because of this, they must be connected to power transmission components (cables and breakers), and these transmission components must be run before node-bearing transformation components like this one, as the transmission components will calculate and -populate these current values. Note that this design is intended to be analogous to a common +populate these current values. When calculate() is called, this component's voltage and current +will be known at its ports. Note that this design is intended to be analogous to a common approach taken in fluid networks within NPSS rocket models. - The battery block contains variables intended to be used in a multi-design-point (MDP) From a24d05078213de6311a2cd440f5687e9b3dc4fc6 Mon Sep 17 00:00:00 2001 From: "Thomas, George" Date: Fri, 20 Aug 2021 12:36:44 -0400 Subject: [PATCH 06/24] initial change of battery model --- src/Battery.int | 106 +++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 60 deletions(-) diff --git a/src/Battery.int b/src/Battery.int index d2d45f8..72a1192 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -117,11 +117,6 @@ this component, see MotorGeneratorMap.int"; description = "Design power factor at output of this source element."; } -// real effDes { -// value = 0.95; IOstatus = "input"; units = "none"; -// description = "Design efficiency of this source element."; -// } - real pf { value = 0; IOstatus = "output"; units = "kW"; // [kilowatts] description = "Actual (calculated) power factor at output of this source element."; @@ -205,19 +200,24 @@ this component, see MotorGeneratorMap.int"; description = "Hours spent running at the current operating point."; } - real Vreal { + real Vout { value = 0; IOstatus = "output"; units = "V"; // [volts] - description = "Real portion of battery output voltage."; + description = "Battery output voltage."; } - real Vimag { + real Vout_guess { value = 0; IOstatus = "output"; units = "V"; // [volts] - description = "Imaginary portion of output voltage."; + description = "Guess value for battery output voltage."; } real Voc { value = 3.414; IOstatus = "output"; units = "V"; // [volts] - description = "Real source voltage of equivalent battery circuit."; + description = "Open circuit battery voltage (before battery's output impedance)."; + } + + real Vdrop { + value = 3.414; IOstatus = "output"; units = "V"; // [volts] + description = "Voltage drop across battery's output impedance."; } real SpecificPower { @@ -293,6 +293,19 @@ this component, see MotorGeneratorMap.int"; // ****** ADD SOLVER INDEPENDENTS & DEPENDENTS ****** //----------------------------------------------------- + Independent ind_Vout { + varName = "Vout_guess"; + autoSetup = TRUE; + indepRef = "1000"; + description = "Varies the battery output voltage to match Vout = Voc - Vdrop."; + } + + Dependent dep_Power { + eq_lhs = "Vout"; + eq_rhs = "Vout_guess"; + autoSetup = TRUE; + } + // MDP variable Independent ind_energyDes { varName = "energyDes"; @@ -328,44 +341,28 @@ this component, see MotorGeneratorMap.int"; // ****** PERFORM ENGINEERING CALCULATIONS ****** //----------------------------------------------- - /** So this component expects you to set Vreal and Vimag. It will - * calculate (resistive only) impedance, power factor, etc. - */ void calculate() { - /** - * If we're on-design, we need to figure out the output impedance based - * on the design efficiency. Otherwise, calculate the loss and the - * efficiency based on the impedance (which is held constant). - */ + // Need to calculate Vout = Voc - Vdrop (Vdrop is drop across the output impedance) + // Output impedance and Voc are map lookup parameters + + // Get output impedance (needs to be a map lookup) + // resistor_R0 = ; + // resistor_R_Th = ; + RTotal = resistor_R0 + resistor_R_Th; - pf = cos(EP_O.S.phase); + // Get open circuit voltage + // Voc = ; - if (switchDes == "DESIGN") { - PDirection = sign(EP_O.S.r); - pfDes = pf; - // eff = effDes; - RTotal = resistor_R0 + resistor_R_Th; - if (sign(EP_O.S.r) < 0){ - cout << "BPM: Hi! You made it." << endl; - Vreal = Voc; - Voc = Vreal - (Vreal/RTotal)*sign(EP_O.S.r) * resistor_R0; - } else { - Vreal = Voc - (Voc/RTotal)*sign(EP_O.S.r) * resistor_R_Th; - } - // internal power, before flowing through this component's output impedance - real PInternal = EP_O.S.r / eff**sign(EP_O.S.r); - Loss_r = PInternal - EP_O.S.r; - Loss_j = 0; - // R = Loss_r / EP_O.I.mag**2; - R = RTotal; - L = 0; - eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); + // Calculate output voltage (which the solver will force to be equal to the guess value) + Vout = Voc - EP_O.I.r*RTotal; + if (switchDes == "DESIGN") { + // Declare design point power. powerDes = EP_O.S.r; - // Energy consumed at this operating point. + // Energy design value. energy = PInternal * segmentTime; // get design values @@ -384,29 +381,18 @@ this component, see MotorGeneratorMap.int"; actualSpecificEnergy = 1000 * energyDes/Mass; // [Wh/kg] actualSpecificPower = powerDes/Mass; // [kW/kg] - - - C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) - - } else { - PDirection = sign(EP_O.S.r); - RTotal = resistor_R0 + resistor_R_Th; - if (sign(EP_O.S.r) < 0){ - cout << "BPM: Hi! You made it." << endl; - Vreal = Voc; - Voc = Vreal - (Vreal/RTotal)*sign(EP_O.S.r) * resistor_R0; - } else { - Vreal = Voc - (Voc/RTotal)*sign(EP_O.S.r) * resistor_R_Th; - } - R = RTotal; - Loss_r = EP_O.I.mag**2 * R; - Loss_j = 0; - eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); - + } + // energy consumed at this operating point. energy = (EP_O.S.r + Loss_r) * segmentTime; } + // Output params common to both on and off design cases. + C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) + R = RTotal; + Loss_r = EP_O.I.mag**2 * R; + Loss_j = 0; + eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); real KW_PER_BTU_PER_SEC = 1.05505585; Q_heat = sqrt(Loss_r**2 + Loss_j**2); Q_heat /= KW_PER_BTU_PER_SEC; @@ -421,7 +407,7 @@ this component, see MotorGeneratorMap.int"; void prePass() { EP_O.frequency = frequency; - EP_O.setIVRMS(EP_O.I.r, EP_O.I.j, Vreal, Vimag); + EP_O.setIVRMS(EP_O.I.r, 0, Vout_guess, 0); } void trackEnergy() { From 3a87e6fd747a13243d1b573ac3172e47cdd9470c Mon Sep 17 00:00:00 2001 From: "Thomas, George" Date: Fri, 20 Aug 2021 16:52:02 -0400 Subject: [PATCH 07/24] got map infrastructure working, needs data --- include/amprius_cell.map | 113 +++++++++++++++++ model/DC_Backflow_batt.mdl | 40 +++--- run/DC_Backflow_batt.run | 19 ++- src/Battery.int | 180 +++++++++------------------ src/BatteryCellSoCTemperatureMap.int | 176 ++++++++++++++++++++++++++ 5 files changed, 373 insertions(+), 155 deletions(-) create mode 100644 include/amprius_cell.map create mode 100644 src/BatteryCellSoCTemperatureMap.int diff --git a/include/amprius_cell.map b/include/amprius_cell.map new file mode 100644 index 0000000..c33a0c2 --- /dev/null +++ b/include/amprius_cell.map @@ -0,0 +1,113 @@ +/*** + -------------------------------------------------------------------------------------------- + | | + | NASA Glenn Research Center | + | 21000 Brookpark Rd | + | Cleveland, OH 44135 | + | | + | File Name: amprius_cell.map | + | Author(s): George Thomas and Brian Malone | + | Date(s): August 2021 | + | | + -------------------------------------------------------------------------------------------- +***/ + +// --------------------------------------------------------------- +// | Amprius silicon nanowire Li-ion battery cell map +// --------------------------------------------------------------- +// | Declaration of a new Subelement instance called S_map +// | that is of the type BatteryCellSoCTemperatureMap +// --------------------------------------------------------------- + +Subelement BatteryCellSoCTemperatureMap S_map { + + // Constant parameters specific to this battery cell. + energyDes_cell = 12.75; // W-h (3.75 V nominal * 3.4 Ah tested at C/5 discharge) + + // ---------------------------------------------------------------------- + // | Declare a table (or function) named TB_Wp(real SPED, real PR) + // | To satisfy the TB_Wp socket requirement. BPM to fill in + // ---------------------------------------------------------------------- + + // Voc vs Temperature and SOC data + Table TB_Voc(real T, real SOC){ + + T = 0.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + Voc = { 3.6, 3.8, 4.0, 4.2 } + } + T = 20.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + Voc = { 3.5, 3.7, 3.9, 4.1 } + } + T = 40.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + Voc = { 3.4, 3.6, 3.8, 4.0 } + } + + T.interp = "linear" ; + T.extrap = "linear" ; + + SOC.interp = "linear" ; + SOC.extrap = "linear" ; + + extrapIsError = 0; + printExtrap = 0; + + } // end TB_Voc + + // Static output resistance vs Temperature and SOC data + Table TB_R_0(real T, real SOC){ + + T = 0.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_0 = { 0.009, 0.009, 0.009, 0.009 } + } + T = 20.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_0 = { 0.009, 0.009, 0.009, 0.009 } + } + T = 40.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_0 = { 0.009, 0.009, 0.009, 0.009 } + } + + T.interp = "linear" ; + T.extrap = "linear" ; + + SOC.interp = "linear" ; + SOC.extrap = "linear" ; + + extrapIsError = 0; + printExtrap = 0; + + } // end TB_R_0 + + // Static output resistance vs Temperature and SOC data + Table TB_R_Th(real T, real SOC){ + + T = 0.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_Th = { 0.002, 0.002, 0.002, 0.002 } + } + T = 20.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_Th = { 0.002, 0.002, 0.002, 0.002 } + } + T = 40.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_Th = { 0.002, 0.002, 0.002, 0.002 } + } + + T.interp = "linear" ; + T.extrap = "linear" ; + + SOC.interp = "linear" ; + SOC.extrap = "linear" ; + + extrapIsError = 0; + printExtrap = 0; + + } // end TB_R_Th + +} // end S_map (subelement) diff --git a/model/DC_Backflow_batt.mdl b/model/DC_Backflow_batt.mdl index 0786474..08cd9c4 100644 --- a/model/DC_Backflow_batt.mdl +++ b/model/DC_Backflow_batt.mdl @@ -31,34 +31,19 @@ cout<<"======================================="< } Element Cable Cable_Single { - R = 0.1; //Ohms + R = 0.001; //Ohms L = 0; //Henries } -// Element DC_DC_Converter DeltaDC -// { -// K = 1; //K = Vout/Vin -// SpecificPower = 10; // kW/kg -// effDes = 0.95; -// } - -// Element Cable CableRight -// { -// R = 0.1; //Ohms -// L = 0; //Henries -// } Element ConstantPowerLoad CLoad { - Pdemand = 10; //kW + Pdemand = 14./1000.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) eff = 0.95; } @@ -80,15 +65,20 @@ solverSequence = { "Cable_Single", "Li_ion_cell", "CLoad" }; void BFPrintOutput() { cout << " Case = " << CASE << endl; - cout << " Battery output voltage = " << Li_ion_cell.Vreal << endl; - cout << " Battery input voltage = " << Li_ion_cell.Voc << endl; - cout << " Battery current = " << Li_ion_cell.Voc/Li_ion_cell.RTotal << endl; - cout << " PDirection = " << Li_ion_cell.PDirection << endl; - cout << " Calculated load eff = " << CLoad.P/CLoad.EP_I.S.r << endl; - cout << " Load eff = " << CLoad.eff << endl; + cout << " Battery open circuit voltage = " << Li_ion_cell.Voc << endl; + cout << " Battery output voltage (actual value) = " << Li_ion_cell.Vout << endl; + cout << " Battery output voltage (guess value) = " << Li_ion_cell.Vout_guess << endl; + cout << " Battery output Resistance (R_0, R_Th) = " << Li_ion_cell.R_0 << ", " << Li_ion_cell.R_Th << endl; + cout << " Battery output voltage (guess value) = " << Li_ion_cell.Vout_guess << endl; + cout << " Battery current (calc) = " << (Li_ion_cell.Voc-Li_ion_cell.Vout)/Li_ion_cell.RTotal << endl; + cout << " Battery current (output port) = " << Li_ion_cell.EP_O.I.r << endl; + cout << " Cable current (output port) = " << Cable_Single.EP_O.I.r << endl; + cout << " Load input voltage = " << CLoad.EP_I.V.r << endl; + cout << " Load input power = " << CLoad.EP_I.S.r << endl; + cout << " Calculated load eff = " << (CLoad.P/CLoad.EP_I.S.r)**sign(CLoad.P) << endl; // GLT: account for negative power flow + cout << " Load eff = " << CLoad.eff << endl; } // Initial independent variable guesses are here. -// DeltaDC.Voltage = 80; CLoad.Vreal = 3; CLoad.Vimag = 0; diff --git a/run/DC_Backflow_batt.run b/run/DC_Backflow_batt.run index 02ab0cd..57eaefc 100644 --- a/run/DC_Backflow_batt.run +++ b/run/DC_Backflow_batt.run @@ -48,12 +48,11 @@ solver.maxIterations=500; solver.maxJacobians=500; cout << endl << solver.dependentNames << endl << solver.independentNames << endl; -// Constant power load 10 kW for Case 0 and 1 +// Constant power load 14 W for Case 0 and 1 run(); -BFPrintOutput(); -CASE++; - +BFPrintOutput(); page.display(); // output data to out file + /************************ Off design ************************/ @@ -61,15 +60,13 @@ Off design setOption("switchDes","OFFDESIGN"); autoSolverSetup(); -run(); +CASE++; run(); BFPrintOutput(); -CASE++; -page.display(); +page.display(); -CLoad.Pdemand = -10; //Backflow condition (current flowing "upstream" (load to source)) +CLoad.Pdemand = -14./1000.; // Charge the battery roughly at 1 C (14 W) -// Constant power load -10 kW for Case 2 -run(); +// Constant power load -14 W for Case 2 +CASE++; run(); BFPrintOutput(); -CASE++; page.display(); diff --git a/src/Battery.int b/src/Battery.int index 72a1192..997a301 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -2,18 +2,18 @@ -------------------------------------------------------------------------------------------- | | | NASA Glenn Research Center | - | 21000 Brookpark Rd | - | Cleveland, OH 44135 | + | 21000 Brookpark Rd | + | Cleveland, OH 44135 | | | - | File Name: Source.int | + | File Name: Battery.int | | Author(s): George Thomas, Jeffrey Csank, David Sadey, Tom Lavelle, Brian Malone | | Date(s): August 2021 | | | -------------------------------------------------------------------------------------------- ***/ -#ifndef __SOURCE__ -#define __SOURCE__ +#ifndef __BATTERY__ +#define __BATTERY__ #include "PSL_math.fnc" int ESO_Id_ExceededEnergyDes = (10000 * 145) + (100 * 22) + 1; @@ -112,29 +112,11 @@ this component, see MotorGeneratorMap.int"; description = "Specific energy used during on-design."; } - real pfDes { - value = 0; IOstatus = "output"; units = "kW"; // [kilowatts] - description = "Design power factor at output of this source element."; - } - - real pf { - value = 0; IOstatus = "output"; units = "kW"; // [kilowatts] - description = "Actual (calculated) power factor at output of this source element."; - } - eff { value = 0.95; IOstatus = "output"; units = "none"; description = "Actual (calculated) efficiency of this source element."; } - real R { - value = .01; IOstatus = "output"; units = "ohm"; - } - - real L { - value = .0000796; IOstatus = "output"; units = "H"; // [henrys] - } - real frequency { value = 0; IOstatus = "input"; units = "Hz"; // [hertz] description = "Output frequency"; @@ -155,19 +137,24 @@ this component, see MotorGeneratorMap.int"; description = "Power dissipation in BTU/s at current time."; } - real energyDes { - value = 0; IOstatus = "output"; units = "none"; // [kW-h] - description = "Design energy for this source."; + real T_batt { + value = 20; IOstatus = "input"; units = "C"; // [degrees C] + description = "Battery Temperature."; } - real energyConsumed { - value = 0; IOstatus = "output"; units = "none"; // [kW-h] - description = "Total energy consumed over mission, only use off-design."; + real desired_energyDes { + value = 100; IOstatus = "input"; units = "none"; // [kW-h] + description = "Desired design energy capacity for this battery."; } - real energy { - value = 0; IOstatus = "output"; units = "none"; // [kW-h] - description = "Energy consumed at the current operating point."; + real energyDes { + value = 100; IOstatus = "output"; units = "none"; // [kW-h] + description = "Actual design energy capacity for this battery."; + } + + real SOC { + value = 1; IOstatus = "output"; units = "none"; // [fraction] + description = "State of charge for this battery."; } real powerDes { @@ -175,50 +162,35 @@ this component, see MotorGeneratorMap.int"; description = "Design power for this source."; } - real PDirection { - value = 0; IOstatus = "output"; units = "none"; //- - description = "+1 for source to load power flow, -1 for load to source."; - } - - real resistor_R0 { - value = 0.6339; IOstatus = "output"; units = "none"; // [Ohm]; tR_0 in Python boring amprius_battery - description = "Design upstream battery resistance."; + real R_0 { + value = 0.01; IOstatus = "output"; units = "none"; // [Ohm]; tR_0 in Python boring amprius_battery + description = "Static battery output resistance."; } - real resistor_R_Th { - value = 0.1578; IOstatus = "output"; units = "none"; // [Ohm]; tR_Th in Python boring amprius_battery - description = "Design downstream battery resistance."; + real R_Th { + value = 0.01578; IOstatus = "output"; units = "none"; // [Ohm]; tR_Th in Python boring amprius_battery + description = "Dynamic battery output resistance."; } real RTotal { - value = 0; IOstatus = "output"; units = "none"; // [Ohm]; tR_Th in Python boring amprius_battery - description = "Design toal battery resistance."; - } - - real segmentTime { - value = 0.25; IOstatus = "output"; units = "hr"; // [h] - description = "Hours spent running at the current operating point."; + value = 0; IOstatus = "output"; units = "none"; // [Ohm] + description = "Total battery resistance."; } real Vout { - value = 0; IOstatus = "output"; units = "V"; // [volts] + value = 3.6; IOstatus = "output"; units = "V"; // [volts] description = "Battery output voltage."; } real Vout_guess { - value = 0; IOstatus = "output"; units = "V"; // [volts] + value = 3.6; IOstatus = "output"; units = "V"; // [volts] description = "Guess value for battery output voltage."; } real Voc { - value = 3.414; IOstatus = "output"; units = "V"; // [volts] + value = 3.7; IOstatus = "output"; units = "V"; // [volts] description = "Open circuit battery voltage (before battery's output impedance)."; } - - real Vdrop { - value = 3.414; IOstatus = "output"; units = "V"; // [volts] - description = "Voltage drop across battery's output impedance."; - } real SpecificPower { value = 13; IOstatus = "input"; units = "none"; // [kW/kg] @@ -230,9 +202,14 @@ this component, see MotorGeneratorMap.int"; description = "Energy to weight ratio for the source."; } + real C_rate_des { + value = 1; IOstatus = "input"; units = "none"; // [-] + description = "C-rate at design point (discharge rate normalized to capacity)."; + } + real C_rate { - value = 130; IOstatus = "input"; units = "none"; // [-] - description = "Computed on-design C-rate for the source."; + value = 1; IOstatus = "input"; units = "none"; // [-] + description = "C-rate at current operating point (discharge rate normalized to capacity)."; } Mass { @@ -257,19 +234,6 @@ this component, see MotorGeneratorMap.int"; rewritableValues = FALSE; // enables converter optimization trigger = TRUE; } - - Option switchTrackEnergy { - allowedValues = { "FALSE", "TRUE" } - description = "Determines if we should track energy or not when running off-design."; - rewritableValues = FALSE; // enables converter optimization - } - - Option multiDes { - allowedValues = { "FALSE", "TRUE" } - description = "Determines if component is undergoing multi-design point simulation."; - rewritableValues = FALSE; - trigger = TRUE; - } //---------------------------------------------------------- // ****** SETUP PORTS, FLOW STATIONS, SOCKETS, TABLES ****** @@ -279,10 +243,18 @@ this component, see MotorGeneratorMap.int"; ElectricOutputPort EP_O { description = "Electric output port."; + ElectricPowerType.allowedValues = { "DC" }; + setOption("ElectricPowerType", "DC"); // only DC output allowed as this is a battery pack } /* SOCKETS */ + Socket S_map { + allowedValues = { "T_batt", "SOC", "Vout_guess", "desired_energyDes" } + description = "Socket for battery cell data map and logic to size pack from cells."; + socketType = "BatteryCellSoCTemperatureMap"; + } + Socket S_eThermMass { allowedValues = { "Q_heat", "Mass" } description = "Thermal mass socket."; @@ -300,23 +272,11 @@ this component, see MotorGeneratorMap.int"; description = "Varies the battery output voltage to match Vout = Voc - Vdrop."; } - Dependent dep_Power { + Dependent dep_Vout { eq_lhs = "Vout"; eq_rhs = "Vout_guess"; autoSetup = TRUE; } - - // MDP variable - Independent ind_energyDes { - varName = "energyDes"; - description = "Varies design energy to match calculated energy at design condition."; - } - - // MDP variable - Dependent dep_energyDes { - eq_lhs = "energyDes"; - eq_rhs = "energy"; - } //------------------------------------------- // ****** VARIABLE CHANGED METHODOLOGY ****** @@ -343,33 +303,27 @@ this component, see MotorGeneratorMap.int"; void calculate() { - // Need to calculate Vout = Voc - Vdrop (Vdrop is drop across the output impedance) - // Output impedance and Voc are map lookup parameters - - // Get output impedance (needs to be a map lookup) - // resistor_R0 = ; - // resistor_R_Th = ; - RTotal = resistor_R0 + resistor_R_Th; - - // Get open circuit voltage - // Voc = ; + // Run the battery map if it is present + if(!S_map.isEmpty()) { + S_map.execute(); + } + else { + // Map logic will calculate number of parallel/series cells and also calculates energy design capacity. + // However if we have no map (no pack building logic), just say our capacity is equal to the desired value. + if (switchDes == "DESIGN") { + energyDes = desired_energyDes; + } + } // Calculate output voltage (which the solver will force to be equal to the guess value) + RTotal = R_0 + R_Th; Vout = Voc - EP_O.I.r*RTotal; if (switchDes == "DESIGN") { - // Declare design point power. + // Declare design point power. Energy is calculated in the map logic. powerDes = EP_O.S.r; - // Energy design value. - energy = PInternal * segmentTime; - - // get design values - if (multiDes != "TRUE") { - energyDes = energy; - } - real energyBasedMass = (energyDes*1000) / SpecificEnergy; // (kW-h/1000) / (W-h/kg) = kg real powerBasedMass = EP_O.S.r / SpecificPower; @@ -382,15 +336,12 @@ this component, see MotorGeneratorMap.int"; actualSpecificEnergy = 1000 * energyDes/Mass; // [Wh/kg] actualSpecificPower = powerDes/Mass; // [kW/kg] } - - // energy consumed at this operating point. - energy = (EP_O.S.r + Loss_r) * segmentTime; + else { } // Output params common to both on and off design cases. C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) - R = RTotal; - Loss_r = EP_O.I.mag**2 * R; + Loss_r = EP_O.I.mag**2 * RTotal; Loss_j = 0; eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); real KW_PER_BTU_PER_SEC = 1.05505585; @@ -409,14 +360,5 @@ this component, see MotorGeneratorMap.int"; EP_O.frequency = frequency; EP_O.setIVRMS(EP_O.I.r, 0, Vout_guess, 0); } - - void trackEnergy() { - Source.energyConsumed += Source.energy; - if (Source.energyConsumed > Source.energyDes) { - ESOreport(ESO_Id_ExceededEnergyDes, - "Source component's energy consumed (" + toStr(Source.energyConsumed) + - ") exceeded design energy (" + toStr(Source.energyDes)+").", 1); - } - } } #endif diff --git a/src/BatteryCellSoCTemperatureMap.int b/src/BatteryCellSoCTemperatureMap.int new file mode 100644 index 0000000..8f4cbd1 --- /dev/null +++ b/src/BatteryCellSoCTemperatureMap.int @@ -0,0 +1,176 @@ +/*** + -------------------------------------------------------------------------------------------- + | | + | NASA Glenn Research Center | + | 21000 Brookpark Rd | + | Cleveland, OH 44135 | + | | + | File Name: BatteryCellSoCTemperatureMap.int | + | Author(s): George Thomas and Brian Malone | + | Date(s): August 2021 | + | | + -------------------------------------------------------------------------------------------- +***/ + +#ifndef __BATTERY_CELL_SOC_TEMPERATURE_MAP__ +#define __BATTERY_CELL_SOC_TEMPERATURE_MAP__ + +#include + +// Variables that exist in the parent element +// and are used in this subelement. AKA input params. +extern real SOC; +extern real T_batt; +// Used for pack sizing +extern real Vout_guess; +extern real desired_energyDes; + +// Variables that exist in the parent element +// and are set by this subelement. AKA output params. +extern real Voc; +extern real R_0; +extern real R_Th; +// Output to tell user what the ACTUAL capacity is. +extern real energyDes; + +class BatteryCellSoCTemperatureMap extends Subelement { + +//------------------------------------------------------------ +// ******* DOCUMENTATION ******* +//------------------------------------------------------------ + + title = ""; + + description = isA() + " manages the calculation of battery performance + map variables. The battery parameters output from these maps are open- + circuit voltage and internal resistance parameters. Inputs to these + maps are state of charge (SOC) and battery temperature"; + + + usageNotes = isA() + +" + +- Revisit, we may need usage notes... For now, see description. +"; + + background = ""; + +//------------------------------------------------------------ +// ******* SETUP VARIABLES ******** +//------------------------------------------------------------ + + real Voc_cell { + value = 0; IOstatus = OUTPUT; units = NONE; + description = "Open circuit voltage for one cell."; + } + real R_0_cell { + value = 0; IOstatus = OUTPUT; units = NONE; + description = "Static output resistance for one cell."; + } + real R_Th_cell { + value = 0; IOstatus = OUTPUT; units = NONE; + description = "Dynamic output resistance for one cell."; + } + real energyDes_cell { + value = 10; IOstatus = OUTPUT; units = NONE; // W-h + description = "Energy design capacity for one cell."; + } + + real num_series { + value = 1; IOstatus = OUTPUT; units = NONE; + description = "Number of series cells in a string"; + } + real num_parallel { + value = 1; IOstatus = OUTPUT; units = NONE; + description = "Number of parallel sets of series cell strings."; + } +//------------------------------------------------------------ +// ******* OPTION VARIABLE SETUP ******* +//------------------------------------------------------------ + + Option switchDes { + allowedValues = { DESIGN, OFFDESIGN }; + description = "Determines if the subelement is in design or off-design mode"; + rewritableValues = FALSE; // Enables converter optimization. + trigger = FALSE; + } + + +//------------------------------------------------------------ +// ****** SETUP PORTS, FLOW STATIONS, SOCKETS, TABLES ******** +//------------------------------------------------------------ + + Socket TB_Voc { + description = "Voc versus Temperature and SOC. A function or table with the name TB_Voc must be declared at the subelement scope in order to fill this socket. The format is TB_Voc (real T, real SOC)."; + socketType = "Function"; + required = TRUE; + argTypes = { "real", "real" } + returnType = "real"; + } + + Socket TB_R_0 { + description = "R_0 versus Temperature and SOC. A function or table with the name TB_R_0 must be declared at the subelement scope in order to fill this socket. The format is TB_R_0 (real T, real SOC)."; + socketType = "Function"; + required = TRUE; + argTypes = { "real", "real" } + returnType = "real"; + } + + Socket TB_R_Th { + description = "R_Th versus Temperature and SOC. A function or table with the name TB_R_Th must be declared at the subelement scope in order to fill this socket. The format is TB_R_Th (real T, real SOC)."; + socketType = "Function"; + required = TRUE; + argTypes = { "real", "real" } + returnType = "real"; + } + +// TABLES + +//------------------------------------------------------------ +// ******* INTERNAL SOLVER SETUP ******* +//------------------------------------------------------------ + +//------------------------------------------------------------ +// ****** ADD SOLVER INDEPENDENTS & DEPENDENTS ****** +//------------------------------------------------------------ + +//------------------------------------------------------------ +// ******* VARIABLE CHANGED METHODOLOGY ******* +//------------------------------------------------------------ + +//------------------------------------------------------------ +// ******* PERFORM ENGINEERING CALCULATIONS ******* +//------------------------------------------------------------ + + void calculate() { + + //------------------------------------------------------------------- + // execute the maps: get cell open circuit voltage and resistances + //------------------------------------------------------------------- + Voc_cell = TB_Voc(T_batt, SOC); + R_0_cell = TB_R_0(T_batt, SOC); + R_Th_cell = TB_R_Th(T_batt, SOC); + + if ( switchDes == DESIGN ) { + //---------------------------------------------------------------------- + // On design, we need to size the pack. That is, figure out number of + // series and parallel cells in the pack. BPM to write this logic. + //---------------------------------------------------------------------- + num_parallel = 1; + num_series = 1; + } // end (switchDes == DESIGN) + + //---------------------------------------------------------------------- + // Now that we've sized the pack and we have cell level Voc/R_0/R_Th, + // let's calculate the pack level quantities. BPM to revisit. + //---------------------------------------------------------------------- + Voc = Voc_cell*num_series; + R_0 = R_0_cell*num_series / num_parallel; + R_Th = R_Th_cell*num_series / num_parallel; + energyDes = energyDes_cell * num_parallel; + + } // end calculate() function + +} // end subelement class + +#endif From 8039074ba4a406f2113768ccd296be4f18c6a747 Mon Sep 17 00:00:00 2001 From: "Thomas, George" Date: Fri, 20 Aug 2021 17:29:31 -0400 Subject: [PATCH 08/24] add series/parallel pack sizing logic --- model/DC_Backflow_batt.mdl | 2 ++ src/Battery.int | 22 ++++++++++------------ src/BatteryCellSoCTemperatureMap.int | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/model/DC_Backflow_batt.mdl b/model/DC_Backflow_batt.mdl index 08cd9c4..24e2fdd 100644 --- a/model/DC_Backflow_batt.mdl +++ b/model/DC_Backflow_batt.mdl @@ -72,6 +72,8 @@ void BFPrintOutput() cout << " Battery output voltage (guess value) = " << Li_ion_cell.Vout_guess << endl; cout << " Battery current (calc) = " << (Li_ion_cell.Voc-Li_ion_cell.Vout)/Li_ion_cell.RTotal << endl; cout << " Battery current (output port) = " << Li_ion_cell.EP_O.I.r << endl; + cout << " Number of series cells in battery = " << Li_ion_cell.S_map.num_series << endl; + cout << " Number of parallel cells in battery = " << Li_ion_cell.S_map.num_parallel << endl; cout << " Cable current (output port) = " << Cable_Single.EP_O.I.r << endl; cout << " Load input voltage = " << CLoad.EP_I.V.r << endl; cout << " Load input power = " << CLoad.EP_I.S.r << endl; diff --git a/src/Battery.int b/src/Battery.int index 997a301..d26657e 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -143,12 +143,12 @@ this component, see MotorGeneratorMap.int"; } real desired_energyDes { - value = 100; IOstatus = "input"; units = "none"; // [kW-h] + value = 10; IOstatus = "input"; units = "none"; // [kW-h] description = "Desired design energy capacity for this battery."; } real energyDes { - value = 100; IOstatus = "output"; units = "none"; // [kW-h] + value = 0; IOstatus = "output"; units = "none"; // [kW-h] description = "Actual design energy capacity for this battery."; } @@ -177,14 +177,19 @@ this component, see MotorGeneratorMap.int"; description = "Total battery resistance."; } + real Vout_des { + value = 4.2; IOstatus = "output"; units = "V"; // [volts] + description = "Design value for battery output voltage."; + } + real Vout { value = 3.6; IOstatus = "output"; units = "V"; // [volts] - description = "Battery output voltage."; + description = "Battery output voltage at current operating point."; } real Vout_guess { value = 3.6; IOstatus = "output"; units = "V"; // [volts] - description = "Guess value for battery output voltage."; + description = "Guess value for battery output voltage at current operating point."; } real Voc { @@ -250,7 +255,7 @@ this component, see MotorGeneratorMap.int"; /* SOCKETS */ Socket S_map { - allowedValues = { "T_batt", "SOC", "Vout_guess", "desired_energyDes" } + allowedValues = { "T_batt", "SOC", "Vout_des", "desired_energyDes" } description = "Socket for battery cell data map and logic to size pack from cells."; socketType = "BatteryCellSoCTemperatureMap"; } @@ -288,13 +293,6 @@ this component, see MotorGeneratorMap.int"; create("", "ThermalInputPort", "Q_I"); } } - - if (name == "multiDes") { - if (switchDes == DESIGN) { - ind_energyDes.autoSetup = TRUE; - dep_energyDes.autoSetup = TRUE; - } - } } //----------------------------------------------- diff --git a/src/BatteryCellSoCTemperatureMap.int b/src/BatteryCellSoCTemperatureMap.int index 8f4cbd1..0951053 100644 --- a/src/BatteryCellSoCTemperatureMap.int +++ b/src/BatteryCellSoCTemperatureMap.int @@ -6,7 +6,7 @@ | Cleveland, OH 44135 | | | | File Name: BatteryCellSoCTemperatureMap.int | - | Author(s): George Thomas and Brian Malone | + | Author(s): George Thomas | | Date(s): August 2021 | | | -------------------------------------------------------------------------------------------- @@ -22,7 +22,7 @@ extern real SOC; extern real T_batt; // Used for pack sizing -extern real Vout_guess; +extern real Vout_des; extern real desired_energyDes; // Variables that exist in the parent element @@ -154,15 +154,15 @@ class BatteryCellSoCTemperatureMap extends Subelement { if ( switchDes == DESIGN ) { //---------------------------------------------------------------------- // On design, we need to size the pack. That is, figure out number of - // series and parallel cells in the pack. BPM to write this logic. + // series and parallel cells in the pack. //---------------------------------------------------------------------- - num_parallel = 1; - num_series = 1; + num_parallel = ceil(desired_energyDes / energyDes_cell); + num_series = ceil(Vout_des/Voc_cell); } // end (switchDes == DESIGN) //---------------------------------------------------------------------- // Now that we've sized the pack and we have cell level Voc/R_0/R_Th, - // let's calculate the pack level quantities. BPM to revisit. + // let's calculate the pack level quantities. //---------------------------------------------------------------------- Voc = Voc_cell*num_series; R_0 = R_0_cell*num_series / num_parallel; From 00d19841d8ed6b04de4c3587367929717d5f7809 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Mon, 23 Aug 2021 17:07:52 -0400 Subject: [PATCH 09/24] Added amprius maps --- include/18650_cell.map | 171 +++++++++++++++++++++++++++++++++++++ include/amprius_cell.map | 169 ++++++++++++++++++++++++++++++------ model/DC_Backflow_batt.mdl | 2 + 3 files changed, 318 insertions(+), 24 deletions(-) create mode 100644 include/18650_cell.map diff --git a/include/18650_cell.map b/include/18650_cell.map new file mode 100644 index 0000000..2ef59e3 --- /dev/null +++ b/include/18650_cell.map @@ -0,0 +1,171 @@ +/*** + -------------------------------------------------------------------------------------------- + | | + | NASA Glenn Research Center | + | 21000 Brookpark Rd | + | Cleveland, OH 44135 | + | | + | File Name: amprius_cell.map | + | Author(s): George Thomas and Brian Malone | + | Date(s): August 2021 | + | | + -------------------------------------------------------------------------------------------- +***/ + +// --------------------------------------------------------------- +// | Samsung silicon nanowire Li-ion battery cell map +// --------------------------------------------------------------- +// | Declaration of a new Subelement instance called S_map +// | that is of the type BatteryCellSoCTemperatureMap +// --------------------------------------------------------------- + +Subelement BatteryCellSoCTemperatureMap S_map { + + // Constant parameters specific to this battery cell. + energyDes_cell = 10.8; // W-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) + + // ---------------------------------------------------------------------- + // | Declare a table (or function) named TB_Wp(real SPED, real PR) + // | To satisfy the TB_Wp socket requirement. + // ---------------------------------------------------------------------- + + // Voc vs Temperature and SOC data + Table TB_Voc(real T, real SOC){ + + T = 0.0 { + SOC = {-0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2} + Voc = { 2.92334783, 2.92334783,3.00653623,3.08972464,3.17291304,3.23989855,3.31010145, + 3.3803913 ,3.44033333,3.49033333,3.52169565,3.54391304,3.58695652, + 3.62095652,3.65437681,3.68604348,3.72430435,3.75531884,3.79102899, + 3.82030435,3.84181159,3.86124638,3.88921739,3.91686957,3.96223188, + 4.00169565,4.04117391,4.06849275,4.07573913,4.08571014,4.10571014, + 4.161,4.161} + } + T = 20.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + Voc = { 2.99293893,2.99293893,3.05400763,3.11507634,3.17614504,3.23506616,3.30371247, + 3.37521374,3.43605852,3.48697455,3.5200229 ,3.54251908,3.58374046, + 3.6329313 ,3.67379644,3.70287532,3.73784733,3.76526463,3.79174809, + 3.81922901,3.84108142,3.87212214,3.90738931,3.93615267,3.98113995, + 4.02093893,4.04504071,4.07114758,4.07583969,4.08371501,4.10560814, + 4.161,4.161 } + } + T = 30.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + Voc = { 2.84084639,2.84084639,2.98428484,3.1050295 ,3.19464496,3.25566531,3.309059 , + 3.37185148,3.43473652,3.49059613,3.51955239,3.541353 ,3.58558494, + 3.62641607,3.6708881 ,3.70814547,3.7392177 ,3.76822075,3.79592981, + 3.82260427,3.84986368,3.88146592,3.91739674,3.94798779,3.98188403, + 4.02274568,4.05623296,4.06830824,4.07468871,4.08175788,4.10853306, + 4.153,4.153} + } + T = 45.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + Voc = { 2.81925101,2.81925101,2.97410931,3.09861134,3.18674899,3.24142105,3.29678138, + 3.35963563,3.42195951,3.47637247,3.51383806,3.54319838,3.59076923, + 3.61940891,3.65574089,3.7067004 ,3.74153441,3.77023887,3.79773684, + 3.82421053,3.85139271,3.88311336,3.91906478,3.94918219,3.98310931, + 4.02401215,4.05611741,4.07036842,4.07774494,4.08190283,4.10867206, + 4.153,4.153} + } + T = 60.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + Voc = { 2.79852227,2.79852227,2.95540486,3.07335223,3.17051822,3.228 ,3.29222672, + 3.34192308,3.39768016,3.46263158,3.49862348,3.53679757,3.59007692, + 3.61315789,3.65250202,3.70067206,3.74025911,3.77023887,3.79773684, + 3.82335628,3.84432794,3.87774899,3.91851822,3.94918219,3.98310931, + 4.02401215,4.05611741,4.06846559,4.07574494,4.08185425,4.10867206, + 4.151,4.151} + } + + T.interp = "linear" ; + T.extrap = "linear" ; + + SOC.interp = "linear" ; + SOC.extrap = "linear" ; + + extrapIsError = 0; + printExtrap = 0; + + } // end TB_Voc + + // Static output resistance vs Temperature and SOC data + Table TB_R_0(real T, real SOC){ + + T = 0.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_0 = { 0.009, 0.009, 0.009, 0.009 } + } + T = 20.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_0 = { 0.009, 0.009, 0.009, 0.009 } + } + T = 40.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_0 = { 0.009, 0.009, 0.009, 0.009 } + } + + T.interp = "linear" ; + T.extrap = "linear" ; + + SOC.interp = "linear" ; + SOC.extrap = "linear" ; + + extrapIsError = 0; + printExtrap = 0; + + } // end TB_R_0 + + // Static output resistance vs Temperature and SOC data + Table TB_R_Th(real T, real SOC){ + + T = 0.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_Th = { 0.002, 0.002, 0.002, 0.002 } + } + T = 20.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_Th = { 0.002, 0.002, 0.002, 0.002 } + } + T = 40.0 { + SOC = { 0.2, 0.4, 0.6, 0.8 } + R_Th = { 0.002, 0.002, 0.002, 0.002 } + } + + T.interp = "linear" ; + T.extrap = "linear" ; + + SOC.interp = "linear" ; + SOC.extrap = "linear" ; + + extrapIsError = 0; + printExtrap = 0; + + } // end TB_R_Th + +} // end S_map (subelement) diff --git a/include/amprius_cell.map b/include/amprius_cell.map index c33a0c2..35a5b03 100644 --- a/include/amprius_cell.map +++ b/include/amprius_cell.map @@ -26,24 +26,65 @@ Subelement BatteryCellSoCTemperatureMap S_map { // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) - // | To satisfy the TB_Wp socket requirement. BPM to fill in + // | To satisfy the TB_Wp socket requirement. // ---------------------------------------------------------------------- // Voc vs Temperature and SOC data Table TB_Voc(real T, real SOC){ T = 0.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - Voc = { 3.6, 3.8, 4.0, 4.2 } + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + Voc = { 3.414,3.414,3.414,3.414,3.42417391,3.44047826, + 3.4546087 ,3.46708696,3.47447826,3.483,3.49295652,3.50752174, + 3.53343478,3.55504348,3.58156522,3.60704348,3.63543478,3.66826087, + 3.70147826,3.73321739,3.76282609,3.81343478,3.87182609,3.91269565, + 3.95313043,3.99395652,4.04556522,4.09230435,4.13904348,4.18726087, + 4.23534783,4.28408696,4.371} } T = 20.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - Voc = { 3.5, 3.7, 3.9, 4.1 } + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + Voc = { 3.36403181,3.37059332,3.37715483,3.38915138,3.41307423,3.43057158, + 3.4458017 ,3.45892471,3.47053977,3.4882561 ,3.50323489,3.51852094, + 3.53543796,3.55665986,3.57962513,3.6050448 ,3.63557688,3.66967577, + 3.70645387,3.74363574,3.78432556,3.83267577,3.88069459,3.92662513, + 3.972807 ,4.02052094,4.06885525,4.11641145,4.16327784,4.20705064, + 4.24888759,4.29225663,4.36} } - T = 40.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - Voc = { 3.4, 3.6, 3.8, 4.0 } + + T = 45.0 { + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + Voc = { 3.35947541,3.36927305,3.37804713,3.39274539,3.41529508,3.43271311, + 3.44734836,3.46041189,3.47172951,3.4903084 ,3.50470287,3.52008248, + 3.53732172,3.55863781,3.58149898,3.60732018,3.63787705,3.67212961, + 3.70881352,3.74582684,3.78658607,3.83510451,3.88277664,3.92849898, + 3.9745123 ,4.02208248,4.07013422,4.11750205,4.16411066,4.20763064, + 4.24926434,4.29245492,4.36 } } + T = 60.0 { + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + Voc = { 3.35947541,3.36927305,3.37804713,3.39274539,3.41529508,3.43271311, + 3.44734836,3.46041189,3.47172951,3.4903084 ,3.50470287,3.52008248, + 3.53732172,3.55863781,3.58149898,3.60732018,3.63787705,3.67212961, + 3.70881352,3.74582684,3.78658607,3.83510451,3.88277664,3.92849898, + 3.9745123 ,4.02208248,4.07013422,4.11750205,4.16411066,4.20763064, + 4.24926434,4.29245492,4.36} + } T.interp = "linear" ; T.extrap = "linear" ; @@ -58,19 +99,59 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Static output resistance vs Temperature and SOC data Table TB_R_0(real T, real SOC){ - + T = 0.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_0 = { 0.009, 0.009, 0.009, 0.009 } + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_0 = { 0.63391304,0.50347826,0.37304348,0.2426087 ,0.16869565,0.13717391, + 0.12130435,0.10347826,0.10913043,0.1,0.09913043,0.09, + 0.09,0.09,0.09,0.09,0.09,0.09, + 0.09,0.09,0.09,0.08,0.08,0.08, + 0.08,0.08,0.08,0.08,0.08,0.08, + 0.08,0.08 ,0.1} } T = 20.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_0 = { 0.009, 0.009, 0.009, 0.009 } - } - T = 40.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_0 = { 0.009, 0.009, 0.009, 0.009 } + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_0 = { 0.55925769,0.40615589,0.25305408,0.12426697,0.08120361,0.06790164, + 0.06,0.06,0.06,0.06,0.06,0.05982635, + 0.05435843,0.05,0.05,0.05,0.05,0.05, + 0.05,0.05,0.05,0.05,0.05,0.05, + 0.05,0.05,0.05,0.05,0.05,0.05, + 0.05,0.05,0.05} } + T = 45.0 { + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_0 = { 0.4154918 ,0.21953893,0.07817623,0.06070184,0.05240779,0.04696465, + 0.04,0.045,0.04063525,0.04,0.04,0.04, + 0.0388627,0.035,0.035,0.035,0.035,0.035, + 0.035,0.03076076,0.03,0.03,0.03,0.03, + 0.03,0.03,0.03,0.03,0.03,0.03, + 0.03,0.03,0.03} + } + T = 60.0 { + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_0 = { 0.4154918 ,0.21953893,0.07817623,0.06070184,0.05240779,0.04696465, + 0.045,0.045,0.04063525,0.04,0.04,0.04, + 0.0388627 ,0.035,0.035,0.035,0.035,0.035, + 0.035,0.03076076,0.03,0.03,0.03,0.03, + 0.03,0.03,0.03,0.03,0.03,0.03, + 0.03,0.03,0.03 } + } T.interp = "linear" ; T.extrap = "linear" ; @@ -87,17 +168,57 @@ Subelement BatteryCellSoCTemperatureMap S_map { Table TB_R_Th(real T, real SOC){ T = 0.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_Th = { 0.002, 0.002, 0.002, 0.002 } + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_Th = { 0.15782609,0.14695652,0.13608696,0.12521739,0.10869565,0.1 , + 0.0926087 ,0.08173913,0.08 ,0.08 ,0.08 ,0.08 , + 0.08 ,0.08 ,0.08 ,0.08 ,0.08 ,0.08 , + 0.08 ,0.08 ,0.08 ,0.08 ,0.08 ,0.08 , + 0.08 ,0.07804348,0.075 ,0.06652174,0.06 ,0.06 , + 0.06 ,0.06 ,0.06 } } T = 20.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_Th = { 0.002, 0.002, 0.002, 0.002 } + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_Th = { 0.14989396,0.12802227,0.10615058,0.08713945,0.08 ,0.08 , + 0.06299576,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 } } - T = 40.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_Th = { 0.002, 0.002, 0.002, 0.002 } + T = 45.0 { + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_Th = { 0.11672131,0.09494877,0.08 ,0.08 ,0.08 ,0.08 , + 0.0591291 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.04265881, + 0.04 ,0.03088627,0.03 } } + T = 60.0 { + SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, + 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, + 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, + 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, + 1.} + R_Th = { 0.11672131,0.09494877,0.08 ,0.08 ,0.08 ,0.08 , + 0.0591291 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , + 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.04265881, + 0.04 ,0.03088627,0.03 } + } T.interp = "linear" ; T.extrap = "linear" ; diff --git a/model/DC_Backflow_batt.mdl b/model/DC_Backflow_batt.mdl index 24e2fdd..f64bcca 100644 --- a/model/DC_Backflow_batt.mdl +++ b/model/DC_Backflow_batt.mdl @@ -32,6 +32,8 @@ Electric Power System Components **************************/ Element Battery Li_ion_cell { //Amprius battery ELD214 #include + + } Element Cable Cable_Single From a0a8f36f280a933f60707c73b383d717f5f56058 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Tue, 24 Aug 2021 08:05:21 -0400 Subject: [PATCH 10/24] Changed battery file names and added full battery arrays --- include/18650_cell.map | 148 ++++++++++++++++-- ...{DC_Backflow_batt.mdl => battery_test.mdl} | 4 +- ...{DC_Backflow_batt.run => battery_test.run} | 4 +- 3 files changed, 137 insertions(+), 19 deletions(-) rename model/{DC_Backflow_batt.mdl => battery_test.mdl} (96%) rename run/{DC_Backflow_batt.run => battery_test.run} (97%) diff --git a/include/18650_cell.map b/include/18650_cell.map index 2ef59e3..cdbf7b7 100644 --- a/include/18650_cell.map +++ b/include/18650_cell.map @@ -118,17 +118,77 @@ Subelement BatteryCellSoCTemperatureMap S_map { Table TB_R_0(real T, real SOC){ T = 0.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_0 = { 0.009, 0.009, 0.009, 0.009 } + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_0 = { 0.2473913 ,0.2473913 ,0.20681159,0.16623188,0.12565217,0.09753623,0.08362319, + 0.08 ,0.07666667,0.0715942 ,0.07 ,0.0415942 ,0.05681159, + 0.067 ,0.067 ,0.067 ,0.067 ,0.067 ,0.06537681, + 0.065 ,0.065 ,0.065 ,0.065 ,0.065 ,0.065 , + 0.065 ,0.065 ,0.065 ,0.065 ,0.065 ,0.065 , + 0.065 ,0.06 } } T = 20.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_0 = { 0.009, 0.009, 0.009, 0.009 } - } - T = 40.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_0 = { 0.009, 0.009, 0.009, 0.009 } + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_0 = { 0.08801527,0.08801527,0.07274809,0.05748092,0.04221374,0.03231552,0.02722646, + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.025 ,0.025 } + } + T = 30.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_0 = { 0.0677823 ,0.0677823 ,0.05252289,0.03726348,0.02733469,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.01311292,0.01809766,0.02 ,0.02 ,0.02430824,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.03 ,0.03 } } + + T = 45.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_0 = { 0.06546559,0.06546559,0.0502834 ,0.03510121,0.02663968,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.01218623,0.01 ,0.01 ,0.01890688,0.02451417,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.03 ,0.03 } + } + + T = 60.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_0 = { 0.06546559,0.06546559,0.0502834 ,0.03510121,0.02663968,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.02072874,0.02 ,0.02 ,0.02 ,0.02451417,0.025 , + 0.025 ,0.025 ,0.025 ,0.025 ,0.025 ,0.025 , + 0.03 ,0.03 } + } T.interp = "linear" ; T.extrap = "linear" ; @@ -145,17 +205,75 @@ Subelement BatteryCellSoCTemperatureMap S_map { Table TB_R_Th(real T, real SOC){ T = 0.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_Th = { 0.002, 0.002, 0.002, 0.002 } + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_Th = { 0.09 ,0.09 ,0.09 ,0.09 ,0.09 ,0.07130435,0.06 , + 0.06 ,0.06 ,0.06 ,0.06 ,0.06 ,0.06 , + 0.08217391,0.07492754,0.07 ,0.07 ,0.07 ,0.07 , + 0.07 ,0.05318841,0.04144928,0.0573913 ,0.06884058,0.07 , + 0.07456522,0.075 ,0.075 ,0.05586957,0.055 ,0.04021739, + 0.04 ,0.04 } } T = 20.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_Th = { 0.002, 0.002, 0.002, 0.002 } + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_Th = { 0.08534351,0.08534351,0.07516539,0.06498728,0.05480916,0.04838931,0.04589059, + 0.045 ,0.045 ,0.04195929,0.03937405,0.03642494,0.035 , + 0.035 ,0.03848601,0.05430025,0.04534351,0.03624682,0.03115776, + 0.03 ,0.03 ,0.03 ,0.03839695,0.04 ,0.04 , + 0.04 ,0.03089059,0.03 ,0.03 ,0.02807125,0.02505344, + 0.02 ,0.02 } } - T = 40.0 { - SOC = { 0.2, 0.4, 0.6, 0.8 } - R_Th = { 0.002, 0.002, 0.002, 0.002 } + T = 30.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_Th = { 0.0677823 ,0.0677823 ,0.05252289,0.045 ,0.045 ,0.045 ,0.045 , + 0.04207528,0.04 ,0.03690234,0.035 ,0.0317294 ,0.02798576, + 0.027 ,0.025588 ,0.025 ,0.02129705,0.02 ,0.02 , + 0.04377416,0.04190234,0.04 ,0.04 ,0.04 ,0.03121058, + 0.02820753,0.028 ,0.02055341,0.02 ,0.02 ,0.02 , + 0.001 ,0.001} } + T = 45.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_Th = { 0.06728745,0.06728745,0.04704453,0.04 ,0.04 ,0.04 ,0.04 , + 0.04 ,0.04 ,0.03267206,0.03 ,0.03 ,0.03 , + 0.03 ,0.02603239,0.025 ,0.02091093,0.02 ,0.02 , + 0.04562753,0.04133603,0.04 ,0.04 ,0.04 ,0.0308502 , + 0.02814575,0.028 ,0.02038866,0.02 ,0.02 ,0.02 , + 0.001 ,0.001 } + } + T = 60.0 { + SOC = { -0.2, 0., 0.03333333, 0.06666667, 0.1, 0.13333333, 0.16666667, + 0.2, 0.23333333, 0.26666667, 0.3, 0.33333333, 0.36666667, + 0.4, 0.43333333, 0.46666667, 0.5, 0.53333333, 0.56666667, + 0.6, 0.63333333, 0.66666667, 0.7, 0.73333333, 0.76666667, + 0.8, 0.83333333, 0.86666667, 0.9, 0.93333333, 0.96666667, + 1., 1.2 } + R_Th = { 0.06728745,0.06728745,0.04704453,0.04 ,0.04 ,0.04 ,0.04 , + 0.04 ,0.04 ,0.03267206,0.03 ,0.03 ,0.03 , + 0.03 ,0.02603239,0.025 ,0.02091093,0.02 ,0.02 , + 0.02 ,0.02433198,0.03378543,0.035 ,0.035 ,0.0304251 , + 0.02536437,0.025 ,0.02024291,0.02 ,0.02 ,0.02 , + 0.001 ,0.001 } + } T.interp = "linear" ; T.extrap = "linear" ; diff --git a/model/DC_Backflow_batt.mdl b/model/battery_test.mdl similarity index 96% rename from model/DC_Backflow_batt.mdl rename to model/battery_test.mdl index f64bcca..ac02a5e 100644 --- a/model/DC_Backflow_batt.mdl +++ b/model/battery_test.mdl @@ -9,14 +9,14 @@ | Author(s): George Thomas, Brian Malone | | Date(s): October 2020 | | | - | Description: DC model with backflow | + | Description: Battery test model with backflow | | | | | ------------------------------------------------------------------------------- ***/ cout<<"======================================="< Date: Fri, 27 Aug 2021 09:25:13 -0400 Subject: [PATCH 11/24] add temperature state, SOC state to battery, and transient test --- include/18650_cell.map | 14 ++--- include/amprius_cell.map | 14 ++--- model/battery_test.mdl | 54 +++++++++++----- run/battery_test.run | 92 +++++++++++++++++++++++++++- src/Battery.int | 48 ++++++++++++++- src/BatteryCellSoCTemperatureMap.int | 11 ++-- src/EThermalMass.int | 2 +- 7 files changed, 195 insertions(+), 40 deletions(-) diff --git a/include/18650_cell.map b/include/18650_cell.map index cdbf7b7..9591d52 100644 --- a/include/18650_cell.map +++ b/include/18650_cell.map @@ -22,7 +22,7 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell. - energyDes_cell = 10.8; // W-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) + energyDes_cell = 10.8/1000.; // kW-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) @@ -104,10 +104,10 @@ Subelement BatteryCellSoCTemperatureMap S_map { } T.interp = "linear" ; - T.extrap = "linear" ; + T.extrap = "none" ; SOC.interp = "linear" ; - SOC.extrap = "linear" ; + SOC.extrap = "none" ; extrapIsError = 0; printExtrap = 0; @@ -191,10 +191,10 @@ Subelement BatteryCellSoCTemperatureMap S_map { } T.interp = "linear" ; - T.extrap = "linear" ; + T.extrap = "none" ; SOC.interp = "linear" ; - SOC.extrap = "linear" ; + SOC.extrap = "none" ; extrapIsError = 0; printExtrap = 0; @@ -276,10 +276,10 @@ Subelement BatteryCellSoCTemperatureMap S_map { } T.interp = "linear" ; - T.extrap = "linear" ; + T.extrap = "none" ; SOC.interp = "linear" ; - SOC.extrap = "linear" ; + SOC.extrap = "none" ; extrapIsError = 0; printExtrap = 0; diff --git a/include/amprius_cell.map b/include/amprius_cell.map index 35a5b03..57d70c2 100644 --- a/include/amprius_cell.map +++ b/include/amprius_cell.map @@ -22,7 +22,7 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell. - energyDes_cell = 12.75; // W-h (3.75 V nominal * 3.4 Ah tested at C/5 discharge) + energyDes_cell = 12.75/1000.; // kW-h (3.75 V nominal * 3.4 Ah tested at C/5 discharge) // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) @@ -87,10 +87,10 @@ Subelement BatteryCellSoCTemperatureMap S_map { } T.interp = "linear" ; - T.extrap = "linear" ; + T.extrap = "none" ; SOC.interp = "linear" ; - SOC.extrap = "linear" ; + SOC.extrap = "none" ; extrapIsError = 0; printExtrap = 0; @@ -154,10 +154,10 @@ Subelement BatteryCellSoCTemperatureMap S_map { } T.interp = "linear" ; - T.extrap = "linear" ; + T.extrap = "none" ; SOC.interp = "linear" ; - SOC.extrap = "linear" ; + SOC.extrap = "none" ; extrapIsError = 0; printExtrap = 0; @@ -221,10 +221,10 @@ Subelement BatteryCellSoCTemperatureMap S_map { } T.interp = "linear" ; - T.extrap = "linear" ; + T.extrap = "none" ; SOC.interp = "linear" ; - SOC.extrap = "linear" ; + SOC.extrap = "none" ; extrapIsError = 0; printExtrap = 0; diff --git a/model/battery_test.mdl b/model/battery_test.mdl index ac02a5e..097b55d 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -31,9 +31,15 @@ cout<<"======================================="< + // Load in the battery map + #include + // Set up the thermal port and thermal mass submodel/socket + setOption("switchThermPort", "TRUE"); + Subelement EThermalMass S_eThermMass { + Cp = 0.5*10; + } } Element Cable Cable_Single @@ -46,10 +52,24 @@ Element Cable Cable_Single Element ConstantPowerLoad CLoad { Pdemand = 14./1000.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) - eff = 0.95; -} + eff = 0.999; +} +// Create a magic thermal output port that represents the heat extraction +// from the battery. +Element TMS{ + ThermalOutputPort Q_O; + // Assume cold side of TMS is ISA temperature + //real T_cool = 518.67, Q_cool; + real T_cool = 500, Q_cool; + real R_cool = 1; // cooling heat transfer resistance to ambient. + void calculate() { + Q_cool = R_cool*(Q_O.MassTemp-T_cool); + Q_O.HeatTransferRate = Q_cool; + } +} +linkPorts("TMS.Q_O","Li_ion_cell.Q_I","Q1"); //------------------------------------------------------------------------------------------------- // Component Linkages @@ -62,27 +82,29 @@ linkPortI( "Cable_Single.EP_O", "CLoad.EP_I" ); findSourcesAndPropagate(); -solverSequence = { "Cable_Single", "Li_ion_cell", "CLoad" }; +solverSequence = { "Cable_Single", "Li_ion_cell", "CLoad", "TMS" }; void BFPrintOutput() { cout << " Case = " << CASE << endl; cout << " Battery open circuit voltage = " << Li_ion_cell.Voc << endl; - cout << " Battery output voltage (actual value) = " << Li_ion_cell.Vout << endl; - cout << " Battery output voltage (guess value) = " << Li_ion_cell.Vout_guess << endl; - cout << " Battery output Resistance (R_0, R_Th) = " << Li_ion_cell.R_0 << ", " << Li_ion_cell.R_Th << endl; - cout << " Battery output voltage (guess value) = " << Li_ion_cell.Vout_guess << endl; - cout << " Battery current (calc) = " << (Li_ion_cell.Voc-Li_ion_cell.Vout)/Li_ion_cell.RTotal << endl; - cout << " Battery current (output port) = " << Li_ion_cell.EP_O.I.r << endl; + cout << " Battery output voltage (actual/guess) = " << Li_ion_cell.Vout << "/" << Li_ion_cell.Vout_guess << endl; + cout << " Battery heat balance (Qin/Oout) = " << Li_ion_cell.Q_heat << "/" << Li_ion_cell.Q_I.HeatTransferRate << endl; + // cout << " Battery output Resistance (R_0, R_Th) = " << Li_ion_cell.R_0 << ", " << Li_ion_cell.R_Th << endl; + // cout << " Battery current (calc) = " << (Li_ion_cell.Voc-Li_ion_cell.Vout)/Li_ion_cell.RTotal << endl; + cout << " Battery current/power = " << Li_ion_cell.EP_O.I.r << "/" << Li_ion_cell.EP_O.S.r << endl; + cout << " Load power/depVal = " << CLoad.P << "/" << 14./1000. << endl; cout << " Number of series cells in battery = " << Li_ion_cell.S_map.num_series << endl; cout << " Number of parallel cells in battery = " << Li_ion_cell.S_map.num_parallel << endl; - cout << " Cable current (output port) = " << Cable_Single.EP_O.I.r << endl; - cout << " Load input voltage = " << CLoad.EP_I.V.r << endl; - cout << " Load input power = " << CLoad.EP_I.S.r << endl; - cout << " Calculated load eff = " << (CLoad.P/CLoad.EP_I.S.r)**sign(CLoad.P) << endl; // GLT: account for negative power flow - cout << " Load eff = " << CLoad.eff << endl; + cout << " Battery temperature/temp state (oC) = " << Li_ion_cell.T_batt << "/" << (Li_ion_cell.S_eThermMass.T - 491.67)*5./9. << endl; + // cout << " Cable current (output port) = " << Cable_Single.EP_O.I.r << endl; + // cout << " Load input voltage = " << CLoad.EP_I.V.r << endl; + // cout << " Load input power = " << CLoad.EP_I.S.r << endl; + // cout << " Calculated load eff = " << (CLoad.P/CLoad.EP_I.S.r)**sign(CLoad.P) << endl; // GLT: account for negative power flow + // cout << " Load eff = " << CLoad.eff << endl; } // Initial independent variable guesses are here. -CLoad.Vreal = 3; +CLoad.Vreal = 3.59; CLoad.Vimag = 0; + diff --git a/run/battery_test.run b/run/battery_test.run index d1f0c7b..8a6b0e2 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -43,9 +43,12 @@ On design setOption("switchDes","DESIGN"); autoSolverSetup(); //solver.solutionMode = "ONE_PASS"; +//solver.switchUBC = "ON"; -solver.maxIterations=500; -solver.maxJacobians=500; +solver.maxIterations=5000; +solver.maxJacobians=5000; +solver.defaultPerturbation = 0.00035; // tell the solver not to perturb so far when calcing jacobian. default: 0.001 +//solver.defaultDxLimit = 0.03; cout << endl << solver.dependentNames << endl << solver.independentNames << endl; // Constant power load 14 W for Case 0 and 1 @@ -70,3 +73,88 @@ CLoad.Pdemand = -14./1000.; // Charge the battery roughly at 1 C (14 W) CASE++; run(); BFPrintOutput(); page.display(); + +// Setup a transient run to match JCC's Simulink data +CLoad.Pdemand = 6./1000.; // discharge such that we get 6 W to load. +run(); // do another steady-state run just to initialize us. + +// BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance +TMS.R_cool = 0; + +// Also start out the temperature at 20 C to match the data +Li_ion_cell.T_batt = 20; +Li_ion_cell.S_eThermMass.T = 20. * 9./5. + 491.67; // 20 C converted to R + +// Turn on integrator for battery SOC +Li_ion_cell.ind_SOC.autoSetup = TRUE; +Li_ion_cell.integ_SOC.autoSetup = TRUE; + +setOption("switchDes","OFFDESIGN"); +setOption("solutionMode", "TRANSIENT"); +transient.stopTime = 6560.0; +transient.baseTimeStep = 0.5; +transient.setup(); +initializeHistory(); +autoSolverSetup(); + +solver.defaultPerturbation = 0.00001; +solver.defaultDxLimit = 0.001; +//solver.solutionMode = "ONE_PASS"; + +cout << "Transient Solver Vars = " << endl << solver.dependentNames << endl << solver.independentNames << endl; + +// Transient data out to a CSV file for plotting +OutFileStream transientCSVStream { filename = "output/batt_transient.csv"; } + +// Write the CSV headers +transientCSVStream << "Li_ion_cell.Voc,"; +transientCSVStream << "Li_ion_cell.Vout,"; +transientCSVStream << "Li_ion_cell.Q_heat,"; +transientCSVStream << "Li_ion_cell.R_0,"; +transientCSVStream << "Li_ion_cell.R_Th,"; +transientCSVStream << "Li_ion_cell.EP_O.I.r,"; +transientCSVStream << "Li_ion_cell.EP_O.S.r,"; +transientCSVStream << "Li_ion_cell.T_batt,"; +transientCSVStream << "Li_ion_cell.S_eThermMass.T,"; +transientCSVStream << "Li_ion_cell.SOC,"; +transientCSVStream << "Li_ion_cell.dSOCqdt,"; +transientCSVStream << "Li_ion_cell.C_rate,"; +transientCSVStream << "time" << endl; + +// Use a variable to print only every 100 timesteps. +int printCounter = 0; +void csvTransientPrint() +{ + if (++printCounter >= 600) + { + printCounter = 0; + transientCSVStream << Li_ion_cell.Voc << ", "; + transientCSVStream << Li_ion_cell.Vout << ", "; + transientCSVStream << Li_ion_cell.Q_heat << ", "; + transientCSVStream << Li_ion_cell.R_0 << ", "; + transientCSVStream << Li_ion_cell.R_Th << ", "; + transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; + transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; + transientCSVStream << Li_ion_cell.T_batt << ", "; + transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; + transientCSVStream << Li_ion_cell.SOC << ", "; + transientCSVStream << Li_ion_cell.dSOCqdt << ", "; + transientCSVStream << Li_ion_cell.C_rate << ", "; + transientCSVStream << time << endl; + + cout << "T_batt (oC), " << Li_ion_cell.T_batt << ", "; + //cout << "HeatRate (BTU/s), " << Li_ion_cell.Q_heat << ", "; + cout << "BattCurrent (A), " << Li_ion_cell.EP_O.I.r << ", "; + cout << "BattSOC, " << Li_ion_cell.SOC << ", "; + cout << "BattdSOCqdt, " << Li_ion_cell.dSOCqdt << ", "; + cout << "C-rate, " << Li_ion_cell.C_rate << ", "; + cout << "CASE, " << CASE << ", "; + cout << "time (s), " << time << endl; + } + if (Li_ion_cell.SOC <= 0) { + quit(); + } +} + +postsolverSequence = { "csvTransientPrint" }; +run(); diff --git a/src/Battery.int b/src/Battery.int index d26657e..133ed5e 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -143,7 +143,7 @@ this component, see MotorGeneratorMap.int"; } real desired_energyDes { - value = 10; IOstatus = "input"; units = "none"; // [kW-h] + value = 10./1000.; IOstatus = "input"; units = "none"; // [kW-h] description = "Desired design energy capacity for this battery."; } @@ -157,6 +157,11 @@ this component, see MotorGeneratorMap.int"; description = "State of charge for this battery."; } + real dSOCqdt { + value = 0; IOstatus = "output"; units = "none"; // [fraction/s] + description = "Time derivative of state of charge for this battery (calculated in map file)."; + } + real powerDes { value = 0; IOstatus = "output"; units = "none"; // [kW] description = "Design power for this source."; @@ -270,18 +275,46 @@ this component, see MotorGeneratorMap.int"; // ****** ADD SOLVER INDEPENDENTS & DEPENDENTS ****** //----------------------------------------------------- + // Solver pair to allow output voltage to sag as current and other vars vary. Independent ind_Vout { varName = "Vout_guess"; autoSetup = TRUE; indepRef = "1000"; description = "Varies the battery output voltage to match Vout = Voc - Vdrop."; } - Dependent dep_Vout { eq_lhs = "Vout"; eq_rhs = "Vout_guess"; autoSetup = TRUE; } + + // SOC state variable. + Independent ind_SOC { + varName = "SOC"; + autoSetup = FALSE; + description = "Varies state of charge (intended to be used with SOC integrator)."; + } + Integrator integ_SOC { + stateName = "SOC"; + derivativeName = "dSOCqdt"; + eq_lhs = "0"; + eq_rhs = "1"; + autoSetup = FALSE; + description = "Balances normalized capacity increments in the battery. Only intended to be used transiently."; + } + + // Solver pair to link up battery temperature variable used for performance and the temperature state. + Independent ind_T_batt { + varName = "T_batt"; + autoSetup = FALSE; + indepRef = "10000"; + description = "Varies the battery temperature to match the eThermalMass temperature state variable."; + } + Dependent dep_T_batt { + eq_lhs = "T_batt*9./5. + 491.67"; // deg C to deg R + eq_rhs = "S_eThermMass.T"; // deg R + autoSetup = FALSE; + } //------------------------------------------- // ****** VARIABLE CHANGED METHODOLOGY ****** @@ -290,7 +323,13 @@ this component, see MotorGeneratorMap.int"; void variableChanged(string name, any oldVal) { if (name == "switchThermPort") { if (switchThermPort == "TRUE") { - create("", "ThermalInputPort", "Q_I"); + create("", "ThermalInputPort", "Q_I"); + ind_T_batt.autoSetup = TRUE; + dep_T_batt.autoSetup = TRUE; + } + else { + ind_T_batt.autoSetup = FALSE; + dep_T_batt.autoSetup = FALSE; } } } @@ -339,6 +378,9 @@ this component, see MotorGeneratorMap.int"; // Output params common to both on and off design cases. C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) + dSOCqdt = -C_rate/3600.; + C_rate = abs(C_rate); // C-rate actually does not typically have an associated sign. + EP_O.S.r; Loss_r = EP_O.I.mag**2 * RTotal; Loss_j = 0; eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); diff --git a/src/BatteryCellSoCTemperatureMap.int b/src/BatteryCellSoCTemperatureMap.int index 0951053..0028661 100644 --- a/src/BatteryCellSoCTemperatureMap.int +++ b/src/BatteryCellSoCTemperatureMap.int @@ -43,8 +43,11 @@ class BatteryCellSoCTemperatureMap extends Subelement { description = isA() + " manages the calculation of battery performance map variables. The battery parameters output from these maps are open- - circuit voltage and internal resistance parameters. Inputs to these - maps are state of charge (SOC) and battery temperature"; + circuit voltage and internal resistance parameters. This subelement also + abstracts away all cell-level calculations (i.e., they live here and not + in battery.int) + + Inputs to these maps are state of charge (SOC) and battery temperature."; usageNotes = isA() + @@ -72,7 +75,7 @@ class BatteryCellSoCTemperatureMap extends Subelement { description = "Dynamic output resistance for one cell."; } real energyDes_cell { - value = 10; IOstatus = OUTPUT; units = NONE; // W-h + value = 10; IOstatus = OUTPUT; units = NONE; // kW-h description = "Energy design capacity for one cell."; } @@ -158,6 +161,7 @@ class BatteryCellSoCTemperatureMap extends Subelement { //---------------------------------------------------------------------- num_parallel = ceil(desired_energyDes / energyDes_cell); num_series = ceil(Vout_des/Voc_cell); + energyDes = energyDes_cell * num_parallel; } // end (switchDes == DESIGN) //---------------------------------------------------------------------- @@ -167,7 +171,6 @@ class BatteryCellSoCTemperatureMap extends Subelement { Voc = Voc_cell*num_series; R_0 = R_0_cell*num_series / num_parallel; R_Th = R_Th_cell*num_series / num_parallel; - energyDes = energyDes_cell * num_parallel; } // end calculate() function diff --git a/src/EThermalMass.int b/src/EThermalMass.int index f8be05c..d54a4e3 100644 --- a/src/EThermalMass.int +++ b/src/EThermalMass.int @@ -152,4 +152,4 @@ class EThermalMass extends Subelement { dTqdt = Q_net /( Mass*Cp ); } } -#endif \ No newline at end of file +#endif From d8047060a194165f0249900d77c38cb37e91ddac Mon Sep 17 00:00:00 2001 From: "Thomas, George" Date: Fri, 27 Aug 2021 09:36:50 -0400 Subject: [PATCH 12/24] add load profile setup with dummy data --- run/battery_test.run | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/run/battery_test.run b/run/battery_test.run index 8a6b0e2..bef6d8e 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -125,7 +125,7 @@ transientCSVStream << "time" << endl; int printCounter = 0; void csvTransientPrint() { - if (++printCounter >= 600) + if (++printCounter >= 120) { printCounter = 0; transientCSVStream << Li_ion_cell.Voc << ", "; @@ -151,10 +151,21 @@ void csvTransientPrint() cout << "CASE, " << CASE << ", "; cout << "time (s), " << time << endl; } - if (Li_ion_cell.SOC <= 0) { +} + +void transient_profile() { + + // Based time points + if ( time < 1000 ) { CLoad.Pdemand = 6./1000.; } + else if ( time < 1500 ) { CLoad.Pdemand = 1./1000.; } + else if ( time < 2000 ) { CLoad.Pdemand = 6./1000.; } + + + // Stop if battery gets fully drained (or close to it) + if (Li_ion_cell.SOC <= 0.01) { quit(); } } -postsolverSequence = { "csvTransientPrint" }; +postsolverSequence = { "csvTransientPrint", "transient_profile" }; run(); From 96744de40c033252171cba182051a54741e1e95a Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Tue, 31 Aug 2021 13:51:39 -0400 Subject: [PATCH 13/24] Set up battery profile and specific heat --- model/battery_test.mdl | 8 +++++++- run/battery_test.run | 16 +++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/model/battery_test.mdl b/model/battery_test.mdl index 097b55d..3b02e9a 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -38,8 +38,14 @@ Element Battery Li_ion_cell { //Amprius battery ELD214 // Set up the thermal port and thermal mass submodel/socket setOption("switchThermPort", "TRUE"); Subelement EThermalMass S_eThermMass { - Cp = 0.5*10; + Cp = 0.5; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 + } + + Vout_des = 524; + SpecificEnergy = 200; //Wh/kg + //BPM TODO: change SE until NPSS temperature data matches Simulink curve + } Element Cable Cable_Single diff --git a/run/battery_test.run b/run/battery_test.run index bef6d8e..ce8dece 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -154,12 +154,18 @@ void csvTransientPrint() } void transient_profile() { - // Based time points - if ( time < 1000 ) { CLoad.Pdemand = 6./1000.; } - else if ( time < 1500 ) { CLoad.Pdemand = 1./1000.; } - else if ( time < 2000 ) { CLoad.Pdemand = 6./1000.; } - + if ( time < 570 ) { CLoad.Pdemand = 10.; } + else if ( time < 855 ) { CLoad.Pdemand = 0.1; } // BPM: if 0 causes failure, put in a small value (0.1) + else if ( time < 1000 ) { CLoad.Pdemand = 119.5 ; } + else if ( time < 1415 ) { CLoad.Pdemand = 0.; } + else if ( time < 1565 ) { CLoad.Pdemand = 120.; } + else if ( time < 3640 ) { CLoad.Pdemand = 60.; } + else if ( time < 4100 ) { CLoad.Pdemand = 18.5; } + else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } + else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } + else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } + else { CLoad.Pdemand = 0;} // Stop if battery gets fully drained (or close to it) if (Li_ion_cell.SOC <= 0.01) { From acd25e723204a53404801ab9405a5f0fcd4400a5 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Wed, 1 Sep 2021 14:48:00 -0400 Subject: [PATCH 14/24] Preliminary battery model work --- include/amprius_cell.map | 2 +- model/battery_test.mdl | 9 +- run/battery_test.run | 222 +++++++++++++-------------- src/Battery.int | 8 +- src/BatteryCellSoCTemperatureMap.int | 16 +- 5 files changed, 133 insertions(+), 124 deletions(-) diff --git a/include/amprius_cell.map b/include/amprius_cell.map index 57d70c2..e4aaa83 100644 --- a/include/amprius_cell.map +++ b/include/amprius_cell.map @@ -23,7 +23,7 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell. energyDes_cell = 12.75/1000.; // kW-h (3.75 V nominal * 3.4 Ah tested at C/5 discharge) - + powerDes_cell = 14./1000; // kW BPM double-check datasheeet // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) // | To satisfy the TB_Wp socket requirement. diff --git a/model/battery_test.mdl b/model/battery_test.mdl index 3b02e9a..e8ac9a2 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -38,12 +38,13 @@ Element Battery Li_ion_cell { //Amprius battery ELD214 // Set up the thermal port and thermal mass submodel/socket setOption("switchThermPort", "TRUE"); Subelement EThermalMass S_eThermMass { - Cp = 0.5; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 + Cp = 0.5; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 } Vout_des = 524; - SpecificEnergy = 200; //Wh/kg + Vout_guess = 520; + SpecificEnergy = 100; //Wh/kg //BPM TODO: change SE until NPSS temperature data matches Simulink curve } @@ -57,7 +58,7 @@ Element Cable Cable_Single Element ConstantPowerLoad CLoad { - Pdemand = 14./1000.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) + Pdemand = 14./1000.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) BPM: was 14./1000 eff = 0.999; } @@ -111,6 +112,6 @@ void BFPrintOutput() } // Initial independent variable guesses are here. -CLoad.Vreal = 3.59; +CLoad.Vreal = 519.9; //BPM was 3.59 CLoad.Vimag = 0; diff --git a/run/battery_test.run b/run/battery_test.run index ce8dece..871fc3f 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -42,13 +42,13 @@ On design ************************/ setOption("switchDes","DESIGN"); autoSolverSetup(); -//solver.solutionMode = "ONE_PASS"; +// solver.solutionMode = "ONE_PASS"; //solver.switchUBC = "ON"; -solver.maxIterations=5000; +solver.maxIterations=50000; solver.maxJacobians=5000; solver.defaultPerturbation = 0.00035; // tell the solver not to perturb so far when calcing jacobian. default: 0.001 -//solver.defaultDxLimit = 0.03; +solver.defaultDxLimit = 0.03; cout << endl << solver.dependentNames << endl << solver.independentNames << endl; // Constant power load 14 W for Case 0 and 1 @@ -67,111 +67,111 @@ CASE++; run(); BFPrintOutput(); page.display(); -CLoad.Pdemand = -14./1000.; // Charge the battery roughly at 1 C (14 W) - -// Constant power load -14 W for Case 2 -CASE++; run(); -BFPrintOutput(); -page.display(); - -// Setup a transient run to match JCC's Simulink data -CLoad.Pdemand = 6./1000.; // discharge such that we get 6 W to load. -run(); // do another steady-state run just to initialize us. - -// BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance -TMS.R_cool = 0; - -// Also start out the temperature at 20 C to match the data -Li_ion_cell.T_batt = 20; -Li_ion_cell.S_eThermMass.T = 20. * 9./5. + 491.67; // 20 C converted to R - -// Turn on integrator for battery SOC -Li_ion_cell.ind_SOC.autoSetup = TRUE; -Li_ion_cell.integ_SOC.autoSetup = TRUE; - -setOption("switchDes","OFFDESIGN"); -setOption("solutionMode", "TRANSIENT"); -transient.stopTime = 6560.0; -transient.baseTimeStep = 0.5; -transient.setup(); -initializeHistory(); -autoSolverSetup(); - -solver.defaultPerturbation = 0.00001; -solver.defaultDxLimit = 0.001; -//solver.solutionMode = "ONE_PASS"; - -cout << "Transient Solver Vars = " << endl << solver.dependentNames << endl << solver.independentNames << endl; - -// Transient data out to a CSV file for plotting -OutFileStream transientCSVStream { filename = "output/batt_transient.csv"; } - -// Write the CSV headers -transientCSVStream << "Li_ion_cell.Voc,"; -transientCSVStream << "Li_ion_cell.Vout,"; -transientCSVStream << "Li_ion_cell.Q_heat,"; -transientCSVStream << "Li_ion_cell.R_0,"; -transientCSVStream << "Li_ion_cell.R_Th,"; -transientCSVStream << "Li_ion_cell.EP_O.I.r,"; -transientCSVStream << "Li_ion_cell.EP_O.S.r,"; -transientCSVStream << "Li_ion_cell.T_batt,"; -transientCSVStream << "Li_ion_cell.S_eThermMass.T,"; -transientCSVStream << "Li_ion_cell.SOC,"; -transientCSVStream << "Li_ion_cell.dSOCqdt,"; -transientCSVStream << "Li_ion_cell.C_rate,"; -transientCSVStream << "time" << endl; - -// Use a variable to print only every 100 timesteps. -int printCounter = 0; -void csvTransientPrint() -{ - if (++printCounter >= 120) - { - printCounter = 0; - transientCSVStream << Li_ion_cell.Voc << ", "; - transientCSVStream << Li_ion_cell.Vout << ", "; - transientCSVStream << Li_ion_cell.Q_heat << ", "; - transientCSVStream << Li_ion_cell.R_0 << ", "; - transientCSVStream << Li_ion_cell.R_Th << ", "; - transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; - transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; - transientCSVStream << Li_ion_cell.T_batt << ", "; - transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; - transientCSVStream << Li_ion_cell.SOC << ", "; - transientCSVStream << Li_ion_cell.dSOCqdt << ", "; - transientCSVStream << Li_ion_cell.C_rate << ", "; - transientCSVStream << time << endl; - - cout << "T_batt (oC), " << Li_ion_cell.T_batt << ", "; - //cout << "HeatRate (BTU/s), " << Li_ion_cell.Q_heat << ", "; - cout << "BattCurrent (A), " << Li_ion_cell.EP_O.I.r << ", "; - cout << "BattSOC, " << Li_ion_cell.SOC << ", "; - cout << "BattdSOCqdt, " << Li_ion_cell.dSOCqdt << ", "; - cout << "C-rate, " << Li_ion_cell.C_rate << ", "; - cout << "CASE, " << CASE << ", "; - cout << "time (s), " << time << endl; - } -} - -void transient_profile() { - // Based time points - if ( time < 570 ) { CLoad.Pdemand = 10.; } - else if ( time < 855 ) { CLoad.Pdemand = 0.1; } // BPM: if 0 causes failure, put in a small value (0.1) - else if ( time < 1000 ) { CLoad.Pdemand = 119.5 ; } - else if ( time < 1415 ) { CLoad.Pdemand = 0.; } - else if ( time < 1565 ) { CLoad.Pdemand = 120.; } - else if ( time < 3640 ) { CLoad.Pdemand = 60.; } - else if ( time < 4100 ) { CLoad.Pdemand = 18.5; } - else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } - else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } - else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } - else { CLoad.Pdemand = 0;} - - // Stop if battery gets fully drained (or close to it) - if (Li_ion_cell.SOC <= 0.01) { - quit(); - } -} - -postsolverSequence = { "csvTransientPrint", "transient_profile" }; -run(); +// CLoad.Pdemand = -120.; // kw Charge the battery roughly at 1 C (14 W) BPM: was 14./1000 + +// // Constant power load -14 W for Case 2 +// CASE++; run(); +// BFPrintOutput(); +// page.display(); + +// // Setup a transient run to match JCC's Simulink data +// CLoad.Pdemand = 6./1000.; // discharge such that we get 6 W to load. +// run(); // do another steady-state run just to initialize us. + +// // BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance +// TMS.R_cool = 0; + +// // Also start out the temperature at 20 C to match the data +// Li_ion_cell.T_batt = 20; +// Li_ion_cell.S_eThermMass.T = 20. * 9./5. + 491.67; // 20 C converted to R + +// // Turn on integrator for battery SOC +// Li_ion_cell.ind_SOC.autoSetup = TRUE; +// Li_ion_cell.integ_SOC.autoSetup = TRUE; + +// setOption("switchDes","OFFDESIGN"); +// setOption("solutionMode", "TRANSIENT"); +// transient.stopTime = 6560.0; +// transient.baseTimeStep = 0.5; +// transient.setup(); +// initializeHistory(); +// autoSolverSetup(); + +// solver.defaultPerturbation = 0.00001; +// solver.defaultDxLimit = 0.001; +// //solver.solutionMode = "ONE_PASS"; + +// cout << "Transient Solver Vars = " << endl << solver.dependentNames << endl << solver.independentNames << endl; + +// // Transient data out to a CSV file for plotting +// OutFileStream transientCSVStream { filename = "output/batt_transient.csv"; } + +// // Write the CSV headers +// transientCSVStream << "Li_ion_cell.Voc,"; +// transientCSVStream << "Li_ion_cell.Vout,"; +// transientCSVStream << "Li_ion_cell.Q_heat,"; +// transientCSVStream << "Li_ion_cell.R_0,"; +// transientCSVStream << "Li_ion_cell.R_Th,"; +// transientCSVStream << "Li_ion_cell.EP_O.I.r,"; +// transientCSVStream << "Li_ion_cell.EP_O.S.r,"; +// transientCSVStream << "Li_ion_cell.T_batt,"; +// transientCSVStream << "Li_ion_cell.S_eThermMass.T,"; +// transientCSVStream << "Li_ion_cell.SOC,"; +// transientCSVStream << "Li_ion_cell.dSOCqdt,"; +// transientCSVStream << "Li_ion_cell.C_rate,"; +// transientCSVStream << "time" << endl; + +// // Use a variable to print only every 100 timesteps. +// int printCounter = 0; +// void csvTransientPrint() +// { +// if (++printCounter >= 120) +// { +// printCounter = 0; +// transientCSVStream << Li_ion_cell.Voc << ", "; +// transientCSVStream << Li_ion_cell.Vout << ", "; +// transientCSVStream << Li_ion_cell.Q_heat << ", "; +// transientCSVStream << Li_ion_cell.R_0 << ", "; +// transientCSVStream << Li_ion_cell.R_Th << ", "; +// transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; +// transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; +// transientCSVStream << Li_ion_cell.T_batt << ", "; +// transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; +// transientCSVStream << Li_ion_cell.SOC << ", "; +// transientCSVStream << Li_ion_cell.dSOCqdt << ", "; +// transientCSVStream << Li_ion_cell.C_rate << ", "; +// transientCSVStream << time << endl; + +// cout << "T_batt (oC), " << Li_ion_cell.T_batt << ", "; +// //cout << "HeatRate (BTU/s), " << Li_ion_cell.Q_heat << ", "; +// cout << "BattCurrent (A), " << Li_ion_cell.EP_O.I.r << ", "; +// cout << "BattSOC, " << Li_ion_cell.SOC << ", "; +// cout << "BattdSOCqdt, " << Li_ion_cell.dSOCqdt << ", "; +// cout << "C-rate, " << Li_ion_cell.C_rate << ", "; +// cout << "CASE, " << CASE << ", "; +// cout << "time (s), " << time << endl; +// } +// } + +// void transient_profile() { +// // Based time points +// if ( time < 570 ) { CLoad.Pdemand = 10.; } +// else if ( time < 855 ) { CLoad.Pdemand = 0.; } // BPM: if 0 causes failure, put in a small value (0.1) +// else if ( time < 1000 ) { CLoad.Pdemand = 119.5 ; } +// else if ( time < 1415 ) { CLoad.Pdemand = 0.; } +// else if ( time < 1565 ) { CLoad.Pdemand = 120.; } +// else if ( time < 3640 ) { CLoad.Pdemand = 60.; } +// else if ( time < 4100 ) { CLoad.Pdemand = 18.5; } +// else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } +// else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } +// else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } +// else { CLoad.Pdemand = 0.;} + +// // Stop if battery gets fully drained (or close to it) +// if (Li_ion_cell.SOC <= 0.01) { +// quit(); +// } +// } + +// postsolverSequence = { "csvTransientPrint", "transient_profile" }; +// run(); diff --git a/src/Battery.int b/src/Battery.int index 133ed5e..11ae575 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -5,7 +5,7 @@ | 21000 Brookpark Rd | | Cleveland, OH 44135 | | | - | File Name: Battery.int | + | File Name: Battery.int | | Author(s): George Thomas, Jeffrey Csank, David Sadey, Tom Lavelle, Brian Malone | | Date(s): August 2021 | | | @@ -340,6 +340,9 @@ this component, see MotorGeneratorMap.int"; void calculate() { + // Declare design point power. Energy is calculated in the map logic. + powerDes = EP_O.S.r; + // Run the battery map if it is present if(!S_map.isEmpty()) { S_map.execute(); @@ -358,9 +361,6 @@ this component, see MotorGeneratorMap.int"; if (switchDes == "DESIGN") { - // Declare design point power. Energy is calculated in the map logic. - powerDes = EP_O.S.r; - real energyBasedMass = (energyDes*1000) / SpecificEnergy; // (kW-h/1000) / (W-h/kg) = kg real powerBasedMass = EP_O.S.r / SpecificPower; diff --git a/src/BatteryCellSoCTemperatureMap.int b/src/BatteryCellSoCTemperatureMap.int index 0028661..d759ba7 100644 --- a/src/BatteryCellSoCTemperatureMap.int +++ b/src/BatteryCellSoCTemperatureMap.int @@ -24,6 +24,7 @@ extern real T_batt; // Used for pack sizing extern real Vout_des; extern real desired_energyDes; +extern real powerDes; // Variables that exist in the parent element // and are set by this subelement. AKA output params. @@ -79,6 +80,11 @@ class BatteryCellSoCTemperatureMap extends Subelement { description = "Energy design capacity for one cell."; } + real powerDes_cell { + value = 10; IOstatus = OUTPUT; units = NONE; // kW + description = "Power design for one cell."; + } + real num_series { value = 1; IOstatus = OUTPUT; units = NONE; description = "Number of series cells in a string"; @@ -158,9 +164,11 @@ class BatteryCellSoCTemperatureMap extends Subelement { //---------------------------------------------------------------------- // On design, we need to size the pack. That is, figure out number of // series and parallel cells in the pack. - //---------------------------------------------------------------------- - num_parallel = ceil(desired_energyDes / energyDes_cell); - num_series = ceil(Vout_des/Voc_cell); + //---------------------------------------------------------------------- + // num_parallel = max(ceil(powerDes / powerDes_cell),ceil(desired_energyDes / energyDes_cell)); + num_parallel = max((powerDes / powerDes_cell),(desired_energyDes / energyDes_cell)); + // num_series = ceil(Vout_des/Voc_cell); + num_series = Vout_des/Voc_cell; energyDes = energyDes_cell * num_parallel; } // end (switchDes == DESIGN) @@ -169,7 +177,7 @@ class BatteryCellSoCTemperatureMap extends Subelement { // let's calculate the pack level quantities. //---------------------------------------------------------------------- Voc = Voc_cell*num_series; - R_0 = R_0_cell*num_series / num_parallel; + R_0 = R_0_cell*num_series / num_parallel; R_Th = R_Th_cell*num_series / num_parallel; } // end calculate() function From cf3ab28c7aeee5b1158932a88b4d9dab12d11682 Mon Sep 17 00:00:00 2001 From: "Thomas, George" Date: Thu, 2 Sep 2021 11:12:52 -0400 Subject: [PATCH 15/24] get steady state runs working again --- model/battery_test.mdl | 2 +- run/battery_test.run | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/model/battery_test.mdl b/model/battery_test.mdl index e8ac9a2..e2eae9e 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -58,7 +58,7 @@ Element Cable Cable_Single Element ConstantPowerLoad CLoad { - Pdemand = 14./1000.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) BPM: was 14./1000 + Pdemand = 120; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) eff = 0.999; } diff --git a/run/battery_test.run b/run/battery_test.run index 871fc3f..51c3be3 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -42,13 +42,13 @@ On design ************************/ setOption("switchDes","DESIGN"); autoSolverSetup(); -// solver.solutionMode = "ONE_PASS"; +//solver.solutionMode = "ONE_PASS"; //solver.switchUBC = "ON"; -solver.maxIterations=50000; +solver.maxIterations=5000; solver.maxJacobians=5000; -solver.defaultPerturbation = 0.00035; // tell the solver not to perturb so far when calcing jacobian. default: 0.001 -solver.defaultDxLimit = 0.03; +solver.defaultPerturbation = 0.0001; // tell the solver not to perturb so far when calcing jacobian. default: 0.001 +//solver.defaultDxLimit = 0.03; cout << endl << solver.dependentNames << endl << solver.independentNames << endl; // Constant power load 14 W for Case 0 and 1 @@ -67,12 +67,12 @@ CASE++; run(); BFPrintOutput(); page.display(); -// CLoad.Pdemand = -120.; // kw Charge the battery roughly at 1 C (14 W) BPM: was 14./1000 +CLoad.Pdemand = -120.; // kw Charge the battery roughly at 1 C (14 W) BPM: was 14./1000 -// // Constant power load -14 W for Case 2 -// CASE++; run(); -// BFPrintOutput(); -// page.display(); +// Constant power load -14 W for Case 2 +CASE++; run(); +BFPrintOutput(); +page.display(); // // Setup a transient run to match JCC's Simulink data // CLoad.Pdemand = 6./1000.; // discharge such that we get 6 W to load. From 8ac41fd3c4be36c6b0aca72fe5aec88f2a5554b5 Mon Sep 17 00:00:00 2001 From: "Thomas, George" Date: Thu, 2 Sep 2021 11:15:42 -0400 Subject: [PATCH 16/24] and transient working too --- run/battery_test.run | 202 +++++++++++++++++++++---------------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/run/battery_test.run b/run/battery_test.run index 51c3be3..9bf593e 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -74,104 +74,104 @@ CASE++; run(); BFPrintOutput(); page.display(); -// // Setup a transient run to match JCC's Simulink data -// CLoad.Pdemand = 6./1000.; // discharge such that we get 6 W to load. -// run(); // do another steady-state run just to initialize us. - -// // BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance -// TMS.R_cool = 0; - -// // Also start out the temperature at 20 C to match the data -// Li_ion_cell.T_batt = 20; -// Li_ion_cell.S_eThermMass.T = 20. * 9./5. + 491.67; // 20 C converted to R - -// // Turn on integrator for battery SOC -// Li_ion_cell.ind_SOC.autoSetup = TRUE; -// Li_ion_cell.integ_SOC.autoSetup = TRUE; - -// setOption("switchDes","OFFDESIGN"); -// setOption("solutionMode", "TRANSIENT"); -// transient.stopTime = 6560.0; -// transient.baseTimeStep = 0.5; -// transient.setup(); -// initializeHistory(); -// autoSolverSetup(); - -// solver.defaultPerturbation = 0.00001; -// solver.defaultDxLimit = 0.001; -// //solver.solutionMode = "ONE_PASS"; - -// cout << "Transient Solver Vars = " << endl << solver.dependentNames << endl << solver.independentNames << endl; - -// // Transient data out to a CSV file for plotting -// OutFileStream transientCSVStream { filename = "output/batt_transient.csv"; } - -// // Write the CSV headers -// transientCSVStream << "Li_ion_cell.Voc,"; -// transientCSVStream << "Li_ion_cell.Vout,"; -// transientCSVStream << "Li_ion_cell.Q_heat,"; -// transientCSVStream << "Li_ion_cell.R_0,"; -// transientCSVStream << "Li_ion_cell.R_Th,"; -// transientCSVStream << "Li_ion_cell.EP_O.I.r,"; -// transientCSVStream << "Li_ion_cell.EP_O.S.r,"; -// transientCSVStream << "Li_ion_cell.T_batt,"; -// transientCSVStream << "Li_ion_cell.S_eThermMass.T,"; -// transientCSVStream << "Li_ion_cell.SOC,"; -// transientCSVStream << "Li_ion_cell.dSOCqdt,"; -// transientCSVStream << "Li_ion_cell.C_rate,"; -// transientCSVStream << "time" << endl; - -// // Use a variable to print only every 100 timesteps. -// int printCounter = 0; -// void csvTransientPrint() -// { -// if (++printCounter >= 120) -// { -// printCounter = 0; -// transientCSVStream << Li_ion_cell.Voc << ", "; -// transientCSVStream << Li_ion_cell.Vout << ", "; -// transientCSVStream << Li_ion_cell.Q_heat << ", "; -// transientCSVStream << Li_ion_cell.R_0 << ", "; -// transientCSVStream << Li_ion_cell.R_Th << ", "; -// transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; -// transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; -// transientCSVStream << Li_ion_cell.T_batt << ", "; -// transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; -// transientCSVStream << Li_ion_cell.SOC << ", "; -// transientCSVStream << Li_ion_cell.dSOCqdt << ", "; -// transientCSVStream << Li_ion_cell.C_rate << ", "; -// transientCSVStream << time << endl; - -// cout << "T_batt (oC), " << Li_ion_cell.T_batt << ", "; -// //cout << "HeatRate (BTU/s), " << Li_ion_cell.Q_heat << ", "; -// cout << "BattCurrent (A), " << Li_ion_cell.EP_O.I.r << ", "; -// cout << "BattSOC, " << Li_ion_cell.SOC << ", "; -// cout << "BattdSOCqdt, " << Li_ion_cell.dSOCqdt << ", "; -// cout << "C-rate, " << Li_ion_cell.C_rate << ", "; -// cout << "CASE, " << CASE << ", "; -// cout << "time (s), " << time << endl; -// } -// } - -// void transient_profile() { -// // Based time points -// if ( time < 570 ) { CLoad.Pdemand = 10.; } -// else if ( time < 855 ) { CLoad.Pdemand = 0.; } // BPM: if 0 causes failure, put in a small value (0.1) -// else if ( time < 1000 ) { CLoad.Pdemand = 119.5 ; } -// else if ( time < 1415 ) { CLoad.Pdemand = 0.; } -// else if ( time < 1565 ) { CLoad.Pdemand = 120.; } -// else if ( time < 3640 ) { CLoad.Pdemand = 60.; } -// else if ( time < 4100 ) { CLoad.Pdemand = 18.5; } -// else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } -// else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } -// else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } -// else { CLoad.Pdemand = 0.;} - -// // Stop if battery gets fully drained (or close to it) -// if (Li_ion_cell.SOC <= 0.01) { -// quit(); -// } -// } - -// postsolverSequence = { "csvTransientPrint", "transient_profile" }; -// run(); +// Setup a transient run to match JCC's Simulink data +CLoad.Pdemand = 6./1000.; // discharge such that we get 6 W to load. +run(); // do another steady-state run just to initialize us. + +// BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance +TMS.R_cool = 0; + +// Also start out the temperature at 20 C to match the data +Li_ion_cell.T_batt = 20; +Li_ion_cell.S_eThermMass.T = 20. * 9./5. + 491.67; // 20 C converted to R + +// Turn on integrator for battery SOC +Li_ion_cell.ind_SOC.autoSetup = TRUE; +Li_ion_cell.integ_SOC.autoSetup = TRUE; + +setOption("switchDes","OFFDESIGN"); +setOption("solutionMode", "TRANSIENT"); +transient.stopTime = 6560.0; +transient.baseTimeStep = 0.5; +transient.setup(); +initializeHistory(); +autoSolverSetup(); + +solver.defaultPerturbation = 0.00001; +solver.defaultDxLimit = 0.001; +//solver.solutionMode = "ONE_PASS"; + +cout << "Transient Solver Vars = " << endl << solver.dependentNames << endl << solver.independentNames << endl; + +// Transient data out to a CSV file for plotting +OutFileStream transientCSVStream { filename = "output/batt_transient.csv"; } + +// Write the CSV headers +transientCSVStream << "Li_ion_cell.Voc,"; +transientCSVStream << "Li_ion_cell.Vout,"; +transientCSVStream << "Li_ion_cell.Q_heat,"; +transientCSVStream << "Li_ion_cell.R_0,"; +transientCSVStream << "Li_ion_cell.R_Th,"; +transientCSVStream << "Li_ion_cell.EP_O.I.r,"; +transientCSVStream << "Li_ion_cell.EP_O.S.r,"; +transientCSVStream << "Li_ion_cell.T_batt,"; +transientCSVStream << "Li_ion_cell.S_eThermMass.T,"; +transientCSVStream << "Li_ion_cell.SOC,"; +transientCSVStream << "Li_ion_cell.dSOCqdt,"; +transientCSVStream << "Li_ion_cell.C_rate,"; +transientCSVStream << "time" << endl; + +// Use a variable to print only every 100 timesteps. +int printCounter = 0; +void csvTransientPrint() +{ + if (++printCounter >= 120) + { + printCounter = 0; + transientCSVStream << Li_ion_cell.Voc << ", "; + transientCSVStream << Li_ion_cell.Vout << ", "; + transientCSVStream << Li_ion_cell.Q_heat << ", "; + transientCSVStream << Li_ion_cell.R_0 << ", "; + transientCSVStream << Li_ion_cell.R_Th << ", "; + transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; + transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; + transientCSVStream << Li_ion_cell.T_batt << ", "; + transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; + transientCSVStream << Li_ion_cell.SOC << ", "; + transientCSVStream << Li_ion_cell.dSOCqdt << ", "; + transientCSVStream << Li_ion_cell.C_rate << ", "; + transientCSVStream << time << endl; + + cout << "T_batt (oC), " << Li_ion_cell.T_batt << ", "; + //cout << "HeatRate (BTU/s), " << Li_ion_cell.Q_heat << ", "; + cout << "BattCurrent (A), " << Li_ion_cell.EP_O.I.r << ", "; + cout << "BattSOC, " << Li_ion_cell.SOC << ", "; + cout << "BattdSOCqdt, " << Li_ion_cell.dSOCqdt << ", "; + cout << "C-rate, " << Li_ion_cell.C_rate << ", "; + cout << "CASE, " << CASE << ", "; + cout << "time (s), " << time << endl; + } +} + +void transient_profile() { + // Based time points + if ( time < 570 ) { CLoad.Pdemand = 10.; } + else if ( time < 855 ) { CLoad.Pdemand = 0.; } // BPM: if 0 causes failure, put in a small value (0.1) + else if ( time < 1000 ) { CLoad.Pdemand = 119.5 ; } + else if ( time < 1415 ) { CLoad.Pdemand = 0.; } + else if ( time < 1565 ) { CLoad.Pdemand = 120.; } + else if ( time < 3640 ) { CLoad.Pdemand = 60.; } + else if ( time < 4100 ) { CLoad.Pdemand = 18.5; } + else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } + else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } + else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } + else { CLoad.Pdemand = 0.;} + + // Stop if battery gets fully drained (or close to it) + if (Li_ion_cell.SOC <= 0.01) { + quit(); + } +} + +postsolverSequence = { "csvTransientPrint", "transient_profile" }; +run(); From 11076a7be6707e8992b870cb53938860aee09009 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Fri, 3 Sep 2021 15:17:50 -0400 Subject: [PATCH 17/24] Battery transient initial try --- include/18650_cell.map | 5 ++-- include/amprius_cell.map | 2 +- model/battery_test.mdl | 12 +++++----- run/battery_test.run | 34 ++++++++++++++-------------- src/Battery.int | 13 ++++++++--- src/BatteryCellSoCTemperatureMap.int | 9 ++++++-- 6 files changed, 44 insertions(+), 31 deletions(-) diff --git a/include/18650_cell.map b/include/18650_cell.map index 9591d52..84f013f 100644 --- a/include/18650_cell.map +++ b/include/18650_cell.map @@ -22,8 +22,9 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell. - energyDes_cell = 10.8/1000.; // kW-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) - + energyDes_cell = 13./1000.; // kW-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) + powerDes_cell = 3./1000.; //kW + QDes_cell = 3./1000.; //Ah // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) // | To satisfy the TB_Wp socket requirement. diff --git a/include/amprius_cell.map b/include/amprius_cell.map index e4aaa83..ba4b471 100644 --- a/include/amprius_cell.map +++ b/include/amprius_cell.map @@ -23,7 +23,7 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell. energyDes_cell = 12.75/1000.; // kW-h (3.75 V nominal * 3.4 Ah tested at C/5 discharge) - powerDes_cell = 14./1000; // kW BPM double-check datasheeet + powerDes_cell = 3./1000.; // kW BPM double-check datasheeet // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) // | To satisfy the TB_Wp socket requirement. diff --git a/model/battery_test.mdl b/model/battery_test.mdl index e2eae9e..b8cc216 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -30,10 +30,10 @@ cout<<"======================================="< + #include <18650_cell.map> // Set up the thermal port and thermal mass submodel/socket setOption("switchThermPort", "TRUE"); @@ -44,7 +44,7 @@ Element Battery Li_ion_cell { //Amprius battery ELD214 Vout_des = 524; Vout_guess = 520; - SpecificEnergy = 100; //Wh/kg + SpecificEnergy = 200; //Wh/kg //BPM TODO: change SE until NPSS temperature data matches Simulink curve } @@ -58,7 +58,7 @@ Element Cable Cable_Single Element ConstantPowerLoad CLoad { - Pdemand = 120; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) + Pdemand = 120./1000.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) eff = 0.999; } @@ -69,7 +69,7 @@ Element TMS{ // Assume cold side of TMS is ISA temperature //real T_cool = 518.67, Q_cool; real T_cool = 500, Q_cool; - real R_cool = 1; // cooling heat transfer resistance to ambient. + real R_cool = 500.; // cooling heat transfer "admittance" to ambient. void calculate() { Q_cool = R_cool*(Q_O.MassTemp-T_cool); @@ -100,7 +100,7 @@ void BFPrintOutput() // cout << " Battery output Resistance (R_0, R_Th) = " << Li_ion_cell.R_0 << ", " << Li_ion_cell.R_Th << endl; // cout << " Battery current (calc) = " << (Li_ion_cell.Voc-Li_ion_cell.Vout)/Li_ion_cell.RTotal << endl; cout << " Battery current/power = " << Li_ion_cell.EP_O.I.r << "/" << Li_ion_cell.EP_O.S.r << endl; - cout << " Load power/depVal = " << CLoad.P << "/" << 14./1000. << endl; + cout << " Load power = " << CLoad.P << endl; cout << " Number of series cells in battery = " << Li_ion_cell.S_map.num_series << endl; cout << " Number of parallel cells in battery = " << Li_ion_cell.S_map.num_parallel << endl; cout << " Battery temperature/temp state (oC) = " << Li_ion_cell.T_batt << "/" << (Li_ion_cell.S_eThermMass.T - 491.67)*5./9. << endl; diff --git a/run/battery_test.run b/run/battery_test.run index 9bf593e..7064257 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -67,7 +67,7 @@ CASE++; run(); BFPrintOutput(); page.display(); -CLoad.Pdemand = -120.; // kw Charge the battery roughly at 1 C (14 W) BPM: was 14./1000 +CLoad.Pdemand = -120./1000.; // kw Charge the battery roughly at 1 C (14 W) // Constant power load -14 W for Case 2 CASE++; run(); @@ -75,7 +75,7 @@ BFPrintOutput(); page.display(); // Setup a transient run to match JCC's Simulink data -CLoad.Pdemand = 6./1000.; // discharge such that we get 6 W to load. +CLoad.Pdemand = 10./1000.; // initial power point in profile run(); // do another steady-state run just to initialize us. // BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance @@ -92,7 +92,7 @@ Li_ion_cell.integ_SOC.autoSetup = TRUE; setOption("switchDes","OFFDESIGN"); setOption("solutionMode", "TRANSIENT"); transient.stopTime = 6560.0; -transient.baseTimeStep = 0.5; +transient.baseTimeStep = 0.1; transient.setup(); initializeHistory(); autoSolverSetup(); @@ -122,12 +122,11 @@ transientCSVStream << "Li_ion_cell.C_rate,"; transientCSVStream << "time" << endl; // Use a variable to print only every 100 timesteps. -int printCounter = 0; +real time_old = 0; void csvTransientPrint() { - if (++printCounter >= 120) + if (time-time_old >= 300) { - printCounter = 0; transientCSVStream << Li_ion_cell.Voc << ", "; transientCSVStream << Li_ion_cell.Vout << ", "; transientCSVStream << Li_ion_cell.Q_heat << ", "; @@ -150,22 +149,23 @@ void csvTransientPrint() cout << "C-rate, " << Li_ion_cell.C_rate << ", "; cout << "CASE, " << CASE << ", "; cout << "time (s), " << time << endl; + time_old = time; } } void transient_profile() { // Based time points - if ( time < 570 ) { CLoad.Pdemand = 10.; } - else if ( time < 855 ) { CLoad.Pdemand = 0.; } // BPM: if 0 causes failure, put in a small value (0.1) - else if ( time < 1000 ) { CLoad.Pdemand = 119.5 ; } - else if ( time < 1415 ) { CLoad.Pdemand = 0.; } - else if ( time < 1565 ) { CLoad.Pdemand = 120.; } - else if ( time < 3640 ) { CLoad.Pdemand = 60.; } - else if ( time < 4100 ) { CLoad.Pdemand = 18.5; } - else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } - else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } - else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } - else { CLoad.Pdemand = 0.;} + if ( time < 570 ) { CLoad.Pdemand = 10./1000.; } + else if ( time < 855 ) { CLoad.Pdemand = 0./1000.; } // BPM: if 0 causes failure, put in a small value (0.1) + else if ( time < 1000 ) { CLoad.Pdemand = 119.5/1000. ; } + else if ( time < 1415 ) { CLoad.Pdemand = 0./1000.; } + else if ( time < 1565 ) { CLoad.Pdemand = 120./1000.; } + else if ( time < 3640 ) { CLoad.Pdemand = 60./1000.; } + else if ( time < 4100 ) { CLoad.Pdemand = 18.5/1000.; } + else if ( time < 4620 ) { CLoad.Pdemand = 0.5/1000.; } + else if ( time < 4760 ) { CLoad.Pdemand = 79.5/1000.; } + else if ( time < 5680 ) { CLoad.Pdemand = 6.5/1000.; } + else { CLoad.Pdemand = 0./1000.;} // Stop if battery gets fully drained (or close to it) if (Li_ion_cell.SOC <= 0.01) { diff --git a/src/Battery.int b/src/Battery.int index 11ae575..6700a51 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -167,6 +167,11 @@ this component, see MotorGeneratorMap.int"; description = "Design power for this source."; } + real QDes { + value = 0; IOstatus = "output"; units = "none"; // [kW] + description = "Design Ah for this battery."; + } + real R_0 { value = 0.01; IOstatus = "output"; units = "none"; // [Ohm]; tR_0 in Python boring amprius_battery description = "Static battery output resistance."; @@ -377,10 +382,12 @@ this component, see MotorGeneratorMap.int"; } // Output params common to both on and off design cases. - C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) - dSOCqdt = -C_rate/3600.; + //C_rate = EP_O.S.r / energyDes; // (design power kW * 1 hour) / (design energy in kW-h) kW/kWh + //dSOCqdt = -C_rate/3600.; //(kW/kWh) / (1h/3600s) + C_rate = EP_O.I.r / QDes; // (design power kW * 1 hour) / (design energy in kW-h) kW/kWh + dSOCqdt = -EP_O.I.r/(QDes*3600.); //(kW/kWh) / (1h/3600s) + C_rate = abs(C_rate); // C-rate actually does not typically have an associated sign. - EP_O.S.r; Loss_r = EP_O.I.mag**2 * RTotal; Loss_j = 0; eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); diff --git a/src/BatteryCellSoCTemperatureMap.int b/src/BatteryCellSoCTemperatureMap.int index d759ba7..325b795 100644 --- a/src/BatteryCellSoCTemperatureMap.int +++ b/src/BatteryCellSoCTemperatureMap.int @@ -33,6 +33,7 @@ extern real R_0; extern real R_Th; // Output to tell user what the ACTUAL capacity is. extern real energyDes; +extern real QDes; class BatteryCellSoCTemperatureMap extends Subelement { @@ -79,8 +80,11 @@ class BatteryCellSoCTemperatureMap extends Subelement { value = 10; IOstatus = OUTPUT; units = NONE; // kW-h description = "Energy design capacity for one cell."; } - - real powerDes_cell { + real QDes_cell { + value = 10; IOstatus = OUTPUT; units = NONE; // kW-h + description = "Ah design capacity for one cell."; + } + real powerDes_cell { value = 10; IOstatus = OUTPUT; units = NONE; // kW description = "Power design for one cell."; } @@ -170,6 +174,7 @@ class BatteryCellSoCTemperatureMap extends Subelement { // num_series = ceil(Vout_des/Voc_cell); num_series = Vout_des/Voc_cell; energyDes = energyDes_cell * num_parallel; + QDes = QDes_cell * num_parallel; } // end (switchDes == DESIGN) //---------------------------------------------------------------------- From c26f81524234cb32269665b3c0c27db122b3f248 Mon Sep 17 00:00:00 2001 From: "Thomas, George" Date: Fri, 10 Sep 2021 12:21:35 -0400 Subject: [PATCH 18/24] yet another again --- include/18650_cell.map | 6 +-- model/battery_test.mdl | 5 ++- run/battery_test.run | 58 ++++++++++++++-------------- src/Battery.int | 2 +- src/BatteryCellSoCTemperatureMap.int | 8 ++-- 5 files changed, 40 insertions(+), 39 deletions(-) diff --git a/include/18650_cell.map b/include/18650_cell.map index 84f013f..cda154e 100644 --- a/include/18650_cell.map +++ b/include/18650_cell.map @@ -21,10 +21,10 @@ Subelement BatteryCellSoCTemperatureMap S_map { - // Constant parameters specific to this battery cell. + // Constant parameters specific to this battery cell energyDes_cell = 13./1000.; // kW-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) - powerDes_cell = 3./1000.; //kW - QDes_cell = 3./1000.; //Ah + powerDes_cell = 3; //kW + QDes_cell = 3; //Ah // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) // | To satisfy the TB_Wp socket requirement. diff --git a/model/battery_test.mdl b/model/battery_test.mdl index b8cc216..acb3580 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -39,12 +39,13 @@ Element Battery Li_ion_cell { //BPM TODO: rename Li_ion_cell to something generi setOption("switchThermPort", "TRUE"); Subelement EThermalMass S_eThermMass { Cp = 0.5; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 + //Cp = 1020.; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 } Vout_des = 524; Vout_guess = 520; - SpecificEnergy = 200; //Wh/kg + SpecificEnergy = 2; // Wh/kg //BPM TODO: change SE until NPSS temperature data matches Simulink curve } @@ -58,7 +59,7 @@ Element Cable Cable_Single Element ConstantPowerLoad CLoad { - Pdemand = 120./1000.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) + Pdemand = 120.; // kW (single cell 1 C current is 3.5 Amps, roughly 14 W) eff = 0.999; } diff --git a/run/battery_test.run b/run/battery_test.run index 7064257..7b80a69 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -67,7 +67,7 @@ CASE++; run(); BFPrintOutput(); page.display(); -CLoad.Pdemand = -120./1000.; // kw Charge the battery roughly at 1 C (14 W) +CLoad.Pdemand = -120.; // kw Charge the battery roughly at 1 C (14 W) // Constant power load -14 W for Case 2 CASE++; run(); @@ -75,7 +75,7 @@ BFPrintOutput(); page.display(); // Setup a transient run to match JCC's Simulink data -CLoad.Pdemand = 10./1000.; // initial power point in profile +CLoad.Pdemand = 10.; // initial power point in profile run(); // do another steady-state run just to initialize us. // BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance @@ -97,7 +97,7 @@ transient.setup(); initializeHistory(); autoSolverSetup(); -solver.defaultPerturbation = 0.00001; +solver.defaultPerturbation = 0.000005; solver.defaultDxLimit = 0.001; //solver.solutionMode = "ONE_PASS"; @@ -125,27 +125,27 @@ transientCSVStream << "time" << endl; real time_old = 0; void csvTransientPrint() { + transientCSVStream << Li_ion_cell.Voc << ", "; + transientCSVStream << Li_ion_cell.Vout << ", "; + transientCSVStream << Li_ion_cell.Q_heat << ", "; + transientCSVStream << Li_ion_cell.R_0 << ", "; + transientCSVStream << Li_ion_cell.R_Th << ", "; + transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; + transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; + transientCSVStream << Li_ion_cell.T_batt << ", "; + transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; + transientCSVStream << Li_ion_cell.SOC << ", "; + transientCSVStream << Li_ion_cell.dSOCqdt << ", "; + transientCSVStream << Li_ion_cell.C_rate << ", "; + transientCSVStream << time << endl; + if (time-time_old >= 300) { - transientCSVStream << Li_ion_cell.Voc << ", "; - transientCSVStream << Li_ion_cell.Vout << ", "; - transientCSVStream << Li_ion_cell.Q_heat << ", "; - transientCSVStream << Li_ion_cell.R_0 << ", "; - transientCSVStream << Li_ion_cell.R_Th << ", "; - transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; - transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; - transientCSVStream << Li_ion_cell.T_batt << ", "; - transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; - transientCSVStream << Li_ion_cell.SOC << ", "; - transientCSVStream << Li_ion_cell.dSOCqdt << ", "; - transientCSVStream << Li_ion_cell.C_rate << ", "; - transientCSVStream << time << endl; - cout << "T_batt (oC), " << Li_ion_cell.T_batt << ", "; //cout << "HeatRate (BTU/s), " << Li_ion_cell.Q_heat << ", "; cout << "BattCurrent (A), " << Li_ion_cell.EP_O.I.r << ", "; cout << "BattSOC, " << Li_ion_cell.SOC << ", "; - cout << "BattdSOCqdt, " << Li_ion_cell.dSOCqdt << ", "; + cout << "BattVoltage (V), " << Li_ion_cell.EP_O.V.r << ", "; cout << "C-rate, " << Li_ion_cell.C_rate << ", "; cout << "CASE, " << CASE << ", "; cout << "time (s), " << time << endl; @@ -155,17 +155,17 @@ void csvTransientPrint() void transient_profile() { // Based time points - if ( time < 570 ) { CLoad.Pdemand = 10./1000.; } - else if ( time < 855 ) { CLoad.Pdemand = 0./1000.; } // BPM: if 0 causes failure, put in a small value (0.1) - else if ( time < 1000 ) { CLoad.Pdemand = 119.5/1000. ; } - else if ( time < 1415 ) { CLoad.Pdemand = 0./1000.; } - else if ( time < 1565 ) { CLoad.Pdemand = 120./1000.; } - else if ( time < 3640 ) { CLoad.Pdemand = 60./1000.; } - else if ( time < 4100 ) { CLoad.Pdemand = 18.5/1000.; } - else if ( time < 4620 ) { CLoad.Pdemand = 0.5/1000.; } - else if ( time < 4760 ) { CLoad.Pdemand = 79.5/1000.; } - else if ( time < 5680 ) { CLoad.Pdemand = 6.5/1000.; } - else { CLoad.Pdemand = 0./1000.;} + if ( time < 570 ) { CLoad.Pdemand = 10.; } + else if ( time < 855 ) { CLoad.Pdemand = 0.; } // BPM: if 0 causes failure, put in a small value (0.1) + else if ( time < 1000 ) { CLoad.Pdemand = 119.5 ; } + else if ( time < 1415 ) { CLoad.Pdemand = 0.; } + else if ( time < 1565 ) { CLoad.Pdemand = 120.; } + else if ( time < 3640 ) { CLoad.Pdemand = 60.; } + else if ( time < 4100 ) { CLoad.Pdemand = 18.5; } + else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } + else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } + else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } + else { CLoad.Pdemand = 0.;} // Stop if battery gets fully drained (or close to it) if (Li_ion_cell.SOC <= 0.01) { diff --git a/src/Battery.int b/src/Battery.int index 6700a51..35a7b56 100644 --- a/src/Battery.int +++ b/src/Battery.int @@ -388,7 +388,7 @@ this component, see MotorGeneratorMap.int"; dSOCqdt = -EP_O.I.r/(QDes*3600.); //(kW/kWh) / (1h/3600s) C_rate = abs(C_rate); // C-rate actually does not typically have an associated sign. - Loss_r = EP_O.I.mag**2 * RTotal; + Loss_r = EP_O.I.mag**2 * RTotal / 1000.; Loss_j = 0; eff = (EP_O.S.r / (EP_O.S.r + Loss_r))**sign(EP_O.S.r); real KW_PER_BTU_PER_SEC = 1.05505585; diff --git a/src/BatteryCellSoCTemperatureMap.int b/src/BatteryCellSoCTemperatureMap.int index 325b795..3e20861 100644 --- a/src/BatteryCellSoCTemperatureMap.int +++ b/src/BatteryCellSoCTemperatureMap.int @@ -169,10 +169,10 @@ class BatteryCellSoCTemperatureMap extends Subelement { // On design, we need to size the pack. That is, figure out number of // series and parallel cells in the pack. //---------------------------------------------------------------------- - // num_parallel = max(ceil(powerDes / powerDes_cell),ceil(desired_energyDes / energyDes_cell)); - num_parallel = max((powerDes / powerDes_cell),(desired_energyDes / energyDes_cell)); - // num_series = ceil(Vout_des/Voc_cell); - num_series = Vout_des/Voc_cell; + num_parallel = max(ceil(powerDes / powerDes_cell),ceil(desired_energyDes / energyDes_cell)); + //num_parallel = max((powerDes / powerDes_cell),(desired_energyDes / energyDes_cell)); + num_series = ceil(Vout_des/Voc_cell); + //num_series = Vout_des/Voc_cell; energyDes = energyDes_cell * num_parallel; QDes = QDes_cell * num_parallel; } // end (switchDes == DESIGN) From cd0c5471d39df0da4712031de5a7b85335008311 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Fri, 10 Sep 2021 15:48:54 -0400 Subject: [PATCH 19/24] Values tweaked to better match LTA battery --- model/battery_test.mdl | 2 +- run/battery_test.run | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/model/battery_test.mdl b/model/battery_test.mdl index acb3580..84ba2f1 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -38,7 +38,7 @@ Element Battery Li_ion_cell { //BPM TODO: rename Li_ion_cell to something generi // Set up the thermal port and thermal mass submodel/socket setOption("switchThermPort", "TRUE"); Subelement EThermalMass S_eThermMass { - Cp = 0.5; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 + Cp = 0.75; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 //Cp = 1020.; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 } diff --git a/run/battery_test.run b/run/battery_test.run index 7b80a69..905cb3d 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -81,9 +81,9 @@ run(); // do another steady-state run just to initialize us. // BTW the Simulink model has NO cooling, so to represent that, just zero out the heat transfer resistance TMS.R_cool = 0; -// Also start out the temperature at 20 C to match the data -Li_ion_cell.T_batt = 20; -Li_ion_cell.S_eThermMass.T = 20. * 9./5. + 491.67; // 20 C converted to R +// Also start out the temperature at 22 C to match the data +Li_ion_cell.T_batt = 22; +Li_ion_cell.S_eThermMass.T = 22. * 9./5. + 491.67; // 20 C converted to R // Turn on integrator for battery SOC Li_ion_cell.ind_SOC.autoSetup = TRUE; From 32464a2e2140385f35400118e23eb422951fab91 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Thu, 16 Sep 2021 08:36:57 -0400 Subject: [PATCH 20/24] Updated data more closely matched to Simulink battery model --- include/18650_cell.map | 2 +- include/amprius_cell.map | 2 +- model/battery_test.mdl | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/18650_cell.map b/include/18650_cell.map index cda154e..ae96904 100644 --- a/include/18650_cell.map +++ b/include/18650_cell.map @@ -23,7 +23,7 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell energyDes_cell = 13./1000.; // kW-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) - powerDes_cell = 3; //kW + powerDes_cell = 3.002; //kW QDes_cell = 3; //Ah // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) diff --git a/include/amprius_cell.map b/include/amprius_cell.map index ba4b471..1b7565e 100644 --- a/include/amprius_cell.map +++ b/include/amprius_cell.map @@ -23,7 +23,7 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell. energyDes_cell = 12.75/1000.; // kW-h (3.75 V nominal * 3.4 Ah tested at C/5 discharge) - powerDes_cell = 3./1000.; // kW BPM double-check datasheeet + powerDes_cell = 3./1000.; // kW // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) // | To satisfy the TB_Wp socket requirement. diff --git a/model/battery_test.mdl b/model/battery_test.mdl index 84ba2f1..7de30d2 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -38,15 +38,15 @@ Element Battery Li_ion_cell { //BPM TODO: rename Li_ion_cell to something generi // Set up the thermal port and thermal mass submodel/socket setOption("switchThermPort", "TRUE"); Subelement EThermalMass S_eThermMass { - Cp = 0.75; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 + Cp = 0.90; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 //Cp = 1020.; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 } - Vout_des = 524; + // Vout_des = 524; + Vout_des = 528.5; Vout_guess = 520; SpecificEnergy = 2; // Wh/kg - //BPM TODO: change SE until NPSS temperature data matches Simulink curve } From a5027ce53993721f0908d26d88103cc70f995f04 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Thu, 16 Sep 2021 13:01:44 -0400 Subject: [PATCH 21/24] Improved battery temperature data tracking --- include/18650_cell.map | 2 +- model/battery_test.mdl | 2 +- run/battery_test.run | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/18650_cell.map b/include/18650_cell.map index ae96904..2ae45fe 100644 --- a/include/18650_cell.map +++ b/include/18650_cell.map @@ -23,7 +23,7 @@ Subelement BatteryCellSoCTemperatureMap S_map { // Constant parameters specific to this battery cell energyDes_cell = 13./1000.; // kW-h (3.6 V nominal * 3.0 Ah tested at C/5 discharge) - powerDes_cell = 3.002; //kW + powerDes_cell = 3.005; //kW QDes_cell = 3; //Ah // ---------------------------------------------------------------------- // | Declare a table (or function) named TB_Wp(real SPED, real PR) diff --git a/model/battery_test.mdl b/model/battery_test.mdl index 7de30d2..ab08608 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -38,7 +38,7 @@ Element Battery Li_ion_cell { //BPM TODO: rename Li_ion_cell to something generi // Set up the thermal port and thermal mass submodel/socket setOption("switchThermPort", "TRUE"); Subelement EThermalMass S_eThermMass { - Cp = 0.90; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 + Cp = 0.78; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 //Cp = 1020.; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 } diff --git a/run/battery_test.run b/run/battery_test.run index 905cb3d..c6c7a9c 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -83,7 +83,7 @@ TMS.R_cool = 0; // Also start out the temperature at 22 C to match the data Li_ion_cell.T_batt = 22; -Li_ion_cell.S_eThermMass.T = 22. * 9./5. + 491.67; // 20 C converted to R +Li_ion_cell.S_eThermMass.T = 22. * 9./5. + 491.67; // 22 C converted to R // Turn on integrator for battery SOC Li_ion_cell.ind_SOC.autoSetup = TRUE; @@ -165,11 +165,11 @@ void transient_profile() { else if ( time < 4620 ) { CLoad.Pdemand = 0.5; } else if ( time < 4760 ) { CLoad.Pdemand = 79.5; } else if ( time < 5680 ) { CLoad.Pdemand = 6.5; } - else { CLoad.Pdemand = 0.;} + else if ( time < 6600 ){ CLoad.Pdemand = 0.;} // Stop if battery gets fully drained (or close to it) if (Li_ion_cell.SOC <= 0.01) { - quit(); + // quit(); } } From e0368dd7c61fa0d9df491f91afa9b0ccd4675d17 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Fri, 17 Sep 2021 12:50:34 -0400 Subject: [PATCH 22/24] Improved NPSS-LTA SOC, VOC, and temperature tracking --- model/battery_test.mdl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/battery_test.mdl b/model/battery_test.mdl index ab08608..d1c5028 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -38,7 +38,7 @@ Element Battery Li_ion_cell { //BPM TODO: rename Li_ion_cell to something generi // Set up the thermal port and thermal mass submodel/socket setOption("switchThermPort", "TRUE"); Subelement EThermalMass S_eThermMass { - Cp = 0.78; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 + Cp = 0.95; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 //Cp = 1020.; // J/(kg°C)= (°C)/(1.8∗°R)∗kg/2.205lb∗0.000948BTU/J=0.000239∗ J/(kg°C) -> Simulink: 1020*2*0.000239 = 0.48756, or ~0.5 } From c6627f16aeafff04e47ca4eb49dbfcef53039b04 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Tue, 5 Oct 2021 13:18:10 -0400 Subject: [PATCH 23/24] Removed Amprius cell map, renamed battery element in battery test model --- include/amprius_cell.map | 234 --------------------------------------- model/battery_test.mdl | 2 +- 2 files changed, 1 insertion(+), 235 deletions(-) delete mode 100644 include/amprius_cell.map diff --git a/include/amprius_cell.map b/include/amprius_cell.map deleted file mode 100644 index 1b7565e..0000000 --- a/include/amprius_cell.map +++ /dev/null @@ -1,234 +0,0 @@ -/*** - -------------------------------------------------------------------------------------------- - | | - | NASA Glenn Research Center | - | 21000 Brookpark Rd | - | Cleveland, OH 44135 | - | | - | File Name: amprius_cell.map | - | Author(s): George Thomas and Brian Malone | - | Date(s): August 2021 | - | | - -------------------------------------------------------------------------------------------- -***/ - -// --------------------------------------------------------------- -// | Amprius silicon nanowire Li-ion battery cell map -// --------------------------------------------------------------- -// | Declaration of a new Subelement instance called S_map -// | that is of the type BatteryCellSoCTemperatureMap -// --------------------------------------------------------------- - -Subelement BatteryCellSoCTemperatureMap S_map { - - // Constant parameters specific to this battery cell. - energyDes_cell = 12.75/1000.; // kW-h (3.75 V nominal * 3.4 Ah tested at C/5 discharge) - powerDes_cell = 3./1000.; // kW - // ---------------------------------------------------------------------- - // | Declare a table (or function) named TB_Wp(real SPED, real PR) - // | To satisfy the TB_Wp socket requirement. - // ---------------------------------------------------------------------- - - // Voc vs Temperature and SOC data - Table TB_Voc(real T, real SOC){ - - T = 0.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - Voc = { 3.414,3.414,3.414,3.414,3.42417391,3.44047826, - 3.4546087 ,3.46708696,3.47447826,3.483,3.49295652,3.50752174, - 3.53343478,3.55504348,3.58156522,3.60704348,3.63543478,3.66826087, - 3.70147826,3.73321739,3.76282609,3.81343478,3.87182609,3.91269565, - 3.95313043,3.99395652,4.04556522,4.09230435,4.13904348,4.18726087, - 4.23534783,4.28408696,4.371} - } - T = 20.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - Voc = { 3.36403181,3.37059332,3.37715483,3.38915138,3.41307423,3.43057158, - 3.4458017 ,3.45892471,3.47053977,3.4882561 ,3.50323489,3.51852094, - 3.53543796,3.55665986,3.57962513,3.6050448 ,3.63557688,3.66967577, - 3.70645387,3.74363574,3.78432556,3.83267577,3.88069459,3.92662513, - 3.972807 ,4.02052094,4.06885525,4.11641145,4.16327784,4.20705064, - 4.24888759,4.29225663,4.36} - } - - T = 45.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - Voc = { 3.35947541,3.36927305,3.37804713,3.39274539,3.41529508,3.43271311, - 3.44734836,3.46041189,3.47172951,3.4903084 ,3.50470287,3.52008248, - 3.53732172,3.55863781,3.58149898,3.60732018,3.63787705,3.67212961, - 3.70881352,3.74582684,3.78658607,3.83510451,3.88277664,3.92849898, - 3.9745123 ,4.02208248,4.07013422,4.11750205,4.16411066,4.20763064, - 4.24926434,4.29245492,4.36 } - } - T = 60.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - Voc = { 3.35947541,3.36927305,3.37804713,3.39274539,3.41529508,3.43271311, - 3.44734836,3.46041189,3.47172951,3.4903084 ,3.50470287,3.52008248, - 3.53732172,3.55863781,3.58149898,3.60732018,3.63787705,3.67212961, - 3.70881352,3.74582684,3.78658607,3.83510451,3.88277664,3.92849898, - 3.9745123 ,4.02208248,4.07013422,4.11750205,4.16411066,4.20763064, - 4.24926434,4.29245492,4.36} - } - - T.interp = "linear" ; - T.extrap = "none" ; - - SOC.interp = "linear" ; - SOC.extrap = "none" ; - - extrapIsError = 0; - printExtrap = 0; - - } // end TB_Voc - - // Static output resistance vs Temperature and SOC data - Table TB_R_0(real T, real SOC){ - - T = 0.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_0 = { 0.63391304,0.50347826,0.37304348,0.2426087 ,0.16869565,0.13717391, - 0.12130435,0.10347826,0.10913043,0.1,0.09913043,0.09, - 0.09,0.09,0.09,0.09,0.09,0.09, - 0.09,0.09,0.09,0.08,0.08,0.08, - 0.08,0.08,0.08,0.08,0.08,0.08, - 0.08,0.08 ,0.1} - } - T = 20.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_0 = { 0.55925769,0.40615589,0.25305408,0.12426697,0.08120361,0.06790164, - 0.06,0.06,0.06,0.06,0.06,0.05982635, - 0.05435843,0.05,0.05,0.05,0.05,0.05, - 0.05,0.05,0.05,0.05,0.05,0.05, - 0.05,0.05,0.05,0.05,0.05,0.05, - 0.05,0.05,0.05} - } - T = 45.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_0 = { 0.4154918 ,0.21953893,0.07817623,0.06070184,0.05240779,0.04696465, - 0.04,0.045,0.04063525,0.04,0.04,0.04, - 0.0388627,0.035,0.035,0.035,0.035,0.035, - 0.035,0.03076076,0.03,0.03,0.03,0.03, - 0.03,0.03,0.03,0.03,0.03,0.03, - 0.03,0.03,0.03} - } - T = 60.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_0 = { 0.4154918 ,0.21953893,0.07817623,0.06070184,0.05240779,0.04696465, - 0.045,0.045,0.04063525,0.04,0.04,0.04, - 0.0388627 ,0.035,0.035,0.035,0.035,0.035, - 0.035,0.03076076,0.03,0.03,0.03,0.03, - 0.03,0.03,0.03,0.03,0.03,0.03, - 0.03,0.03,0.03 } - } - - T.interp = "linear" ; - T.extrap = "none" ; - - SOC.interp = "linear" ; - SOC.extrap = "none" ; - - extrapIsError = 0; - printExtrap = 0; - - } // end TB_R_0 - - // Static output resistance vs Temperature and SOC data - Table TB_R_Th(real T, real SOC){ - - T = 0.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_Th = { 0.15782609,0.14695652,0.13608696,0.12521739,0.10869565,0.1 , - 0.0926087 ,0.08173913,0.08 ,0.08 ,0.08 ,0.08 , - 0.08 ,0.08 ,0.08 ,0.08 ,0.08 ,0.08 , - 0.08 ,0.08 ,0.08 ,0.08 ,0.08 ,0.08 , - 0.08 ,0.07804348,0.075 ,0.06652174,0.06 ,0.06 , - 0.06 ,0.06 ,0.06 } - } - T = 20.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_Th = { 0.14989396,0.12802227,0.10615058,0.08713945,0.08 ,0.08 , - 0.06299576,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 } - } - T = 45.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_Th = { 0.11672131,0.09494877,0.08 ,0.08 ,0.08 ,0.08 , - 0.0591291 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.04265881, - 0.04 ,0.03088627,0.03 } - } - T = 60.0 { - SOC = {0., 0.03125, 0.0625 , 0.09375, 0.125 , 0.15625, 0.1875 , 0.21875, - 0.25, 0.28125, 0.3125 , 0.34375, 0.375 , 0.40625, 0.4375 , 0.46875, - 0.5, 0.53125, 0.5625 , 0.59375, 0.625 , 0.65625, 0.6875 , 0.71875, - 0.75, 0.78125, 0.8125 , 0.84375, 0.875 , 0.90625, 0.9375 , 0.96875, - 1.} - R_Th = { 0.11672131,0.09494877,0.08 ,0.08 ,0.08 ,0.08 , - 0.0591291 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.05 , - 0.05 ,0.05 ,0.05 ,0.05 ,0.05 ,0.04265881, - 0.04 ,0.03088627,0.03 } - } - - T.interp = "linear" ; - T.extrap = "none" ; - - SOC.interp = "linear" ; - SOC.extrap = "none" ; - - extrapIsError = 0; - printExtrap = 0; - - } // end TB_R_Th - -} // end S_map (subelement) diff --git a/model/battery_test.mdl b/model/battery_test.mdl index d1c5028..d41fd7d 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -30,7 +30,7 @@ cout<<"======================================="< From 6ec0d917c4aba4eb77ba983a45abaabd193df759 Mon Sep 17 00:00:00 2001 From: Brian Malone Date: Tue, 5 Oct 2021 13:46:36 -0400 Subject: [PATCH 24/24] Fixed battery variable --- model/battery_test.mdl | 24 +++++++-------- run/battery_test.run | 70 +++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/model/battery_test.mdl b/model/battery_test.mdl index d41fd7d..7c8aad2 100644 --- a/model/battery_test.mdl +++ b/model/battery_test.mdl @@ -77,12 +77,12 @@ Element TMS{ Q_O.HeatTransferRate = Q_cool; } } -linkPorts("TMS.Q_O","Li_ion_cell.Q_I","Q1"); +linkPorts("TMS.Q_O","Li_ion_battery.Q_I","Q1"); //------------------------------------------------------------------------------------------------- // Component Linkages //------------------------------------------------------------------------------------------------- -linkPortI( "Li_ion_cell.EP_O", "Cable_Single.EP_I" ); +linkPortI( "Li_ion_battery.EP_O", "Cable_Single.EP_I" ); linkPortI( "Cable_Single.EP_O", "CLoad.EP_I" ); // linkPortI( "CableLeft.EP_O", "DeltaDC.EP_I" ); // linkPortI( "DeltaDC.EP_O", "CableRight.EP_I" ); @@ -90,21 +90,21 @@ linkPortI( "Cable_Single.EP_O", "CLoad.EP_I" ); findSourcesAndPropagate(); -solverSequence = { "Cable_Single", "Li_ion_cell", "CLoad", "TMS" }; +solverSequence = { "Cable_Single", "Li_ion_battery", "CLoad", "TMS" }; void BFPrintOutput() { cout << " Case = " << CASE << endl; - cout << " Battery open circuit voltage = " << Li_ion_cell.Voc << endl; - cout << " Battery output voltage (actual/guess) = " << Li_ion_cell.Vout << "/" << Li_ion_cell.Vout_guess << endl; - cout << " Battery heat balance (Qin/Oout) = " << Li_ion_cell.Q_heat << "/" << Li_ion_cell.Q_I.HeatTransferRate << endl; - // cout << " Battery output Resistance (R_0, R_Th) = " << Li_ion_cell.R_0 << ", " << Li_ion_cell.R_Th << endl; - // cout << " Battery current (calc) = " << (Li_ion_cell.Voc-Li_ion_cell.Vout)/Li_ion_cell.RTotal << endl; - cout << " Battery current/power = " << Li_ion_cell.EP_O.I.r << "/" << Li_ion_cell.EP_O.S.r << endl; + cout << " Battery open circuit voltage = " << Li_ion_battery.Voc << endl; + cout << " Battery output voltage (actual/guess) = " << Li_ion_battery.Vout << "/" << Li_ion_battery.Vout_guess << endl; + cout << " Battery heat balance (Qin/Oout) = " << Li_ion_battery.Q_heat << "/" << Li_ion_battery.Q_I.HeatTransferRate << endl; + // cout << " Battery output Resistance (R_0, R_Th) = " << Li_ion_battery.R_0 << ", " << Li_ion_battery.R_Th << endl; + // cout << " Battery current (calc) = " << (Li_ion_battery.Voc-Li_ion_battery.Vout)/Li_ion_battery.RTotal << endl; + cout << " Battery current/power = " << Li_ion_battery.EP_O.I.r << "/" << Li_ion_battery.EP_O.S.r << endl; cout << " Load power = " << CLoad.P << endl; - cout << " Number of series cells in battery = " << Li_ion_cell.S_map.num_series << endl; - cout << " Number of parallel cells in battery = " << Li_ion_cell.S_map.num_parallel << endl; - cout << " Battery temperature/temp state (oC) = " << Li_ion_cell.T_batt << "/" << (Li_ion_cell.S_eThermMass.T - 491.67)*5./9. << endl; + cout << " Number of series cells in battery = " << Li_ion_battery.S_map.num_series << endl; + cout << " Number of parallel cells in battery = " << Li_ion_battery.S_map.num_parallel << endl; + cout << " Battery temperature/temp state (oC) = " << Li_ion_battery.T_batt << "/" << (Li_ion_battery.S_eThermMass.T - 491.67)*5./9. << endl; // cout << " Cable current (output port) = " << Cable_Single.EP_O.I.r << endl; // cout << " Load input voltage = " << CLoad.EP_I.V.r << endl; // cout << " Load input power = " << CLoad.EP_I.S.r << endl; diff --git a/run/battery_test.run b/run/battery_test.run index c6c7a9c..6e6a57c 100644 --- a/run/battery_test.run +++ b/run/battery_test.run @@ -82,12 +82,12 @@ run(); // do another steady-state run just to initialize us. TMS.R_cool = 0; // Also start out the temperature at 22 C to match the data -Li_ion_cell.T_batt = 22; -Li_ion_cell.S_eThermMass.T = 22. * 9./5. + 491.67; // 22 C converted to R +Li_ion_battery.T_batt = 22; +Li_ion_battery.S_eThermMass.T = 22. * 9./5. + 491.67; // 22 C converted to R // Turn on integrator for battery SOC -Li_ion_cell.ind_SOC.autoSetup = TRUE; -Li_ion_cell.integ_SOC.autoSetup = TRUE; +Li_ion_battery.ind_SOC.autoSetup = TRUE; +Li_ion_battery.integ_SOC.autoSetup = TRUE; setOption("switchDes","OFFDESIGN"); setOption("solutionMode", "TRANSIENT"); @@ -107,46 +107,46 @@ cout << "Transient Solver Vars = " << endl << solver.dependentNames << endl << s OutFileStream transientCSVStream { filename = "output/batt_transient.csv"; } // Write the CSV headers -transientCSVStream << "Li_ion_cell.Voc,"; -transientCSVStream << "Li_ion_cell.Vout,"; -transientCSVStream << "Li_ion_cell.Q_heat,"; -transientCSVStream << "Li_ion_cell.R_0,"; -transientCSVStream << "Li_ion_cell.R_Th,"; -transientCSVStream << "Li_ion_cell.EP_O.I.r,"; -transientCSVStream << "Li_ion_cell.EP_O.S.r,"; -transientCSVStream << "Li_ion_cell.T_batt,"; -transientCSVStream << "Li_ion_cell.S_eThermMass.T,"; -transientCSVStream << "Li_ion_cell.SOC,"; -transientCSVStream << "Li_ion_cell.dSOCqdt,"; -transientCSVStream << "Li_ion_cell.C_rate,"; +transientCSVStream << "Li_ion_battery.Voc,"; +transientCSVStream << "Li_ion_battery.Vout,"; +transientCSVStream << "Li_ion_battery.Q_heat,"; +transientCSVStream << "Li_ion_battery.R_0,"; +transientCSVStream << "Li_ion_battery.R_Th,"; +transientCSVStream << "Li_ion_battery.EP_O.I.r,"; +transientCSVStream << "Li_ion_battery.EP_O.S.r,"; +transientCSVStream << "Li_ion_battery.T_batt,"; +transientCSVStream << "Li_ion_battery.S_eThermMass.T,"; +transientCSVStream << "Li_ion_battery.SOC,"; +transientCSVStream << "Li_ion_battery.dSOCqdt,"; +transientCSVStream << "Li_ion_battery.C_rate,"; transientCSVStream << "time" << endl; // Use a variable to print only every 100 timesteps. real time_old = 0; void csvTransientPrint() { - transientCSVStream << Li_ion_cell.Voc << ", "; - transientCSVStream << Li_ion_cell.Vout << ", "; - transientCSVStream << Li_ion_cell.Q_heat << ", "; - transientCSVStream << Li_ion_cell.R_0 << ", "; - transientCSVStream << Li_ion_cell.R_Th << ", "; - transientCSVStream << Li_ion_cell.EP_O.I.r << ", "; - transientCSVStream << Li_ion_cell.EP_O.S.r << ", "; - transientCSVStream << Li_ion_cell.T_batt << ", "; - transientCSVStream << Li_ion_cell.S_eThermMass.T << ", "; - transientCSVStream << Li_ion_cell.SOC << ", "; - transientCSVStream << Li_ion_cell.dSOCqdt << ", "; - transientCSVStream << Li_ion_cell.C_rate << ", "; + transientCSVStream << Li_ion_battery.Voc << ", "; + transientCSVStream << Li_ion_battery.Vout << ", "; + transientCSVStream << Li_ion_battery.Q_heat << ", "; + transientCSVStream << Li_ion_battery.R_0 << ", "; + transientCSVStream << Li_ion_battery.R_Th << ", "; + transientCSVStream << Li_ion_battery.EP_O.I.r << ", "; + transientCSVStream << Li_ion_battery.EP_O.S.r << ", "; + transientCSVStream << Li_ion_battery.T_batt << ", "; + transientCSVStream << Li_ion_battery.S_eThermMass.T << ", "; + transientCSVStream << Li_ion_battery.SOC << ", "; + transientCSVStream << Li_ion_battery.dSOCqdt << ", "; + transientCSVStream << Li_ion_battery.C_rate << ", "; transientCSVStream << time << endl; if (time-time_old >= 300) { - cout << "T_batt (oC), " << Li_ion_cell.T_batt << ", "; - //cout << "HeatRate (BTU/s), " << Li_ion_cell.Q_heat << ", "; - cout << "BattCurrent (A), " << Li_ion_cell.EP_O.I.r << ", "; - cout << "BattSOC, " << Li_ion_cell.SOC << ", "; - cout << "BattVoltage (V), " << Li_ion_cell.EP_O.V.r << ", "; - cout << "C-rate, " << Li_ion_cell.C_rate << ", "; + cout << "T_batt (oC), " << Li_ion_battery.T_batt << ", "; + //cout << "HeatRate (BTU/s), " << Li_ion_battery.Q_heat << ", "; + cout << "BattCurrent (A), " << Li_ion_battery.EP_O.I.r << ", "; + cout << "BattSOC, " << Li_ion_battery.SOC << ", "; + cout << "BattVoltage (V), " << Li_ion_battery.EP_O.V.r << ", "; + cout << "C-rate, " << Li_ion_battery.C_rate << ", "; cout << "CASE, " << CASE << ", "; cout << "time (s), " << time << endl; time_old = time; @@ -168,7 +168,7 @@ void transient_profile() { else if ( time < 6600 ){ CLoad.Pdemand = 0.;} // Stop if battery gets fully drained (or close to it) - if (Li_ion_cell.SOC <= 0.01) { + if (Li_ion_battery.SOC <= 0.01) { // quit(); } }