home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 15 / 15.iso / s / s300 / 1.ddi / CHAP7 / THERM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-18  |  12.8 KB  |  567 lines

  1. /*****************************************************************
  2. Real time simulation of a thermal control system
  3.  
  4. File: therm.c
  5.  
  6. This program schedules a simulation of a thermal control system to
  7. run at highest priority, with its controller running at lower priority.
  8.  
  9. The background uses the screen graphic display package to maintain a
  10. display of the system's state and to get operator input for changing setpoint
  11. or control mode.
  12.  
  13.  
  14. copyright (c) 1987, D.M. Auslander
  15.  
  16. Created: 30-June-87
  17.  
  18. Updates:
  19.     12-July-87, DMA, initial debugging
  20.     14-July-87, DMA, add scheduling
  21.     18-Aug-88, DMA, modified for Microsoft C and xignal
  22. */
  23.  
  24. #include <stdio.h>
  25. #include "display.h"
  26. #include "dparam.h"
  27. #include "envir.h"
  28. #include "xignal.h"
  29.  
  30. #define UP 0xc8       /* Key definitions */
  31. #define RIGHT 0xcd
  32. #define LEFT 0xcb
  33. #define DOWN 0xd0
  34. #define SH_UP 0x38    /* Note that these (shifted arrows) are not unique */
  35. #define SH_DOWN 0x32
  36.  
  37. extern float get_th1(),get_ref1(),get_act(),get_th2(),get_ref2(),get_m1();
  38. extern float fv2b();
  39. extern int loop1(),loop2(),sim_h();    /* Functions that are scheduled */
  40. extern int chronos();        /* Scheduler */
  41.  
  42. static float v2a,v2b;    /* Dummy variables */
  43. static int rltm = 2;    /* Flag to indicate real time operation
  44.                         0 - Pure simulation
  45.                         1 - Use scheduler, but no clock interrupt
  46.                         2 - Full real time, with clock
  47.                         */
  48. static int cmode = 1;    /* Control mode; 0 - manual, 1 - automatic */
  49. static float t;        /* Running time */
  50. static float t1,t2;    /* Computation of sampling interval for non-real-time */
  51. static float dv = 0.02,dvl = 0.1,dm = 0.02,dml = 0.1;    /* Increment
  52.             associated with arrow keys */
  53.  
  54. /* Simulation system variables: */
  55.  
  56. static float th1;    /* object (pot) temperature */
  57. static float th2;    /* heater temperature */
  58. static float th0;    /* ambient temperature */
  59. static float k12;    /* heat transfer coefficient, object-to-heater */
  60. static float k10;    /* heat transfer coefficient, object-to-ambient */
  61. static float k20;    /* heat transfer coefficient, heater-to-ambient */
  62. static float q12;    /* heat transfer rate. object-to-heater */
  63. static float q10;    /* heat transfer rate, object-to-ambient */
  64. static float q20;    /* heat transfer rate, heater-to-ambient */
  65. static float qv;    /* electrical energy input to heater */
  66. static float c1;    /* heat capacity * mass, object */
  67. static float c2;    /* heat capacity * mass, heater */
  68. static float rh;    /* heater electrical resistance */
  69. static float vmax;    /* maximum voltage from power amplifier */
  70. static float v;        /* voltage input to power amplifier */
  71. static float vp;    /* voltage output from power amplifier 
  72.                 (unity voltage gain) */
  73. static float dt;    /* simulation step size */
  74.  
  75. /* Controller variables: */
  76.  
  77. static float errt1;        /* temperature error for object (pot) */
  78. static float errt2;        /* temperature error for heater */
  79. static float kp1, kp2;        /* controller proportional gains */
  80. static float ki1, ki2;        /* controller integral gains */
  81. static float ref1;        /* reference (desired) temperature 
  82.                 of object */
  83. static float ref2;        /* reference temperature for heater */
  84. static float m1min,m1max;    /* output limits, outer control loop */
  85. static float m2min,m2max;    /* output limits, inner control loop */
  86. static float i1min,i1max;    /* integrator limits, outer loop */
  87. static float i2min,i2max;    /* integrator limits, inner loop */
  88. static float tsmp1;        /* sample time, outer loop */
  89. static float tsmp2;        /* sample time, inner loop */
  90. static long mstick;        /* millisec per clock tick */
  91. static float i1,i2;        /* integrator values, outer, inner loop */
  92. static float m1,m2;        /* controller outputs */
  93.  
  94. static int tn0,tn1,tn2;    /* Timer ID numbers for scheduler */
  95.  
  96. main()
  97. {
  98. struct display d1,d2,d3;
  99. int i,dum;
  100. char cbuf[50];
  101. long ReadClock();
  102. float tm,tmold = -10.0;
  103.  
  104. /* Initialize simulation and controller variables */
  105.  
  106. th1 = 0.0;    /* Temperatures */
  107. th2 = 0.0;
  108.  
  109. i1 = 0.0;    /* Controller integrators */
  110. i2 = 0.0;
  111.  
  112. m1 = 0.0;    /* Controller output */
  113. m2 = 0.0;
  114.  
  115. /* Parameter values */
  116.  
  117. c1 = 4.0;    /* Heat capacities */
  118. c2 = 4.0;
  119.  
  120. k12 = 1.0;    /* Heat transfer coefficients */
  121. k10 = 0.3;
  122. k20 = 0.1;
  123.  
  124. vmax = 4.0;    /* Maximum voltage */
  125. rh = 1.0;    /* Electrical resistance */
  126. th0 = 0.0;    /* Ambient temperature */
  127.  
  128. t = 0.0;    /* Initialize running time */
  129. dt = 0.25;    /* Simulation time step */
  130.  
  131. tsmp1 = 2.0;    /* Sample times for control */
  132. tsmp2 = 1.0;
  133. mstick = 50;    /* Tick period in millisec */
  134.  
  135. m1min = m2min = i1min = i2min = 0.0;    /* Limits */
  136. m1max = 2.0;
  137. m2max = 1.0;
  138. i1max = 1.0;
  139. i2max = 2.0;
  140.  
  141. ref1 = 0.2;    /* Setpoint */
  142.  
  143. kp1 = 0.7;    /* Controller gains */
  144. kp2 = 1.7;
  145. ki1 = 0.4;
  146. ki2 = 0.4;
  147.  
  148. /* Definition of dsp_set, for reference:
  149. dsp_set(pd,x,y,label,lngth,lcolor,vbot,vtop,fv1,fv2,fmt,dblnk)    */
  150.  
  151. /* First display, pot temperature */
  152. dsp_set(&d1,3.0,2.,"T_Pot",6.,1,0.0,1.0,get_th1,get_ref1,"%4.2f","     ");
  153.  
  154. /* Second display, voltage to heater */
  155. dsp_set(&d2,10.0,2.,"V_Out",6.,2,0.0,2.0,get_act,fv2b,"%4.2f","     ");
  156. dsp_flag(&d2,1,1,0,0);    /* No second variable */
  157.  
  158. /* Third display, heater temperature */
  159. dsp_set(&d3,15.0,2.,"T_Heat",6.,3,0.0,1.0,get_th2,get_ref2,"%4.2f","     ");
  160.  
  161.  
  162. init_scr();    /* Initialize the screen */
  163. dsp_init(&d1);    /* Display the screen static part */
  164. dsp_init(&d2);
  165. dsp_init(&d3);
  166.  
  167. mv_cur(15.0,18.0);    /* Print the label for time */
  168. printf("Time:");
  169.  
  170. /* Schedule the control tasks
  171. Highest priority is for the simulation, then loop1, then loop2.
  172. Loop1 is given higher priority because, if they happen to request service
  173. simultaneously, loop1 produces data that loop2 uses.  This is the reverse of
  174. the normal convention that would give higher priority to the faster loop.
  175. */
  176.  
  177. if(rltm >= 1)
  178.     {
  179.     InitTime(mstick);    /* Initialize chronos */
  180.  
  181.     if((tn0 = NewDTimer(sim_h,&dum,100)) < 0)
  182.         {
  183.         printf("Can't allocate timer\n");
  184.         exit();
  185.         }
  186.     SetDTimer(tn0,(long)(1000.0 * dt));        /* Set sample interval */
  187.     
  188.     if((tn1 = NewDTimer(loop1,&dum,90)) < 0)
  189.         {
  190.         printf("Can't allocate timer\n");
  191.         exit();
  192.         }
  193.     SetDTimer(tn1,(long)(1000.0 * tsmp1));        /* Set sample interval */
  194.  
  195.  
  196.     if((tn2 = NewDTimer(loop2,&dum,80)) < 0)
  197.         {
  198.         printf("Can't allocate timer\n");
  199.         exit();
  200.         }
  201.     SetDTimer(tn2,(long)(1000.0 * tsmp2));        /* Set sample interval */
  202.  
  203.     if(cmode == 0)
  204.         {
  205.         StopDTimer(tn1);    /* Don't allow controllers to run if in 
  206.                     manual mode */
  207.         StopDTimer(tn2);
  208.         }
  209.     if(rltm == 2)
  210.         {
  211.         setalarm(mstick);        /* set the system clock */
  212.         xignal(XIGTMR,chronos);     /* Turn on the interrupt */
  213.         }
  214.     }
  215. /* Set dummy variables */
  216. v2a =  v2b = 0.0;
  217.  
  218. t1 = tsmp1;    /* Initialize sample interval so controller runs immediately,
  219.             only used for pure simulation (rltm = 0) */
  220. t2 = tsmp2;    
  221. mode_msg();        /* Put mode indicator on screen */
  222.  
  223. for(i = 0; ;i++)
  224.     {
  225.     int chr;
  226.  
  227.     if(rltm == 0)
  228.         {        /* Use this to run a "pure" simulation --
  229.                 i.e., no real time at all */
  230.  
  231.         if(cmode)        /* Check to see if mode is automatic */
  232.             {
  233.             if(t1 >= tsmp1)
  234.                 {
  235.                 loop1();    /* Control */
  236.                 t1 = 0.0;
  237.                 }
  238.             if(t2 >= tsmp2)
  239.                 {
  240.                 loop2();
  241.                 t2 = 0.0;
  242.                 }
  243.             t1 += dt;
  244.             t2 += dt;
  245.             }
  246.         sim_h();    /* Run the simulation here if not real time */
  247.         }
  248.  
  249.     if(rltm == 1)chronos();        /* Run the scheduler from the background */
  250.     if(rltm >= 1)tm = ReadClock() / 1000.0;
  251.     else    tm = t;
  252.  
  253.     if((tm - tmold) >= 1.0)
  254.         {
  255.         mv_cur(16.0,18.0);        /* Print the current time */
  256.         printf("%5.0f",tm);
  257.         tmold = tm;
  258.         }
  259.  
  260.     dsp_data(&d1);
  261.     dsp_data(&d2);
  262.     dsp_data(&d3);
  263.  
  264.     chr = char_in();    /* Read the keyboard */
  265.  
  266.     if(chr)        /* If character has been entered */
  267.         {
  268.         switch(chr)
  269.             {
  270.             case UP:
  271.                 if(cmode)set_ref1(get_ref1() + dv);
  272.                 else    set_act(get_act() + dm);
  273.                 break;
  274.  
  275.             case DOWN:
  276.                 if(cmode)set_ref1(get_ref1() - dv);
  277.                 else    set_act(get_act() - dm);
  278.                 break;
  279.  
  280.             case SH_UP:
  281.                 if(cmode)set_ref1(get_ref1() + dvl);
  282.                 else    set_act(get_act() + dml);
  283.                 break;
  284.  
  285.             case SH_DOWN:
  286.                 if(cmode)set_ref1(get_ref1() - dvl);
  287.                 else    set_act(get_act() - dml);
  288.                 break;
  289.  
  290.             case 'm':
  291.             case 'M':    /* Set to manual mode */
  292.                 if(cmode)
  293.                     {
  294.                     cmode = 0;    /* Set mode */
  295.                     mode_msg();    /* Set mode indicator on screen */
  296.  
  297.                     if(rltm >= 1)
  298.                         {
  299.                         StopDTimer(tn1);    /* Turn off controllers */
  300.                         StopDTimer(tn2);
  301.                         }
  302.                     }
  303.                 break;
  304.  
  305.             case 'a':
  306.             case 'A':    /* Set to automatic mode */
  307.                 if(!cmode)
  308.                     {
  309.                     /* Set integrators for bumpless transfer;
  310.                     "atomic" change is not necessary because the control
  311.                     can't run until the mode is changed. */
  312.  
  313.                     m1 = get_th2();    /* Set outer loop so inner loop is
  314.                                 in balance */
  315.  
  316.                     if(ki1 != 0.0)    /* Don't change the integrator value if
  317.                                     the integral gain is zero. */
  318.                         {
  319.                         i1 = (m1 - kp1 * (ref1 - get_th1()));
  320.                         }
  321.                     if(ki2 != 0.0)
  322.                         {
  323.                         i2 = v;
  324.                         }
  325.                     cmode = 1;
  326.                     if(rltm >= 1)
  327.                         {
  328.                         StartDTimer(tn1);
  329.                         StartDTimer(tn2);    /* Turn Controllers on */
  330.                         }
  331.                     mode_msg();        /* Set mode indicator on screen */
  332.                     }
  333.                 break;
  334.  
  335.             }
  336.  
  337.         if(chr == '\r')break;
  338.         }
  339.     }
  340. if(rltm == 2)
  341.     {
  342.     setalarm(0L);        /* Set timer back to DOS */
  343.     xignal(XIGTMR,XIG_DFL); /* Turn off interrupt */
  344.     }
  345. rst_scr();        /* Reset the screen */
  346. }
  347.  
  348. /* Functions that return process variables -- these are all "atomic"
  349. processes and must disable interrupts while fetching data.
  350.  
  351. When doing a non-real-time simulation, dummies must be supplied for
  352. enable() and disable().
  353. */
  354.  
  355. float get_th1()
  356. {
  357. float vv;
  358.  
  359. disable();
  360. vv = th1;
  361. enable();
  362. return(vv);
  363. }
  364.  
  365. float get_th2()
  366. {
  367. float vv;
  368.  
  369. disable();
  370. vv = th2;
  371. enable();
  372. return(vv);
  373. }
  374.  
  375. float get_m1()
  376. {
  377. float vv;
  378.  
  379. disable();
  380. vv = m1;
  381. enable();
  382. return(vv);
  383. }
  384.  
  385. float get_act()
  386. {
  387. float vv;
  388.  
  389. disable();
  390. vv = v;
  391. enable();
  392. return(vv);
  393. }
  394.  
  395. float get_ref1()
  396. {
  397. float vv;
  398.  
  399. disable();
  400. vv = ref1;
  401. enable();
  402. return(vv);
  403. }
  404.  
  405. float get_ref2()
  406. {
  407. float vv;
  408.  
  409. disable();
  410. vv = ref2;
  411. enable();
  412. return(vv);
  413. }
  414.  
  415. /* Set process values -- also atomic */
  416.  
  417. set_ref1(val)
  418. float val;
  419. {
  420. disable();
  421. ref1 = val;
  422. enable();
  423. }
  424.  
  425. set_ref2(val)
  426. float val;
  427. {
  428. disable();
  429. ref2 = val;
  430. enable();
  431. }
  432.  
  433. set_m1(val)
  434. float val;
  435. {
  436. disable();
  437. m1 = val;
  438. enable();
  439. }
  440.  
  441. set_act(val)
  442. float val;
  443. {
  444. disable();
  445. v = val;
  446. enable();
  447. }
  448.  
  449.  
  450. float fv2b()    /* Return a value for the process variable
  451. ------------    */
  452. {
  453. return(v2b);
  454. }
  455.  
  456. /* Controller functions */
  457.  
  458. pi_cntrl(erp,pt_intg,intmin,intmax,kp,ki,mmin,mmax,pt_m)    /* Compute a
  459. --------------------------------------------------------    PI control */
  460. float erp,*pt_intg,intmin,intmax,kp,ki,mmin,mmax,*pt_m;
  461. {
  462. float flim();
  463.  
  464. /* New integrator value */
  465. *pt_intg = flim(*pt_intg + ki * erp, intmin,intmax);
  466.  
  467. /* Controller output */
  468. *pt_m = flim(kp *erp + *pt_intg, mmin, mmax);    /* Controller output */
  469. }
  470.  
  471. loop1(pdum)        /* Outer loop
  472. -------        */
  473. int *pdum;        /* Dummy argument from scheduler */
  474. {
  475. float mm;
  476.  
  477. if(rltm >= 1)SetDTimer(tn1,(long)(1000.0 * tsmp1));   /* Set sample interval */
  478.  
  479. errt1 = get_ref1() - get_th1();
  480. pi_cntrl(errt1,&i1,i1min,i1max,kp1,ki1,m1min,m1max,&mm);
  481.  
  482. set_m1(mm);
  483. }
  484.  
  485. loop2(pdum)        /* Inner loop
  486. -------        */
  487. int *pdum;        /* Dummy argument */
  488. {
  489. float mm;
  490.  
  491. if(rltm >= 1)SetDTimer(tn2,(long)(1000.0 * tsmp2));   /* Set sample interval */
  492.  
  493. set_ref2(get_m1());        /* Use output of outer loop for setpoint */
  494. errt2 = get_ref2() - get_th2();
  495. pi_cntrl(errt2,&i2,i2min,i2max,kp2,ki2,m2min,m2max,&mm);
  496. set_act(mm);
  497. }
  498.  
  499. /* Simulation task -- This can be replaced by data in and out for
  500. a real control problem */
  501.  
  502. sim_h(pdum)        /* Simulation; use the Euler method to integrate one step 
  503. -------        each time called. */
  504. int *pdum;        /* Dummy argument from chronos */
  505. {
  506. float flim();
  507.  
  508. if(rltm >= 1)SetDTimer(tn0,(long)(1000.0 * dt));         /* Set sample interval */
  509.  
  510. q12 = k12 * (th1 - th2);    /* Heat transfer rates */
  511. q10 = k10 * (th1 - th0);
  512. q20 = k20 * (th2 - th0);
  513.  
  514. vp = flim(get_act(),0.0,vmax);    /* Power amplifier output */
  515. qv = vp * vp / rh;        /* Electric power into the heater */
  516.  
  517. th1 -= dt * (q12 + q10)/c1;        /* Pot temperature */
  518. th2 += dt * (q12 - q20 + qv)/c2;    /* Heater temperature */
  519.  
  520. t += dt;        /* Increment time */
  521. }
  522.  
  523. float flim(x,xmin,xmax)
  524. float x,xmin,xmax;
  525. {
  526. if(x < xmin)return(xmin);
  527. if(x > xmax)return(xmax);
  528. return(x);
  529. }
  530.  
  531. mode_msg()    /* Print a mode indicator on screen
  532. ----------    */
  533. {
  534. mv_cur(0.0,13.0);
  535.  
  536. if(cmode)
  537.     {
  538.     printf("Mode: Automatic");
  539.     }
  540. else
  541.     {
  542.     printf("Mode: Manual   ");
  543.     }
  544. }
  545.  
  546. /* These dummies must be supplied if rltm != 2 -- they can be supplied
  547. here or in a separate file. */
  548.  
  549. /*
  550. enable(){}
  551. disable(){}
  552. */
  553.  
  554. /* They are commented out at this point since the default parameter setting
  555. is to run real time. */
  556.  
  557. /* Panic routine shuts off interrupts and exits (called from chronos) */
  558.  
  559. panic(msg)    /* Shut off real time and exit
  560. ----------    */
  561. char *msg;
  562. {
  563. if(rltm == 2)xignal(XIGTMR,XIG_DFL);
  564. printf("<Panic> %s\n",msg);
  565. exit();
  566. }
  567.