################# Custom components ################# .. highlight:: Modelica In the :ref:`Physical components ` chapter, we've seen how to *use* Modelica components, in particular components from the Modelica Standard Library. In this session, you'll *create new custom components*. To do so, you'll learn what components are made of, in particular ``Connector`` objects. Main ressource needed: Michael Tiller's online book *"Modelica by Example"* [Tiller-2014]_ * chapter `Connectors`_ (e.g. the intro and the review on Connector Definitions) * chapter `Components`_ Thermistor ========== For this work, you need to download an save the ``ThermistorPackage`` :download:`ThermistorPackage.mo <./examples/Thermistor/ThermistorPackage_blank.mo>`. Background theory: a `thermistor `_ is a resistor whose resistance depends on temperature. In particular, :abbr:`NTC (Negative Temperature Coefficient)` thermistors are typically used as temperature sensors. Their resistance decreases with temperature, with a relationship typically described with the so-called "B parameter equation": .. math:: \frac{1}{T} = \frac{1}{T_0} + \frac{1}{B}\ln \left(\frac{R}{R_0}\right) where :math:`R_0` is the resistance at a reference temperature :math:`T_0` (25°C for example) and :math:`B` is the gain (slope of :math:`ln(R)` vs :math:`1/T`). The following plot is the :math:`R(T)` relationship for a `10 kΩ thermistor "NTC 3950" `_ with coefficient :math:`B` equal to 3950, thus the name. .. image:: ./examples/Thermistor/Thermistor_plot.png :width: 20em .. image:: ./examples/Thermistor/Thermistor.jpg :width: 16em Objective: implement the ``Thermistor`` component using this :math:`R(T)` relation. * the ``Thermistor`` component should work when connected with the provided ``TestBlank`` model. Thus it should have two electrical Pins (connector from ``Modelica.Electrical.Analog``) and one Heatport (from ``Modelica.Thermal.HeatTransfer``). * the parameters of the :math:`R(T)` relation should be tunable. * the package provided contains the first few lines Remark: * A good modeling practice, based on the DRY principle (see chapter :ref:`org-mode`), would suggest that the ``Thermistor`` model should inherit from ``Modelica.Electrical.Analog.Interfaces.OnePort``. However, the objective here is to understand how to build acausal components *from scratch*, so we give up on inheritance in this specific case. Visual touch: * Edit in the "Icon view" the appearance of the component so that it looks like a kind of resistance. * Add text with the placeholders for some parameters (like ``B=%B``) so that the user can have an immediate view the their value. Similarly, you can use ``%name`` to show the name of the component instance. Advanced version ---------------- If you've finished the Thermistor, you can complexify its equation to allow the user to switch between 3 different model types: * linear model (with a first-order temperature coefficient) * B parameter equation (used above) * and the more accurate `Steinhart–Hart equation `_. You can use an `Enumeration `_ to hold the model kind. The ``if`` statement (cf. the `If section`_ in *Modelica by Example*) enables the conditional definition of the :math:`R(T)` behavior equation. Custom parameter tuning dialog ------------------------------ As a final touch, you can use the `Dialog `_ annotation to get a well-organized parameter tuning dialog (i.e. the small window popping up when double-clicking a component). This annotation is heavily used in complex components such as those in ``Modelica.Electrical.Machines``:: final parameter Modelica.SIunits.Temperature TpmOperational=293.15 "Operational temperature of permanent magnet" annotation (Dialog(group="Operational temperatures")); Electro active damper ===================== The 2nd supporting example of this session is to enhance the component-based :ref:`vehicle suspension ` with what can be found in some luxury cars: an **electro active damper**. You will replace the existing mechanical damper by an electrical generator. Then, this generator can be connected to a resistor (which yields the same behavior as the mechanical damper), or use a more complex electronical circuitry. The key component for such a generator is an EMF, like the one found in the model of DC motors, but within the translational mechanical domain, rather than the usual rotational EMF. Organization of the work ------------------------ To create such an electromechanical components, it is useful to take inspiration from existing standard electrical and mechanical components, like the ``Damper`` or the ``Resistor``. This is made possible by the opensource nature of MSL. As a first step, we will create a custom mechanical-only component which will behave exactly like the MSL Damper, but where we have full control over the code. Then, we will complexify this model to add the two necessary electrical pins and implement the EMF equation. Testing ....... For testing purpose, you will connect the EMF electrical port to a resistance which value will be computed so as to generate the exact same behavior as the damper with damping factor ``a``. Custom mechanical component --------------------------- This ``Damper`` model from ``Modelica.Mechanics.Translational.Components`` is defined within the single-file package ``Translational.mo``. You can open this MSL file with any text editor but, in OMEdit, the most convenient way to look at this model is two use "Open Class" action from the context menu in OMEdit. ``Damper`` code:: model Damper "Linear 1D translational damper" extends Translational.Interfaces.PartialCompliantWithRelativeStates; parameter SI.TranslationalDampingConstant d(final min=0, start=0) "Damping constant"; extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPortWithoutT; equation f = d*v_rel; lossPower = f*v_rel; annotation (/*…*/); end Damper; This ``Damper`` model extands a base (:term:`partial`) model ``PartialCompliantWithRelativeStates``, defined within ``Modelica.Mechanics.Translational.Interfaces`` (in the same ``Translational.mo`` file):: partial model PartialCompliantWithRelativeStates "Base model for the compliant connection of two translational 1-dim. shaft flanges where the relative position and relative velocities are used as states" parameter StateSelect stateSelect=StateSelect.prefer "Priority to use phi_rel and w_rel as states" annotation (HideResult=true, Dialog(tab="Advanced")); parameter SI.Distance s_nominal=1e-4 "Nominal value of s_rel (used for scaling)" annotation (Dialog(tab="Advanced")); SI.Position s_rel( start=0, stateSelect=stateSelect, nominal=s_nominal) "Relative distance (= flange_b.s - flange_a.s)"; SI.Velocity v_rel(start=0, stateSelect=stateSelect) "Relative velocity (= der(s_rel))"; SI.Force f "Forces between flanges (= flange_b.f)"; Translational.Interfaces.Flange_a flange_a "Left flange of compliant 1-dim. translational component" annotation ( Placement(transformation(extent={{-110,-10},{-90,10}}))); Translational.Interfaces.Flange_b flange_b "Right flange of compliant 1-dim. translational component" annotation ( Placement(transformation(extent={{90,-10},{110,10}}))); equation s_rel = flange_b.s - flange_a.s; v_rel = der(s_rel); flange_b.f = f; flange_a.f = -f; annotation (/*…*/); end PartialCompliantWithRelativeStates; With these code extracts, you should be able to create a custom ``ElecMechConv`` class, defined within your Suspension package created in the previous section. As a first step, this component should behave exactly as the ``Damper``. Custom electro-mechanical component ----------------------------------- ``Resistor`` (defined within ``Modelica.Electrical.Analog.Basic`` package in the ``/usr/lib/omlibrary/Modelica 3.2.2/Electrical/Analog/Basic.mo`` file):: model Resistor "Ideal linear electrical resistor" parameter SI.Resistance R(start=1) "Resistance at temperature T_ref"; parameter SI.Temperature T_ref=300.15 "Reference temperature"; parameter SI.LinearTemperatureCoefficient alpha=0 "Temperature coefficient of resistance (R_actual = R*(1 + alpha*(T_heatPort - T_ref))"; extends Modelica.Electrical.Analog.Interfaces.OnePort; extends Modelica.Electrical.Analog.Interfaces.ConditionalHeatPort(T=T_ref); SI.Resistance R_actual "Actual resistance = R*(1 + alpha*(T_heatPort - T_ref))"; equation assert((1 + alpha*(T_heatPort - T_ref)) >= Modelica.Constants.eps, "Temperature outside scope of model!"); R_actual = R*(1 + alpha*(T_heatPort - T_ref)); v = R_actual*i; LossPower = v*i; annotation (/*…*/); end Resistor; and ``Resistor`` extends partial model ``OnePort`` (defined within ``Modelica.Electrical.Analog.Interfaces``):: partial model OnePort "Component with two electrical pins p and n and current i from p to n" SI.Voltage v "Voltage drop between the two pins (= p.v - n.v)"; SI.Current i "Current flowing from pin p to pin n"; PositivePin p "Positive pin (potential p.v > n.v for positive voltage drop v)" annotation (Placement( transformation(extent={{-110,-10},{-90,10}}))); NegativePin n "Negative pin" annotation (Placement(transformation(extent={{ 110,-10},{90,10}}))); equation v = p.v - n.v; 0 = p.i + n.i; i = p.i; annotation (/*…*/); end OnePort; Using inspiration from these classes, you should expand your ``ElecMechConv`` component to add two electrical pins. The equation for a translational EMF are adapted from the EMF of the usal (rotational) DC motor: .. math:: u = K.v, f = K.i where :math:`K` is the translational emf constant (in V/(m/s) or N/A), :math:`u,i` are the electrical voltage and current, and :math:`v,f` the mechanichal velocity and force. Notice that the name of the variables in this equation should be adapted to match the names used in the Modelica code. Appearance: Icon View --------------------- Use the "Icon View" of OMEdit to customize the appearance of your ``ElecMechConv`` component. In particular: * place the four connectors at reasonable places * add an artistic touch to give a distinctive appearance of the EMF block in the general suspension model. Also, you can use the ``%name`` text, which will be replaced by the actual name of the component. .. _Connectors: https://mbe.modelica.university/components/connectors/ .. _Components: https://mbe.modelica.university/components/components/ .. _If section: https://mbe.modelica.university/behavior/discrete/if/