www.gusucode.com > rtwdemos 工具箱matlab源码程序 > rtwdemos/rtwdemo_fuelsys_fxp_script.m

    %% Fixed-Point Fuel Rate Control System
% This example shows how to generate and optimize the code for a
% fixed-point fuel rate control system designed using Simulink(R) and
% Stateflow(R).  The example uses the
% Embedded Coder(R) (ERT target), however the concepts also
% apply for Simulink(R) Coder(TM).

% Copyright 1994-2012 The MathWorks, Inc.

%% Familiarize Yourself with the Relevant Portions of the Model
% Figures 1-4 show relevant portions of the sldemo_fuelsys model, which is
% a closed-loop system containing a "plant" and "controller".  The plant is
% used to validate the controller in simulation early in the design cycle.
% In this example, we'll generate code for the relevant controller
% subsystem, "fuel_rate_control".  Figure 1 shows the top-level simulation
% model.

% Open sldemo_fuelsys via rtwdemo_fuelsys_fxp and compile the diagram to
% view the signal data types.
rtwdemo_fuelsys_fxp;

sldemo_fuelsys([],[],[],'compile');
sldemo_fuelsys([],[],[],'term');

%%
% *Figure 1: Top-level model of the "plant" and "controller"*
%
% The fuel rate control system is comprised of Simulink(R) and Stateflow(R)
% blocks, and is the portion of the model for which we'll generated code.

open_system('sldemo_fuelsys/fuel_rate_control');

%%
% *Figure 2: The fuel rate controller subsystem*
%
% The intake airflow estimation and closed loop correction system contains
% two lookup tables, Pumping Constant and Ramp Rate Ki, which we'll refer
% to later in this example as we optimize the generated code.

open_system('sldemo_fuelsys/fuel_rate_control/airflow_calc');

%%
% *Figure 3: The airflow_calc subsystem*
%
% The control logic is a Stateflow(R) chart that specifies the different
% modes of operation.

open_system('sldemo_fuelsys/fuel_rate_control/control_logic');

%%
% *Figure 4: Fuel rate controller logic*
%

%%
% Now let's remove the window clutter.
close_system('sldemo_fuelsys/fuel_rate_control/airflow_calc');
close_system('sldemo_fuelsys/fuel_rate_control/fuel_calc');
close_system('sldemo_fuelsys/fuel_rate_control/control_logic');
hDemo.rt=sfroot;hDemo.m=hDemo.rt.find('-isa','Simulink.BlockDiagram');
hDemo.c=hDemo.m.find('-isa','Stateflow.Chart','-and','Name','control_logic');
hDemo.c.visible=false;
close_system('sldemo_fuelsys/fuel_rate_control');

%%
% Let's build the fuel rate control system only.  Once the code generation
% process is complete, an HTML report detailing the generated code is
% displayed automatically.  The main body of the code is located in
% fuel_rate_control.c.

rtwbuild('sldemo_fuelsys/fuel_rate_control');

%%
% Figure 5 shows snippets of the generated code for the lookup table
% <matlab:rtwdemo_fuelsys_fxp,hilite_system(sprintf('sldemo_fuelsys/fuel_rate_control/airflow_calc/Pumping%sConstant',char(32))) Pumping Constant>.
%
% To see the code for Pumping Constant, right-click the block and select
% *Code Generation > Navigate to code...*

rtwtrace('sldemo_fuelsys/fuel_rate_control/airflow_calc/Pumping Constant');

%%
% The code for pumping constant contains two breakpoint searches and
% a 2D interpolation.  The SpeedVect breakpoint is unevenly spaced, and
% while the PressVect breakpoint is evenly spaced, neither have power of
% two spacing.  This leads to extra code (ROM), including a division, and
% requires all breakpoints to be in memory (RAM).

%%
%
% <<rtwdemo_fuelsys_fxp_uneven_lookup_c1.jpg>>
%
% <<rtwdemo_fuelsys_fxp_uneven_lookup_c2.jpg>>
%
% <<rtwdemo_fuelsys_fxp_uneven_lookup_c3.jpg>>
%
% <<rtwdemo_fuelsys_fxp_uneven_lookup_d1.jpg>>
%

%%
% *Figure 5: Generated code for Pumping Constant lookup (contains unevenly
% spaced breakpoints)*

%% Optimizing Code With Evenly Spaced Power of Two Breakpoints
% The generated code performance can be optimized using evenly spaced power
% of two breakpoints.  In this example, we'll remap the lookup table data
% in the fuel rate control system based on the existing measured data.
%
% The lookup table data is loaded into the model workspace when the model
% loads via the model's PostLoadFcn.  We will retrieve the original table
% data via sldemo_fuelsys_data, modify it for evenly spaced power of two
% and reassign it in the model workspace.
td = sldemo_fuelsys_data('sldemo_fuelsys', 'get_table_data');

