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 #3676

Open
wants to merge 46 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
4c1f2ae
first implementation
Dec 27, 2023
ca8b5fe
cleanup
Dec 28, 2023
5422c41
add OM scripts
Dec 28, 2023
f1557a8
update the plot script
Dec 28, 2023
526d305
reference data generation
Dec 28, 2023
5c410d4
improve model doc
Dec 29, 2023
4702143
model restruct
Jan 11, 2024
763d5d2
model doc update
Jan 14, 2024
b0477ad
update release note
Jan 14, 2024
7ddd341
Merge pull request #3620 from SenHuang19/issue3618_airFilter
JayHuLBL Mar 1, 2024
083dc1f
Merge branch 'master' into issue3618_airFilter
JayHuLBL Mar 1, 2024
27d9538
deleted invalid word [ci skip]
JayHuLBL Mar 1, 2024
8e2a608
refactored formatting
JayHuLBL Mar 1, 2024
d3f0636
fixed validation folder
JayHuLBL Mar 1, 2024
87e5370
improved graphic arrangement
JayHuLBL Mar 1, 2024
2602d9c
corrected release note
JayHuLBL Mar 4, 2024
033ac22
merged master
JayHuLBL Apr 10, 2024
0a6a806
changed connector name
JayHuLBL Apr 10, 2024
0be4dbb
improved text [ci skip]
JayHuLBL Apr 10, 2024
54cc4a6
merged master
JayHuLBL Apr 12, 2024
e37292a
add asserts
SenHuang19 Apr 15, 2024
1b6cbae
format update
SenHuang19 Apr 16, 2024
92fe476
Merge pull request #3807 from SenHuang19/issue3618_airFilter
JayHuLBL Apr 19, 2024
f7c67ee
improved text and documentation
JayHuLBL Apr 19, 2024
ed0bd65
added variable in reference results
JayHuLBL Apr 19, 2024
2a98e8a
refactoring and adding an example
SenHuang19 Aug 26, 2024
5d10a8e
script update
SenHuang19 Aug 26, 2024
6c49dab
example update
SenHuang19 Sep 2, 2024
63142ce
ref dataset update
SenHuang19 Sep 2, 2024
db1b8b0
model doc update and small issues fix
SenHuang19 Sep 2, 2024
021d6b7
model doc improve
SenHuang19 Sep 3, 2024
a11b196
typos fix
SenHuang19 Sep 4, 2024
7e1f587
minor fix
SenHuang19 Sep 4, 2024
07ad4e9
minor doc update
SenHuang19 Sep 25, 2024
f649536
model doc enhance and move the per to the top level class
Nov 8, 2024
d3a9dfe
model doc improve
Nov 11, 2024
5fd768e
eliminate unnecessary calculations
Nov 12, 2024
2f7c2f2
minor model doc update
Nov 13, 2024
b731d7a
update the file name
Nov 13, 2024
d53922b
fix typo
Nov 13, 2024
929e92b
Merge pull request #3986 from SenHuang19/issue3618_airFilter
JayHuLBL Nov 20, 2024
2a5e2c1
merged master
JayHuLBL Nov 20, 2024
18e0ad8
corrected package order
JayHuLBL Nov 20, 2024
c70d36a
updated reference
JayHuLBL Nov 20, 2024
53a0558
Deleted openmodelica script
JayHuLBL Nov 20, 2024
e746684
improved code
JayHuLBL Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions Buildings/Fluid/AirFilters/BaseClasses/FiltrationEfficiency.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
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";
Buildings.Controls.OBC.CDL.Interfaces.RealInput mCon(
final unit="kg")
"Mass of the contaminant captured by the filter"
annotation (Placement(
transformation(
extent={{20,-20},{-20,20}},
rotation=180,
origin={-120,0}), iconTransformation(
extent={{-20,-20},{20,20}},
rotation=0,
origin={-120,0})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput y(
final unit="1",
final min=0,
final max=1)
"Filtration efficiency"
annotation (Placement(transformation(extent={{100,-80},{140,-40}}),
iconTransformation(extent={{100,-80},{140,-40}})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput rat(
final unit="1",
Copy link
Contributor Author

@JayHuLBL JayHuLBL Jan 2, 2025

Choose a reason for hiding this comment

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

In this class, the rat is a scale variable, while in class Buildings.Fluid.AirFilters.BaseClasses.Characteristics.FiltrationEfficiencyParameters, the rat is a vector. Are they same or different?
Through commit e746684, I removed each declaration. Is it a correct change? As in Modelica, each should only be used by the vector variable declaration.

Choose a reason for hiding this comment

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

Buildings.Fluid.AirFilters.BaseClasses.FilterationEfficiency defines rat while in Buildings.Fluid.AirFilters.BaseClasses.Characteristics.FiltrationEfficiencyParameters, we declare a list of rat and each rat corresponds to a specific type of containment. Should I rename the rat in Buildings.Fluid.AirFilters.BaseClasses.Characteristics.FiltrationEfficiencyParameters to avoid confusions?

final min=0,
final max=1)
"Relative mass of the contaminant captured by the filter"
annotation (Placement(transformation(extent={{100,40},{140,80}}),
iconTransformation(extent={{100,40},{140,80}})));

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 should be in the range of [0, 1],
check the filter efficiency curve.",
level=AssertionLevel.error);

annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(
extent={{-100,100},{100,-100}},
lineColor={28,108,200},
fillColor={255,255,255},
fillPattern=FillPattern.Solid),
Text(
extent={{-100,140},{100,100}},
textColor={0,0,255},
textString="%name")}),
Diagram(coordinateSystem(preserveAspectRatio=false)),
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>;
</p>
<p>
The <i>rat</i> is the relative mass of the contaminant captured by the filter
and is calculated by
</p>
<p align=\"center\" style=\"font-style:italic;\">
rat = mCon/mCon_nominal,
</p>
<p>
where <i>mCon</i> is the mass of the contaminant captured by the filter,
<i>mCon_nominal</i> is the maximum mass of the contaminant captured by the filter.
</p>
<P>
<b>Note:</b>
The upper limit of <i>rat</i> is 1 and any value above it is overwritten by 1.
</p>
</html>", revisions="<html>
<ul>
<li>
December 22, 2023, by Sen Huang:<br/>
First implementation.
</li>
</ul>
</html>"));
end FiltrationEfficiency;
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
within Buildings.Fluid.AirFilters.BaseClasses;
model FlowCoefficientCorrection
"Component that calculates the flow coefficient correction factor"
parameter Real b(
final min = 1 + 1E-3)
"Resistance coefficient";
Buildings.Controls.OBC.CDL.Interfaces.RealInput rat(
final unit="1",
final min=0,
final max=1)
"Relative mass of the contaminant captured by the filter"
annotation (Placement(
transformation(
extent={{20,-20},{-20,20}},
rotation=180,
origin={-120,0}), iconTransformation(
extent={{-20,-20},{20,20}},
rotation=0,
origin={-120,0})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput y(
final unit="1",
final min=1)
"Flow coefficient correction"
annotation (Placement(transformation(extent={{100,-20},{140,20}}),
iconTransformation(extent={{100,-20},{140,20}})));
equation
y = b^rat;
annotation (Dialog(group="Pressure"),
Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(
extent={{-100,100},{100,-100}},
lineColor={28,108,200},
fillColor={255,255,255},
fillPattern=FillPattern.Solid),
Text(
extent={{-100,140},{100,100}},
textColor={0,0,255},
textString="%name")}),
Diagram(coordinateSystem(preserveAspectRatio=false)),
defaultComponentName="kCor",
Documentation(info="<html>
<p>
This model calculates the flow coefficient of the filter by
</p>
<p align=\"center\" style=\"font-style:italic;\">
kCor = b<sup>rat</sup>,
</p>
<p>
where <code>b</code> is the resistance coefficient and it has to be greater than 1,
<code>rat</code> is the relative mass of the contaminant captured by the filter
(see descriptions in
<a href=\"modelica://Buildings.Fluid.AirFilters.BaseClasses.FiltrationEfficiency\">
Buildings.Fluid.AirFilters.BaseClasses.FiltrationEfficiency</a>).
</p>
<h4>References</h4>
<p>
Qiang Li ta al., (2022). Experimental study on the synthetic dust loading characteristics of air filters.
Separation and Purification Technology 284 (2022), 120209
</p>
</html>", revisions="<html>
<ul>
<li>
December 22, 2023, by Sen Huang:<br/>
First implementation.
</li>
</ul>
</html>"));
end FlowCoefficientCorrection;
98 changes: 98 additions & 0 deletions Buildings/Fluid/AirFilters/BaseClasses/MassAccumulation.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
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 Real mCon_reset(
final min = 0)
"Initial contaminant mass of the filter after replacement";
Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uRep
"Replacing the filter when trigger becomes true"
annotation (Placement(
transformation(
extent={{20,-20},{-20,20}},
rotation=180,
origin={-120,-60}), iconTransformation(
extent={{-20,-20},{20,20}},
rotation=0,
origin={-120,-62})));
Buildings.Controls.OBC.CDL.Interfaces.RealInput mCon_flow(
final unit = "kg/s")
"Contaminant mass flow rate"
annotation (Placement(transformation(
extent={{20,-20},{-20,20}},
rotation=180,
origin={-120,60}), iconTransformation(
extent={{-20,-20},{20,20}},
rotation=0,
origin={-120,60})));
Buildings.Controls.OBC.CDL.Interfaces.RealOutput mCon(
final unit = "kg")
"Mass of the contaminant captured by the filter"
annotation (Placement(transformation(extent={{100,-20},{140,20}}),
iconTransformation(extent={{100,-20},{140,20}})));
Buildings.Controls.OBC.CDL.Reals.IntegratorWithReset intWitRes
"Calculate the mass of contaminant"
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
Buildings.Controls.OBC.CDL.Reals.Sources.Constant con(
final k=mCon_reset)
"Constant"
annotation (Placement(transformation(extent={{-80,-30},{-60,-10}})));
Modelica.Blocks.Logical.Greater greater
"Check if the filter is full"
annotation (Placement(transformation(extent={{40,-48},{60,-28}})));
Buildings.Controls.OBC.CDL.Reals.Sources.Constant con1(
final k=mCon_nominal)
"Constant"
annotation (Placement(transformation(extent={{0,40},{20,60}})));
Buildings.Controls.OBC.CDL.Utilities.Assert assMes(
message="In " + getInstanceName() + ":the filter needs to be replaced")
"Error message when the filter is full, i.e., the mass captured by the filter is larger than the nominal value"
annotation (Placement(transformation(extent={{72,-48},{92,-28}})));
equation
connect(intWitRes.u, mCon_flow) annotation (Line(points={{-12,0},{-40,0},{-40,
60},{-120,60}}, 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)
annotation (Line(points={{-58,-20},{-20,-20},
{-20,-8},{-12,-8}},color={0,0,127}));
connect(intWitRes.trigger, uRep)
annotation (Line(points={{0,-12},{0,-60},{-120,-60}}, color={255,0,255}));
connect(assMes.u, greater.y)
annotation (Line(points={{70,-38},{61,-38}}, color={255,0,255}));
connect(greater.u2, intWitRes.y)
annotation (Line(points={{38,-46},{20,-46},{20,
0},{12,0}}, color={0,0,127}));
connect(con1.y, greater.u1)
annotation (Line(points={{22,50},{30,50},{30,-38},
{38,-38}}, color={0,0,127}));
annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(
extent={{-100,100},{100,-100}},
lineColor={28,108,200},
fillColor={255,255,255},
fillPattern=FillPattern.Solid),
Text(
extent={{-100,140},{100,100}},
textColor={0,0,255},
textString="%name")}),
Diagram(coordinateSystem(
preserveAspectRatio=false)),
defaultComponentName="masAcc",
Documentation(info="<html>
<p>
This model mimics the process for a filter to capture the contaminants.
The mass of the contaminants, <code>mCon</code>, increases by time.
However, when the input signal <code>uRep</code> changes from <code>false</code>
to <code>true</code>, <code>mCon</code> is reinitialized to a constant, <code>mCon_reset</code>.
</p>
</html>", revisions="<html>
<ul>
<li>
December 22, 2023, by Sen Huang:<br/>
First implementation.
</li>
</ul>
</html>"));
end MassAccumulation;
83 changes: 83 additions & 0 deletions Buildings/Fluid/AirFilters/BaseClasses/MassTransfer.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
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=270,
origin={0,120}), iconTransformation(
extent={{-20,-20},{20,20}},
rotation=270,
origin={0,120})));
Buildings.Controls.OBC.CDL.Interfaces.RealInput eps(
final unit = "1",
final min = 0,
final max= 1)
"Mass transfer coefficient"
annotation (Placement(transformation(
extent={{20,-20},{-20,20}},
rotation=180,
origin={-120,60}), iconTransformation(
extent={{-20,-20},{20,20}},
rotation=0,
origin={-120,60})));
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;
// Mass balance (no storage).
port_a.Xi_outflow = inStream(port_b.Xi_outflow);
port_b.Xi_outflow = inStream(port_a.Xi_outflow);
port_a.m_flow = -port_b.m_flow;
// Pressure balance (no pressure drop).
port_a.p = port_b.p;
// Energy balance (no heat exchange).
port_a.h_outflow = inStream(port_b.h_outflow);
port_b.h_outflow = inStream(port_a.h_outflow);

if not allowFlowReversal then
assert(m_flow > -m_flow_small,
"In " + getInstanceName() + ":Reverting flow occurs even though allowFlowReversal is false",
level=AssertionLevel.error);
end if;

annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(
extent={{-100,100},{100,-100}},
fillColor={255,255,255},
fillPattern=FillPattern.Solid,
pattern=LinePattern.None)}), Diagram(
coordinateSystem(preserveAspectRatio=false)),
defaultComponentName="masTra",
Documentation(info="<html>
<p>
This model sets the trace substance
of the medium that leaves <code>port_b</code> by
</p>
<pre>
port_b.C_outflow = inStream(port_a.C_outflow) - eps * C_inflow;
</pre>
<p>
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>.
</p>
</html>", revisions="<html>
<ul>
<li>
December 22, 2023, by Sen Huang:<br/>
First implementation.
</li>
</ul>
</html>"));
end MassTransfer;
Loading