1
\$\begingroup\$

I am trying to simulate a microcontroller controlled boost converter on Simulink. Because Simulink doesn't have a microcontroller, I wrote a MATLAB function that emulates one.

enter image description here

In case you're wondering why I'm doing this instead of using a PID control block (which is native to Simulink), it's because I'm going to make an STM32 controlled DC-DC converter, which is why I am trying to emulate a microcontroller.

Before I explain the problem, let me explain the MCU function. The MCU function has two inputs: ADC0 and ADC1. These inputs read an analog value and convert it into a 12-bit equivalent value (which you will see in a bit). I am feeding the output voltage to ADC0 and the reference voltage to ADC1.

The MUC function has one output: Dcontrol. This outputs a value between 0 and 1, which is fed to a PWM block. The output Dcontrol is calculated using a praportional-integral (PI) algorithm.

function Dcontrol = MCU(ADC0, ADC1)
    
    %Initialising the integral error term to zero
    err_I = 0; 
    %This, as I shall demonstrate, causes a problem.

    %Converting inputs into 12-bit equivalent value
    Vout = (ADC0/3.3)*4096;
    Vref = (ADC1/3.3)*4096;  

    %Calculating the error, i.e., difference between set-point and
    %measured-value
    err = Vref - Vout;
    
    %Calculating the proporational error
    err_P = err;
    %Calculating the integral error
    err_I = err_I + err;
    
    %Saturating err_I to prevent integral windup
    if(err_I > 800)
        err_I = 800;
    end

    if(err_I < 0)
        err_I = 0;
    end

    %Saturating err_P
    if(err_P > 100)
        err_P = 100;
    end

    if(err_P < -100)
        err_P = -100;
    end

    %Calculating PI
    PI = err_I + err_P;

    %Disallowing a negaive PI value
    if(PI < 0)
        PI = 0;
    end

    %The dutycycle control output is PI/1000, which gives a max dutycycle of 0.9 
    Dcontrol = PI/1000;
end

The equivalent circuit using the native PI control block looks like this: enter image description here

I'm just showing this for clarity.

Coming back to the microcontroller circuit, I've set the reference voltage to 3V, which should give me 30V at the output. But when I run the simulation, this happens:

enter image description here

My output voltage is around 26V. This is due to the following line in the code

%Initialising the integral error term to zero
err_I = 0; 

Every time the MCU function runs, the integral error gets initialised to zero. This results in the error term (and hence Dcontrol) getting improperly calculated. If I change my input voltage, the output voltage also changes. This is due to the integral term getting reinitialised. If is remove that line, I get an error:

Undefined function or variable 'err_I'. The first assignment to a local variable determines its class.

So my question is - is there a way to initialise the integral error term during runtime only, the way it's possible with the native PID block?

enter image description here

In other words, I want to modify the code to have this effect

    %Initialising the integral error term to zero
    void setup()
    {
    err_I = 0; 
    }

   void loop()
   { 
   %Converting inputs into 12-bit equivalent value
    Vout = (ADC0/3.3)*4096;
    Vref = (ADC1/3.3)*4096;  

    %Calculating the error, i.e., difference between set-point and
    %measured-value
    err = Vref - Vout;
    
    %Calculating the proporational error
    err_P = err;
    %Calculating the integral error
    err_I = err_I + err;
    
    %Saturating err_I to prevent integral windup
    if(err_I > 800)
        err_I = 800;
    end

    if(err_I < 0)
        err_I = 0;
    end

    %Saturating err_P
    if(err_P > 100)
        err_P = 100;
    end

    if(err_P < -100)
        err_P = -100;
    end

    %Calculating PI
    PI = err_I + err_P;

    %Disallowing a negaive PI value
    if(PI < 0)
        PI = 0;
    end

    %The dutycycle control output is PI/1000, which gives a max dutycycle of 0.9 
    Dcontrol = PI/1000;
end
}
\$\endgroup\$
3
  • \$\begingroup\$ It looks like err_I is reset everytime the function is called, so if (if) it's called 100 times, it will be reset 100 times. Maybe it will help to set err_i as a global parameter that is initialized to zero before the simulation and then leave the function to do what it wills with it? \$\endgroup\$ Commented Sep 29, 2021 at 16:39
  • \$\begingroup\$ "it looks like err_I is reset everytime the function is called" yes, that is precisely what is happening. How do I "set err_i as a global parameter that is initialized to zero before the simulation and then leave the function to do what it wills with it"? I want zero to be assigned to err_I just before the simulation and not during the simulation. \$\endgroup\$ Commented Sep 29, 2021 at 16:49
  • \$\begingroup\$ I don't have Matlab, and I only vaguely remember that in Simulink you could RClick in the schematic and then, somewhere in the menu, you would select to modify or add parameters. Or just write in the Matlab (not Simulink) window err_I=0 and use err_I as a global parameter, before the simulation starts. IIRC, it works that way, too. But only vague memories. \$\endgroup\$ Commented Sep 29, 2021 at 19:29

1 Answer 1

0
\$\begingroup\$

Use an S-Function instead of .m code block.

With S-Function you can write C code with one-time-run-only functions, there you can declare variables once to initialize their values and then have them in the main loop function.

\$\endgroup\$
1
  • \$\begingroup\$ I shall try it. \$\endgroup\$ Commented Sep 30, 2021 at 13:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.