├── .gitignore ├── Propellant ├── sorbitol_coarse.br └── sorbitol_fine.br ├── README.md ├── Propellant.m ├── SRM.m └── Motor.m /.gitignore: -------------------------------------------------------------------------------- 1 | *.m~ 2 | -------------------------------------------------------------------------------- /Propellant/sorbitol_coarse.br: -------------------------------------------------------------------------------- 1 | 1841 1600 1.1361 0.03986 2 | 500 5.13 0.222 -------------------------------------------------------------------------------- /Propellant/sorbitol_fine.br: -------------------------------------------------------------------------------- 1 | 1841 1600 1.1361 0.03986 2 | 8.07 10.708 0.625 3 | 15.03 8.763 -0.314 4 | 37.92 7.852 -0.013 5 | 70.33 3.907 0.535 6 | 500 9.653 0.064 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SRM_Sim 2 | A solid rocket motor simulator in Matlab 3 | 4 | To use, open the file SRM.m and change the values to the specific motor, nozzle, grain geometry and erosive burning properties. More details on the file itself. Currently only fine KNSB propellant is available. 5 | 6 | TO-DO LIST: 7 | - GUI; 8 | - Multi-phase flow; 9 | - Variable gas properties; 10 | - Add more propellants; 11 | -------------------------------------------------------------------------------- /Propellant.m: -------------------------------------------------------------------------------- 1 | classdef Propellant p_old && p <= pp(i,1)); 32 | p_old = pp(i,1); 33 | else 34 | r = @(p) r(p) + (1e-3)*pp(i,2)*((p/10)^pp(i,3))*(p > p_old); 35 | end 36 | end 37 | obj.r = r; 38 | obj.Lg = Lg; 39 | obj.Dg = Dg; 40 | obj.Dc = Dcore; 41 | obj.Seg = Seg; 42 | obj.b = b; 43 | obj.Vol = 0; 44 | end 45 | 46 | function [mp, Sr] = burn(obj, pc, dt) 47 | obj.Vol = (pi/4)*(obj.Dg^2 - obj.Dc^2)*obj.Lg; 48 | Sr = 0; 49 | if obj.Vol < 0 50 | mp = 0; 51 | else 52 | if bitand(obj.b, 1) 53 | Sr = pi*obj.Dc*obj.Lg; 54 | end 55 | if bitand(obj.b, 2) 56 | Sr = Sr + (pi/2)*(obj.Dg^2 - obj.Dc^2); 57 | end 58 | if bitand(obj.b, 4) 59 | Sr = Sr + pi*obj.Dg*obj.Lg; 60 | end 61 | r = obj.r(pc); 62 | Sr = obj.Seg*Sr*r; 63 | mp = obj.ro*Sr; 64 | 65 | if bitand(obj.b, 1) 66 | obj.Dc = obj.Dc + 2*r*dt; 67 | end 68 | if bitand(obj.b, 2) 69 | obj.Lg = obj.Lg - 2*r*dt; 70 | end 71 | if bitand(obj.b, 4) 72 | obj.Dg = obj.Dg - 2*r*dt; 73 | end 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /SRM.m: -------------------------------------------------------------------------------- 1 | %% Solid Rocket Motor Simulator - by Ftps 2 | 3 | clear 4 | 5 | % Propellant 6 | prop = "Propellant/sorbitol_coarse.br"; % For now, only available propellant 7 | Cc = 0.95; % Combustion efficiency 8 | n_c = 0.95; % Real/Ideal density 9 | 10 | % Grain Geometry (cylindrical) 11 | Lg = 107e-3; % Grain length 12 | Dg = 76.6e-3; % Grain diamter 13 | Dcore = 25e-3; % Core diameter 14 | Seg = 1; % Number of grain segments 15 | 16 | % Burn Type 17 | core = true; % core burning 18 | ends = false; % ends burning 19 | outer = false; % outer surface burning 20 | 21 | %Nozzle 22 | Dt = 7e-3; % Nozzle throat diameter 23 | De = 14e-3; % Nozzle eixt diameter 24 | Cn = 0.5*(1 + cosd(12)); % Nozzle losses (Divergence losses: 0.5*(1+cosd(a)), a = divergence half-angle 25 | 26 | % Chamber Geometry 27 | Lc = 118.9e-3; % Chamber length 28 | Dc = 80e-3; % Chamber diameter 29 | 30 | % Simulation Time-Step 31 | dt = 1e-3; 32 | 33 | % Sea level (1) or vacuum (0) 34 | Sea_level = 1; % DON'T CHANGE, NO BURN MODEL FOR VACCUM PRESSURES AND NULL-MASS ERRORS 35 | 36 | % Estimated Burn Time 37 | t_est = 4; 38 | 39 | %% NO CHANGE FROM HERE 40 | 41 | % Simulation Set Up and Run 42 | b = core*(2^0) + ends*(2^1) + outer*(2^2); 43 | m = Motor(prop, Lg, Dg, Dcore, Seg, b, Dt, De, Lc, Dc, Cc, Cn, Sea_level, n_c); 44 | m.simulation(dt, t_est); 45 | 46 | 47 | % Plot Display 48 | figure('Name', 'SRM Simulator', 'NumberTitle', 'off', 'Position', [50, 200 1600, 350]) 49 | subplot(1, 3, 1); 50 | plot(m.t, m.Th, 'r'); 51 | hold on; 52 | title("Thrust"); 53 | xlabel("Time - s"); 54 | ylabel("T - N"); 55 | 56 | subplot(1, 3, 2); 57 | plot(m.t, m.pc, 'b'); 58 | title("Chamber Pressure"); 59 | xlabel("Time - s"); 60 | ylabel("p_c - bar"); 61 | 62 | subplot(1, 3, 3); 63 | plot(m.t, m.m_dot, 'm'); 64 | title("Mass Flow Rate"); 65 | xlabel("Time - s"); 66 | ylabel("m_d - kg/s"); 67 | hold off; 68 | 69 | g0 = 9.81; 70 | I = 0; 71 | F_av = 0; 72 | F_max = 0; 73 | [~,l] = size(m.Th); 74 | for i = 1:l 75 | if m.Th(i) > F_max 76 | F_max = m.Th(i); 77 | end 78 | F_av = F_av + m.Th(i); 79 | I = I + m.Th(i)*dt; 80 | end 81 | F_av = F_av/l; 82 | Isp = I/(m.p.ro*(Seg*Lg*pi*(Dg^2 - Dcore^2)/4)*g0); 83 | 84 | disp(" "); 85 | disp("%%%%% MOTOR DATA %%%%%"); 86 | disp(" "); 87 | disp("Total Impulse = " + I + " Ns"); 88 | disp("Isp = " + Isp + " s"); 89 | disp("Max Thrust = " + F_max + " N"); 90 | disp("Average Thrust = " + F_av + " N"); 91 | disp("Burn Time = " + m.t_burn + " s"); 92 | disp("Thrust Time = " + m.t_t + " s"); 93 | -------------------------------------------------------------------------------- /Motor.m: -------------------------------------------------------------------------------- 1 | classdef Motor m.amb.p && m.m(i) > 0) || Sr ~= 0 72 | i = i+1; 73 | if i > max 74 | 75 | max = max + extra; 76 | 77 | m.pc = [m.pc, zeros(1, extra)]; 78 | m.Tc = [m.Tc, zeros(1, extra)]; 79 | m.m_dot = [m.m_dot, zeros(1, extra)]; 80 | m.Th = [m.Th, zeros(1, extra)]; 81 | m.t = [m.t, zeros(1, extra)]; 82 | m.m = [m.m, zeros(1, extra)]; 83 | end 84 | 85 | m.t(i) = m.t(i-1) + dt; 86 | m.m(i) = m.m(i-1) + (mp - m.m_dot(i-1))*dt; 87 | 88 | if Sr ~= 0 89 | %phi = (phi*(m.m(i-1)-dm) + dm)/m.m(i-1); % mass percentage of propelant 90 | phi = phi + (1-phi)*mp*dt/m.m(i-1); 91 | M = 1/(phi/m.p.M + (1-phi)/m.amb.M); 92 | R = 8.3144/M; 93 | cp = phi*m.p.cp + (1-phi)*m.amb.cp; 94 | cv = cp - R; 95 | k = cp/cv; 96 | G = sqrt(k)*(2/(k+1))^((k+1)/(2*(k-1))); 97 | dcv = (1-phi)*(mp/m.m(i))*(cp-m.amb.cp + 8.3144*(1/m.p.M - 1/m.amb.M)); 98 | Vc = Vc + Sr*dt; 99 | m.Tc(i) = m.Tc(i-1) + ((mp*m.p.cp*m.p.Tf - m.pc(i)*bar*Sr)/(m.m(i)*cv) - m.Tc(i-1)*(k*(m.m_dot(i-1)/m.m(i)) + (mp-m.m_dot(i-1))/m.m(i) + dcv/cv))*dt; 100 | %m.pc(i) = m.pc(i-1) + ((R*m.Tc(i-1)/Vc)*(dm1 - m.m_dot(i-1)*dt) + (1/m.Tc(i-1))*(m.Tc(i) - m.Tc(i-1)))/bar; 101 | m.pc(i) = m.m(i)*R*m.Tc(i)/(Vc*bar); 102 | [mp, Sr] = m.p.burn(m.pc(i), dt); 103 | else 104 | if m.t_burn == 0 105 | m.t_burn = m.t(i); 106 | %C = m.pc(i-1)/(m.Tc(i-1)^(k/(k-1))); 107 | end 108 | m.Tc(i) = m.Tc(i-1) - (k-1)*m.Tc(i-1)*m.m_dot(i-1)*dt/m.m(i); 109 | m.pc(i) = m.m(i)*R*m.Tc(i)/(Vc*bar); 110 | %m.pc(i) = C*m.Tc(i)^(k/(k-1)); 111 | 112 | end 113 | 114 | Me = fzero(@(x) (1/x)*sqrt((1+((k-1)/2)*x^2)/(1+((k-1)/2)))^((k+1)/(k-1)) - m.e, [1, 10]); 115 | tt = 1+0.5*(k-1)*Me^2; 116 | p_exit = m.pc(i)/(tt^(k/(k-1))); 117 | m.m_dot(i) = bar*m.pc(i)*m.At*G/sqrt(R*m.Tc(i)); 118 | m.Th(i) = m.Ceff*m.m_dot(i)*Me*sqrt(k*R*m.Tc(i)/tt) + m.Ae*(p_exit - m.amb.p)*bar; 119 | 120 | if m.Th(i) < 0 121 | m.Th(i) = 0; 122 | if m.t_t == 0 && Sr == 0 123 | m.t_t = m.t(i); 124 | end 125 | end 126 | end 127 | 128 | m.t = m.t(1:i); 129 | m.Tc = m.Tc(1:i); 130 | m.pc = m.pc(1:i); 131 | m.m = m.m(1:i); 132 | m.m_dot = m.m_dot(1:i); 133 | m.Th = m.Th(1:i); 134 | disp(i); 135 | end 136 | end 137 | 138 | end 139 | --------------------------------------------------------------------------------