From e84bc3278dfc658ff6e71486886c5fa4f19e1f11 Mon Sep 17 00:00:00 2001 From: brendan fattig Date: Fri, 21 Aug 2026 15:39:52 -0500 Subject: [PATCH 1/3] Fix bugs in cannon sim and tutorial. --- docs/tutorial/ATutASimpleSim.md | 94 +++++----- docs/tutorial/ATutAnalyticSim.md | 165 ++++++++++-------- .../cannon/gravity/src/cannon_analytic.c | 4 +- 3 files changed, 141 insertions(+), 122 deletions(-) diff --git a/docs/tutorial/ATutASimpleSim.md b/docs/tutorial/ATutASimpleSim.md index 62a8619e6..f51f38eed 100644 --- a/docs/tutorial/ATutASimpleSim.md +++ b/docs/tutorial/ATutASimpleSim.md @@ -76,7 +76,11 @@ y-coordinate again reaches 0. Solving for t (using the quadratic formula), we get the time of impact: -![equation_analytic_t_impact](images/equation_analytic_t_impact.png) +```math + -v_y0 - sqrt(v_y0^2 - 2*g*y0) +t_impact = ----------------------------- + g +``` --- @@ -88,57 +92,59 @@ Solving for t (using the quadratic formula), we get the time of impact: ```c /* Cannonball without Trick */ -#include #include +#include -int main (int argc, char * argv[]) { - - /* Declare variables used in the simulation */ - double pos[2]; double pos_orig[2] ; - double vel[2]; double vel_orig[2] ; - double acc[2]; - double init_angle ; - double init_speed ; - double time ; - int impact; - double impactTime; - - /* Initialize data */ - pos[0] = 0.0 ; pos[1] = 0.0 ; - vel[0] = 0.0 ; vel[1] = 0.0 ; - acc[0] = 0.0 ; acc[1] = -9.81 ; - time = 0.0 ; - init_angle = M_PI/6.0 ; - init_speed = 50.0 ; - impact = 0; - - /* Do initial calculations */ - pos_orig[0] = pos[0] ; - pos_orig[1] = pos[1] ; - vel_orig[0] = cos(init_angle)*init_speed ; - vel_orig[1] = sin(init_angle)*init_speed ; +int main(void) +{ + /* Initial conditions */ + const double acc[2] = {0.0, -9.81}; // acceleration in m/s^2 + const double init_angle = M_PI / 6.0; // initial angle in radians + const double init_speed = 50.0; // initial speed in m/s + const double time_step = 0.01; // time step in seconds + + const double init_pos[2] = {0.0, 0.0}; // initial position in meters + const double init_vel[2] // initial velocity in m/s + = { + cos(init_angle) * init_speed, + sin(init_angle) * init_speed, + }; + + /* Initialize simulation state */ + double pos[2] = {init_pos[0], init_pos[1]}; // current position in meters + double vel[2] = {init_vel[0], init_vel[1]}; // current velocity in m/s + double sim_time = 0.0; // current simulation time in seconds + double impact_time = 0.0; // time of impact in seconds + int impact = 0; // flag indicating whether an impact has occurred + + printf("time, pos[0], pos[1], vel[0], vel[1]\n"); /* Run simulation */ - printf("time, pos[0], pos[1], vel[0], vel[1]\n" ); - while ( !impact ) { - vel[0] = vel_orig[0] + acc[0] * time ; - vel[1] = vel_orig[1] + acc[1] * time ; - pos[0] = pos_orig[0] + (vel_orig[0] + 0.5 * acc[0] * time) * time ; - pos[1] = pos_orig[1] + (vel_orig[1] + 0.5 * acc[1] * time) * time ; - printf("%7.2f, %10.6f, %10.6f, %10.6f, %10.6f\n", time, pos[0], pos[1], vel[0], vel[1] ); - if (pos[1] < 0.0) { - impact = 1; - impactTime = (- vel_orig[1] - - sqrt(vel_orig[1] * vel_orig[1] - 2.0 * pos_orig[1]) - ) / -9.81; - pos[0] = impactTime * vel_orig[0]; + while (!impact) { + vel[0] = init_vel[0] + acc[0] * sim_time; + vel[1] = init_vel[1] + acc[1] * sim_time; + + pos[0] = init_pos[0] + (init_vel[0] + 0.5 * acc[0] * sim_time) * sim_time; + pos[1] = init_pos[1] + (init_vel[1] + 0.5 * acc[1] * sim_time) * sim_time; + + printf("%7.2f, %10.6f, %10.6f, %10.6f, %10.6f\n", sim_time, pos[0], pos[1], vel[0], vel[1]); + + if (pos[1] < 0.0) { // check for impact + impact_time + = (-init_vel[1] - sqrt(init_vel[1] * init_vel[1] - 2.0 * acc[1] * init_pos[1])) + / acc[1]; + + pos[0] = init_pos[0] + (init_vel[0] + 0.5 * acc[0] * impact_time) * impact_time; pos[1] = 0.0; + + impact = 1; } - time += 0.01 ; + + sim_time += time_step; } /* Shutdown simulation */ - printf("Impact time=%lf position=%lf\n", impactTime, pos[0]); + printf("Impact time=%f position=%f\n", impact_time, pos[0]); return 0; } @@ -147,7 +153,7 @@ int main (int argc, char * argv[]) { If we compile and run the program in listing 1: ```bash -% cc cannon.c -o cannon -lm +% cc cannon.c -o cannon % ./cannon ``` diff --git a/docs/tutorial/ATutAnalyticSim.md b/docs/tutorial/ATutAnalyticSim.md index d829f32a2..75aba7919 100644 --- a/docs/tutorial/ATutAnalyticSim.md +++ b/docs/tutorial/ATutAnalyticSim.md @@ -74,28 +74,28 @@ PURPOSE: (Represent the state and initial conditions of a cannonball) typedef struct { - double vel0[2] ; /* *i m Init velocity of cannonball */ - double pos0[2] ; /* *i m Init position of cannonball */ - double init_speed ; /* *i m/s Init barrel speed */ - double init_angle ; /* *i rad Angle of cannon */ + double vel0[2]; /* *i m Init velocity of cannonball */ + double pos0[2]; /* *i m Init position of cannonball */ + double init_speed; /* *i m/s Init barrel speed */ + double init_angle; /* *i rad Angle of cannon */ - double acc[2] ; /* m/s2 xy-acceleration */ - double vel[2] ; /* m/s xy-velocity */ - double pos[2] ; /* m xy-position */ + double acc[2]; /* m/s2 xy-acceleration */ + double vel[2]; /* m/s xy-velocity */ + double pos[2]; /* m xy-position */ - double time; /* s Model time */ + double time; /* s Model time */ - int impact ; /* -- Has impact occured? */ - double impactTime; /* s Time of Impact */ + int impact; /* -- Has impact occurred? */ + double impactTime; /* s Time of Impact */ -} CANNON ; +} CANNON; #ifdef __cplusplus extern "C" { #endif - int cannon_default_data(CANNON*) ; - int cannon_init(CANNON*) ; - int cannon_shutdown(CANNON*) ; +int cannon_default_data(CANNON*); +int cannon_init(CANNON*); +int cannon_shutdown(CANNON*); #ifdef __cplusplus } #endif @@ -285,40 +285,42 @@ PURPOSE: (Set the initial data values) *************************************************************************/ /* Model Include files */ -#include #include "../include/cannon.h" +#include /* default data job */ -int cannon_default_data( CANNON* C ) { +int cannon_default_data(CANNON* C) +{ + C->acc[0] = 0.0; // m/s^2 + C->acc[1] = -9.81; // m/s^2 + + C->init_angle = M_PI / 6.0; // rad + C->init_speed = 50.0; // m/s - C->acc[0] = 0.0; - C->acc[1] = -9.81; - C->init_angle = M_PI/6 ; - C->init_speed = 50.0 ; - C->pos0[0] = 0.0 ; - C->pos0[1] = 0.0 ; + C->pos0[0] = 0.0; // m + C->pos0[1] = 0.0; // m - C->time = 0.0 ; + C->time = 0.0; // s - C->impact = 0 ; - C->impactTime = 0.0 ; + C->impact = 0; // no impact yet + C->impactTime = 0.0; // s - return 0 ; + return 0; } /* initialization job */ -int cannon_init( CANNON* C) { - - C->vel0[0] = C->init_speed*cos(C->init_angle); - C->vel0[1] = C->init_speed*sin(C->init_angle); +int cannon_init(CANNON* C) +{ + C->vel0[0] = C->init_speed * cos(C->init_angle); + C->vel0[1] = C->init_speed * sin(C->init_angle); - C->vel[0] = C->vel0[0] ; - C->vel[1] = C->vel0[1] ; + C->pos[0] = C->pos0[0]; + C->pos[1] = C->pos0[1]; - C->impactTime = 0.0; - C->impact = 0.0; + C->vel[0] = C->vel0[0]; + C->vel[1] = C->vel0[1]; - return 0 ; + return 0; } ``` @@ -360,7 +362,7 @@ PURPOSE: ( Cannon Analytic Model ) #ifdef __cplusplus extern "C" { #endif -int cannon_analytic(CANNON*) ; +int cannon_analytic(CANNON*); #ifdef __cplusplus } #endif @@ -381,36 +383,43 @@ Type in the contents of **Listing 4** and save. /***************************************************************************** PURPOSE: ( Analytical Cannon ) *****************************************************************************/ -#include -#include #include "../include/cannon_analytic.h" +#include +#include + +int cannon_analytic(CANNON* C) +{ + const double time_step = 0.01; // must match this job's rate in the S_define + + C->vel[0] = C->vel0[0] + C->acc[0] * C->time; + C->vel[1] = C->vel0[1] + C->acc[1] * C->time; + + C->pos[0] = C->pos0[0] + (C->vel0[0] + 0.5 * C->acc[0] * C->time) * C->time; + C->pos[1] = C->pos0[1] + (C->vel0[1] + 0.5 * C->acc[1] * C->time) * C->time; + + if (C->pos[1] < 0.0) { // check for impact + C->impactTime = (-C->vel0[1] - sqrt(C->vel0[1] * C->vel0[1] - 2.0 * C->acc[1] * C->pos0[1])) + / C->acc[1]; -int cannon_analytic( CANNON* C ) { - - C->acc[0] = 0.00; - C->acc[1] = -9.81 ; - C->vel[0] = C->vel0[0] + C->acc[0] * C->time ; - C->vel[1] = C->vel0[1] + C->acc[1] * C->time ; - C->pos[0] = C->pos0[0] + (C->vel0[0] + (0.5) * C->acc[0] * C->time) * C->time ; - C->pos[1] = C->pos0[1] + (C->vel0[1] + (0.5) * C->acc[1] * C->time) * C->time ; - if (C->pos[1] < 0.0) { - C->impactTime = (- C->vel0[1] - sqrt( C->vel0[1] * C->vel0[1] - 2 * C->pos0[1]))/C->acc[1]; - C->pos[0] = C->impactTime * C->vel0[0]; + C->pos[0] = C->pos0[0] + (C->vel0[0] + 0.5 * C->acc[0] * C->impactTime) * C->impactTime; C->pos[1] = 0.0; + C->vel[0] = 0.0; C->vel[1] = 0.0; - if ( !C->impact ) { + + if (!C->impact) { C->impact = 1; - fprintf(stderr, "\n\nIMPACT: t = %.9f, pos[0] = %.9f\n\n", C->impactTime, C->pos[0] ) ; + fprintf(stderr, "\n\nIMPACT: t = %.9f, pos[0] = %.9f\n\n", C->impactTime, C->pos[0]); } } + /* - * Increment time by the time delta associated with this job - * Note that the 0.01 matches the frequency of this job - * as specified in the S_define. + * Increment model time by the time delta associated with this job. + * time_step must match the frequency of this job as specified in the S_define. */ - C->time += 0.01 ; - return 0 ; + C->time += time_step; + + return 0; } ``` @@ -443,19 +452,22 @@ In our case we're just going to print the final cannon ball state. /************************************************************************ PURPOSE: (Print the final cannon ball state.) *************************************************************************/ -#include #include "../include/cannon.h" #include "trick/exec_proto.h" +#include + +int cannon_shutdown(CANNON* C) +{ + const double t = exec_get_sim_time(); // s + + printf("========================================\n"); + printf(" Cannon Ball State at Shutdown \n"); + printf("t = %g\n", t); + printf("pos = [%.9f, %.9f]\n", C->pos[0], C->pos[1]); + printf("vel = [%.9f, %.9f]\n", C->vel[0], C->vel[1]); + printf("========================================\n"); -int cannon_shutdown( CANNON* C) { - double t = exec_get_sim_time(); - printf( "========================================\n"); - printf( " Cannon Ball State at Shutdown \n"); - printf( "t = %g\n", t); - printf( "pos = [%.9f, %.9f]\n", C->pos[0], C->pos[1]); - printf( "vel = [%.9f, %.9f]\n", C->vel[0], C->vel[1]); - printf( "========================================\n"); - return 0 ; + return 0; } ``` @@ -493,18 +505,19 @@ LIBRARY DEPENDENCIES: class CannonSimObject : public Trick::SimObject { - public: - CANNON cannon; +public: + CANNON cannon; - CannonSimObject() { - ("default_data") cannon_default_data( &cannon ) ; - ("initialization") cannon_init( &cannon ) ; - (0.01, "scheduled") cannon_analytic( &cannon ) ; - ("shutdown") cannon_shutdown( &cannon ) ; - } -} ; + CannonSimObject() + { + ("default_data") cannon_default_data(&cannon); + ("initialization") cannon_init(&cannon); + (0.01, "scheduled") cannon_analytic(&cannon); + ("shutdown") cannon_shutdown(&cannon); + } +}; -CannonSimObject dyn ; +CannonSimObject dyn; ``` The `S_define` file syntax is C++ with a couple of Trick specific constructs. diff --git a/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c b/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c index c0c1eff99..ad262d5a6 100644 --- a/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c +++ b/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c @@ -14,8 +14,8 @@ int cannon_analytic( CANNON* C ) { C->pos[0] = C->pos0[0] + (C->vel0[0] + (0.5) * C->acc[0] * C->time) * C->time ; C->pos[1] = C->pos0[1] + (C->vel0[1] + (0.5) * C->acc[1] * C->time) * C->time ; if (C->pos[1] < 0.0) { - C->impactTime = (C->vel0[1] + sqrt( C->vel0[1] * C->vel0[1] - 2 * C->g * C->pos0[1])) / C->g; - C->pos[0] = C->impactTime * C->vel0[0]; + C->impactTime = (C->vel0[1] + sqrt( C->vel0[1] * C->vel0[1] + 2 * C->g * C->pos0[1])) / C->g; + C->pos[0] = C->pos0[0] + (C->vel0[0] + (0.5) * C->acc[0] * C->impactTime) * C->impactTime ; C->pos[1] = 0.0; C->vel[0] = 0.0; C->vel[1] = 0.0; From 4ba9d8adb93b15f42fb96bcec98159ef4a85d92f Mon Sep 17 00:00:00 2001 From: brendan fattig Date: Fri, 21 Aug 2026 15:44:47 -0500 Subject: [PATCH 2/3] Other fixs in the AnalyticSim tutorial step. --- docs/tutorial/ATutAnalyticSim.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/tutorial/ATutAnalyticSim.md b/docs/tutorial/ATutAnalyticSim.md index 75aba7919..820d28520 100644 --- a/docs/tutorial/ATutAnalyticSim.md +++ b/docs/tutorial/ATutAnalyticSim.md @@ -59,8 +59,9 @@ The CANNON data-type contains the cannonball's initial conditions, its acceleration, velocity, and position, the model time, whether the cannonball has impacted the ground, and the time of impact. -The prototypes will declare two functions for initializing our CANNON data-type. -We'll discuss these in the next section. +The prototypes will declare two functions for initializing our CANNON data-type, +plus a third that runs when the simulation ends. We'll discuss these in the +next sections. **Listing 2 - `cannon.h`** @@ -556,12 +557,12 @@ prototypes in a header file (the preferred method). ### Data Lines -`Class CannonSimObject : public Trick::SimObject` +`class CannonSimObject : public Trick::SimObject` The sim object is defined as a C++ class and must be derived from the base class SimObject. -* `Class CannonSimObject` +* `class CannonSimObject` The name of the sim_object class is arbitrary. * `public Trick::SimObject` @@ -573,7 +574,10 @@ class SimObject. * `CANNON` This is the name of the structure typedef that you created in the cannon.h header. -* `cannon` This is an alias for the CANNON structure. It is mandatory. +* `cannon` This is the name of the CANNON member. Like the class name, it is +yours to choose, but choose it deliberately: together with the sim_object +instance name it forms the path you will use to reach the member's variables +from the input file and from Trick's tools, as in `dyn.cannon.pos`. * `CannonSimObject()` This is the constructor of the sim_object and it will contain the job declarations. @@ -594,7 +598,7 @@ Jobs that are classified `initialization` will be called once before the main executive loop and will not be called again. * `cannon_init(` -The name of the function we created in $HOME/trick_sims/models/cannon/src/cannon_init.c. +The name of the function we created in $HOME/trick_sims/SIM_cannon_analytic/models/cannon/src/cannon_init.c. * `&cannon)` This is the actual value passed to cannon_init(). It is the address of the @@ -658,10 +662,10 @@ In the files that we have created so far, the file paths in `#include` directive and in the `LIBRARY_DEPENDENCY` sections, are **relative** paths. These paths are relative to a **base-path**, that we still need to specify. -For example, the `S_define` file listed above `#includes` the relative path: +For example, the `S_define` file listed above `##includes` the relative path: `cannon/include/cannon_analytic.h`. We intend for this path to be relative to the `models` directory that we created in our `SIM_cannon_analytic` directory. The complete -path to our cannon.h header file should be: +path to our `cannon_analytic.h` header file should be: ``` ${HOME}/trick_sims/SIM_cannon_analytic/models/cannon/include/cannon_analytic.h @@ -704,9 +708,9 @@ export TRICK_CXXFLAGS="-g -Wall -Wextra -Wshadow" ``` ##### For Your .cshrc File -```bash -TRICK_CFLAGS= -g -Wall -Wmissing-prototypes -Wextra -Wshadow -TRICK_CXXFLAGS= -g -Wall -Wextra -Wshadow +```csh +setenv TRICK_CFLAGS "-g -Wall -Wmissing-prototypes -Wextra -Wshadow" +setenv TRICK_CXXFLAGS "-g -Wall -Wextra -Wshadow" ``` ### trick-CP @@ -806,7 +810,6 @@ pos = [220.699644186, 0.000000000] vel = [0.000000000, 0.000000000] ======================================== REALTIME SHUTDOWN STATS: - REALTIME TOTAL OVERRUNS: 0 ACTUAL INIT TIME: 0.203 ACTUAL ELAPSED TIME: 12.434 SIMULATION TERMINATED IN From deae3c8b2e55c660d486b19f1c8234a67199da4c Mon Sep 17 00:00:00 2001 From: brendan fattig Date: Fri, 21 Aug 2026 15:47:28 -0500 Subject: [PATCH 3/3] format --- trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c b/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c index ad262d5a6..3bb24eeab 100644 --- a/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c +++ b/trick_sims/Cannon/models/cannon/gravity/src/cannon_analytic.c @@ -14,8 +14,8 @@ int cannon_analytic( CANNON* C ) { C->pos[0] = C->pos0[0] + (C->vel0[0] + (0.5) * C->acc[0] * C->time) * C->time ; C->pos[1] = C->pos0[1] + (C->vel0[1] + (0.5) * C->acc[1] * C->time) * C->time ; if (C->pos[1] < 0.0) { - C->impactTime = (C->vel0[1] + sqrt( C->vel0[1] * C->vel0[1] + 2 * C->g * C->pos0[1])) / C->g; - C->pos[0] = C->pos0[0] + (C->vel0[0] + (0.5) * C->acc[0] * C->impactTime) * C->impactTime ; + C->impactTime = (C->vel0[1] + sqrt(C->vel0[1] * C->vel0[1] + 2 * C->g * C->pos0[1])) / C->g; + C->pos[0] = C->pos0[0] + (C->vel0[0] + (0.5) * C->acc[0] * C->impactTime) * C->impactTime; C->pos[1] = 0.0; C->vel[0] = 0.0; C->vel[1] = 0.0;