// main.cpp
// StringModel
//
// Created by Sam Logan on 07/06/2023.
//
#include <iostream>
#include "StringModel.h"
/**
This script simulates a stiff string using the FDTD method
*/
StringModel::StringModel()
{
// Memory
u = udata;
u1 = u1data;
u2 = u2data;
prev_out = 0.0;
memset(udata, 0, max_string_ss * sizeof(double));
memset(u1data, 0, max_string_ss * sizeof(double));
memset(u2data, 0, max_string_ss * sizeof(double));
}
/**
Sets up the physical parameters of the string
@param T0 tension (N)
@param L length (m)
@param E0 young's Modulus
@param rho0 density (kg/m^3)
@param r0 radius (m)
@param low_T60 low decay (s)
@param high_T60P high decay (s)
*/
void StringModel::FirstSet(double T0, double L, double E0, double rho0, double r0, double low_T60, double high_T60P, double sampleR)
{
memset(udata, 0, max_string_ss * sizeof(double));
memset(u1data, 0, max_string_ss * sizeof(double));
memset(u2data, 0, max_string_ss * sizeof(double));
double high_T60 = high_T60P*low_T60;
double k = 1.0/sampleR;
double A0 = M_PI*r0*r0; // cross sectional area
double I0 = 0.25*M_PI*r0*r0*r0*r0; // moment of inertia
double kappa = sqrt(E0*I0/(rho0*A0)); // stiffness parameter
c = sqrt(T0/(rho0*A0)); // wave speed
_sig0 = 6.0*log(10.0)/low_T60; // numerical loss parameter
double z1 = (-c*c + sqrt(c*c*c*c + 4.0*kappa*kappa*(2.0*M_PI*1000.0)*(2.0*M_PI*1000.0) )) / (2.0*kappa*kappa);
if(kappa<0.1) z1 = (2.0*M_PI*1000.0)*(2.0*M_PI*1000.0) / (c*c);
if(c<0.1) z1 = 2.0*M_PI*1000.0/kappa;
double sig_1 = (6.0*log(10.0)/z1)*(1.0/high_T60 - 1.0/low_T60);
_h = sqrt(c*c*k*k + 4.0*sig_1*k + sqrt( (c*c*k*k + 4.0*sig_1*k)*(c*c*k*k + 4.0*sig_1*k) + 16.0*kappa*kappa*k*k));
_N = floor(L/_h);
_h = L/_N;
double mu = k*kappa / (_h*_h); // Courant number (stiffness)
double lambda = c*k/_h;
// Check not over max array size !!
if (_N>(max_string_ss-6))
{
_N = max_string_ss-6;
std::cout<<"\nState size is larger than memory...\n";
}
double mu2 = mu*mu;
double sik = 1.0+_sig0*k;
double sk = sig_1*k/(_h*_h);
double l2 = lambda*lambda;
_B0 = (2.0 - 6.0*mu2 - 2.0*l2 - 4.0*sk ) / sik;
_B1 = ( 4.0*mu2 + l2 + 2*sk ) / sik;
_B2 = ( -mu2 ) / sik;
_C0 = (_sig0*k - 1.0 + 4*sk ) /sik;
_C1 = ( -2.0*sk ) /sik;
_C10 = ( -4.0*sk ) /sik;
_B00 = (2.0 - 5.0*mu2 - 2.0*l2 - 4.0*sk ) / sik;
_B10 = ( 2.0*mu2 + l2 + 2*sk ) / sik;
_B100 = ( 4.0*mu2 + 2.0*l2 + 4*sk ) / sik;
_B000 = (2.0 - 2.0*mu2 - 2.0*l2 - 4.0*sk ) / sik;
_B20 = ( -2.0*mu2 ) / sik;
}
void StringModel::UpdateParams(double T0, double L, double E0, double rho0, double r0, double low_T60, double high_T60P, double sampleR)
{
double high_T60 = high_T60P*low_T60;
double k = 1.0/sampleR;
double A0 = M_PI*r0*r0; // cross sectional area
double I0 = 0.25*M_PI*r0*r0*r0*r0; // moment of inertia
double kappa = sqrt(E0*I0/(rho0*A0)); // stiffness parameter
c = sqrt(T0/(rho0*A0)); // wave speed
_sig0 = 6.0*log(10.0)/low_T60; // numerical loss parameter
double z1 = (-c*c + sqrt(c*c*c*c + 4.0*kappa*kappa*(2.0*M_PI*1000.0)*(2.0*M_PI*1000.0) )) / (2.0*kappa*kappa);
if(kappa<0.1) z1 = (2.0*M_PI*1000.0)*(2.0*M_PI*1000.0) / (c*c);
if(c<0.1) z1 = 2.0*M_PI*1000.0/kappa;
double sig_1 = (6.0*log(10.0)/z1)*(1.0/high_T60 - 1.0/low_T60);
_h = sqrt(c*c*k*k + 4.0*sig_1*k + sqrt( (c*c*k*k + 4.0*sig_1*k)*(c*c*k*k + 4.0*sig_1*k) + 16.0*kappa*kappa*k*k));
_N = floor(L/_h);
_h = L/_N;
double mu = k*kappa / (_h*_h); // Courant number (stiffness)
double lambda = c*k/_h;
// Check not over max array size !!
if (_N>(max_string_ss-6))
{
_N = max_string_ss-6;
std::cout<<"\nState size is larger than memory...\n";
}
double mu2 = mu*mu;
double sik = 1.0+_sig0*k;
double sk = sig_1*k/(_h*_h);
double l2 = lambda*lambda;
_B0 = (2.0 - 6.0*mu2 - 2.0*l2 - 4.0*sk ) / sik;
_B1 = ( 4.0*mu2 + l2 + 2*sk ) / sik;
_B2 = ( -mu2 ) / sik;
_C0 = (_sig0*k - 1.0 + 4*sk ) /sik;
_C1 = ( -2.0*sk ) /sik;
_C10 = ( -4.0*sk ) /sik;
_B00 = (2.0 - 5.0*mu2 - 2.0*l2 - 4.0*sk ) / sik;
_B10 = ( 2.0*mu2 + l2 + 2*sk ) / sik;
_B100 = ( 4.0*mu2 + 2.0*l2 + 4*sk ) / sik;
_B000 = (2.0 - 2.0*mu2 - 2.0*l2 - 4.0*sk ) / sik;
_B20 = ( -2.0*mu2 ) / sik;
}
/**
Calculates the state equation for the FDTD Stiff String and defines the boundaries
*/
void StringModel::UpdateState()
{
int cp;
// This loop will hopefully be vectorized by the compiler..
for(cp=2;cp<(_N-1);cp++)
{
u[cp] = _B0*u1[cp] + _B1*( u1[cp-1] + u1[cp+1] ) + _B2*( u1[cp-2] + u1[cp+2] ) + _C0*u2[cp] + _C1*( u2[cp-1] + u2[cp+1] );
}
// Boundaries
u[1] = _B00*u1[1] + _B10*u1[0] + _B1*u1[2] + _B2*u1[3] + _C0*u2[1] + _C1*(u2[0] + u2[2]);
u[_N-1] = _B00*u1[_N-1] + _B10*u1[_N] + _B1*u1[_N-2] + _B2*u1[_N-3] + _C0*u2[_N-1] + _C1*(u2[_N] + u2[_N-2]);
u[0] = _B000*u1[0] + _B100*u1[1] + _B20*u1[2] + _C0*u2[0] + _C10*u2[1];
u[_N] = _B000*u1[_N] + _B100*u1[_N-1] + _B20*u1[_N-2] + _C0*u2[_N] + _C10*u2[_N-1];
}
/**
Defines the position and scale of the 'pluck' of the string
@param inpos input position (where the string is plucked)
@param fin output position
@param scale the amplitude of the pluck
*/
void StringModel::UpdateInput(double inpos,double fin,double scale)
{
int in_cell = floor(inpos*(_N + 1)) - 1;
u[in_cell]+= fin*scale;
}
/**
Reads the output and shifts the state
*/
double StringModel::Output()
{
double read = u[10];
// Differentiate the output
double output = read - prev_out;
prev_out = read;
// swap pointers
double *dummy_ptr;
dummy_ptr = u2;
u2 = u1;
u1 = u;
u = dummy_ptr;
return output;
}
```~