u is wrapped to the "));
end WrapAngle;
+ block UnwrapAngle "Angle tracking observer"
+ extends Modelica.Blocks.Interfaces.SISO(u(final unit="rad", displayUnit="deg"),
+ y(final unit="rad", displayUnit="deg"));
+ Modelica.Blocks.Interfaces.RealOutput w(final unit="rad/s", displayUnit="rpm")
+ "Angular velocity"
+ annotation (Placement(transformation(extent={{100,-70},{120,-50}})));
+ parameter Modelica.Units.SI.Time Ti=1e-6 "Integral time constant of controller";
+ parameter Modelica.Units.SI.Angle phi0=0 "Initial angle";
+ Modelica.Blocks.Math.Cos cos1
+ annotation (Placement(transformation(extent={{-70,-30},{-50,-10}})));
+ Modelica.Blocks.Math.Sin sin1
+ annotation (Placement(transformation(extent={{-70,10},{-50,30}})));
+ Modelica.Electrical.Machines.SpacePhasors.Blocks.Rotator rotator
+ annotation (Placement(transformation(extent={{-30,10},{-10,-10}})));
+ Modelica.Blocks.Continuous.Integrator integralController(
+ k=1,
+ initType=Modelica.Blocks.Types.Init.InitialOutput,
+ y_start=phi0)
+ annotation (Placement(transformation(extent={{40,-10},{60,10}})));
+ Modelica.Blocks.Math.Gain gain(k=1/Ti)
+ annotation (Placement(transformation(extent={{0,-10},{20,10}})));
+ equation
+ connect(u, sin1.u) annotation (Line(points={{-120,0},{-80,0},{-80,20},{-72,20}},
+ color={0,0,127}));
+ connect(u, cos1.u) annotation (Line(points={{-120,0},{-80,0},{-80,-20},{-72,-20}},
+ color={0,0,127}));
+ connect(integralController.y,rotator. angle) annotation (Line(points={{61,0},{
+ 80,0},{80,20},{-20,20},{-20,12}}, color={0,0,127}));
+ connect(gain.y,integralController. u)
+ annotation (Line(points={{21,0},{38,0}}, color={0,0,127}));
+ connect(rotator.y[2],gain. u)
+ annotation (Line(points={{-9,0},{-2,0}}, color={0,0,127}));
+ connect(sin1.y, rotator.u[2]) annotation (Line(points={{-49,20},{-40,20},{-40,
+ 0},{-32,0}}, color={0,0,127}));
+ connect(cos1.y, rotator.u[1]) annotation (Line(points={{-49,-20},{-40,-20},{-40,
+ 0},{-32,0}}, color={0,0,127}));
+ connect(integralController.y, y)
+ annotation (Line(points={{61,0},{110,0}}, color={0,0,127}));
+ connect(gain.y, w) annotation (Line(points={{21,0},{30,0},{30,-60},{110,-60}},
+ color={0,0,127}));
+ annotation (
+ Icon(graphics={
+ Polygon(
+ points={{0,90},{-8,68},{8,68},{0,90}},
+ lineColor={192,192,192},
+ fillColor={192,192,192},
+ fillPattern=FillPattern.Solid),
+ Line(points={{0,-80},{0,68}}, 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={{-90,0},{68,0}}, color={192,192,192}),
+ Line(points={{-72,20},{-72,20},{-40,60},{-40,-40},{40,60},{40,-60},{56,-40}}),
+ Line(
+ points={{56,80},{-72,-80}},
+ color={0,0,127},
+ thickness=0.5)}),
+ Documentation(info="
+
+This block "unwraps" the input angle u having time discontinuities.
+Such discontinuities are typical for angles exceeding interval limits,
+e.g. ]-π, π], cf.
+Modelica.Blocks.Math.WrapAngle.
+The output angle y approximates the input angle u in continuous matter.
+
+The used calculation method is based on an angle tracking observer as common in electrical
+engineering. This implementation is very robust.
+It determines the angle of a space phasor calculating cos(u) and
+sin(u) of a wrapped angle u – independent of the
+angle interval. Note: the angles are often wrapped within the interval ]-π, +π] or
+[0, 2π[.
+
+The angle of a complex space phasor is controlled in such a way that its imaginary part is equal to zero.
+The controlled angle y is the unwrapped continuous angle.
+The output y approximates the desired angle by a first order system
+which time constant is the integral time constant of the controller:
+
++Im(ej*(u-y)) = sin(u - y) +
+This expression can be approximated for small differences by
+(u - y).
+Using an integral controller, the transfer function of the closed loop can, thus, be
+determined as:
+y = u / (1 + s*Ti).
+
+The derivative of the output y is the angular velocity w,
+provided as an output signal as well.
+