www.gusucode.com > ident_featured 案例代码 matlab源码程序 > ident_featured/idnlgreydemo6.m

    %% Signal Transmission System: C MEX-File Modeling Using Optional Input Arguments
% This example shows how to provide optional input arguments to IDNLGREY
% models. The discussion concentrates on how to do this for C-MEX types of
% model files, yet to some minor extent we will also address the most
% relevant parallels to MATLAB file modeling.
%
% The basis for our discussion will be the signal transmission system
% (a telegraph wire) schematically depicted in the following figure.
%
% <<../signaltransmission.png>>
%
% *Figure 1:* Schematic view of a signal transmission system.

%   Copyright 2005-2015 The MathWorks, Inc.

%% Signal Transmission Modeling
% At a distance x (counted from where an input voltage is applied) in a
% telegraph wire flows at time t the current i(t, x). The corresponding
% voltage is u(t, x) and the relationship between current and voltage can
% be described by two coupled Partial Differential Equations (PDEs):
%
% $$- \frac{\partial u(t, x)}{\partial x} = L \frac{\partial i(t, x)}{\partial t}$$
%
%
% $$- \frac{\partial i(t, x)}{\partial x} = C \frac{\partial u(t, x)}{\partial t}$$
%
% The equations above are often referred to as (a variant of) the so-called
% "Telegraph equation", with L and C being inductance and capacitance per
% unit length, respectively. 
%
%%
% The telegraph equation can be approximated by a system of ordinary
% differential equations by only considering the current and the voltage at
% discrete distance points 0, h, 2h, ..., Nh, where h is the discretization
% distance and N the total number of such distances. After this
% approximation, the wire can be thought of as being composed of a number
% of structurally equal segments connected to each other in a chain. In the
% literature this type of approximation is commonly referred to as
% aggregation.

%%
% Let the voltage and the current at distance x = kh, for k = 0, 1, ..., N,
% at time t be denoted u_k(t) and i_k(t), respectively. Approximate d/dx
% u(t, x) and d/dx i(t, x) through the following simple difference
% approximations:
%
%    d u(t, x)   u_{k+1}(t) - u_k(t)
%    --------- ~ -------------------           Forward approximation.
%       dx               h
%
%    d i(t, x)   i_k(t) - i_{k-1}(t)
%    --------- ~ -------------------           Backward approximation.
%       dx               h
%
% for x = kh.

