// PROGRAM poincare // 外力を受けた減衰単振り子の位相図とポアンカレ・プロット #include "TrueBASIC.h" int main(); void initial(double *theta0, double *ang_vel0, double *gamma, double *A, double *t0, double *dt, int *nstep, double *dA, int *IC1_, int *IC2_, char* flag); void set_up_windows(double A, int IC1_, int IC2_); void draw_axes(double A, int IC1_, int IC2_); void RK4(double *theta, double *ang_vel, double gamma, double A, double *t, double dt); double force(double theta, double ang_vel, double gamma, double A, double t); void phase_space(double theta, double ang_vel, int IC9_); void change_amplitude(double *A, double dA, int IC1_, int IC2_, char* flag); void Poincare(double theta, double ang_vel, int IC9_); int main() { int IC1_ = 1, IC2_ = 2, istep, nstep; double A, ang_vel, dA, dt, gamma, t, theta; char flag[_LBUFF_]; GWopen(0); initial(&theta, &ang_vel, &gamma, &A, &t, &dt, &nstep, &dA, &IC1_, &IC2_, flag); set_up_windows(A, IC1_, IC2_); draw_axes(A, IC1_, IC2_); do { for(istep = 1; istep <= nstep; ++istep) { RK4(&theta, &ang_vel, gamma, A, &t, dt); phase_space(theta, ang_vel, IC1_); } Poincare(theta, ang_vel, IC2_); if(TBkeyinput()) change_amplitude(&A, dA, IC1_, IC2_, flag); } while(!(strcmp(flag, "stop") == 0)); GWquit(); return 0; } void initial(double *theta0, double *ang_vel0, double *gamma, double *A, double *t0, double *dt, int *nstep, double *dA, int *IC1_, int *IC2_, char* flag) { double T; char Stmp1_[_LBUFF_]; printf("initial angle = "); fgets(Stmp1_, _LBUFF_, stdin); sscanf(Stmp1_, "%lg", theta0); printf("initial angular velocity = "); fgets(Stmp1_, _LBUFF_, stdin); sscanf(Stmp1_, "%lg", ang_vel0); (*t0) = 0; // 初期時刻 printf("damping constant = "); fgets(Stmp1_, _LBUFF_, stdin); sscanf(Stmp1_, "%lg", gamma); printf("amplitude of external force = "); fgets(Stmp1_, _LBUFF_, stdin); sscanf(Stmp1_, "%lg", A); // 外力の角振動数は 2 // したがってその周期は pi である (*nstep) = 100; // ポアンカレ・プロットの点が描画される間の反復回数 T = pi; // 外力の周期 (*dt) = T/(*nstep); // 時間幅 (*dA) = 0.01; // 外力の振幅の増減幅 // スクリーンの左半分は位相図に用いられる GWvport(0.0f, 0.0f, 0.49f*GWaspect(1), 1.0f); // ポアンカレ・プロットのために第2のウィンドウを開く GWsavevp(*IC1_); GWsetogn(0, *IC1_); GWvport(0.51f*GWaspect(1), 0.0f, GWaspect(1), 1.0f); strcpy(flag, ""); GWsavevp(*IC2_); GWsetogn(0, *IC2_); } void set_up_windows(double A, int IC1_, int IC2_) { double vmax; vmax = 4*A; GWselvp(IC1_); GWsetogn(0, IC1_); GWindow((float)(-pi), (float)(-vmax), (float)(pi), (float)(vmax)); GWselvp(IC2_); GWsetogn(0, IC2_); GWindow((float)(-pi), (float)(-vmax), (float)(pi), (float)(vmax)); } void draw_axes(double A, int IC1_, int IC2_) { float vmax; char Stmp1_[_LBUFF_]; GWclear(-1); GWselvp(IC1_); GWsetogn(0, IC1_); GWerase(IC1_, -1); GWsetpen(BLACK, -1, -1, -1); vmax = (float)(4*A); GWline(0.0f, -vmax, 0.0f, vmax); GWline((float)(-pi), 0.0f, (float)(pi), 0.0f); sprintf(Stmp1_, "A = %7.5f", A); GWputtxt(-3.0f, vmax*22.5f/24, Stmp1_); GWselvp(IC2_); GWsetogn(0, IC2_); GWerase(IC2_, -1); GWsetpen(BLACK, -1, -1, -1); GWline((float)(-pi), 0.0f, (float)(pi), 0.0f); GWline(0.0f, -vmax, 0.0f, vmax); } void RK4(double *theta, double *ang_vel, double gamma, double A, double *t, double dt) // 4次のルンゲ-クッタ法 { double k1v, k1x, k2v, k2x, k3v, k3x, k4v, k4x; k1v = force(*theta, *ang_vel, gamma, A, *t)*dt; k1x = (*ang_vel)*dt; (*t) += 0.5*dt; k2v = force((*theta)+0.5*k1x, (*ang_vel)+0.5*k1v, gamma, A, *t)*dt; k2x = ((*ang_vel) + 0.5*k1v)*dt; k3v = force((*theta)+0.5*k2x, (*ang_vel)+0.5*k2v, gamma, A, *t)*dt; k3x = ((*ang_vel) + 0.5*k2v)*dt; (*t) += 0.5*dt; k4v = force((*theta)+k3x, (*ang_vel)+k3v, gamma, A, *t)*dt; k4x = ((*ang_vel) + k3v)*dt; (*ang_vel) += (k1v + 2*k2v + 2*k3v + k4v)/6; (*theta) += (k1x + 2*k2x + 2*k3x + k4x)/6; if((*theta) > pi) (*theta) -= 2*pi; if((*theta) < -pi) (*theta) += 2*pi; } double force(double theta, double ang_vel, double gamma, double A, double t) { double force_; // A は外力の振幅 force_ = -gamma*ang_vel - (1 +2*A*cos(2*t))*sin(theta); return force_; } void phase_space(double theta, double ang_vel, int IC9_) { GWselvp(IC9_); GWsetogn(0, IC9_); GWsetpxl((float)(theta), (float)(ang_vel), RED); } void change_amplitude(double *A, double dA, int IC1_, int IC2_, char* flag) { int k = TBgetkey(); if(k == 's') // 任意のキーを押せばスクリーンは消去される strcpy(flag, "stop"); if(k == 'i') (*A) += dA; if(k == 'd') (*A) -= dA; if(k == 'i' || k == 'd') set_up_windows(*A, IC1_, IC2_); if(strcmp(flag, "") == 0) draw_axes(*A, IC1_, IC2_); } void Poincare(double theta, double ang_vel, int IC9_) { // 点を描画してから,外力の振幅の変更を可能にする GWselvp(IC9_); GWsetogn(0, IC9_); GWsetpxl((float)(theta), (float)(ang_vel), BLUE); }