Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue3618 air filter #3986

Merged
merged 15 commits into from
Nov 20, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
within Buildings.Fluid.AirFilters.BaseClasses.Characteristics;
record filtrationEfficiencyParameters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change name to FiltrationEfficiencyParameters

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The record name has been changed.

"Record for filtration efficiency vs. relative mass of the contaminant captured by the filter"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use versus, rather than vs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace versus with vs.

extends Modelica.Icons.Record;
parameter Real rat[:,:](each max=1, each min=0)
"Relative mass of the contaminant captured by the filter";
parameter Real eps[:,:](each max=1, each min=0)
"Filtration efficiency";

annotation (Documentation(info="<html>
<p>
Data record that describes the relative mass of the contaminant captured by the filter <code>rat</code> versus
the filtration efficiency <code>eps</code>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data record that describes the relative mass of the contaminant <code>rat</code> captured by the filter when it has the filtration efficiency specified as <code>eps</code>.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update it as suggested

The elements of the vector <code>rat</code> should be in ascending order,
i.e.,<code>rat[i] &lt; rat[i+1]</code>.
Both vectors, <code>rat</code> and <code>eps</code>
must have the same size.
</p>
</html>", revisions="<html>
<ul>
<li>
June 27, 2023, by Sen Huang:<br/>
First implementation.
</li>
</ul>
</html>"));
end filtrationEfficiencyParameters;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
within Buildings.Fluid.AirFilters.BaseClasses;
package Characteristics "Functions for filter characteristics"

annotation (Documentation(info="<html>
<p>
This package implements performance curves for air filters.
</p>
</html>"));
end Characteristics;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
filtrationEfficiencyParameters
49 changes: 49 additions & 0 deletions Buildings/Fluid/AirFilters/BaseClasses/Data/Generic.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
within Buildings.Fluid.AirFilters.BaseClasses.Data;
record Generic "Generic data record for air filters"
extends Modelica.Icons.Record;
parameter Real mCon_nominal(
final unit = "kg")
"Maximum mass of the contaminant can be captured by the filter";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maximum mass of the contaminant that can be ...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the typo.

parameter String substanceName[:] = {"CO2"}
"Name of trace substance";
parameter
Buildings.Fluid.AirFilters.BaseClasses.Characteristics.filtrationEfficiencyParameters
filterationEfficiencyParameters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may use shorter parameter name, like filEffPar

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace filterationEfficiencyParameters with filEffPar

"Filtration efficiency vs. relative mass of the contaminant";
parameter Real b = 1.1
"Resistance coefficient";
annotation (
defaultComponentPrefixes = "parameter",
defaultComponentName = "per",
Documentation(revisions="<html>
<ul>
<li>
June 27, 2023, by Sen Huang:<br/>
First implementation.
</li>
</ul>
</html>", info="<html>
<p>
Record containing performance parameters for air filters.
</p>
<p>
It is used as a template of performance data
for the variable-speed wheel models in
<a href=\"modelica://Buildings.Fluid.AirFilters\">
Buildings.Fluid.AirFilters</a>.
</p>
<p>
The record contains one dataset:
relative mass of the contaminant
(see <a href=\"modelica://Buildings.Fluid.AirFilters.BaseClasses.FiltrationEfficiency\">
Copy link
Contributor

@JayHuLBL JayHuLBL Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it the right link to the right class? I think it should like to Buildings.Fluid.AirFilters.BaseClasses.Characteristics.filtrationEfficiencyParameters?

Or you may mean The record contains one dataset <Characteristics.filtrationEfficiencyParameters> for <Buildings.Fluid.AirFilters.BaseClasses.FiltrationEfficiency>?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant the definition of the relative mass is provided in modelica://Buildings.Fluid.AirFilters.BaseClasses.FiltrationEfficiency.
I update the document to avoid confusions.

Buildings.Fluid.AirFilters.BaseClasses.FiltrationEfficiency</a>)
versus filtration efficiency.
</p>
<p>
It also contains a parameter that defines how the pressure drop
changes by the relative mass of the contaminant
(see <a href=\"modelica://Buildings.Fluid.AirFilters.BaseClasses.FlowCoefficientCorrection\">
Buildings.Fluid.AirFilters.BaseClasses.FlowCoefficientCorrection</a>).
</p>
</html>"));
end Generic;
10 changes: 10 additions & 0 deletions Buildings/Fluid/AirFilters/BaseClasses/Data/package.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
within Buildings.Fluid.AirFilters.BaseClasses;
package Data "Performance data for air filters"
extends Modelica.Icons.MaterialPropertiesPackage;

annotation (Documentation(info="<html>
<p>
This package contains data for air filters.
</p>
</html>"));
end Data;
1 change: 1 addition & 0 deletions Buildings/Fluid/AirFilters/BaseClasses/Data/package.order
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic
58 changes: 28 additions & 30 deletions Buildings/Fluid/AirFilters/BaseClasses/FiltrationEfficiency.mo
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
within Buildings.Fluid.AirFilters.BaseClasses;
model FiltrationEfficiency
"Component that calculates the filtration efficiency"
parameter Real mCon_nominal(
final unit="kg")
"Maximum mass of the contaminant can be captured by the filter";
parameter Real epsFun[:]
"Filtration efficiency curve";
parameter Buildings.Fluid.AirFilters.BaseClasses.Data.Generic per
"Record with performance data"
annotation (Placement(transformation(extent={{20,62},{40,82}})));
Buildings.Controls.OBC.CDL.Interfaces.RealInput mCon(
final unit="kg")
"Mass of the contaminant captured by the filter"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput y(
final unit="1",
final min=0,
final max=1)
"Filtration efficiency"
Buildings.Controls.OBC.CDL.Interfaces.RealOutput y[size(per.substanceName, 1)](
each final unit="1",
each final min=0,
each final max=1) "Filtration efficiency"
annotation (Placement(transformation(extent={{100,-80},{140,-40}})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput rat(
final unit="1",
final min=0,
final max=1)
each final unit="1",
each final min=0,
each final max=1)
"Relative mass of the contaminant captured by the filter"
annotation (Placement(transformation(extent={{100,40},{140,80}})));

Copy link
Contributor

@JayHuLBL JayHuLBL Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a protected section to find out the total types of the contaminant

protected
  parameter Integer nConSub = size(per.substanceName,1) "Total types of contaminant substances";

and then
change above y[size(per.substanceName,1) to y[nConSub], and below the for loop.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change it as suggested

equation
rat = Buildings.Utilities.Math.Functions.smoothMin(x1=1, x2= mCon/mCon_nominal, deltaX=0.1);
y = Buildings.Utilities.Math.Functions.polynomial(a=epsFun, x=rat);
assert(
y > 0 and y < 1,
"In " + getInstanceName() + ": The filter efficiency has to be in the range of [0, 1],
check the filter efficiency curve.",
level=AssertionLevel.error);

rat = Buildings.Utilities.Math.Functions.smoothMin(
x1=1,
x2= mCon/per.mCon_nominal,
deltaX=0.1)
"Calculate the relative mass of the contaminant captured by the filter";
for i in 1:size(per.substanceName, 1) loop
y[i] = Buildings.Utilities.Math.Functions.smoothInterpolation(
x=rat,
xSup=per.filterationEfficiencyParameters.rat[i],
ySup=per.filterationEfficiencyParameters.eps[i])
"Calculate the filtration efficiency";
end for;
annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(
extent={{-100,100},{100,-100}},
Expand All @@ -46,13 +46,11 @@ annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
defaultComponentName="eps",
Documentation(info="<html>
<p>
This model calculates the filtration efficiency, <i>eps</i>, by
</p>
<p align=\"center\" style=\"font-style:italic;\">
eps = epsFun<sub>1</sub> + epsFun<sub>2</sub>rat + epsFun<sub>3</sub> rat<sup>2</sup> + ...,
</p>
<p>
where the coefficients <i>epsFun<sub>i</sub></i> are declared by the parameter <i>epsFun</i>;
This model calculates the filtration efficiency, <i>eps</i>, based on the cubic hermite spline interpolation of
the filter dataset (see
<a href=\"modelica://Buildings.Fluid.AirFilters.BaseClasses.Characteristics.filtrationEfficiencyParameters\">
Buildings.Fluid.AirFilters.BaseClasses.Characteristics.filtrationEfficiencyParameters</a>)
with respect to <i>rat</i>.
</p>
<p>
The <i>rat</i> is the relative mass of the contaminant captured by the filter
Expand All @@ -62,7 +60,7 @@ and is calculated by
rat = mCon/mCon_nominal,
</p>
<p>
where <i>mCon</i> is the mass of the contaminant captured by the filter,
where <i>mCon</i> is the mass of the contaminant captured by the filter, and
<i>mCon_nominal</i> is the maximum mass of the contaminant captured by the filter.
</p>
<P>
Expand Down
26 changes: 14 additions & 12 deletions Buildings/Fluid/AirFilters/BaseClasses/FlowCoefficientCorrection.mo
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
within Buildings.Fluid.AirFilters.BaseClasses;
model FlowCoefficientCorrection
"Component that calculates the flow coefficient correction factor"
parameter Real b
"Resistance coefficient";
parameter Buildings.Fluid.AirFilters.BaseClasses.Data.Generic per
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to instantiate the per parameter in the base class? I think it may be enough to have the per been instantiated only in the top level class, i.e. Buildings.Fluid.AirFilters.Empirical.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change it as suggested

"Record with performance data"
annotation (Placement(transformation(extent={{20,62},{40,82}})));
Buildings.Controls.OBC.CDL.Interfaces.RealInput rat(
final unit="1",
final min=0,
final max=1)
each final unit="1",
each final min=0,
each final max=1)
"Relative mass of the contaminant captured by the filter"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput y(
final unit="1",
final min=1)
each final unit="1",
each final min=1)
"Flow coefficient correction"
annotation (Placement(transformation(extent={{100,-20},{140,20}})));

initial equation
assert(b > 1,
"In " + getInstanceName() + ": Resistance coefficient has to be greater than 1.",
level=AssertionLevel.error);
assert(per.b - 1.0 > 0.01,
"In " + getInstanceName() + ":The resistance coefficient should be larger
than 1",
level = AssertionLevel.error)
"Validate the resistance coefficient";
equation
y = b^rat;
y = per.b^rat;

annotation (defaultComponentName="coeCor",
Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Expand Down
23 changes: 15 additions & 8 deletions Buildings/Fluid/AirFilters/BaseClasses/MassAccumulation.mo
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
within Buildings.Fluid.AirFilters.BaseClasses;
model MassAccumulation
"Component that mimics the accumulation of the contaminants"
parameter Real mCon_nominal
"Maximum mass of the contaminant captured by the filter";
parameter Integer nin(
min=1)=1
"Number of input connections";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mean the total types of contaminant substances? So can we change the nin to nConSub and change the comment to Total number of contaminant substance types?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change it as suggested

parameter Buildings.Fluid.AirFilters.BaseClasses.Data.Generic per
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is no need to have the per parameter. We just need the nominal contaminant mass. Why don't we keep the mCon_nominal?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change it as suggested

"Record with performance dat"
annotation (Placement(transformation(extent={{20,62},{40,82}})));
parameter Real mCon_reset(
final min = 0)
"Initial contaminant mass of the filter after replacement";
Buildings.Controls.OBC.CDL.Interfaces.RealInput mCon_flow(
final unit = "kg/s")
Buildings.Controls.OBC.CDL.Interfaces.RealInput mCon_flow[nin](
each final unit="kg/s")
"Contaminant mass flow rate"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uRep
Expand All @@ -28,17 +32,17 @@ model MassAccumulation
"Check if the filter is full"
annotation (Placement(transformation(extent={{40,40},{60,60}})));
Buildings.Controls.OBC.CDL.Reals.Sources.Constant con1(
final k=mCon_nominal)
final k=per.mCon_nominal)
"Constant"
annotation (Placement(transformation(extent={{-20,40},{0,60}})));
Buildings.Controls.OBC.CDL.Utilities.Assert assMes(
message="In " + getInstanceName() + ": The filter needs to be replaced.")
"Warning message when the filter is full"
annotation (Placement(transformation(extent={{72,40},{92,60}})));
Buildings.Controls.OBC.CDL.Reals.MultiSum mulSum(nin=nin) "Summation of the inputs"
annotation (Placement(transformation(extent={{-52,-10},{-32,10}})));

equation
connect(intWitRes.u, mCon_flow)
annotation (Line(points={{-12,0},{-120,0}}, color={0,0,127}));
connect(intWitRes.y, mCon)
annotation (Line(points={{12,0},{120,0}}, color={0,0,127}));
connect(con.y, intWitRes.y_reset_in)
Expand All @@ -51,7 +55,10 @@ equation
annotation (Line(points={{38,42},{20,42},{20,0},{12,0}}, color={0,0,127}));
connect(con1.y, greater.u1)
annotation (Line(points={{2,50},{38,50}}, color={0,0,127}));

connect(mulSum.y, intWitRes.u)
annotation (Line(points={{-30,0},{-12,0}}, color={0,0,127}));
connect(mulSum.u, mCon_flow)
annotation (Line(points={{-54,0},{-120,0}}, color={0,0,127}));
annotation (defaultComponentName="masAcc",
Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(extent={{-100,100},{100,-100}}, lineColor={28,108,200},
Expand Down
84 changes: 66 additions & 18 deletions Buildings/Fluid/AirFilters/BaseClasses/MassTransfer.mo
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,75 @@ within Buildings.Fluid.AirFilters.BaseClasses;
model MassTransfer
"Component that sets the trace substance at port_b based on an input trace substance mass flow rate and an input mass transfer efficiency"
extends Buildings.Fluid.Interfaces.PartialTwoPortInterface;
Buildings.Controls.OBC.CDL.Interfaces.RealInput C_inflow[Medium.nC]
"Input trace substance rate"
annotation (Placement(transformation(extent={{-20,-20},{20,20}},
rotation=-90, origin={0,120})));
Buildings.Controls.OBC.CDL.Interfaces.RealInput eps(
final unit = "1",
final min = 0,
final max= 1)
parameter String substanceName[:] = {"CO2"}
"Name of trace substance";
Buildings.Controls.OBC.CDL.Interfaces.RealInput eps[size(substanceName,1)](
each final unit = "1",
each final min = 0,
each final max= 1)
"Mass transfer coefficient"
annotation (Placement(transformation(extent={{-140,40},{-100,80}})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput mCon_flow[size(substanceName,1)](
each final unit = "kg/s")
"Contaminant mass flow rate"
annotation (Placement(transformation(extent={{100,40},{140,80}})));

protected
parameter Real s1[:,:]= {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can add the parameter nConSub in the protected section and defined it as nConSub=size(substanceName,1). This will avoid calculating the size(substanceName,1) multiple times.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change it as suggested

{if (Modelica.Utilities.Strings.isEqual(string1=Medium.extraPropertiesNames[i],
string2=substanceName[j],
caseSensitive=false))
then 1 else 0 for i in 1:Medium.nC}
for j in 1:size(substanceName,1)}
"Vector to check if the trace substances are included in the medium"
annotation(Evaluate=true);
parameter Real s2[:,:]= {
{if (Modelica.Utilities.Strings.isEqual(string1=Medium.extraPropertiesNames[i],
string2=substanceName[j],
caseSensitive=false))
then 1 else 0 for i in 1:size(substanceName,1)}
for j in 1:Medium.nC}
"Vector to check if the trace substances in the medium are included in the performance dataset"
annotation(Evaluate=true);
initial equation
assert(abs(sum(s1) - size(substanceName,1)) < 0.1,
"In " + getInstanceName() + ":Some specified trace substances are
not present in medium '" + Medium.mediumName + "'.\n"
+ "Check filter parameter and medium model.",
level = AssertionLevel.warning)
"Check if all the specified substances are included in the medium";

equation
if allowFlowReversal then
port_b.C_outflow =inStream(port_a.C_outflow) - eps*C_inflow;
port_a.C_outflow = inStream(port_a.C_outflow);
else
port_b.C_outflow = inStream(port_a.C_outflow);
port_a.C_outflow = inStream(port_b.C_outflow);
end if;
// Modify the substances individually.
for i in 1:Medium.nC loop
if max(s2[i]) > 0.9 then
for j in 1:size(substanceName,1) loop
if (Modelica.Utilities.Strings.isEqual(string1=Medium.extraPropertiesNames[i],
string2=substanceName[j],
caseSensitive=false)) then
port_b.C_outflow[i] =inStream(port_a.C_outflow[i])*(1 - eps[j]);
port_a.C_outflow[i] = inStream(port_a.C_outflow[i]);
end if;
end for;
else
port_b.C_outflow[i] = inStream(port_a.C_outflow[i]);
port_a.C_outflow[i] = inStream(port_b.C_outflow[i]);
end if;
end for;
// Calculate the amount of removed contaminants.
for i in 1:size(substanceName,1) loop
if max(s1[i]) > 0.9 then
for j in 1:Medium.nC loop
if (Modelica.Utilities.Strings.isEqual(string1=Medium.extraPropertiesNames[j],
string2=substanceName[i],
caseSensitive=false)) then
mCon_flow[i] = inStream(port_a.C_outflow[j])* eps[i];
end if;
end for;
else
mCon_flow[i] = 0;
end if;
end for;
// Mass balance (no storage).
port_a.Xi_outflow = inStream(port_b.Xi_outflow);
port_b.Xi_outflow = inStream(port_a.Xi_outflow);
Expand Down Expand Up @@ -55,9 +105,7 @@ where <code>eps</code> is an input mass transfer efficiency and
<code>C_inflow</code> is an input trace substance rate.
</p>
<p>
This model has no pressure drop. In the case of reverse flow,
the fluid that leaves <code>port_a</code> has the same
properties as the fluid that enters <code>port_b</code>.
This model has no pressure drop.
</p>
</html>", revisions="<html>
<ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ This block is implemented based on
<a href=\"modelica://Buildings.Fluid.FixedResistances.PressureDrop\">
Buildings.Fluid.FixedResistances.PressureDrop</a>
and inherits most of its configuration.
However, it is different when calculating the mass flow rate
However, its mass flow rate is calculated differently by
</p>
<p align=\"center\" style=\"font-style:italic;\">
m&#775; = m_flow_nominal/(&radic;<span style=\"text-decoration:overline;\">dp_nominal*kCor</span>)
Expand Down
Loading