Basic usage and introduction to the Python package
This tutorial illustrates basic usage of the python package, gives pointer to some examples, and shows how to install everything on a Linux/MacOS/Windows system.
Outline
- Induction motor example
- Some more examples
- Installation
Induction motor example
To illustrate the functionality, a small induction motor example will be used where the model equations are borrowed from the paper Aguilera, F., et al. “Current-sensor fault detection and isolation for induction-motor drives using a geometric approach”, Control Engineering Practice 53 (2016): 35-46.
Modelling
For reference, the equations are given below
There are also three measurement equations, where the two current sensors have modeled faults as
The modeling part is where the main differences between Python and Matlab versions are. This is due to that SymPy is used instead of the symbolic toolbox in Matlab. Therefore, let’s import the toolbox and sympy
import faultdiagnosistoolbox as fdt
import sympy as sym
Now, we define the model as a python dictionary with keys
type
- type of model, here we are definic a model using symbolic expressionsx
- list of unknown variables in the modelf
- list of fault variablesz
- list of known variablesrels
- list of model equationsparameters
- list of parameters (optional) For the induction motor model, this corresponds to
model_def = {'type': 'Symbolic',
'x': ['i_a', 'i_b', 'lambda_a', 'lambda_b',
'w', 'di_a', 'di_b', 'dlambda_a',
'dlambda_b', 'dw', 'q_a', 'q_b', 'Tl'],
'f': ['f_a', 'f_b'],
'z': ['u_a', 'u_b', 'y1', 'y2', 'y3'],
'parameters': ['a', 'b', 'c', 'd', 'L_M',
'k', 'c_f', 'c_t']}
# Make symbolic objects of all variables/parameters before writing down equations.
sym.var(model_def['x'])
sym.var(model_def['f'])
sym.var(model_def['z'])
sym.var(model_def['parameters'])
model_def['rels'] = [
-q_a + w*lambda_a,
-q_b + w*lambda_b,
-di_a + -a*i_a + b*c*lambda_a + b*q_b+d*u_a,
-di_b + -a*i_b + b*c*lambda_b + b*q_a+d*u_b,
-dlambda_a + L_M*c*i_a - c*lambda_a-q_b,
-dlambda_b + L_M*c*i_b - c*lambda_b-q_a,
-dw + -k*c_f*w + k*c_t*(i_a*lambda_b - i_b*lambda_a) - k*Tl,
fdt.DiffConstraint('di_a','i_a'),
fdt.DiffConstraint('di_b','i_b'),
fdt.DiffConstraint('dlambda_a','lambda_a'),
fdt.DiffConstraint('dlambda_b','lambda_b'),
fdt.DiffConstraint('dw','w'),
-y1 + i_a + f_a,
-y2 + i_b + f_b,
-y3 + w]
Now, the DiagnosisModel
object can be created as
model = fdt.DiagnosisModel(model_def, name ='Induction motor')
and the API is very close to the Matlab version as described in the documentation.
Model information, basic plotting, and MSO/MTES
As before, to display model information use the Lint
class method
model.Lint()
which gives
Model: Induction motor
Type:Symbolic, dynamic
Variables and equations
13 unknown variables
5 known variables
2 fault variables
15 equations, including 5 differential constraints
Degree of redundancy: 2
Degree of redundancy of MTES set: 1
Model validation finished with 0 errors and 0 warnings.
The degree of redundancy is 2 in the model since there are 3 output sensors and 1 unknown input to the system, the load torque Tl
. To plot the model structure, use the PlotModel
method as
# Plot model
model.PlotModel()
which gives the figure
Computing the set of MSO and MTES sets is done as below
# Find set of MSOS and MTES
msos = model.MSO()
mtes = model.MTES()
print(f"Found {len(msos)} MSO sets and {len(mtes)} MTES sets.")
# Check observability and low index for MSO sets
oi_mso = [model.IsObservable(m_i) for m_i in msos]
li_mso = [model.IsLowIndex(m_i) for m_i in msos]
print(f'Out of {len(msos)} MSO sets, {sum(oi_mso)} observable, {sum(li_mso)} low (structural) differential index')
# Check observability and low index for MTES sets
oi_mtes = [model.IsObservable(m_i) for m_i in mtes]
li_mtes = [model.IsLowIndex(m_i) for m_i in mtes]
print(f'Out of {len(mtes)} MTES sets, {sum(oi_mtes)} observable, {sum(li_mtes)} low (structural) differential index')
and the code outputs
Found 9 MSO sets and 2 MTES sets.
Out of 9 MSO sets, 9 observable, 4 low (structural) differential index
Out of 2 MTES sets, 2 observable, 2 low (structural) differential index
Isolability analysis
To plot the isolability properties of the model under mixed casaliyu asssumption
# Isolability analysis
model.IsolabilityAnalysis(plot=True, causality='mixed')
and to examine in more detail, the Dulmage-Mendelsohn decomposition with a canonical form of the overdetermined subsystem is plotted by
model.PlotDM(fault=True, eqclass=True)
which gives the figure
For more details on the canonical decomposition of the overdetermined part, see Mattias Krysander, Jan Åslund, and Mattias Nyberg, “An Efficient Algorithm for Finding Minimal Over-constrained Sub-systems for Model-based Diagnosis”. IEEE Transactions on Systems, Man, and Cybernetics – Part A: Systems and Humans, 38(1), 2008.
Code generation and residual generation
To wrap up this example, let us use one of the MTES sets and generate C++-code for a residual generator. First, let’s see which redundant equation that can be used for integral causality residual generation using the MSOCausalitySweep
class method
model.MSOCausalitySweep(mtes[0])
This outputs
['mixed', 'mixed', 'mixed', 'mixed', 'mixed', 'mixed', 'mixed', 'int', 'mixed', 'mixed', 'int', 'mixed']
and thus the 11:th element in the first MTES can be used. The 11:th element correspond to the second measurement equation
red_eq = mtes[0][10]
model.syme[red_eq]
Out[50]: Eq(f_b + i_b - y2, 0)
Now, get the rest of the equations to form the exactly determined set of equations and compute a mathing using the Matching
class method
M0 = [e for e in mtes[0] if e != red_eq]
Gamma = model.Matching(M0)
Now, all is set to generate the residual generator code using the SeqResGen
class method
model.SeqResGen(Gamma, red_eq, 'ResGen', batch=True, language='C')
which generate files ResGen.cc
and ResGen_setup.py
. Have a look at the ResGen_core()
function in the generated C++-file and you’ll se how things work. The generated code can now be compiled by executing
python ResGen_setup.py build_ext --inplace
in a terminal.
More examples
In the distribution, there are a few more examples included. To find where pip
puts everything, run
fdt.__path__
and have a look in the examples
sub-folder.
Installation
The package needs Python version 3.6 or newer, check which version you have installed with
python3 --version
Now, create a virtual environment, don’t install into the system wide python installation. You can do this as (only needed once) with
python3 -m venv env
and then activate the environment as
source ./env/bin/activate # Linux/MacOS
in MacOS/Linux or if you’re on a Windows machine
.\env\Scripts\activate # Windows
Always a good idea to upgrade the package manager pip
before continuing
pip install --upgrade pip
Then, install the toolbox
pip install faultdiagnosistoolbox
and that is that.