%%
% The reason for using the forward approximation for d/dx u(t, x) is that
% i_N(t) = 0 (open wire), so that the remaining N discretized currents can
% be modeled by the following N differential equations:
%
%     d i_k(t)     1 
%     -------- = - -- (u_{k+1}(t) - u_k(t)) for k = 0, 1, 2, ..., N-1
%        dt        Lh
%
% Similarly, as u_0(t) is a known input signal and no differential
% equation is needed to describe it, it is convenient to use the backward
% approximation scheme to model d/dx i(t, x) at the points h, 2h, ..., N:
%
%     d u_k(t)     1
%     -------- = - -- (i_k(t) - i_{k-1}(t)) for k = 1, 2, ..., N-1
%        dt        Ch
%
%     d u_N(t)     1                         1
%     -------- = - -- (i_N(t) - i_{N-1}(t) = -- i_{N-1}(t)
%        dt        Ch                        Ch
%
% By this we have now arrived at the model approximation shown in Figure 1,
% in which the equations have been expressed in terms of a number of
% interconnected coils and condensators.

%%
% Let us now introduce the 2*N states x1(t) = i_0(t), x2(t) = u_1(t),
% x3(t) = i_1(t), x4(t) = u_2(t), ..., x2N-1(t) = i_{N-1}(t), x2N(t) =
% u_N(t). Also, denote the input u(t) = u_0(t) and let the output be the
% voltage at the end of the wire, i.e., y(t) = x2N(t) = u_N(t). Apparent
% substitutions finally lead to the following state space model structure.
%
%       x1(t) = -1/(Lh)*(x2(t) - u(t))
%       x2(t) = -1/(Ch)*(x3(t) - x1(t))
%       x3(t) = -1/(Lh)*(x4(t) - x2(t))
%       x4(t) = -1/(Ch)*(x5(t) - x3(t))
%            ...
%    x2N-1(t) = -1/(Lh)*(x2N(t) - x2N-2(t))
%      x2N(t) =  1/(Ch)*x2N-1(t)
%
%        y(t) = x2N(t)
%
% All in all, the above mathematical manipulations have taken us to a
% standard linear state space model structure, which very well can be
% handled by IDGREY - the linear counterpart of IDNLGREY. We will not
% perform any IDGREY modeling here, but instead show how optional input
% arguments may be used by IDNLGREY to enhance its modeling flexibility.

%% IDNLGREY Signal Transmission Model Object
% To gain flexibility it is here desirable to have an IDNLGREY model object
% that immediately is able to deal with a wire of any length L. For
% modeling quality purposes, it should also be straightforward to vary the
% number of aggregated blocks N so that a good enough system approximation
% can be obtained. These requirements can be handled through the passing
% of N and L in the FileArgument property of an IDNLGREY object. The
% FileArgument property must be a cell array, but this array may hold any
% kind of data. In this application, we choose to provide N and L in a
% structure, and for a wire of length 1000 m we will try three different
% values of N: 10, 30 and 100. The following three FileArguments will
% subsequently be used when performing IDNLGREY modeling:
FileArgument10  = {struct('N', 10, 'L', 1000)};   % N = 10  --> 20 states.
FileArgument30  = {struct('N', 30, 'L', 1000)};   % N = 30  --> 60 states.
FileArgument100 = {struct('N', 100, 'L', 1000)};  % N = 100 --> 200 states.

%%
% The parsing and checking of the data contained in FileArgument must be
% carried out in the IDNLGREY model file, where it is up to the model file
% designer to implement this functionality. In order to obtain h and N in
% the function without any error checking the following commands can be used:
%
%    N = varargin{1}{1}.N;
%    h = varargin{1}{1}.L/N;
%
% Notice that FileArgument here corresponds to varargin{1}, which is the
% last argument passed to the model file. The file signaltransmission_m.m
% implements the signal transmission model. Type "type signaltransmission_m.m"
% to see the whole file. 

%%
% The situation is a bit more involved when using C-MEX model files as will
% be done further on. In this case we do not beforehand know the number of
% states Nx, but it is computed in the main interface function and can thus
% be passed as an input argument to compute_dx and compute_y. The
% declaration of these functions become:
%
%   void compute_dx(double *dx, int nx, double *x, double *u, double **p,
%                const mxArray *auxvar)
%   void compute_y(double *y, int nx, double *x)
%
% where we have taken away the t-variable (not used in the equations) and
% instead included an integer nx as a second argument to both these
% functions. In addition, we have also removed the standard three trailing
% arguments of compute_y as these are not used to compute the output. With
% these changes, compute_dx and compute_y are called from the main
% interface function as follows.
%
%    /* Call function for state derivative update. */
%    compute_dx(dx, nx, x, u, p, auxvar);
%     
%    /* Call function for output update. */
%    compute_y(y, nx, x);

%%
% The first part of compute_dx is shown below. ("type signaltransmission_c.c"
% displays the whole file in the MATLAB(R) command window.)
%
%    /* State equations. */
%    void compute_dx(double *dx, int nx, double *x, double *u, double **p,
%                    const mxArray *auxvar)
%    {
%       /* Declaration of model parameters and intermediate variables. */
%       double *L, *C;      /* Model parameters.                  */
%       double h, Lh, Ch;   /* Intermediate variables/parameters. */
%       int    j;           /* Equation counter.                  */
%    
%       /* Retrieve model parameters. */
%       L = p[0];   /* Inductance per unit length.  */
%       C = p[1];   /* Capacitance per unit length. */
%       
%       /* Get and check FileArgument (auxvar). */
%       if (mxGetNumberOfElements(auxvar) < 1) {
%           mexErrMsgIdAndTxt("IDNLGREY:ODE_FILE:InvalidFileArgument",
%                             "FileArgument should at least hold one element.");
%       } else if (mxIsStruct(mxGetCell(auxvar, 0)) == false) {
%           mexErrMsgIdAndTxt("IDNLGREY:ODE_FILE:InvalidFileArgument",
%                             "FileArgument should contain a structure.");
%       } else if (   (mxGetFieldNumber(mxGetCell(auxvar, 0), "N") < 0)
%                  || (mxGetFieldNumber(mxGetCell(auxvar, 0), "L") < 0)) {
%           mexErrMsgIdAndTxt("IDNLGREY:ODE_FILE:InvalidFileArgument",
%                             "FileArgument should contain a structure with fields 'N' and 'L'.");
%       } else {
%           /* Skip further error checking to obtain execution speed. */
%           h = *mxGetPr(mxGetFieldByNumber(mxGetCell(auxvar, 0), 0, 
%                        mxGetFieldNumber(mxGetCell(auxvar, 0), "L"))) / (0.5*((double) nx));
%       }
%       Lh = -1.0/(L[0]*h);
%       Ch = -1.0/(C[0]*h);
%       ...
%
% Worth stressing here is that FileArgument is passed to compute_dx in the
% variable auxvar. After declaring and retrieving model parameters (and
% also declaring intermediate variables, like h, auxvar is checked for
% consistency through a number of external interface routines (so-called
% mx-routines). These MATLAB routines allow you to create, access,
% manipulate, and destroy mxArray variables. Consult the MATLAB
% documentation on External Interfaces for more information about this. The
% final else-clause is executed if all checks are passed, in which case the
% value of the auxvar field N is used do determine the value of h. It and
% the model parameters L and C are finally used to compute the required
% parameter quantities Lh = -1/(L*h) and Ch = -1/(C*h). See "Tutorials on
% Nonlinear Grey Box Model Identification: Creating IDNLGREY Model Files"
% for complimentary information about FileArgument.

%%
% With Lh and Ch computed, the second part of compute_dx is as follows.
% Notice in particular how nx is used in the for-loop of compute_dx to
% define the number of states of the present model.
%
%        ...
%        /* x[0]   : Current i_0(t).    */
%        /* x[1]   : Voltage u_1(t).    */
%        /* x[2]   : Current i_1(t).    */
%        /* x[3]   : Voltage u_1(t).    */
%        /* ...                         */
%        /* x[Nx-2]: Current i_Nx-1(t). */
%        /* x[Nx-1]: Voltage u_Nx(t).   */
%        for (j = 0; j < nx; j = j+2) {
%            if (j == 0) {
%                /* First transmitter section. */
%                dx[j]   = Lh*(x[j+1]-u[0]);
%                dx[j+1] = Ch*(x[j+2]-x[j]);
%            } else if (j < nx-3) {
%                /* Intermediate transmitter sections. */
%                dx[j]   = Lh*(x[j+1]-x[j-1]);
%                dx[j+1] = Ch*(x[j+2]-x[j]);
%            } else {
%                /* Last transmitter section. */
%                dx[j]   = Lh*(x[j+1]-x[j-1]);
%                dx[j+1] = -Ch*x[j];
%            }
%        }
%    }

%%
% The output update function compute_dy is much simpler than the state
% update function:
%
%    /* Output equation. */
%    void compute_y(double *y, int nx, double *x)
%    {
%        /* y[0]: Voltage at the end of the transmitter. */
%        y[0] = x[nx-1];
%    }

%%
% We are now in a position where we straightforwardly can enter the above
% information into three different IDNLGREY objects, one for N = 10, one
% for N = 30 and one for N = 100. Notice that the differences when creating
% these models are the order, the initial state vector and the used
% optional input argument, but that is it.
FileName        = 'signaltransmission_c';            % File describing the model structure.
Parameters      = struct('Name',    {'Inductance per unit length'    ... % Initial parameters.
                                     'Capacitance per unit length'}, ...
                         'Unit',    {'H/m' 'F/m'},                   ...
                         'Value',   {0.99e-3 0.99e-3},               ...
                         'Minimum', {eps(0) eps(0)},                 ... % L, C > 0!
                         'Maximum', {Inf Inf},                       ...
                         'Fixed',   {false false});

% A. Signal transmission model with N = 10;
Order10         = [1 1 2*FileArgument10{1}.N];       % Model orders [ny nu nx].
InitialStates10 = zeros(2*FileArgument10{1}.N, 1);   % Initial intitial states.
nlgr10 = idnlgrey(FileName, Order10, Parameters, InitialStates10, 0, ...
                'FileArgument', FileArgument10,                      ...
                'Name', '10 blocks', 'TimeUnit', 's');

% B. Signal transmission model with N = 30;
Order30         = [1 1 2*FileArgument30{1}.N];       % Model orders [ny nu nx].
InitialStates30 = zeros(2*FileArgument30{1}.N, 1);   % Initial intitial states.
nlgr30 = idnlgrey(FileName, Order30, Parameters, InitialStates30, 0, ...
                'FileArgument', FileArgument30,                      ...
                'Name', '30 blocks', 'TimeUnit', 's');

% C. Signal transmission model with N = 100;
Order100         = [1 1 2*FileArgument100{1}.N];     % Model orders [ny nu nx].
InitialStates100 = zeros(2*FileArgument100{1}.N, 1); % Initial intitial states.
nlgr100 = idnlgrey(FileName, Order100, Parameters, InitialStates100, 0, ...
                'FileArgument', FileArgument100,                        ...
                'Name', '100 blocks', 'TimeUnit', 's');            

%%
% The names and units of the three signal transmission models are also set,
% whereupon the sizes of the models are textually confirmed.
set(nlgr10, 'InputName', 'Voltage applied to the wire', 'InputUnit', 'V', ...
            'OutputName', 'Voltage at the end of the wire', 'OutputUnit', 'V');
set(nlgr30, 'InputName', nlgr10.InputName, 'InputUnit', nlgr10.InputUnit, ...
            'OutputName', nlgr10.OutputName, 'OutputUnit', nlgr10.OutputUnit);
set(nlgr100, 'InputName', nlgr10.InputName, 'InputUnit', nlgr10.InputUnit, ...
             'OutputName', nlgr10.OutputName, 'OutputUnit', nlgr10.OutputUnit);
nlgr10
nlgr30
nlgr100

%% Input-Output Data
% At hand is simulated input-output data from a signal transmission wire of
% length 1000 m. This data was simulated using the above aggregated model
% structure, but a much larger N (1500) was employed. The simulation was
% performed during 20 seconds, using a sampling rate of 0.1 seconds. The
% model parameters used were L = C = 1e-3 and the starting point was a
% zero voltage wire (all initial states are thus zero). Both model
% parameters are admittedly much higher than for a typical signal
% transmission wire, but were so chosen to better illustrate the transport
% delay involved for this type of systems. We load this data and put it
% into an IDDATA object z:
load(fullfile(matlabroot, 'toolbox', 'ident', 'iddemos', 'data', 'signaltransmissiondata'));
z = iddata(vout, vin, 0.1, 'Name', 'Signal transmission',                ...
           'InputName', 'Voltage applied to the wire', 'InputUnit', 'V', ...
           'OutputName', 'Voltage at the end of the wire',               ...
           'OutputUnit', 'V', 'Tstart', 0, 'TimeUnit', 's');

%%
% A plot of the input-output data clearly unveils the transport delay from
% applied voltage to the output voltage at the end of the wire. The first
% input voltage pulse at around 1.4 seconds shows up in the output roughly
% a second later.
figure('Name', [z.Name ': input-output data']);
plot(z);

%%
% *Figure 2:* Input-output data from a signal transmission system.

%% Performance of the Initial Signal Transmission Models
% How well do these three initial models perform? Let us investigate this
% by conducting model simulations using COMPARE. From an execution point of
% view, it is here vital that the initial states are not estimated, thus
% the choice of zero initial state vectors. The reason for this is that the
% number of states is very high, especially for nlgr100 (= 200), and that
% the estimation of the initial state vectors would then result in really
% lengthy computations.
compare(z, nlgr100, nlgr30, nlgr10, compareOptions('InitialCondition', 'zero'));

%%
% *Figure 3:* Comparison between true output and the simulated outputs
% of three initial signal transmission models.

%%
% In terms of fit, there is a significant difference between the three
% models and, as expected, the most complex model outperforms the other
% two. The difference in modeling power is perhaps best viewed by looking
% at the prediction errors of each model.
peOpt = peOptions('InitialCondition','zero');
e = {pe(z, nlgr100, peOpt) pe(z, nlgr30, peOpt) pe(z, nlgr10, peOpt)};
figtitle = {'nlgr100 : e@' 'nlgr30 : e@' 'nlgr10 : e@'};
figure('Name', [z.Name ': prediction errors']);
for i = 1:3
    subplot(3, 1, i);
    plot(e{i}.SamplingInstants, e{i}.OutputData, 'r');
    title(['Initial ' figtitle{i} z.OutputName{1}]);
    axis('tight');
end

%%
% *Figure 4:* Prediction errors obtained with the three initial IDNLGREY
% signal transmission models.

%% Parameter Estimation
% Although we have here started off with almost the correct parameter
% values of the true system, this does not necessarily mean that these
% values are the ones producing the best model fit. Let us investigate this
% by estimating the two model parameters of the three signal transmission
% models using NLGREYEST. These computations may take some time.
opt = nlgreyestOptions('Display', 'on', 'EstCovar', false);

nlgr100 = nlgreyest(z, nlgr100, opt);
nlgr30  = nlgreyest(z, nlgr30, opt);
nlgr10  = nlgreyest(z, nlgr10, opt);

%% Performance of the Estimated Signal Transmission Models
% The Final Prediction Error (FPE) criterion applied to the estimated
% models continues to indicate that the most complex model is superior:
fpe(nlgr100, nlgr30, nlgr10)

%%
% The estimated parameter values are not changed that much as compared to
% the initial values. As can be seen below, an interesting point is that
% the parameter values of the two least involved models actually move
% further away from the true parameter values, whereas the opposite occurs
% for the most complex model. There are several reasons for why this might
% happen, e.g., a too coarse aggregation or that the minimization procedure
% ended up with parameter values corresponding to a local minimum.
disp('   True        nlgr100     nlgr30      nlgr10');
ptrue = [1e-3; 1e-3];
fprintf('   %1.7f   %1.7f   %1.7f   %1.7f\n', ...
       [ptrue'; getpvec(nlgr100)'; getpvec(nlgr30)'; getpvec(nlgr10)']);

%%
% Next, we again utilize COMPARE to perform simulations of the three
% estimated signal transmission models.
compare(z, nlgr100, nlgr30, nlgr10, compareOptions('InitialCondition', 'zero'));

%%
% *Figure 5:* Comparison between true output and the simulated outputs
% of three estimated signal transmission models.

%%
% In all three cases we get a slightly improved fit. Although small, the
% improvement can be recognized by comparing the prediction errors obtained
% after and before parameter estimation.
peOpt = peOptions('InitialCondition','zero');
e = {pe(z, nlgr100, peOpt) pe(z, nlgr30, peOpt) pe(z, nlgr10, peOpt)};
figtitle = {'nlgr100 : e@' 'nlgr30 : e@' 'nlgr10 : e@'};
figure('Name', [z.Name ': prediction errors']);
for i = 1:3
    subplot(3, 1, i);
    plot(e{i}.SamplingInstants, e{i}.OutputData, 'r');
    title(['Estimated ' figtitle{i} z.OutputName{1}]);
    axis('tight');
end

%%
% *Figure 6:* Prediction errors obtained with the three estimated IDNLGREY
% signal transmission models.

%%
% We conclude this tutorial by looking at the unit step responses of the
% estimated signal transmission models. As can be seen, all these models
% seem to be able to pick up the transport delay. However, the poles of
% these linear models are all located on the imaginary axes, i.e., on the
% stability boundary. It is well-known that simulations of such models
% are delicate to perform and might result in oscillating step responses of
% the kind shown in this figure.
%
% The main problem here is that this variant of the telegraph equation does
% not model any losses; such effects can be included by adding "resistors"
% (in series with the coils) and "resistors of conductance" (in parallel
% with the condensators) to each Lh-Ch sub-block of Figure 1. By this, the
% models will become more "stable" and simulations will be "easier".
figure('Name', [z.Name ': step responses']);
step(nlgr100, nlgr30, nlgr10);
grid on;
legend('nlgr100', 'nlgr30', 'nlgr10', 'Location', 'NorthWest');

%%
% *Figure 7:* Step responses of three estimated IDNLGREY signal
% transmission models.

%% Conclusions
% This tutorial has first and foremost addressed how to use optional
% input file arguments when doing IDNLGREY modeling. We focused on C-MEX
% type of modeling, but indicated how to do this with MATLAB files too. For
% certain kinds of systems, it turns out to be beneficial (model reuse) to
% design a model file with more flexibility than normal, e.g., in terms of
% the number of states to use. The signal transmission system treated in
% this tutorial is one example in this category.

%% Additional Information
% For more information on identification of dynamic systems with System Identification Toolbox(TM) 
% visit the
% <http://www.mathworks.com/products/sysid/ System Identification Toolbox>
% product information page.