// sprfft - Program to compute the power spectrum of a // coupled mass-spring system. #include "NumMeth.h" void sprrk(double x[], double t, double param[], double deriv[]); void rk4( double x[], int nX, double t, double tau, void (*derivsRK)(double x[], double t, double param[], double deriv[]), double param[]); void fft( Matrix& RealA, Matrix& ImagA); void main() { //* Set parameters for the system (initial positions, etc.). const int nState = 6; Matrix x(3), v(3); double state[nState+1]; cout << "Enter initial displacement of:" << endl; cout << " Mass #1 = "; cin >> x(1); cout << " Mass #2 = "; cin >> x(2); cout << " Mass #3 = "; cin >> x(3); v(1) = 0.0; v(2) = 0.0; v(3) = 0.0; // Masses are initially at rest state[1] = x(1); state[2] = x(2); state[3] = x(3); state[4] = v(1); state[5] = v(2); state[6] = v(3); cout << "Enter timestep: "; double tau; cin >> tau; double k_over_m = 1; // Ratio of spring const. over mass double param[1+1]; param[1] = k_over_m; //* Loop over the desired number of time steps. double time = 0; // Set initial time int nStep = 256; // Number of steps in the main loop int nprint = nStep/8; // Number of steps between printing progress Matrix xplot(nStep,3), tplot(nStep); // Plotting variables int i, iStep; for( iStep=1; iStep<=nStep; iStep++ ) { //* Use Runge-Kutta to find new displacements of the masses. rk4(state,nState,time,tau,sprrk,param); time = time + tau; //* Record the positions for graphing and to compute spectra. xplot(iStep,1) = state[1]; // Record positions xplot(iStep,2) = state[2]; xplot(iStep,3) = state[3]; tplot(iStep) = time; if( (iStep%nprint) < 1 ) cout << "Finished " << iStep << " out of " << nStep << " steps" << endl; } //* Calculate the power spectrum of the time series for mass #1 Matrix f(nStep), x1fftR(nStep), x1fftI(nStep), spect(nStep); for( i=1; i<=nStep; i++ ) { f(i) = (i-1)/(tau*nStep); // Frequency double x1 = xplot(i,1); // Displacement of mass 1 x1fftR(i) = x1; x1fftI(i) = 0.0; // Copy data for input to fft } fft(x1fftR, x1fftI); // Fourier transform of displacement for( i=1; i<=nStep; i++ ) // Power spectrum of displacement spect(i) = x1fftR(i)*x1fftR(i) + x1fftI(i)*x1fftI(i); //* Apply the Hanning window to the time series and calculate // the resulting power spectrum double window, pi = 3.141592654; Matrix x1fftRw(nStep), x1fftIw(nStep), spectw(nStep); for( i=1; i<=nStep; i++ ) { window = 0.5*(1.0-cos(2.0*pi*(i-1.0)/nStep)); // Hanning window double x1w = xplot(i,1) * window; // Windowed time series x1fftRw(i) = x1w; x1fftIw(i) = 0.0; // Copy data for input to fft } fft(x1fftRw, x1fftIw); // Fourier transf. (windowed data) for( i=1; i<=nStep; i++ ) // Power spectrum (windowed data) spectw(i) = x1fftRw(i)*x1fftRw(i) + x1fftIw(i)*x1fftIw(i); //* Print out the plotting variables: // tplot, xplot, f, spect, spectw ofstream tplotOut("tplot.txt"), xplotOut("xplot.txt"), fOut("f.txt"), spectOut("spect.txt"), spectwOut("spectw.txt"); for( i=1; i<=nStep; i++ ) { tplotOut << tplot(i) << endl; xplotOut << xplot(i,1) << ", " << xplot(i,2) << ", " << xplot(i,3) << endl; fOut << f(i) << endl; spectOut << spect(i) << endl; spectwOut << spectw(i) << endl; } } /***** To plot in MATLAB; use the script below ******************** load tplot.txt; load xplot.txt; load f.txt; load spect.txt; load spectw.txt nstep = length(tplot); nprint = nstep/8; %* Graph the displacements of the three masses. figure(1); clf; % Clear figure 1 window and bring forward ipr = 1:nprint:nstep; % Used to graph limited number of symbols plot(tplot(ipr),xplot(ipr,1),'o',tplot(ipr),xplot(ipr,2),'+',... tplot(ipr),xplot(ipr,3),'*',... tplot,xplot(:,1),'-',tplot,xplot(:,2),'-.',... tplot,xplot(:,3),'--'); legend('Mass #1','Mass #2','Mass #3'); title('Displacement of masses (relative to rest positions)'); xlabel('Time'); ylabel('Displacement'); %* Graph the power spectra for original and windowed data figure(2); clf; % Clear figure 2 window and bring forward semilogy(f(1:(nstep/2)),spect(1:(nstep/2)),'-',... f(1:(nstep/2)),spectw(1:(nstep/2)),'--'); title('Power spectrum (dashed is windowed data)'); xlabel('Frequency'); ylabel('Power'); ******************************************************************/