From 138ce0b3916e76b83171940cbce8cce8a7351400 Mon Sep 17 00:00:00 2001 From: Anton Haumer Date: Mon, 13 Dec 2021 18:30:00 +0100 Subject: [PATCH 1/4] Implemented and tested Triggered{Mean, RectifiedMean, RootMeanSquare} --- Modelica/Blocks/Math.mo | 188 ++++++++++++++++-- Modelica/Blocks/package.mo | 83 ++++++++ .../comparisonSignals.txt | 4 + 3 files changed, 254 insertions(+), 21 deletions(-) create mode 100644 Modelica/Resources/Reference/Modelica/Blocks/Examples/DemonstrateSignalCharaceristicVaryingFrequency/comparisonSignals.txt diff --git a/Modelica/Blocks/Math.mo b/Modelica/Blocks/Math.mo index 0755db73b8..1d9c631e8f 100644 --- a/Modelica/Blocks/Math.mo +++ b/Modelica/Blocks/Math.mo @@ -2264,37 +2264,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 + 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="

-This block calculates the rectified mean of the input signal u over the given period 1/f, using the -mean block. +This block calculates the mean of the input signal u over the period dtermined by the edges of the trigger:

+
+ 1   T
+---- ∫ u(t) dt
+T-t0 t0
+

-Note: The output is updated after each period defined by 1/f. +Note: The output is updated at each trigger instance. +

+ +

+If parameter yGreaterOrEqualZero in the Advanced tab is true (default = false), +then the modeller provides the information that the mean of the input signal is guaranteed +to be ≥ 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.

"), 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" @@ -2379,6 +2406,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=" +

+This block calculates the rectified mean of the input signal u over the given period 1/f, using the +mean block. +

+

+Note: The output is updated after each period defined by 1/f. +

+"), 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 + 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=" +

+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 +triggered mean block. +

+

+Note: The output is updated at each trigger instance. +

+"), 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"; @@ -2421,6 +2520,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 + 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=" +

+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 +triggered mean block. +

+

+Note: The output is updated at each trigger instance. +

+"), 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; diff --git a/Modelica/Blocks/package.mo b/Modelica/Blocks/package.mo index da7b420f75..3ac20539be 100644 --- a/Modelica/Blocks/package.mo +++ b/Modelica/Blocks/package.mo @@ -1576,6 +1576,89 @@ The output is constant from the beginning. ")); 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=" +

+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. +

+

Note:

+

+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. +

+")); + end DemoSignalCharacteristicVaryingFrequency; + package Noise "Library of examples to demonstrate the usage of package Blocks.Noise" extends Modelica.Icons.ExamplesPackage; diff --git a/Modelica/Resources/Reference/Modelica/Blocks/Examples/DemonstrateSignalCharaceristicVaryingFrequency/comparisonSignals.txt b/Modelica/Resources/Reference/Modelica/Blocks/Examples/DemonstrateSignalCharaceristicVaryingFrequency/comparisonSignals.txt new file mode 100644 index 0000000000..6a57c7655d --- /dev/null +++ b/Modelica/Resources/Reference/Modelica/Blocks/Examples/DemonstrateSignalCharaceristicVaryingFrequency/comparisonSignals.txt @@ -0,0 +1,4 @@ +time +triggeredMean.y +triggeredRectifiedMean.y +triggeredRootMeanSquare.y From 00102209d81208a9244862278e4c92f9e401440c Mon Sep 17 00:00:00 2001 From: Christian Kral Date: Sat, 25 Dec 2021 15:55:25 +0100 Subject: [PATCH 2/4] Remove colon --- Modelica/Blocks/package.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modelica/Blocks/package.mo b/Modelica/Blocks/package.mo index 3ac20539be..75e1c95f90 100644 --- a/Modelica/Blocks/package.mo +++ b/Modelica/Blocks/package.mo @@ -1648,7 +1648,7 @@ 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.

-

Note:

+

Note

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). From 0c40bd288c0564c01967316bb6886d2d8f66be2c Mon Sep 17 00:00:00 2001 From: Christian Kral Date: Sat, 25 Dec 2021 16:03:01 +0100 Subject: [PATCH 3/4] Add docstring to trigger input --- Modelica/Blocks/Math.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modelica/Blocks/Math.mo b/Modelica/Blocks/Math.mo index 1d9c631e8f..981b1b838d 100644 --- a/Modelica/Blocks/Math.mo +++ b/Modelica/Blocks/Math.mo @@ -2272,7 +2272,7 @@ explicitly set to 0.0, if the mean value results in a negative value. 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 + Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input" annotation (Placement( transformation( extent={{-20,-20},{20,20}}, From 70d1a579194ea43d08dc294507fe80b13955e67b Mon Sep 17 00:00:00 2001 From: Christian Kral Date: Sat, 25 Dec 2021 17:06:33 +0100 Subject: [PATCH 4/4] More docsrings of trigger input --- Modelica/Blocks/Math.mo | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modelica/Blocks/Math.mo b/Modelica/Blocks/Math.mo index 981b1b838d..ddc26e752d 100644 --- a/Modelica/Blocks/Math.mo +++ b/Modelica/Blocks/Math.mo @@ -2272,7 +2272,7 @@ explicitly set to 0.0, if the mean value results in a negative value. 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" + Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input signal" annotation (Placement( transformation( extent={{-20,-20},{20,20}}, @@ -2443,7 +2443,7 @@ Note: The output is updated after each period defined by 1/f. 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 + Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input signal" annotation (Placement( transformation( extent={{-20,-20},{20,20}}, @@ -2525,7 +2525,7 @@ Note: The output is updated after each period defined by 1/f. 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 + Modelica.Blocks.Interfaces.BooleanInput trigger "Trigger input signal" annotation (Placement( transformation( extent={{-20,-20},{20,20}},