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

Add a block (based on time events) to calculate the extrema of a signal #3762

Merged
merged 11 commits into from
Mar 15, 2021
109 changes: 109 additions & 0 deletions Modelica/Blocks/Math.mo
Original file line number Diff line number Diff line change
Expand Up @@ -2416,6 +2416,115 @@ Note: The output is updated after each period defined by 1/f.
textString="f=%f")}));
end RootMeanSquare;

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

parameter SI.Time Ts(start=0.01) "Sample time";
Modelica.Blocks.Interfaces.RealInput
u "Connector of Real input signal" annotation (Placement(
transformation(extent={{-140,-20},{-100,20}})));
Modelica.Blocks.Interfaces.RealOutput
y_min "Min of input signal" annotation (Placement(
transformation(extent={{100,-70},{120,-50}})));
Modelica.Blocks.Interfaces.RealOutput
y_max "Max of input signal" annotation (Placement(
transformation(extent={{100,50},{120,70}})));
discrete Real t_min "Sample time of last found minimum";
discrete Real t_max "Sample time of last found maximum";

protected
parameter SI.Time t0(fixed=false) "Start time of simulation";

initial equation
t0 = time;
y_min = u;
y_max = u;
t_min = time;
t_max = time;

equation
when sample(t0 + Ts, Ts) then
y_min = min(u, pre(y_min));
y_max = max(u, pre(y_max));
if y_min<pre(y_min) then
t_min = time;
t_max=pre(t_max);
elseif y_max>pre(y_max) then
t_max = time;
t_min=pre(t_min);
else
t_min=pre(t_min);
t_max=pre(t_max);
end if;
end when;
annotation (Icon(graphics={
Line(points={{-80,68},{-80,-80}}, color={192,192,192}),
Polygon(
points={{-80,90},{-88,68},{-72,68},{-80,90}},
lineColor={192,192,192},
fillColor={192,192,192},
fillPattern=FillPattern.Solid),
Line(points={{-90,0},{68,0}}, color={192,192,192}),
Polygon(
points={{90,0},{68,8},{68,-8},{90,0}},
lineColor={192,192,192},
fillColor={192,192,192},
fillPattern=FillPattern.Solid),
Line(
points={{-80,0},{-75.2,32.3},{-72,50.3},{-68.7,64.5},{-65.5,74.2},{-62.3,79.3},{-59.1,79.6},{-55.9,75.3},{-52.7,67.1},{-48.6,52.2},{-43,25.8},{-35,-13.9},{-30.2,-33.7},{-26.1,-45.9},{-22.1,-53.2},{-18,-56},{-14.1,-52.5},{-10.1,-45.3},{-5.23,-32.1},{8.44,13.7},{13.3,26.4},{18.1,34.8},{22.1,38},{26.9,37.2},{31.8,31.8},{38.2,19.4},{51.1,-10.5},{57.5,-21.2},{63.1,-25.9},{68.7,-25.9},{75.2,-20.5},{80,-13.8}},
smooth=Smooth.Bezier,
color={192,192,192}),
Text(extent={{-150,-110},{150,-150}},
textString="Ts=%Ts", lineColor={0,0,0}),
Line(
points={{-60,80},{52,80}},
color={0,0,0},
pattern=LinePattern.Dash), Text(
extent={{-150,150},{150,110}},
textString="%name",
lineColor={0,0,255}),
Text(extent={{60,70},{92,50}},
lineColor={0,0,0},
textString="max"),
Text(extent={{60,-50},{92,-70}},
lineColor={0,0,0},
textString="min"),
Line(
points={{-18,-56},{50,-56}},
color={0,0,0},
pattern=LinePattern.Dash)}), Documentation(info="<html>
<p>
This block calculates the min and the max of the input signal <code>u</code>
and stores the time at which the last min or max was reached in the
variables <code>t_min</code> and <code>t_max</code> respectively.
</p>
<h5>Note:</h5>
<p>The output is updated after each sample period defined by <code>Ts</code>.
This means that:</p>
<ul>
<li>The extrema will be approximate as it only return the extremas at the sampling points.</li>
<li>The sampling will generate many events which may slow down the simulation.</li>
</ul>

</html>", revisions="<html>
<table border=\"1\" cellspacing=\"0\" cellpadding=\"2\">
<tr>
<th>Version</th>
<th>Date</th>
<th>Author</th>
<th>Comment</th>
</tr>
<tr>
<td>1.0.0</td>
<td>2021-02-25</td>
<td><a href=\"https://github.com/dietmarw\">dietmarw</a>,
<a href=\"https://github.com/tinrabuzin\">tinrabuzin</a></td>
<td>Initial version</td>
</tr>
</table>
</html>"));
end SignalExtrema;

block Variance "Calculates the empirical variance of its input signal"
extends Modelica.Blocks.Icons.Block;
parameter SI.Time t_eps(min=100*Modelica.Constants.eps)=1e-7
Expand Down
46 changes: 45 additions & 1 deletion Modelica/Blocks/package.mo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
within Modelica;
within Modelica;
package Blocks "Library of basic input/output control blocks (continuous, discrete, logical, table blocks)"

extends Modelica.Icons.Package;
Expand Down Expand Up @@ -1447,6 +1447,50 @@ Compare the sinc signal and an exponentially damped sine.
</html>"));
end CompareSincExpSine;

model DemonstrateSignalExtrema "Test detection of signal extrema"
extends Modelica.Icons.Example;
inner Modelica.Blocks.Noise.GlobalSeed globalSeed(useAutomaticSeed=true)
annotation (Placement(transformation(extent={{-80,60},{-60,80}})));
Modelica.Blocks.Noise.UniformNoise uniformNoiseAmplitude(
samplePeriod=1e-2,
y_min=1,
y_max=5) annotation (Placement(transformation(extent={{-80,10},{-60,30}})));
Modelica.Blocks.Noise.UniformNoise uniformNoiseFrequency(
samplePeriod=1e-2,
y_min=10,
y_max=100)
annotation (Placement(transformation(extent={{-80,-30},{-60,-10}})));
Modelica.Blocks.Sources.SineVariableFrequencyAndAmplitude sine(
useConstantFrequency=false, phi(fixed=true))
annotation (Placement(transformation(extent={{-20,-10},{0,10}})));
Modelica.Blocks.Math.SignalExtrema signalExtrema1(Ts=1e-2)
annotation (Placement(transformation(extent={{40,10},{60,30}})));
Modelica.Blocks.Math.SignalExtrema signalExtrema2(Ts=1e-4)
annotation (Placement(transformation(extent={{40,-30},{60,-10}})));
equation
connect(sine.y, signalExtrema1.u)
annotation (Line(points={{1,0},{20,0},{20,20},{38,20}}, color={0,0,127}));
connect(sine.y, signalExtrema2.u) annotation (Line(points={{1,0},{20,0},{20,-20},
{38,-20}}, color={0,0,127}));
connect(uniformNoiseAmplitude.y, sine.amplitude) annotation (Line(points={{-59,
20},{-40,20},{-40,6},{-22,6}}, color={0,0,127}));
connect(uniformNoiseFrequency.y, sine.f) annotation (Line(points={{-59,-20},{-40,
-20},{-40,-6},{-22,-6}}, color={0,0,127}));
annotation (experiment(
StopTime=1.5,
Interval=1e-05,
Tolerance=1e-06), Documentation(info="<html>
<p>
This example uses a sinusoidal signal with amplitude and frequency randomly set every 10 ms.
Amplitude varies in the range of [1,5] and frequency varies in the range of [10, 100] Hz.
</p>
<p>
Note that signalExtrema1 doesn't find the extrema exactly since sampling frequency 100 Hz is too small compared to maximum frequency of the input signal,
whereas signalExtrema2 catches the extrema rather good due to the fact that sampling frequency 10 kHz is high enough.
</p>
</html>"));
end DemonstrateSignalExtrema;

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

Expand Down
8 changes: 8 additions & 0 deletions ModelicaTest/Blocks.mo
Original file line number Diff line number Diff line change
Expand Up @@ -2038,4 +2038,12 @@ the whole homotopy transformation.</p>
</html>"));
end LimPID;

model SignalExtrema "Test of determining the extrema (min and max) of a signal"
extends Modelica.Icons.Example;
Modelica.Blocks.Math.SignalExtrema signalExtrema(Ts(displayUnit="ms") = 0.001) annotation (Placement(transformation(extent={{12,-10},{32,10}})));
Modelica.Blocks.Sources.ExpSine expSine(f=10, damping=-1) annotation (Placement(transformation(extent={{-32,-10},{-12,10}})));
equation
connect(expSine.y, signalExtrema.u) annotation (Line(points={{-11,0},{10,0}}, color={0,0,127}));
annotation (experiment(StopTime=1));
end SignalExtrema;
end Blocks;