Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
188 changes: 167 additions & 21 deletions Modelica/Blocks/Math.mo
Original file line number Diff line number Diff line change
Expand Up @@ -2299,37 +2299,64 @@ explicitly set to 0.0, if the mean value results in a negative value.
textString="f=%f")}));
end Mean;

block RectifiedMean "Calculate rectified mean over period 1/f"
block TriggeredMean "Calculate mean over period determined by trigger"
extends Modelica.Blocks.Interfaces.SISO;
parameter SI.Frequency f(start=50) "Base frequency";
import Modelica.Constants.eps;
parameter Real x0=0 "Start value of integrator state";
parameter Real y0(final min=0)=0 "Start value of output";
Mean mean(final f=f, final x0=x0,
final y0=y0)
annotation (Placement(transformation(extent={{0,-10},{20,10}})));
Blocks.Math.Abs abs1
annotation (Placement(transformation(extent={{-60,-10},{-40,10}})));
parameter Real y0=0 "Start value of output";
parameter Boolean yGreaterOrEqualZero=false
"= true, if output y is guaranteed to be >= 0 for the exact solution"
annotation (Evaluate=true, Dialog(tab="Advanced"));
Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input signal"
annotation (Placement(
transformation(
extent={{-20,-20},{20,20}},
rotation=90,
origin={0,-120})));
protected
Modelica.Units.SI.Time t0 "Last trigger instance";
Real x "Integrator state";
discrete Real y_last "Last sampled mean value";
initial equation
pre(trigger)=false;
t0 = time;
x = x0;
y_last = y0;
equation
connect(u, abs1.u) annotation (Line(
points={{-120,0},{-62,0}}, color={0,0,127}));
connect(abs1.y, mean.u) annotation (Line(
points={{-39,0},{-2,0}}, color={0,0,127}));
connect(mean.y, y) annotation (Line(
points={{21,0},{110,0}}, color={0,0,127}));
der(x) = u;
when edge(trigger) then
y_last = if noEvent((time - pre(t0))>eps) then
if not yGreaterOrEqualZero then pre(x)/(time - pre(t0))
else max(0.0, pre(x)/(time - pre(t0)))
else pre(y_last);
t0 = time;
reinit(x, 0);
end when;
y = y_last;
annotation (Documentation(info="<html>
<p>
This block calculates the rectified mean of the input signal u over the given period 1/f, using the
<a href=\"modelica://Modelica.Blocks.Math.Mean\">mean block</a>.
This block calculates the mean of the input signal u over the period dtermined by the edges of the trigger:
</p>
<blockquote><pre>
1 T
---- &int; u(t) dt
T-t0 t0
</pre></blockquote>
<p>
Note: The output is updated after each period defined by 1/f.
Note: The output is updated at each trigger instance.
</p>

<p>
If parameter <strong>yGreaterOrEqualZero</strong> in the Advanced tab is <strong>true</strong> (default = <strong>false</strong>),
then the modeller provides the information that the mean of the input signal is guaranteed
to be &ge; 0 for the exact solution. However, due to inaccuracies in the numerical integration scheme,
the output might be slightly negative. If this parameter is set to true, then the output is
explicitly set to 0.0, if the mean value results in a negative value.
Comment on lines +2350 to +2354

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am afraid I do not understand the reason for the implementation of yGreaterOrEqualZero:

  • Is it a side effect that has to be suppressed or is this just a "normal" integration phenomenon?
  • It possibly shall be explained under which circumstances a slightly negative output occurs
  • What happens if -- in the above case -- the negative input is fed to the block in a simulation model:
    • Is then the output slightly positive (instead of negative)?
    • Shall we also implement countermeasure for this case?

Simulation results

  • Possibly some analytical reference signals shall be provided and compared to the triggered block calculations.
  • We shall then also explain in the documentation what signals shall be compared to each other.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was Introduced some time ago (I'm not sure who did that). The reason is simple:
The result of mean could be slightly negative due to numerical reasons, although the analytical result is zero.
This is annoying since Mean is used in RootMeanSquare, and RMS can only be greater or euqal to zero.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Simulation results

  • Possibly some analytical reference signals shall be provided and compared to the triggered block calculations.
  • We shall then also explain in the documentation what signals shall be compared to each other.

@AHaumer this shall be provided to the users to better understand the purpose of the example(s)

</p>
</html>"), Icon(graphics={Text(
extent={{-80,60},{80,20}},
textString="RM"), Text(
extent={{-80,-20},{80,-60}},
textString="f=%f")}));
end RectifiedMean;
textString="mean")}));
end TriggeredMean;