%%
% Compute new table data for evenly spaced power of two breakpoints
ntd.SpeedVect   = 64 : 2^5 : 640;             % 32 rad/sec
ntd.PressVect   = 2*2^-5 : 2^-5 : 1-(2*2^-5); % 0.03 bar
ntd.ThrotVect   = 0:2^1:88;                   % 2 deg
ntd.RampRateKiX = 128:2^7:640;                % 128 rad/sec
ntd.RampRateKiY = 0:2^-2:1;                   % 0.25 bar

%%
% Remap table data
ntd.PumpCon  = interp2(td.PressVect,td.SpeedVect,td.PumpCon, ntd.PressVect',ntd.SpeedVect);
ntd.PressEst = interp2(td.ThrotVect,td.SpeedVect,td.PressEst,ntd.ThrotVect',ntd.SpeedVect);
ntd.SpeedEst = interp2(td.PressVect,td.ThrotVect,td.SpeedEst,ntd.PressVect',ntd.ThrotVect);
ntd.ThrotEst = interp2(td.PressVect,td.SpeedVect,td.ThrotEst,ntd.PressVect',ntd.SpeedVect);

%%
% Recompute Ramp Rate table data
ntd.RampRateKiZ = (1:length(ntd.RampRateKiX))' * (1:length(ntd.RampRateKiY)) * td.Ki;

%% Pumping Constant Power Of Two Spacing
figure('Tag','CloseMe');
mesh(td.PressVect,td.SpeedVect,td.PumpCon), hold on
mesh(ntd.PressVect,ntd.SpeedVect,ntd.PumpCon)
xlabel('PressVect'), ylabel('SpeedVect'), zlabel('PumpCon')
title(sprintf('Pumping Constant\nOriginal Spacing (%dx%d) vs. Power of Two Spacing (%dx%d)',...
    size(td.PumpCon,1),size(td.PumpCon,2),size(ntd.PumpCon,1),size(ntd.PumpCon,2)));

%% Pressure Estimate Power Of Two Spacing
clf
mesh(td.ThrotVect,td.SpeedVect,td.PressEst), hold on
mesh(ntd.ThrotVect,ntd.SpeedVect,ntd.PressEst)
xlabel('ThrotVect'), ylabel('SpeedVect'), zlabel('PressEst')
title(sprintf('Pressure Estimate\nOriginal Spacing (%dx%d) vs. Power of Two Spacing (%dx%d)',...
    size(td.PressEst,1),size(td.PressEst,2),size(ntd.PressEst,1),size(ntd.PressEst,2)));

%% Speed Estimate Power Of Two Spacing
clf
mesh(td.PressVect,td.ThrotVect,td.SpeedEst), hold on,
mesh(ntd.PressVect,ntd.ThrotVect,ntd.SpeedEst)
xlabel('PressVect'), ylabel('ThrotVect'), zlabel('SpeedEst')
title(sprintf('Speed Estimate\nOriginal Spacing (%dx%d) vs. Power of Two Spacing (%dx%d)',...
    size(td.SpeedEst,1),size(td.SpeedEst,2),size(ntd.SpeedEst,1),size(ntd.SpeedEst,2)));

%% Throttle Estimate Power Of Two Spacing
clf
mesh(td.PressVect,td.SpeedVect,td.ThrotEst), hold on
mesh(ntd.PressVect,ntd.SpeedVect,ntd.ThrotEst)
xlabel('PressVect'), ylabel('SpeedVect'), zlabel('ThrotEst')
title(sprintf('Throttle Estimate\nOriginal Spacing (%dx%d) vs. Power of Two Spacing (%dx%d)',...
    size(td.ThrotEst,1),size(td.ThrotEst,2),size(ntd.ThrotEst,1),size(ntd.ThrotEst,2)));

%% Ramp Rate Ki Power Of Two Spacing
clf
mesh(td.RampRateKiX,td.RampRateKiY,td.RampRateKiZ'), hold on
mesh(ntd.RampRateKiX,ntd.RampRateKiY,ntd.RampRateKiZ'), hidden off
xlabel('RampRateKiX'), ylabel('RampRateKiY'), zlabel('RampRateKiZ')
title(sprintf('Ramp Rate Ki\nOriginal Spacing (%dx%d) vs. Power of Two Spacing (%dx%d)',...
    size(td.RampRateKiZ,1),size(td.RampRateKiZ,2),size(ntd.RampRateKiZ,1),size(ntd.RampRateKiZ,2)));

%%
% The model is configured to log simulation data for the top-level signals,
% whereby the result of a simulation is stored into workspace variable
% sldemo_fuelsys_output.  Before updating the model workspace with the new
% data we'll save the result of the simulation in hDemo.orig_data for
% later comparison with the evenly spaced power of two table simulation.
set_param('sldemo_fuelsys','StopTime','8')
sim('sldemo_fuelsys')
hDemo.orig_data = sldemo_fuelsys_output;

%%
% Reassign the new table data in the model workspace
hDemo.hWS = get_param('sldemo_fuelsys', 'ModelWorkspace');
hDemo.hWS.assignin('PressEst',   ntd.PressEst);
hDemo.hWS.assignin('PressVect',  ntd.PressVect);
hDemo.hWS.assignin('PumpCon',    ntd.PumpCon);
hDemo.hWS.assignin('SpeedEst',   ntd.SpeedEst);
hDemo.hWS.assignin('SpeedVect',  ntd.SpeedVect);
hDemo.hWS.assignin('ThrotEst',   ntd.ThrotEst);
hDemo.hWS.assignin('ThrotVect',  ntd.ThrotVect);
hDemo.hWS.assignin('RampRateKiX',ntd.RampRateKiX);
hDemo.hWS.assignin('RampRateKiY',ntd.RampRateKiY);
hDemo.hWS.assignin('RampRateKiZ',ntd.RampRateKiZ);

%%
% Reconfigure lookup tables for evenly spaced data.
hDemo.lookupTables = find_system(get_param('sldemo_fuelsys','Handle'),...
    'BlockType','Lookup_n-D');

for hDemo_blkIdx = 1 : length(hDemo.lookupTables)
    hDemo.blkH = hDemo.lookupTables(hDemo_blkIdx);
    set_param(hDemo.blkH,'IndexSearchMethod','Evenly spaced points')
    set_param(hDemo.blkH,'InterpMethod','None - Flat')
    set_param(hDemo.blkH,'ProcessOutOfRangeInput','None')
end

%%
% Rerun the simulation for the evenly spaced power of two implementation,
% and store the result of the simulation in hDemo.pow2_data.
sim('sldemo_fuelsys')
hDemo.pow2_data = sldemo_fuelsys_output;

%%
% Let's compare the result of the simulation for the fuel flow rate and the
% air fuel ratio.  The simulation exercised the Pumping Constant and Ramp
% Rate Ki lookup tables, and shows an excellent match for the evenly spaced
% power of two breakpoints relative to the original table data.
figure('Tag','CloseMe');
subplot(2,1,1);
plot(hDemo.orig_data.get('fuel').Values.Time, ...
     hDemo.orig_data.get('fuel').Values.Data,'r-');
hold
plot(hDemo.pow2_data.get('fuel').Values.Time, ...
     hDemo.pow2_data.get('fuel').Values.Data,'b-');
ylabel('FuelFlowRate (g/sec)');
title('Fuel Control System: Table Data Comparison');
legend('original','even power of two')
axis([0 8 .75 2.25]);
subplot(2,1,2);
plot(hDemo.orig_data.get('air_fuel_ratio').Values.Time, ...
     hDemo.orig_data.get('air_fuel_ratio').Values.Data,'r-');
hold
plot(hDemo.pow2_data.get('air_fuel_ratio').Values.Time, ...
     hDemo.pow2_data.get('air_fuel_ratio').Values.Data,'b-');
ylabel('Air/Fuel Ratio');
xlabel('Time (sec)')
legend('original','even power of 2','Location','SouthEast')
axis([0 8 11 16]);

%%
% Finally, let's rebuild the fuel rate control system and compare the
% difference in the generated lookup table code.

rtwbuild('sldemo_fuelsys/fuel_rate_control');

%%
% Figure 6 shows the same snippets of the generated code for the
% 'Pumping Constant' lookup table.  As you can see, the generated code for
% evenly spaced power of two breakpoints is significantly more efficient
% than the unevenly spaced breakpoint case.  The code consists of two
% simple breakpoint calculations and a direct index into the 2D lookup
% table data.  The expensive division is avoided and the breakpoint data
% is not required in memory.

rtwtrace('sldemo_fuelsys/fuel_rate_control/airflow_calc/Pumping Constant');

%%
%
% <<rtwdemo_fuelsys_fxp_pow2_lookup_c1.jpg>>
%
% <<rtwdemo_fuelsys_fxp_pow2_lookup_c2.jpg>>
%

%%
% *Figure 6: Generated code for Pumping Constant lookup (evenly spaced
% power of two breakpoints)*

%%
% Close the example.
close(findobj(0,'Tag','CloseMe'));
clear hDemo* td ntd
close_system('sldemo_fuelsys',0);

%% Closing Remarks
% We touched on improving code efficiency using evenly spaced power of 2
% breakpoints.  This is one such optimization important for fixed-point
% code generation.  The Simulink(R) Model Advisor is a great tool for
% identifying other methods of improving code efficiency for a Simulink(R) and
% Stateflow(R) model.  In particular, run the checks under the  Embedded Coder(R) 
% folder.