|
| 1 | +clearvars, |
| 2 | +close all |
| 3 | + |
| 4 | +%%%%% flags |
| 5 | + |
| 6 | +plot_on = 0; % in-loop plotting on (1) or off (0) |
| 7 | +itype = 1; % type of input: 1: struck, 2: plucked |
| 8 | +bctype = 1; % boundary condition type: 1: simply supported, 2: clamped |
| 9 | +outtype = 1; % output type: 1: string displacement, 2: string velocity |
| 10 | + |
| 11 | +%%%%% parameters |
| 12 | + |
| 13 | +% physical string parameters (see Q7a) |
| 14 | +L(1:6) = 0.648; % guitar scale length(m) |
| 15 | +rho(1:6)= 7750; % Density of steel (kg/m^3) |
| 16 | +% Strings: E B G D A E |
| 17 | +% gauges: .046 .036 .026 .017 .013 .01 |
| 18 | +r = [1.1684e-3 9.144e-4 6.604e-4 4.3e-4 3.3e-4 2.5e-4]; % string radius (m) |
| 19 | + |
| 20 | +% Young's modulus (Pa) taken from |
| 21 | +% http://srjcstaff.santarosa.edu/~yataiiya/E45/PROJECTS/guitar%20strings.pdf |
| 22 | +% considering the lowest three strings to be wound and the top three |
| 23 | +% single-wire |
| 24 | +E = [6.4e10 6.4e10 6.4e10 1.88e11 1.88e11 1.88e11] ; |
| 25 | +freq= [82.41 110 146.83 196 246.94 329.63]; % Note frequencies |
| 26 | + |
| 27 | + |
| 28 | + |
| 29 | +% T60 (s) was left to 5 s. Although longer T60 were found by analysing |
| 30 | +% decays of plucked guitar strings, 5 s produced nicer sound. |
| 31 | +T60(1:6) = 5; |
| 32 | + |
| 33 | +% I/O |
| 34 | +SR = 44100; % sample rate (Hz) |
| 35 | +Tf = 5; % duration of simulation (s) |
| 36 | + |
| 37 | +xi(1:6) = 0.3; % coordinate of excitation (normalised, 0-1) |
| 38 | +famp = [1 1 1 1 1 1]; % peak amplitude of excitation (N) |
| 39 | +dur = [0.001 0.001 0.001 0.001 0.001 0.001]; % duration of excitation (s) |
| 40 | +exc_st = [0 0.5 1 1.5 2 2.5]; % start time of excitation (s) |
| 41 | +xo(1:6) = 0.2; % coordinate of output (normalised, 0-1) |
| 42 | +window_dur = 0.01; % duration of fade-out window (s). See Q6. |
| 43 | + |
| 44 | +%%%%% Error checking |
| 45 | + |
| 46 | +if any([r, rho, T60, L, SR, Tf, famp, window_dur]<=0) |
| 47 | + error('Parameters must be positive'); |
| 48 | +end |
| 49 | +if any(E<0) |
| 50 | + error('Young''s modulus must be non-negative'); |
| 51 | +end |
| 52 | +if any(exc_st<0 | exc_st>Tf) |
| 53 | + error('Start time of excitation are beyond the simulation time') |
| 54 | +end |
| 55 | +if any([xi, xo]>=1 | [xi, xo]<=0) |
| 56 | + error('Excitation and output coordinates must be between 0 and 1') |
| 57 | +end |
| 58 | +if any([all(plot_on~=[0 1]) all(itype~=[1 2])... |
| 59 | + all(bctype~=[1 2]) all(outtype~=[1 2])]) |
| 60 | + error('Flag values are incorrect') |
| 61 | +end |
| 62 | +if any(exc_st+dur>Tf) |
| 63 | + error('Excitation duration exceeds simulation duration') |
| 64 | +end |
| 65 | + |
| 66 | +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 67 | + |
| 68 | +%%%%% derived parameters |
| 69 | +A = pi*r.^2; % string cross-sectional area |
| 70 | +I = 0.25*pi*r.^4; % string moment of intertia |
| 71 | +K = sqrt(E.*I./(rho.*A)); % stiffness constant |
| 72 | + |
| 73 | +% Tension (N) using stiff string frequency equation (7.21) from NSS |
| 74 | +T = (4*L.^2.*freq.^2+K.^2*pi^2).*rho.*A; |
| 75 | + |
| 76 | +c = sqrt(T./(rho.*A)); % wave speed |
| 77 | + |
| 78 | +sig = 6*log(10)./T60; % loss parameter |
| 79 | + |
| 80 | +%%%%% grid |
| 81 | + |
| 82 | +k = 1/SR; % time step |
| 83 | +hmin = sqrt(0.5*(c.^2.*k^2+sqrt(c.^4.*k^4+16*K.^2.*k^2))); % minimal grid spacing |
| 84 | + |
| 85 | +N = floor(L./hmin); % number of segments (N+1 is number of grid points) |
| 86 | + |
| 87 | +%%%%% rest of error checking |
| 88 | +if any(N>10000) |
| 89 | + error('Too many grid points.') |
| 90 | +end |
| 91 | + |
| 92 | +h = L./N; % adjusted grid spacing |
| 93 | + |
| 94 | +lambda = c*k./h; % Courant number |
| 95 | +mu = K*k./h.^2; % numerical stiffness constant |
| 96 | + |
| 97 | +%%%%% I/O |
| 98 | + |
| 99 | +Nf = floor(SR*Tf); % number of time steps |
| 100 | + |
| 101 | +li = floor(xi.*N); % grid index of excitation |
| 102 | +lo = floor(xo.*N); % grid index of output |
| 103 | + |
| 104 | +Nstr = length(T); % number of strings |
| 105 | + |
| 106 | + |
| 107 | +%%%% Adjusting li and lo in case they are out of range and calculating |
| 108 | +%%%% indeces for I/O in the case of concatenated u |
| 109 | + |
| 110 | +mli=zeros(1,Nstr); % Input for matrix form |
| 111 | +mlo=zeros(1,Nstr); % Output for matrix form |
| 112 | + |
| 113 | +for s=1:Nstr |
| 114 | + if any([li(s),lo(s)]<2 | [li(s), lo(s)]>N(s)) |
| 115 | + warning('Param:outRange',... |
| 116 | + ['Excitation and/or output is outside the range of h to L-h.' ... |
| 117 | + '\n Forcing it to the range.']) |
| 118 | + end |
| 119 | + if li(s)<2 |
| 120 | + li(s)=2; |
| 121 | + elseif li(s)>N(s) |
| 122 | + li(s)=N(s); |
| 123 | + end |
| 124 | + if lo(s)<2 |
| 125 | + lo(s)=2; |
| 126 | + elseif lo(s)>N(s) |
| 127 | + lo(s)=N(s); |
| 128 | + end |
| 129 | + |
| 130 | + % Adding the summed number of grid points of the previous strings and |
| 131 | + % subtracting s number of points, since the 1st point of each string is |
| 132 | + % missing |
| 133 | + mli(s)=li(s)+sum(N(1:s-1))-s; |
| 134 | + mlo(s)=lo(s)+sum(N(1:s-1))-s; |
| 135 | +end |
| 136 | +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 137 | + |
| 138 | +% create force signal |
| 139 | + |
| 140 | +f = zeros(Nf,Nstr); % input force signal |
| 141 | +durint = floor(dur*SR); % duration of force signal, in samples |
| 142 | +exc_st_int = floor(exc_st*SR)+1; % start time index for excitation |
| 143 | + |
| 144 | + |
| 145 | +% Computing forcing terms for each string |
| 146 | +for s=1:Nstr |
| 147 | + f(exc_st_int(s):exc_st_int(s)+durint(s)-1,s)=famp(s)*0.5.*... |
| 148 | + (1-cos(2/itype*pi*(0:durint(s)-1)/durint(s))); |
| 149 | +end |
| 150 | + |
| 151 | +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 152 | + |
| 153 | +%%%%% scheme coefficients |
| 154 | +out = zeros(Nf, 1); % output |
| 155 | +tic |
| 156 | +% loop over the strings |
| 157 | +AA=cell(1,Nstr); |
| 158 | +BB=cell(1,Nstr); |
| 159 | +CC=cell(1,Nstr); |
| 160 | + |
| 161 | +% Finding matrices for each string |
| 162 | +for s=1:Nstr |
| 163 | + % interior |
| 164 | + I = speye(N(s) - 1); |
| 165 | + Dxx = fidimat(N(s)-1,'xx', 1); |
| 166 | + Dxxxx = fidimat(N(s)-1,'xxxx', 1); |
| 167 | + |
| 168 | + a = 1/(1+sig(s)*k); |
| 169 | + BB{s} = a*(2*I + (lambda(s)^2*Dxx) + (-mu(s)^2) * Dxxxx); |
| 170 | + CC{s} = a*(-(1-sig(s)*k)*I); |
| 171 | +end |
| 172 | + |
| 173 | +% Concatenating them into block diagonal matrices |
| 174 | +AA=blkdiag(AA{:}); |
| 175 | +BB=blkdiag(BB{:}); |
| 176 | +CC=blkdiag(CC{:}); |
| 177 | + |
| 178 | + |
| 179 | +% input |
| 180 | +d0 = 1./(1+sig*k).*(k^2./(h.*rho.*A)); |
| 181 | + |
| 182 | +%%%%% initialise scheme variables |
| 183 | + |
| 184 | +u2 = zeros(sum(N)-Nstr,1); % state |
| 185 | +u1 = u2; % state |
| 186 | +u = u2; % state |
| 187 | + |
| 188 | +% plot |
| 189 | +if(plot_on==1) |
| 190 | + % draw current state |
| 191 | + fig=figure; |
| 192 | + for s=1:Nstr |
| 193 | + subplot(Nstr,1,s) |
| 194 | + pl(s)=plot((0:N(s)-2)'*h(s), u(1-s+1+sum(N(1:s-1)):sum(N(1:s))-s), 'k'); |
| 195 | + axis([0 L(s)-h(s) -0.0005 0.0005]) |
| 196 | + % set data source (to be later used for refreshing data) |
| 197 | + set(pl(s),'YDataSource',['u(' num2str(1-s+1+sum(N(1:s-1)))... |
| 198 | + ':' num2str(sum(N(1:s))-s) ')']) |
| 199 | + ylabel(['String ' num2str(s)]) |
| 200 | + end |
| 201 | + drawnow |
| 202 | +end |
| 203 | + |
| 204 | +%%%%% main loop |
| 205 | +for n=1:Nf |
| 206 | + |
| 207 | + u=(BB*u1+CC*u2); |
| 208 | + |
| 209 | + % send in input |
| 210 | + u(mli) = u(mli)+(d0.*f(n,:))'; |
| 211 | + |
| 212 | + % read output |
| 213 | + if(outtype==1) |
| 214 | + out(n)= sum(u(mlo)); |
| 215 | + end |
| 216 | + if(outtype==2) |
| 217 | + out(n) = sum((u(mlo)-u1(mlo))/k); |
| 218 | + end |
| 219 | + |
| 220 | + % plot |
| 221 | + if(plot_on==1) |
| 222 | + refreshdata(fig) |
| 223 | + drawnow |
| 224 | + end |
| 225 | + |
| 226 | + % shift state |
| 227 | + u2 = u1; |
| 228 | + u1 = u; |
| 229 | + |
| 230 | +end |
| 231 | + |
| 232 | +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 233 | + |
| 234 | +%%%% windowing the end |
| 235 | +nWin=floor(SR*window_dur); |
| 236 | +out(end-nWin:end)=0.5*(1+cos(pi*(0:nWin)/nWin))'.*out(end-nWin:end); |
| 237 | + |
| 238 | +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 239 | + |
| 240 | +toc |
| 241 | +%%%%% play sound |
| 242 | +soundsc(out,SR); |
| 243 | + |
| 244 | +%%%%% plot spectrum |
| 245 | + |
| 246 | +figure(1) |
| 247 | +outfft = 10*log10(abs(fft(out))); |
| 248 | +plot((0:SR/Nf:SR*(1-1/Nf))', outfft, 'k') |
| 249 | +xlabel('Frequency (Hz)') |
| 250 | +ylabel('Magnitude') |
| 251 | +title('Frequency Spectrum of Output Signal') |
| 252 | +set(gca, 'FontSize', 12) |
| 253 | +xlim([0 SR/2]) |
| 254 | + |
0 commit comments