block ContinuousMean
"Calculates the empirical expectation (mean) value of its input signal"
Expand Down Expand Up @@ -2416,6 +2443,78 @@ This block is demonstrated in the examples
points={{-76,-24},{70,-24}})}));
end ContinuousMean;

block RectifiedMean "Calculate rectified mean over period 1/f"
extends Modelica.Blocks.Interfaces.SISO;
parameter SI.Frequency f(start=50) "Base frequency";
parameter Real x0=0 "Start value of integrator state";
parameter Real y0(final min=0)=0 "Start value of output";
Mean mean(final f=f, final x0=x0,
final y0=y0)
annotation (Placement(transformation(extent={{0,-10},{20,10}})));
Blocks.Math.Abs abs1
annotation (Placement(transformation(extent={{-60,-10},{-40,10}})));
equation
connect(u, abs1.u) annotation (Line(
points={{-120,0},{-62,0}}, color={0,0,127}));
connect(abs1.y, mean.u) annotation (Line(
points={{-39,0},{-2,0}}, color={0,0,127}));
connect(mean.y, y) annotation (Line(
points={{21,0},{110,0}}, color={0,0,127}));
annotation (Documentation(info="<html>
<p>
This block calculates the rectified mean of the input signal u over the given period 1/f, using the
<a href=\"modelica://Modelica.Blocks.Math.Mean\">mean block</a>.
</p>
<p>
Note: The output is updated after each period defined by 1/f.
</p>
</html>"), Icon(graphics={Text(
extent={{-80,60},{80,20}},
textString="RM"), Text(
extent={{-80,-20},{80,-60}},
textString="f=%f")}));
end RectifiedMean;

block TriggeredRectifiedMean
"Calculate rectified mean over period determined by trigger"
extends Modelica.Blocks.Interfaces.SISO;
parameter Real x0=0 "Start value of integrator state";
parameter Real y0=0 "Start value of output";
Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input signal"
annotation (Placement(
transformation(
extent={{-20,-20},{20,20}},
rotation=90,
origin={0,-120})));
Modelica.Blocks.Math.TriggeredMean triggeredMean(
final yGreaterOrEqualZero=true,
final x0=x0,
final y0=y0)
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
Modelica.Blocks.Math.Abs abs1
annotation (Placement(transformation(extent={{-60,-10},{-40,10}})));
equation
connect(u, abs1.u) annotation (Line(
points={{-120,0},{-62,0}}, color={0,0,127}));
connect(abs1.y, triggeredMean.u)
annotation (Line(points={{-39,0},{-12,0}}, color={0,0,127}));
connect(triggeredMean.y, y)
annotation (Line(points={{11,0},{110,0}}, color={0,0,127}));
connect(trigger, triggeredMean.trigger)
annotation (Line(points={{0,-120},{0,-12}}, color={255,0,255}));
annotation (Documentation(info="<html>
<p>
This block calculates the rectified mean of the input signal u over the period the period dtermined by the edges of the trigger, using the
<a href=\"modelica://BLDC.CommonBlocks.TriggeredMean\">triggered mean block</a>.
</p>
<p>
Note: The output is updated at each trigger instance.
</p>
</html>"), Icon(graphics={Text(
extent={{-80,60},{80,20}},
textString="RM")}));
end TriggeredRectifiedMean;

