├── 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 | ![](Capture.PNG) 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); --------------------------------------------------------------------------------