├── Capture.PNG
├── MPPT Algorithms
├── ConstVolt.m
├── CurrentSweep.m
├── IncCond.m
├── PandO.m
├── compareMPPT.jpg
└── total_mppt_comparison.png
├── PV_generator_sim.slx
├── PV_generator_sim.slxc
├── README.md
├── input_distb_plot.m
├── parameter-study.xlsx
├── passive_parameters_overduty.m
├── passiveparams_overVin&Iin.m
├── slprj
├── _jitprj
│ ├── sSrjcJsl5QCSDH3ehEoQOKB.l
│ └── sSrjcJsl5QCSDH3ehEoQOKB.mat
├── _sfprj
│ ├── EMLReport
│ │ └── sSrjcJsl5QCSDH3ehEoQOKB.mat
│ ├── PV_generator_sim
│ │ ├── _self
│ │ │ └── sfun
│ │ │ │ └── info
│ │ │ │ └── binfo.mat
│ │ └── amsi_serial.mat
│ └── precompile
│ │ └── CHHaOyep6HZiuO3JElBnTB.mat
├── accel
│ └── PV_generator_sim
│ │ ├── PV_generator_sim_top_vm.bc
│ │ ├── amsi_serial.mat
│ │ └── tmwinternal
│ │ └── simulink_cache.xml
├── sim
│ └── varcache
│ │ └── PV_generator_sim
│ │ ├── checksumOfCache.mat
│ │ ├── tmwinternal
│ │ └── simulink_cache.xml
│ │ └── varInfo.mat
└── sl_proj.tmw
├── statespaceLQRsetup.m
└── statespace_ackerman_setup.m
/Capture.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/Capture.PNG
--------------------------------------------------------------------------------
/MPPT Algorithms/ConstVolt.m:
--------------------------------------------------------------------------------
1 | function D = ConstVolt(Vpv)
2 |
3 | % incremental duty cycle change
4 | delta_d = 0.005;
5 |
6 | % grabs workspace variables or initializes them below
7 | persistent Dprev Vprev
8 |
9 | if isempty(Dprev)
10 | Dprev = 0.01;
11 | Vprev = 0;
12 | end
13 | Voc = 36.7;
14 | Vref = 0.76*Voc;
15 |
16 | % Increase or decrease duty cycle based on conditions
17 | if abs(Vref - Vpv)<44
18 | D = Dprev;
19 | else
20 | if Vpv>Vref
21 | D = Dprev+delta_d;
22 | else
23 | D = Dprev - delta_d;
24 | end
25 | end
26 |
27 | % Update internal values
28 | Dprev = D;
29 | Vprev = Vpv;
30 |
--------------------------------------------------------------------------------
/MPPT Algorithms/CurrentSweep.m:
--------------------------------------------------------------------------------
1 | function D = CurrentSweep(Vpv,Iload)
2 |
3 | % incremental duty cycle change
4 | delta_d = 0.0005;
5 | delta_t=1/100000;
6 | % grabs workspace variables or initializes them below
7 | persistent Dprev Vprev Iprev
8 |
9 | if isempty(Dprev)
10 | Dprev = 0.01;
11 | Vprev = 0;
12 | Iprev = 0;
13 | end
14 |
15 | dVpv = (Vpv-Vprev)/delta_t;
16 | dIload = (Iload - Iprev)/delta_t;
17 |
18 | % Increase or decrease duty cycle based on conditions
19 | % Increase or decrease duty cycle based on conditions
20 | if abs(dVpv)<3300
21 | D = Dprev;
22 | else
23 | if sign(dIload) && sign(dVpv)
24 | D=Dprev+delta_d;
25 | else
26 | D=Dprev-delta_d;
27 | end
28 | end
29 | % Update internal values
30 | Dprev = D;
31 | Vprev = Vpv;
32 | Iprev = Iload;
33 |
--------------------------------------------------------------------------------
/MPPT Algorithms/IncCond.m:
--------------------------------------------------------------------------------
1 | function D = IncCond(V,I)
2 |
3 | D_initial = 0.05; %Initial value for D output
4 | D_max = 1; %Maximum value for D
5 | D_min = 0; %Minimum value for D
6 | deltaD = 0.005; %Increment value used to increase/decrease the duty cycle D
7 |
8 | persistent Vold Pold Dold M Iold;
9 |
10 | dataType = 'double';
11 |
12 | if isempty(Vold)
13 | Vold=0;
14 | Pold=0;
15 | Iold=0;
16 | Dold=D_initial;
17 | M=1;
18 | end
19 | P= V*I;
20 | dV= V - Vold;
21 | dP= P - Pold;
22 | dI= I - Iold;
23 | M=abs(dP);
24 |
25 | if M < 0.005
26 | D=Dold;
27 | else
28 | if dV == 0
29 | if dI == 0
30 | D=Dold;
31 | elseif dI>0
32 | D=Dold - (M*deltaD);
33 | else
34 | D=Dold + (M*deltaD);
35 | end
36 | else
37 | if dI/dV == -I/V
38 | D=Dold;
39 | elseif dI/dV>-I/V
40 | D=Dold - (M*deltaD);
41 | else
42 | D=Dold + (M*deltaD);
43 | end
44 | end
45 | end
46 |
47 | % Forced filtering
48 | if D >= 1 | D<= 0
49 | D=Dold;
50 | end
51 |
52 | Dold=D;
53 | Vold=V;
54 | Pold=P;
55 | Iold=I;
56 |
--------------------------------------------------------------------------------
/MPPT Algorithms/PandO.m:
--------------------------------------------------------------------------------
1 | function D = PandO(Vpv,Ipv)
2 |
3 | % incremental duty cycle change
4 | delta_D = 0.005;
5 |
6 | % grabs workspace variables or initializes them below
7 | persistent Dprev Pprev Vprev
8 |
9 | if isempty(Dprev)
10 | Dprev = 0.01;
11 | Vprev = 0;
12 | Pprev = 0;
13 | end
14 |
15 | % Calculate measured array power
16 | Ppv = Vpv*Ipv;
17 |
18 | % Increase or decrease duty cycle based on conditions
19 | if (Ppv-Pprev) ~= 0
20 | if (Ppv-Pprev) > 0
21 | if (Vpv-Vprev) > 0
22 | D = Dprev - delta_D;
23 | else
24 | D = Dprev + delta_D;
25 | end
26 | else
27 | if (Vpv-Vprev) > 0
28 | D = Dprev + delta_D;
29 | else
30 | D = Dprev - delta_D;
31 | end
32 | end
33 | else
34 | D = Dprev;
35 | end
36 |
37 | % Forced filtering
38 | if D >= 1 | D<= 0
39 | D=Dold;
40 | end
41 |
42 | % Update internal values
43 | Dprev = D;
44 | Vprev = Vpv;
45 | Pprev = Ppv;
46 |
--------------------------------------------------------------------------------
/MPPT Algorithms/compareMPPT.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/MPPT Algorithms/compareMPPT.jpg
--------------------------------------------------------------------------------
/MPPT Algorithms/total_mppt_comparison.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/MPPT Algorithms/total_mppt_comparison.png
--------------------------------------------------------------------------------
/PV_generator_sim.slx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/PV_generator_sim.slx
--------------------------------------------------------------------------------
/PV_generator_sim.slxc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/PV_generator_sim.slxc
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PV Generator Dynamic Model
2 | MATLAB | Simulink project where a photovoltaic generator system is modelled directly. Both a temperature and irradiance distribution is fed into a Solar Array module from Matlab. The positive and negative terminals feed into a boost converter electrical circuit, and the digital outputs are used for two purposes. The digital output array voltage and current are used to determine appropriate cycle based upon an MPPT algorithm. The duty cycle then feeds to a PWM signal generator and back to a MOSFET in the boost converter circuit. It should be noted that the electrical circuit terminates at a battery. The digital outputs are also fed into a state-feedback controller mimicking a charge controller. Altogether, several PV generator parameter system variables are monitored, and this framework can act as a useful tool for designing such a system
3 |
4 | Note the entire model below
5 | 
6 | To run the 120 second simulation, one must first run either 'statespace_ackerman_setup.m' or 'statespaceLQRsetup.m'. Both similarly initialize workspace variables, but determine the controller feedback gain differently.
7 |
8 | 'passiveparams_overVin&Iin.m' and 'passive_parameters_overduty.m' can be used to determine appropriate sizing for electrical circuit elements.
9 |
10 | ## Built With
11 |
12 | * [Matlab R2019b](https://www.mathworks.com/products/matlab/whatsnew.html) - Matlab version used
13 | * [Simulink](https://www.mathworks.com/products/simulink.html) - Model block simulating module (Version 10.0)
14 | * [Control Systems Toolbox](https://www.mathworks.com/products/control.html) - Required toolbox for controller tuning
15 |
16 |
--------------------------------------------------------------------------------
/input_distb_plot.m:
--------------------------------------------------------------------------------
1 | irr=[100 400 550 700 700 800 800 750 600 500 400 200 200];
2 | temp=[10 11 14 16 18 20 20 19 17 15 14 10 8];
3 | time=[0 10 20 30 40 50 60 70 80 90 100 110 120];
4 | figure(4)
5 | hold on
6 | title('Example Input Distributions for Victoria Spring Day')
7 | xlabel('Time');
8 | yyaxis left
9 | plot(time,irr,'LineWidth',2);
10 | ylim([0 1000]);
11 | ylabel('Irradiance [W/m^2]');
12 | yyaxis right
13 | plot(time, temp,'LineWidth',2);
14 | ylabel('Temperature [\circ C]');
15 | ylim([0 21]);
16 | hold off
--------------------------------------------------------------------------------
/parameter-study.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/parameter-study.xlsx
--------------------------------------------------------------------------------
/passive_parameters_overduty.m:
--------------------------------------------------------------------------------
1 | function [L,C,R_load] = passive_parameters(temp, ripple)
2 | % Use this function to plot capacitance and inductance over duty cycle
3 | % based on ripple and temperature. Displayed current and voltage values are
4 | % for a set solar array configuration. Match appropriate values to the
5 | % exact array of choice. This ultimately helps better size boost converter
6 | % and PWM signal generator.
7 | if temp > 10
8 | Vin = 64.41;
9 | Iin = 15.17;
10 | elseif temp > 12
11 | Vin = 63.83;
12 | Iin = 15.19;
13 | elseif temp > 14
14 | Vin = 63.34;
15 | Iin = 15.17;
16 | elseif temp > 16
17 | Vin = 62.15;
18 | Iin = 15.24;
19 | elseif temp > 18
20 | Vin = 61.6;
21 | Iin = 15.25;
22 | end
23 |
24 | delta_t = 0.001;
25 | duty_cycle = 0.000125:0.000125:1;
26 |
27 | L=zeros(size(duty_cycle));
28 | C=zeros(size(duty_cycle));
29 | R_load=zeros(size(duty_cycle));
30 |
31 | for i=1:size(duty_cycle)
32 | L(i)=(Vin*duty_cycle(i)*delta_t)/(Iin*ripple);
33 | C(i)=(duty_cycle(i)*delta_t*Iin*(1-duty_cycle(i))^2)/(Vin*ripple);
34 | Vout(i) = Vin/duty_cycle(i);
35 | Iout(i)=Vin*Iin/Vout;
36 | R_load(i)=(Vout/Iout);
37 | end
38 |
39 | figure(1)
40 | plot(duty_cycle, L);
41 | title('Inductance over duty cycle');
42 | xlabel('Duty Cycle (%)');
43 | xlim([0 0.01]);
44 | ylabel('Inductance [mH]');
45 |
46 | figure(2)
47 | plot(duty_cycle, C*1000000);
48 | title('Capacitance over duty cycle');
49 | xlabel('Duty Cycle (%)');
50 | ylabel('Capacitance [uF]');
51 |
52 | fprintf('L>%1.16f mH C>%.16f uF R=%f \n', max(L)*1000,max(C)*1000000,mean(R_load));
53 |
54 |
--------------------------------------------------------------------------------
/passiveparams_overVin&Iin.m:
--------------------------------------------------------------------------------
1 | % Run this file after the simulation is done
2 | % Use this file to get an idea of desired passive parameter variables for
3 | % inductance and capacitance
4 |
5 | % Input voltage and current signals (need to change the output from the Simulink file to these values)
6 | Vin=(out.PV.signals.values(:,1));
7 | Iin=(out.PV.signals.values(:,3));
8 |
9 | % Cap first ant last values for better analysis
10 | Vin = Vin(2:end-1);
11 | Iin = Iin(2:end-1);
12 |
13 | % Variable initialization
14 | delta_t = 1/100000;
15 | ripple=0.05;
16 | duty_cycle=1-0.000125;
17 | L=zeros(size(Vin));
18 | Cap=zeros(size(Vin));
19 | R_load=zeros(size(Vin));
20 |
21 | % Determine required inductance and capacitance
22 | for i=1:size(Vin)
23 | L(i)=(Vin(i)*duty_cycle*delta_t)/((Iin(i))*ripple);
24 | Cap(i)=(duty_cycle*delta_t*(Iin(i))*(1-duty_cycle)^2)/(Vin(i)*ripple);
25 | Vout(i) = Vin(i)/duty_cycle;
26 | Iout(i)=Vin(i)*Iin(i)/Vout(i);
27 | R_load(i)=(Vout(i)/Iout(i));
28 | end
29 | R_load=R_load(1:end-1);
30 |
31 | % Plot required inductance over voltage distbn
32 | figure(1)
33 | plot(Vin,L*1000);
34 | title('Inductance over Voltage');
35 | ylabel('Inductance [mH]');
36 | xlabel('Voltage [V]');
37 |
38 | % Plot required capacitance over voltage distbn
39 | figure(2)
40 | plot(Vin, Cap*1000000);
41 | title('Capacitance over Voltage');
42 | xlabel('Voltage [V]');
43 | ylabel('Capacitance [\muF]');
44 | fprintf('L>%1.16f mH C>%.16f uF\n', max(L)*1000,max(Cap)*1000000);
--------------------------------------------------------------------------------
/slprj/_jitprj/sSrjcJsl5QCSDH3ehEoQOKB.l:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/_jitprj/sSrjcJsl5QCSDH3ehEoQOKB.l
--------------------------------------------------------------------------------
/slprj/_jitprj/sSrjcJsl5QCSDH3ehEoQOKB.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/_jitprj/sSrjcJsl5QCSDH3ehEoQOKB.mat
--------------------------------------------------------------------------------
/slprj/_sfprj/EMLReport/sSrjcJsl5QCSDH3ehEoQOKB.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/_sfprj/EMLReport/sSrjcJsl5QCSDH3ehEoQOKB.mat
--------------------------------------------------------------------------------
/slprj/_sfprj/PV_generator_sim/_self/sfun/info/binfo.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/_sfprj/PV_generator_sim/_self/sfun/info/binfo.mat
--------------------------------------------------------------------------------
/slprj/_sfprj/PV_generator_sim/amsi_serial.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/_sfprj/PV_generator_sim/amsi_serial.mat
--------------------------------------------------------------------------------
/slprj/_sfprj/precompile/CHHaOyep6HZiuO3JElBnTB.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/_sfprj/precompile/CHHaOyep6HZiuO3JElBnTB.mat
--------------------------------------------------------------------------------
/slprj/accel/PV_generator_sim/PV_generator_sim_top_vm.bc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/accel/PV_generator_sim/PV_generator_sim_top_vm.bc
--------------------------------------------------------------------------------
/slprj/accel/PV_generator_sim/amsi_serial.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/accel/PV_generator_sim/amsi_serial.mat
--------------------------------------------------------------------------------
/slprj/accel/PV_generator_sim/tmwinternal/simulink_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | KdIebkY+s2nAvY9VXhR6Yw==
5 |
6 |
--------------------------------------------------------------------------------
/slprj/sim/varcache/PV_generator_sim/checksumOfCache.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/sim/varcache/PV_generator_sim/checksumOfCache.mat
--------------------------------------------------------------------------------
/slprj/sim/varcache/PV_generator_sim/tmwinternal/simulink_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | KdIebkY+s2nAvY9VXhR6Yw==
5 |
6 |
--------------------------------------------------------------------------------
/slprj/sim/varcache/PV_generator_sim/varInfo.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spsvision/PV-Dynamic-Model/215b909e55d8b20aeca8eddd0271addfd0544174/slprj/sim/varcache/PV_generator_sim/varInfo.mat
--------------------------------------------------------------------------------
/slprj/sl_proj.tmw:
--------------------------------------------------------------------------------
1 | Simulink Coder project marker file. Please don't change it.
2 | slprjVersion: 10.0_078
--------------------------------------------------------------------------------
/statespaceLQRsetup.m:
--------------------------------------------------------------------------------
1 | % Passive Parameter Variables
2 | L = 0.01;
3 | C_eq = 500e-6;
4 | R = 20;
5 | R_L = 0.10;
6 | R_s=0.29304;
7 | R_sh=120.6455;
8 | R_m=0.38;
9 | V_d=0.8;
10 | R_c=0.0001;
11 |
12 | % Additional variables
13 | duty = 0.000874370313024986;
14 | Vd = 0.6;
15 |
16 | A1=[(-R_L/L) 0; 0 -1/(C_eq*(R+R_c))];
17 | A2=[(-R_L/L-((R*R_c)/(L*(R+R_c)))) (-R/(L*(R+R_c))); R/(C_eq*(R+R_c)) -1/(C_eq*(R+R_c))];
18 | A=A1*duty+A2*(1-duty);
19 | B=[1/L;0];
20 | %H=[-(1-d)/L; 0];
21 | C_state = [1 0; ((1-duty)*(R*R_c)/(R+R_c)) R/(R+R_c)];
22 | D=[0;0];
23 |
24 | poly=charpoly(A);
25 |
26 | % Monitoring controllability and tuning model
27 | Wr = [B A*B];
28 | rank(Wr)
29 | Wr_tilde=inv([1 poly(2) poly(3); 0 1 poly(2); 0 0 1]);
30 |
31 | % LQR parameter setup
32 | % Linear Quadratic Regulator - https://www.mathworks.com/help/control/ref/lqr.html
33 | q1=1;
34 | q2=1;
35 | Q=[[q1 0 0];[0 q2 0];[0 0 1]];
36 | rho=10;
37 | R=rho;
38 |
39 | % Define Gains using LQR() function
40 | [K,S,E]=lqr(A,B,Q,R)
41 | K_r=-1/([1 0 0]*inv(A-B*K)*B)
--------------------------------------------------------------------------------
/statespace_ackerman_setup.m:
--------------------------------------------------------------------------------
1 | % Passive Parameter Variables
2 | L = 0.01;
3 | C_eq = 500e-6;
4 | R = 20;
5 | R_L = 0.10;
6 | R_s=0.29304;
7 | R_sh=120.6455;
8 | R_m=0.38;
9 | V_d=0.8;
10 | R_c=0.0001;
11 |
12 | % Additional variables
13 | duty = 0.000874370313024986;
14 | Vd = 0.6;
15 |
16 | % Define State-space matrix
17 | A1=[(-R_L/L) 0; 0 -1/(C_eq*(R+R_c))];
18 | A2=[(-R_L/L-((R*R_c)/(L*(R+R_c)))) (-R/(L*(R+R_c))); R/(C_eq*(R+R_c)) -1/(C_eq*(R+R_c))];
19 | A=A1*duty+A2*(1-duty);
20 | B=[1/L;0];
21 | %H=[-(1-duty)/L; 0];
22 | C_state = [1 0; ((1-duty)*(R*R_c)/(R+R_c)) R/(R+R_c)];
23 | D=[0;0];
24 |
25 | poly=charpoly(A);
26 | [num,den]=ss2tf(A,B,C_state,D);
27 |
28 | % Check Controllability. Rank must be 2!
29 | [num,den]=ss2tf(A,B,C_state,D);
30 | Wr = [B A*B];
31 | rank(Wr)
32 | eigs=[(-55+3*i) (-55-3*i)];
33 |
34 | % Check Observability. Rank must be 2!
35 | obs=obsv(A,C_state);
36 | rank(obs)
37 | defs=eig(A)
38 |
39 | % Define Gains using place() function - https://www.mathworks.com/help/control/ref/place.html
40 | K=place(A,B,eigs);
41 | K_r=-1/([((1-duty)*(R*R_c)/(R+R_c)) R/(R+R_c)]*inv(A-B*K)*B);
42 |
43 | % Step response of control variables
44 | figure(1)
45 | num1=[num(1,2) num(1,3)];
46 | sys1=tf(num1,den);
47 | step(sys1);
48 | inf1=stepinfo(sys1);
49 | title('Inductor Current Step Response');
50 |
51 | figure(2)
52 | num2=[num(2,2) num(2,3)];
53 | sys2=tf(num2,den);
54 | step(sys2);
55 | inf2=stepinfo(sys2);
56 | title('Capacitor Voltage Step Response');
57 |
58 | % Frequency response of control variables
59 | figure(3)
60 | bode(sys1);
61 | title('Inductor Current Bode Plot');
62 | figure(4)
63 | bode(sys2);
64 | title('Capacitor Voltage Bode Plot');
65 |
66 | % Step response of control variables with applied gain
67 | figure(5)
68 | ss2=ss(A-B*K,B,C_state,D);
69 | step(ss2);
70 | inf_fin=stepinfo(ss2);
71 | final_dampened_response=damp(ss2);
--------------------------------------------------------------------------------