block RootMeanSquare "Calculate root mean square over period 1/f"
extends Modelica.Blocks.Interfaces.SISO;
parameter SI.Frequency f(start=50) "Base frequency";
Expand Down Expand Up @@ -2458,6 +2557,53 @@ Note: The output is updated after each period defined by 1/f.
textString="f=%f")}));
end RootMeanSquare;

block TriggeredRootMeanSquare
"Calculate root mean square over period determined by trigger"
extends Modelica.Blocks.Interfaces.SISO;
parameter Real x0=0 "Start value of integrator state";
parameter Real y0=0 "Start value of output";
Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input signal"
annotation (Placement(
transformation(
extent={{-20,-20},{20,20}},
rotation=90,
origin={0,-120})));
Modelica.Blocks.Math.MultiProduct product(nu=2)
annotation (Placement(transformation(extent={{-60,-10},{-40,10}})));
Modelica.Blocks.Math.TriggeredMean triggeredMean(
final yGreaterOrEqualZero=true,
final x0=x0,
final y0=y0*y0)
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
Modelica.Blocks.Math.Sqrt sqrt1
annotation (Placement(transformation(extent={{40,-10},{60,10}})));
equation

connect(product.y, triggeredMean.u)
annotation (Line(points={{-38.3,0},{-12,0}}, color={0,0,127}));
connect(triggeredMean.y, sqrt1.u)
annotation (Line(points={{11,0},{38,0}}, color={0,0,127}));
connect(sqrt1.y, y) annotation (Line(
points={{61,0},{110,0}}, color={0,0,127}));
connect(u, product.u[1]) annotation (Line(
points={{-120,0},{-80,0},{-80,3.5},{-60,3.5}}, color={0,0,127}));
connect(u, product.u[2]) annotation (Line(
points={{-120,0},{-80,0},{-80,-3.5},{-60,-3.5}}, color={0,0,127}));
connect(trigger, triggeredMean.trigger)
annotation (Line(points={{0,-120},{0,-12}}, color={255,0,255}));
annotation (Documentation(info="<html>
<p>
This block calculates the root mean square of the input signal u over the period the period dtermined by the edges of the trigger:, using the
<a href=\"modelica://BLDC.CommonBlocks.TriggeredMean\">triggered mean block</a>.
</p>
<p>
Note: The output is updated at each trigger instance.
</p>
</html>"), Icon(graphics={Text(
extent={{-80,60},{80,20}},
textString="RMS")}));
end TriggeredRootMeanSquare;

block SignalExtrema "Calculate min and max of a signal"
extends Modelica.Blocks.Icons.Block;

Expand Down
83 changes: 83 additions & 0 deletions Modelica/Blocks/package.mo
Original file line number Diff line number Diff line change
Expand Up @@ -1677,6 +1677,89 @@ The output is constant from the beginning.
</html>"));
end DemoSignalCharacteristic;

model DemoSignalCharacteristicVaryingFrequency
"Demonstrate characteristic values of a signal"
extends Modelica.Icons.Example;
import Modelica.Constants.pi;
Modelica.Blocks.Sources.Ramp rampFrequency(
height=40,
duration=0.5,
offset=10,
startTime=0.25)
annotation (Placement(transformation(extent={{-80,40},{-60,60}})));
Modelica.Blocks.Continuous.Integrator integrator(k=2*pi)
annotation (Placement(transformation(extent={{-50,40},{-30,60}})));
Modelica.Blocks.Math.WrapAngle wrapAngle(positiveRange=false)
annotation (Placement(transformation(extent={{-20,40},{0,60}})));
Modelica.Blocks.Logical.LessEqualThreshold lessEqualThreshold(threshold=0)
annotation (Placement(transformation(
extent={{-10,-10},{10,10}},
rotation=270,
origin={10,22})));
Modelica.Blocks.Math.Sin sin1
annotation (Placement(transformation(extent={{20,40},{40,60}})));
Modelica.Blocks.Sources.Ramp rampOffset(
height=1,
duration=0.5,
offset=0,
startTime=0.25)
annotation (Placement(transformation(extent={{-80,70},{-60,90}})));
Modelica.Blocks.Math.Add add annotation (Placement(transformation(
extent={{-10,-10},{10,10}},
rotation=270,
origin={60,30})));
Modelica.Blocks.Math.TriggeredMean triggeredMean
annotation (Placement(transformation(extent={{70,0},{90,20}})));
Modelica.Blocks.Math.TriggeredRectifiedMean triggeredRectifiedMean
annotation (Placement(transformation(extent={{70,-40},{90,-20}})));
Modelica.Blocks.Math.TriggeredRootMeanSquare triggeredRootMeanSquare
annotation (Placement(transformation(extent={{70,-80},{90,-60}})));
equation
connect(rampFrequency.y, integrator.u)
annotation (Line(points={{-59,50},{-52,50}}, color={0,0,127}));
connect(integrator.y, wrapAngle.u)
annotation (Line(points={{-29,50},{-22,50}}, color={0,0,127}));
connect(wrapAngle.y, sin1.u)
annotation (Line(points={{1,50},{18,50}}, color={0,0,127}));
connect(wrapAngle.y, lessEqualThreshold.u)
annotation (Line(points={{1,50},{10,50},{10,34}}, color={0,0,127}));
connect(lessEqualThreshold.y, triggeredRectifiedMean.trigger) annotation (Line(
points={{10,11},{10,-50},{80,-50},{80,-42}}, color={255,0,255}));
connect(lessEqualThreshold.y, triggeredRootMeanSquare.trigger) annotation (
Line(points={{10,11},{10,-90},{80,-90},{80,-82}}, color={255,0,255}));
connect(lessEqualThreshold.y, triggeredMean.trigger)
annotation (Line(points={{10,11},{10,-10},{80,-10},{80,-2}},
color={255,0,255}));
connect(sin1.y, add.u2)
annotation (Line(points={{41,50},{54,50},{54,42}}, color={0,0,127}));
connect(rampOffset.y, add.u1)
annotation (Line(points={{-59,80},{66,80},{66,42}}, color={0,0,127}));
connect(add.y, triggeredMean.u)
annotation (Line(points={{60,19},{60,10},{68,10}}, color={0,0,127}));
connect(add.y, triggeredRectifiedMean.u)
annotation (Line(points={{60,19},{60,-30},{68,-30}}, color={0,0,127}));
connect(add.y, triggeredRootMeanSquare.u)
annotation (Line(points={{60,19},{60,-70},{68,-70}}, color={0,0,127}));
annotation (experiment(
Interval=0.0001,
Tolerance=1e-06),
Documentation(info="<html>
<p>
A sine with continuously varying frequency is added to an offset.
The triggered blocks detect mean, rectifiedMean and rootMeanSquare of the signal.
The trigger condition (i.e. the edge of the trigger) is detected when the wrapped angle is below zero, i.e. when the sine crosses zero from positive to negative values.
</p>
<h4>Note</h4>
<p>
Mathematically it is not correct to talk about characteristc values like rootMeanSquare,
if the period of the input signal is not constant (as in this example).
So the values during the frequency ramp are more or less an estimaton,
but at the beginning and at the end - when frequency is constant - the result is mathematically correct:
Since the amplitude of the sine is 1, at the beginning (offset=0) rms=1/sqrt(2) and at the end (offset=0) rms=sqrt(3/2) are correct.
</p>
</html>"));
end DemoSignalCharacteristicVaryingFrequency;

package Noise "Library of examples to demonstrate the usage of package Blocks.Noise"
extends Modelica.Icons.ExamplesPackage;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
time
triggeredMean.y
triggeredRectifiedMean.y
triggeredRootMeanSquare.y