* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Download section 1
Flip-flop (electronics) wikipedia , lookup
Josephson voltage standard wikipedia , lookup
Surge protector wikipedia , lookup
Oscilloscope history wikipedia , lookup
Power MOSFET wikipedia , lookup
Analog-to-digital converter wikipedia , lookup
Valve audio amplifier technical specification wikipedia , lookup
Two-port network wikipedia , lookup
Wilson current mirror wikipedia , lookup
Integrating ADC wikipedia , lookup
Valve RF amplifier wikipedia , lookup
Transistor–transistor logic wikipedia , lookup
Voltage regulator wikipedia , lookup
Resistive opto-isolator wikipedia , lookup
Power electronics wikipedia , lookup
Operational amplifier wikipedia , lookup
Schmitt trigger wikipedia , lookup
Switched-mode power supply wikipedia , lookup
Current mirror wikipedia , lookup
Immunity-aware programming wikipedia , lookup
ANSWERS TO QUESTIONS AND EXERCISES OF THE CLIL MODULE: “C PROGRAMMING APPLICATIONS TO SYSTEMS ANALYSIS” SECTION 1 Step response of L-R linear system: 1) What is the crucial parameter that determines the accuracy of a finite difference solution of an ordinary differential equation? - The stepsize, that should be sufficiently small to consider the variations of voltage/current during each step negligible. In case of first order linear systems this means to choose a stepsize at least 10 times lower than the time constant of the system. 2) Run the C program that calculates the transient response of the L-R system for three different values of the stepsize: τ/2, τ/10 and τ/50. Explain if and why the three solutions are different. What’s the most accurate one? - The solution with τ/2 stepsize is not accurate because during each step variations in current/voltage are significant and the incremental ratio approximation is poor. The τ/10 stepsize is more accurate, but the graph of the solution still exhibits a non-continuous behavior. With the τ/50 stepsize it would be difficult to distinguish between the theoretical solution and the finite difference approximation. 3) Try to change the directive #define tau (L/R) with the directive #define tau L/R (i.e. rewrite the directive without parentheses). The program stops working correctly. Can you explain why? - The reason is that tau is replaced by L/R in the formula: I[j+1]=I[j]+Dt*(VIf/L-I[j]/tau); Hence the formula becomes: I[j+1]=I[j]+Dt*(VIf/L-I[j]/L/R); that is not correct because it corresponds to I[j]/(L*R) and not I[j]*R/L as it should correctly be when tau is replaced by (L/R). 1 4) The C program of Figure 5b) asks the user to insert the values of the initial and final input voltage values, VIi and VIf. Can you explain why in Fig. 5a) the user digits the character ‘q’ instead of a voltage value and why the program reads 0V as VIi and 5V as VIf? - Because the program expects a float value (%f) for the input variables VIi and VIf. When the user digits the character ‘q’, scanf function returns the value 0 into the char variable risp. When risp is 0, VIi and/or VIf are set to their default values, i.e. 0V for VIi and 5V for VIf. 5) I want to find the transient response of the same circuit but with different values of L and R, for instance L=100µH and R=5KΩ. What should I change in the C program? - I simply need to change the two values in the directives: #define L 500E-6 // 500uH inductor #define R 1E3 // 1KOhm resistor from 500E-6 to 100E-6 and from 1E3 to 5E3. Then compile and re-run the program. 6) Try to run the C program for different values of VIi and VIf, for instance VIi=8V and VIf=2V. What is the behavior of the output voltage waveform? Is it still correct? - Yes, the behavior is still correct: the result would be an inductor discharge from 8mA to 2mA. In fact, the underlying theory, and hence the equation describing inductor charging and discharging phenomenon, is the same. 7) In Eq. 1.6 In+1 depends only on In and other known quantities. A recursive algorithm is therefore possible. What code lines should be changed to implement the recursive algorithm? And what are the pros. and cons. of the recursive solution? - Rearranging Eq. 1.6 we get: 5V ∆t Eq. A.1: I n +1 = 1 − I n + ∆t ⋅ ; τ L Therefore it is sufficient to define the recursive function curr(n) that implements Eq. A.1: float curr(int n){ // returns the current value at discrete time instant tn=n*Dt if (!n) return VIi/R; // if n==0 current is VIi/R else return (Dt*VIf/L+(1-Dt/tau)*curr(n-1)); } and to modify the instructions to write the data into the output file: for (j=0; j<=N; j++) fprintf(fp,"\t%.3e\t%.3f\n",j*Dt,R*curr(j)); Note that we chose to write only the output voltage in the output file. In this way we do not need to store discrete current values or call curr(n) function more than once. In fact, if we wanted to write both current and voltage values, we could have chosen between two possible solutions: 1) store the current value curr(j) into a temporary variable and then use this variable to write both current and voltage in the output file; 2) call curr(j) twice, once to store the current value and the other to store the voltage value – this second solution is, of course, the worse because it doubles calculation time. The pros. of this recursive approach is that we do not need any array I[n] where to store the data (it spares memory). The cons. is that the program is more demanding in terms of numerical calculations and use of stack memory: therefore, the recursive program 2 execution time is longer for the same number of discrete time instants. Here follows the complete code of the recursive program, with modified code lines highlighted in grey color: // LR finite difference method solution with recursive function – LRrecursive.cpp #include <stdio.h> // program defined input data #define L 500E-6 // 500uH inductor #define R 1E3 // 1KOhm resistor #define tau (L/R) // time constant of the system #define tTR (5*tau) // duration of the transient fixed at 5 time constant // function declaration float curr (unsigned int n); // program variables definition FILE *fp; // pointer to the output file unsigned int j, N; char risp, filename[10]; float VIi, VIf, Dt; int main (){ // reading of user defined input data printf("\nPlease insert step waveform initial voltage in V (0 default): "); risp=scanf("%f",&VIi); fflush(stdin); if (!risp) VIi=0; printf("Step waveform initial voltage is %.2fV\n",VIi); printf("\nPlease insert step waveform final voltage in V (5 default): "); risp=scanf("%f",&VIf); fflush(stdin); if (!risp) VIf=5; printf("Step waveform final voltage is %.2fV\n",VIf); printf("\nPlease insert finite difference analysis stepsize in s (%g default): ",((L/R)/10)); risp=scanf("%f",&Dt); fflush(stdin); if ( (!risp) || (Dt<=0) || (Dt>=(L/R)) ) Dt=(L/R)/10; printf("Finite difference analysis stepsize is %.3g s\n",Dt); printf("\nPlease insert the output file name\n"); scanf("%s",filename); fflush(stdin); printf("Press any key to start output file writing..."); getchar(); fflush(stdin); fp=fopen(filename,"w"); // open the file in write mode fprintf(fp,"##\t L-R output voltage waveform\n"); fprintf(fp,"##\t problem inputs: VIi=%.2fV, VIf=%.2fV, Dt=%gs, L=%gH, R=%gOhm\n##\n",VIi,VIf,Dt,L,R); fprintf(fp,"##\tt[s]\t\tVO[V]\n"); // initialization N=tTR/Dt+1; if (N>1000){ N=1000; printf("\n\nWarning: Dt is too small, I'll calculate transient response only up to %gs\n\n",N*Dt); } // calculate current and write voltage to output file for (j=0; j<=N; j++) fprintf(fp,"\t%.3e\t%.3f\n",j*Dt,R*curr(j)); // close the output file fclose(fp); printf("\nPress any key to exit... "); getchar(); } // close the main // function body float curr (unsigned int n) // returns current value at time instant tn=n*Dt { if (!n) return (VIi/R); // if n is 0 (initial instant), then current is VIi/R else return (Dt*VIf/L+(1-Dt/tau)*curr(n-1)); } C programming Laplace method solution: 1) Write a C program able to plot the Laplace solution of the circuit of Fig. 10 when I(0) is different from 0A. (Suggestion: first derive the exact mathematical resolution formula by using Laplace transform table of Appendix A, and then implement it with a C code). - We start from the solution of the circuit of Fig. 10 – the first part of Eq. 1.8: 3 VIf + L ⋅ I (0) VIf + s ⋅ L ⋅ I (0) R VIf + s ⋅ L ⋅ I (0) VIf 1 R L ⋅ I (0) VO ( s ) = R ⋅ ( s ) = R⋅ = ⋅ = ⋅ + ⋅ 1 1 L 1 τ R + sL s ⋅ (R + sL ) L s ⋅s + s ⋅s + s + τ τ τ where VIf is the final input voltage value (5V in Eq. 1.8) and R is the resistor (R5 in Eq. 1.8). The Laplace transform of the output voltage is the sum of two contributions: the first contribution VIf τ ⋅ 1 1 s ⋅s + τ − is dependent only on VIf and τ=L/R, and its inverse t R L ⋅ I ( 0) R ⋅ I ( 0) VIi , that ⋅ = = 1 1 1 L s + s + s + τ τ τ τ transform is VIf ⋅ (1 − e ) . The second contribution is − t τ depends only on VIi (initial condition) and τ, and whose inverse transform is VIi ⋅ e . Therefore, the exact output voltage waveform is the sum of the two inverse transforms − t too: VO (t ) = VIf ⋅ (1 − e τ ) + VIi ⋅ e − t τ = VIf + (VIi − VIf ) ⋅ e − t τ . This formula is valid both for inductor charging (VIi < VIf) and discharging (VIi > VIf) and it provides correct results even when VIi and/or VIf are negative voltages. The following C program implements the formula: /*** LR step response – LRlaplfull.cpp *** This program implements the L-R inductor charging transient. Data inputs (user defined): input waveform, VIi and VIf - initial and final voltage values (in V), and the number of data points to be plotted, N Other inputs (program defined): component values, L (in H) and R (in Ohm) Data elaboration: the program calculates the output voltage value at each specified data points Data Outputs: file containing N data points reporting output voltage versus time */ // ANSI-C libraries included by the program #include <stdio.h> #include <math.h> // program defined input data #define L 500E-6 // 500uH inductor #define R 1E3 // 1KOhm resistor #define tau (L/R) // time constant of the system #define tTR (5*tau) // duration of the transient fixed at 5 time constant // program variables definition FILE *fp; // pointer to the output file unsigned int j, N; char risp, filename[10]; float VIi, VIf; int main (){ // reading of user defined input data printf("\nPlease insert step waveform initial voltage in V (0 default): "); risp=scanf("%f",&VIi); fflush(stdin); if (!risp) VIi=0; printf("Step waveform initial voltage is %.2fV\n",VIi); printf("\nPlease insert step waveform final voltage in V (5 default): "); risp=scanf("%f",&VIf); fflush(stdin); if (!risp) VIf=5; printf("Step waveform final voltage is %.2fV\n",VIf); printf("\nPlease insert the number of data points to be plotted (100 default): "); risp=scanf("%d",&N); fflush(stdin); if ( (!risp) || (N<=1) ) N=100; printf("The number of data points is %d\n",N); printf("\nPlease insert the output file name\n"); scanf("%s",filename); fflush(stdin); printf("Press any key to start output file writing..."); getchar(); 4 fflush(stdin); fp=fopen(filename,"w"); // open the file in write mode fprintf(fp,"##\t L-R output voltage waveform\n"); fprintf(fp,"##\t problem inputs: VIi=%.2fV, VIf=%.2fV,L=%gH, R=%gOhm\n##\n",VIi,VIf,L,R); fprintf(fp,"##\tt[s]\t\tVO[V]\n"); // calculate output voltage and write to output file for (j=0; j<=N; j++) fprintf(fp,"\t%.3e\t%.3f\n",j*tTR/N,(VIf+(VIi-VIf)*exp(-(j*tTR/N)/tau))); // close the output file fclose(fp); printf("\nPress any key to exit... "); getchar(); } 2) Run the program of Fig. 13 with VIi > VIf, by simulating an inductor discharge. What is the sign of the finite difference percentage error and where is the highest percentage error found? Also try to use a negative voltage value for VIi and/or VIf and discuss the behavior of the corresponding percentage error. - The Figure below shows with a black solid line the percentage error of the finite difference solution for an inductor discharge with input voltage from 5V to 0V. The red dashed line is the percentage error of the finite difference solution for an inductor charge with input voltage from -3V to 3V. By comparing these results with Fig. 14 where the percentage error was maximum at the beginning of the transient it is clear that: for the step input voltage from 5V to 0V maximum percentage error occurs at the end of the transient, where output voltage is close to 0V; for the step input voltage from -3V to 3V maximum percentage error occurs after 350ns from the beginning of the transient, where again output voltage is close to 0V. In conclusion, these results demonstrate that percentage error is maximum when output voltage value is close to 0V. In fact, Eq. 1.10 shows that Errj is higher for lower values of VOLT[j] for the same difference (VOLT[j]-VOFE[j]). 3) Modify the C code of Fig. 13 in order to find the maximum Dt value able to guarantee a given input accuracy. In practice, the program input is the desired level of accuracy (for instance ±0,5%) and the output is the maximum Dt value able to guarantee the specified accuracy. - The new program is essentially the same as in Fig. 13 with the difference that it needs a new user defined input variable, Acc. The variable Dt is still used and it is initialized to 5 the value τ/c, with c=10 (c is a new unsigned int variable). The program calculates the percentage error for each discrete time instant and stores its maximum value in the new variable MaxErr. When MaxErr becomes lower than Acc the desired accuracy is reached and the program prints Errj versus time in the output file; also Dt value is printed on the screen before the program exits. On the contrary, each time MaxErr is higher than Acc c is incremented, Dt=τ/c decreases and the percentage error calculation starts again with a smaller value of Dt. Finally, c will be so high that MaxErr will become lower than Acc and the program exits. However, in some cases, the percentage error remains high however small Dt value is. This is the case when the input step waveform goes from positive to negative voltage or vice versa. When the output voltage becomes close to 0V the percentage error remains high even for very small Dt values. A new parameter is added to the program to avoid excessive computational time: NMAX is the maximum number of steps calculated by the program whatever Dt value is. This means that if the number of steps corresponding to the Dt value is higher than NMAX, only NMAX steps are calculated (only a portion of the total transient time is calculated). Hence, in the case of transients from positive to negative voltage or vice versa, the program will be able to reach the target accuracy only in the portion of the transient where the output voltage is only positive (or negative). The C code implementing this algorithm is shown below: // ANSI-C libraries included by the program - LRcalcDt.cpp #include <stdio.h> #include <math.h> // program defined input data #define L 500E-6 // 500uH inductor #define R 1E3 // 1KOhm resistor #define tau (L/R) // time constant of the system #define tTR (5*tau) // duration of the transient fixed at 5 time constant #define NMAX 2000 // maximum number of data points // functions declaration float cfe(unsigned int n); // returns finite difference current value at instant tn=n*Dt float clt(unsigned int n); // returns exact current value at instant tn=n*Dt // program variables definition FILE *fp; // pointer to the output file unsigned int j, N, c; char risp, filename[10]; float VIi, VIf, Acc, Dt, Ife, Ilt, MaxErr; int main (){ // reading of user defined input data printf("\nPlease insert step waveform initial voltage in V (0 default): "); risp=scanf("%f",&VIi); fflush(stdin); if (!risp) VIi=0; printf("Step waveform initial voltage is %.2fV\n",VIi); printf("\nPlease insert step waveform final voltage in V (5 default): "); risp=scanf("%f",&VIf); fflush(stdin); if (!risp) VIf=5; printf("Step waveform final voltage is %.2fV\n",VIf); printf("\nPlease insert desired accuracy in %c (5%c default): ",37,37); risp=scanf("%f",&Acc); fflush(stdin); if ( (!risp) || (Acc<1e-10) || (Acc>=30) ) Acc=5; printf("Finite difference analysis accuracy is fixed to %.2f\%c\n",Acc,37); // initialization c=9; do{ c++, MaxErr=0, Dt=tau/c, N=tTR/Dt+1; if (N>NMAX){ N= NMAX; printf("\n\nWarning: Dt is too small, calculation stops at %gs\n\n",N*Dt); } for (j=1; j<=N; j++){ Ilt=clt(j), Ife=cfe(j); if (fabs(Ilt)<1e-18) Ilt=fabs(Ilt)+1e-18; 6 if (MaxErr < fabs(100*(Ilt-Ife)/Ilt)) MaxErr=fabs(100*(Ilt-Ife)/Ilt); } }while(MaxErr > Acc); printf("\nDesired accuracy is reached for c=%d corresponding to Dt=%.3gs\n",c,Dt); printf("Maximum percentage error is %.2f%c\n",MaxErr,37); printf("\nPlease insert the output file name\n"); scanf("%s",filename); fflush(stdin); printf("Press any key to start output file writing..."); getchar(); fflush(stdin); fp=fopen(filename,"w"); // open the file in write mode fprintf(fp,"##\t L-R output voltage waveform\n"); fprintf(fp,"##\t problem inputs: VIi=%.2fV, VIf=%.2fV, Dt=%gs, L=%gH, R=%gOhm\n",VIi,VIf,Dt,L,R); fprintf(fp,"##\t outputs: percentage error Err, exact output voltage VOlt and numerical output voltage VOfe\n##\n"); fprintf(fp,"##\tt[s]\t\tErr[%c]\t\tVOlt[V]\t\tVOfe[V]\n",37); fprintf(fp,"\t%.2e\t%.2f\t\t%.3f\t\t%.3f\n",0.0,0.0,VIi,VIi); for (j=1; j<=N; j++){ Ilt=clt(j), Ife=cfe(j); // current values stored in temporary variables if (fabs(Ilt)<1e-18) Ilt=fabs(Ilt)+1e-18; fprintf(fp,"\t%.2e\t%.2f\t\t%.3f\t\t%.3f\n",j*Dt,100*(Ilt-Ife)/Ilt,R*Ilt,R*Ife); } // close the output file fclose(fp); printf("\nPress any key to exit... "); getchar(); } // functions body float cfe(unsigned int n){ // returns the finite difference current value at instant tn=n*Dt if (!n) return (VIi/R); // if n==0 current is VIi/R else return (Dt*VIf/L+(1-Dt/tau)*cfe(n-1)); } float clt(unsigned int n){ // returns the exact current value at instant tn=n*Dt return ((VIf+(VIi-VIf)*exp(-(n*Dt/tau)))/R); } Try to run this program in these three different cases: • Input voltage from 6V to 1V • Input voltage from 1V to 6V • Input voltage from 3V to -2V In all 3 cases the total voltage swing is 5V but the percentage error behavior versus time is quite different… 4) Write a C code similar to that of Fig. 13 but whose objective is the evaluation of the absolute error of the finite difference method, i.e. ErAj=VOLT[j]-VOFE[j]. Then run the new program with the same inputs as in Fig. 14 and for the same three different values of Dt of Fig. 14, namely Dt=τ/10 (50ns), Dt=τ/25 (20ns) and Dt=τ/50 (10ns); finally plot the resulting absolute errors versus time as in Fig. 14. What is the difference between absolute and percentage errors? Explain the differences between the plots of absolute and percentage errors versus time. - The program to write is essentially the same as in Fig. 13 where the following code lines: for (j=1; j<=N; j++){ Ilt=clt(j), Ife=cfe(j); // current values stored in temporary variables if (Ilt==0) Ilt+=1e-18; fprintf(fp,"\t%.2e\t%.2f\t\t%.3f\t\t%.3f\n",j*Dt,100*(Ilt-Ife)/Ilt,R*Ilt,R*Ife); } are replaced by: for (j=1; j<=N; j++){ 7 Ilt=clt(j), Ife=cfe(j); // current values stored in temporary variables fprintf(fp,"\t%.2e\t%.3f\t\t%.3f\t\t%.3f\n",j*Dt,R*(Ilt-Ife),R*Ilt,R*Ife); } The C source code LRabs.cpp contains the whole program code. The results of the three runs are shown in the Figure below: the maximum absolute error (negative because VOLT < VOFE) is below 20mV for Dt=10ns, increases up to 38mV for Dt=20ns and is close to 0,1V when Dt=50ns (τ/10). Another important observation is that maximum error occurs at about t=500ns=τ in all three cases. This is quite different from the results of Fig. 14 where the maximum percentage error occurs immediately after the beginning of the transient. In fact, percentage error is higher when output voltage is close to 0V for a given value of absolute error. When VOLT[j] is close to 0V, even small differences between VOLT[j] and VOFE[j] may result in a high percentage error. On the other hand, at t=500ns=τ the difference between VOLT[j] and VOFE[j] is maximum, but VOLT[j] is high, close to 3,16V: the result is a low percentage error. In actual numerical simulators you can usually specify both percentage and absolute error, according to what kind of precision is desired. 5) Write the C code to calculate the step response of the following first-order linear systems by using the Laplace transform or the finite difference method: R-L system, R-C system, C-R system. - The four possible first-order linear systems we can analyze with the finite difference or Laplace methods are shown in the next page. We have already investigated the L-R system in detail. Now just as examples we’ll apply the Laplace method to the R-L system and the finite difference method to the C-R system. By transforming the R-L system into the Laplace domain, for t ≥ 0 we obtain the circuit shown in the next page, where I0 is the current value at instant t=0 (I0) and VIf is the final input voltage value. Note I0=VIi/R depends on initial input voltage value. The solution of the circuit in the Laplace domain provides: VIf + L ⋅ I0 VIf s VIi VIf VIi VO (s ) = s ⋅ L ⋅ I (s ) − L ⋅ I 0 = s ⋅ L ⋅ s − L ⋅ I0 = + VIi ⋅ τ − L⋅ = − 1 1 1 1 R+ s⋅L R s+ s+ s+ s+ τ τ τ τ that is the sum of two contributions, the first dependent on VIf and τ and the second 8 − t dependent on VIi and τ. The inverse transform of the first term provides VIf ⋅ e τ , while − t the inverse transform of the second term provides − VIi ⋅ e τ . Hence, the solution of the − t system is the sum of the two inverse transforms: VO (t ) = (VIf − VIi) ⋅ e τ . L 100µ VI(t) VO(t) R L-R system 1K L VI(t) 1K R VO(t) 100µ C C 1K VI(t) R-L system R R-C system VO(t) 10µ VI(t) 10µ R 1K VO(t) C-R system R s*L VI(t) VO(t) VIf/s L*I0 Note that after 5 time constants VO(t) is close to 0V and the circuit goes into steady state condition. The C program implementing the Laplace solution of the system is the same as the code of Fig. 11 with the only difference that the code line: for (j=0; j<=N; j++) fprintf(fp,"\t%.3e\t%.3f\n",j*tTR/N,VIf*(1-exp(-(j*tTR/N)/tau))); is replaced by: for (j=0; j<=N; j++) fprintf(fp,"\t%.3e\t%.3f\n",j*tTR/N,(VIf-VIi)*exp(-(j*tTR/N)/tau)); The whole C source code can be found in the file RLlapl.cpp. Now, let’s move to the finite difference calculation for the C-R system. The capacitor is described by the differential equation I (t ) = C ⋅ dVC , where I(t) is the circuit current equal to VO(t)/R and dt VC(t) is the voltage drop across the capacitor, i.e. VC(t)= VI(t)-VO(t). Therefore the characteristic equation of the capacitor can be rewritten as: 9 VO (t ) dV = −C ⋅ O , since for t≥0 VI is constant, hence its derivative is zero. Rearranging the R dt dVO VO (t ) equation we get + = 0 , where τ=R*C is the time constant of the circuit. By dt τ using the finite difference method where at each discrete time instant tj=j*Dt=j*∆t a discrete output voltage value VOj corresponds, we can approximate the derivative with the incremental ratio: dVO ∆VO VOn+1 − VOn ≈ = . dt ∆t t n+1 − t n The smaller the stepsize Dt=∆t the better this approximation is. By solving the equation τ − ∆t for VOn+1 we find the Euler resolution formula: VOn +1 = ⋅ VOn . If VO0 is known, we τ can calculate VO1 by using the resolution formula; once VO1 is known VO2 can be calculated and so on until the end of the transient is reached. So we need to find the initial condition VO0 to solve the problem with the finite difference method. VO0 calculation derives from the law of continuity of the voltage drop across capacitors. At the instant t=0- (just before the step on input voltage) VC(0-)=VIi-0V=VIi. At the instant t=0+ (just after the step on input voltage) VC(0+)=VIf-VO(0+)=VIf-VO0. Since VC(t) should be a continuous function of time, i.e. VC(0-)=VC(0+), we get VIi=VIf-VO0, from which VO0=VIf-VIi. We can now write the C program by solving the C-R system with the finite element method: it is the same program as in Fig. 5b where the array I[1000] is replaced by the array VO[1000] and the following code lines: I[0]=VIi/R, j=0, N=tTR/Dt+1; fprintf(fp,"\t%.3e\t%.3f\t\t%.3g\n",j*Dt,R*I[j],I[j]); I[j+1]=I[j]+Dt*(VIf/L-I[j]/tau); are replaced by: VO[0]=VIf-VIi, j=0, N=tTR/Dt+1; fprintf(fp,"\t%.3e\t%.3f\t\t%.3g\n",j*Dt,VO[j],VO[j]/R); VO[j+1]=(1-Dt/tau)*VO[j]; The whole C code can be found in the file CRfindiff.cpp. Try and enjoy it for various values of VIi and VIf. SECTION 2 1) Draw a plot of the Dirac pulse waveform. Can we generate a Dirac pulse in the lab? - The Dirac pulse waveform is a voltage equal to 0 for any value of time different from 0 and equal to +∞ when t=0 and is indicated with the symbol ∂(t). The area below the Dirac pulse is equal to 1Vs (1 Volt times second). In a voltage versus time axis it is a horizontal line coincident with the x-axis with a vertical line in correspondence of t=0 (see Appendix A for its plot). We cannot generate unbounded physical quantities in nature not even with an instant duration. The Dirac pulse is only an abstract concept with important 10 mathematical properties. In the lab we can only approximate the Dirac pulse with a pulse with a high amplitude (but bounded) and a small width – however finite. 2) Can I use the finite difference method to find the Dirac pulse transient response of an RC system? And the RC transient response to a bounded pulse of finite width t0? - The finite difference method cannot be used to find the Dirac transient response of an RC circuit. In fact, the Dirac pulse has 0 width, so we cannot divide it into a number of smaller steps. The finite difference method can be used with real pulse inputs, with a bounded amplitude and a finite width. However, if the width t0 of the pulse is much smaller than the time constant τ of the system, the stepsize Dt should be chosen much smaller than t0 in order to get a good approximation of the real transient response. So it is convenient to divide the pulse response into two different time intervals. The first time interval is when the pulse is active and its width is t0: this time interval is divided into steps Dt=t0/20 in order to approximate the pulse transient response correctly. At the end of the first time interval the RC output voltage will have reached a finite value V1. The second time interval is when the pulse is no more applied: the RC output voltage starts to discharge beginning from the previously calculated voltage V1. The analysis of this second time interval can be done by choosing Dt=τ/20. If, on the other hand, t0 is comparable with or greater than the time constant τ of the system, there is no need to divide the simulation into two time intervals and the choice of the stepsize Dt can be based solely on τ (Dt=τ/20 may give a good approximation). 3) Implement an LR linear system in the lab and apply a bounded pulse of amplitude V0 and width t0 to its input. What output waveform do you expect? Is there current continuity in the inductor? - The LR circuit behaves exactly as the RC. So we may have two different cases: 1. t0 much smaller than τ: the LR step response can be approximated with the Dirac pulse response: VO (t ) = V0 ⋅ t 0 − t τ ⋅ e , where V0*t0 is the area below the input pulse waveform. τ Remember this formula is only an approximation of the actual pulse response of the system; it provides VO(0+)=V0*t0/τ and hence I(0+)= V0*t0/(R*τ). Since I(0-)=0 it seems there is a discontinuity in the inductor current. Actually, VO(0+) starts from 0 and reaches the V0*t0/τ value during the time interval [0,t0] where the pulse is applied. So there isn’t any current discontinuity. Simply, since t0 is much smaller than τ, we can at all practical purposes draw the waveform as if it started directly from the V0*t0/τ value at t=0 instead of t=t0. 2. t0 comparable with or much greater than τ: during the time interval [0,t0] where the pulse − t is applied VO (t ) = V0 ⋅ (1 − e τ ) ; hence, at the end of the pulse VO has reached the value: VO (t 0 ) = V0 ⋅ (1 − e − t0 τ ) . After the pulse is finished VO(t) starts discharging from the initial 11 voltage VO(t0), hence VO (t ) = V0 ⋅ (1 − e − t0 τ )⋅e − t −t0 τ . There is no current discontinuity in the inductor and the total transient time is t0+5*τ. 4) Explain the reason why the step response of a CL system features damped oscillations. What would the step response of an ideal CL system be? - From the Laplace transform table of Appendix A the step response of an ideal CL circuit is Vf*cos(wn*t), where Vf is the step input voltage final value and ω n = 1 L⋅C is the natural angular frequency of the circuit. However, in an actual CL system realized in the lab the capacitor and the inductor feature parasitic effects. In particular, the capacitor has an ESR (Equivalent Series Resistance) of a few Ω. The inductor features a series resistance of a few Ω, too. So the actual circuit can be approximated as an RCL series circuit characterized by the damping factor ζ = R < 2⋅ R C ⋅ . For small values of R (i.e. for 2 L L , corresponding to ζ<1) the system works in underdamped conditions and C oscillations are present. This is the typical case of any CL system where C value is usually much smaller than L. However, a CL circuit where the value of C is higher than the value of L may be working in overdamped condition (ζ>1): in this case oscillations won’t be present and the step response of the CL circuit would resemble that of a CR circuit. 5) Write a C program that calculates the step response of an RCL series system. The program reads the values of the circuit components (R, C and L) and the final value of the step input voltage (Vf). The output of the program should be a text file that contains the waveforms of VR(t), VC(t) and VL(t) (the voltages across the resistor, capacitor and inductor, respectively). Finally, the text file should be imported in Excel to draw the corresponding waveforms. - It is convenient to use the C library tranlib.cpp of Appendix B, that already contains the function: void RCLstep(float R, float L, float C, float Vf, int Np); this function generates a file RCLstep.txt containing Np data points describing the step response of the RCL system (including three columns, VR(t), VC(t) and VL(t) that are the voltages across the resistor, capacitor and inductor, respectively). So the algorithm is extremely simple: it is sufficient to read R, C, L and Vf values and then call RCLstep() function. You can define Np in the program and remember to include the library tranlib.cpp with its full path. Here’s the C code: /*** RCL series circuit step response: RCL_series.cpp *** This program calculates the RCL series circuit step response. Data inputs (user defined): R, C, L values + VIf final step voltage value. Parameters (program defined): Np, the number of data points Data elaboration: it is performed by routine RCLstep() defined in tranlib.cpp library 12 Data Outputs: file containing Np data points reporting circuit output voltages versus time */ // ANSI-C libraries included by the program #include <stdio.h> // User defined libraries included by the program - with full library path #include "C:\Scuola\ANNO 2010-2011\CLIL IV SISTEMI\tranlib.cpp" // program defined parameters #define Npoints 200 // number of data points to be plotted in the output file // program variables definition char risp; float R, C, L, Vf; int main (){ // reading of user defined input data printf("\nPlease insert step waveform final voltage in V (5 default): "); risp=scanf("%f",&Vf); fflush(stdin); if (!risp) Vf=5; printf("Step waveform final voltage is %.2fV\n",Vf); printf("\nPlease insert circuit resistor value R in Ohm (1E3 default): "); risp=scanf("%f",&R); fflush(stdin); if (!risp) R=1E3; printf("Circuit resistor value is %g Ohm\n",R); printf("\nPlease insert circuit capacitor value C in F (100E-9 default): "); risp=scanf("%f",&C); fflush(stdin); if (!risp) C=100E-9; printf("Circuit capacitor value is %gF\n",C); printf("\nPlease insert circuit inductor value L in H (500E-6 default): "); risp=scanf("%f",&L); fflush(stdin); if (!risp) L=500E-6; printf("Circuit inductor value is %gH\n",L); printf("Press any key to start output file writing..."); getchar(); fflush(stdin); // CALL to function RCLstep() to calculate output voltages and write to output file RCLstep(R,L,C,Vf,Npoints); printf("\nPress any key to exit... "); getchar(); } After importing the output file RCLstep.txt into an MS Excel spreadsheet, the plot shown in the next page is obtained (the input values are Vf=6V, R=300Ω, C=10nF and L=1mH, corresponding to a damping factor of 0,47). VL starts from 6V and after two bounces it goes to 0V. VR features two bounces too: it starts from 0V, goes to a maximum of about 3V and then decreases back to 0V. VC final value is 6V: it starts from 0, goes to a maximum of about 7V and then decreases back to 6V final value. Different waveforms are obtained for different values of circuit components depending on the values of the damping factor and of the natural angular frequency of the system. 13 8 7 VC 6 5 VL 4 3 2 1 VR 0 -1 -2 0 0,000005 0,00001 0,000015 0,00002 0,000025 0,00003 0,000035 6) Write a C program that asks the user what kind of linear circuit (system) and input stimulus he wants to solve among the options shown in Table 1. The program output is a text file containing the waveform of the desired transient response of the selected system. - The user can select among the fifteen possibilities shown in Table 1. A function in the library tranlib.cpp corresponds to one of the possible user’s choices. Table 1 is made of 7 rows for three columns. We may associate an integer number to each row of the Table, let’s call it j, from 1 to 7 (j=1 corresponds to RC, j=2 to CR, j=3 to LR, j=4 to RL, j=5 to LC, j=6 to CL and j=7 to RCL series). Another integer number, let’s call it k, is associated to one of the three columns (k=1 corresponds to the Dirac pulse, k=2 to the step input voltage and k=3 to the ramp input voltage). The program asks the user what value of j and k he wants to select and, based on the user’s choice, it calls the corresponding function in the library tranlib.cpp. However, the program should handle cases where the user, by mistake, selects a number outside the allowed range (j>7 or k>3). There are also allowed values of (j, k) that do not correspond to any function in tranlib.cpp: for instance j=2 and k=1 corresponds to the CR circuit with Dirac pulse input, but there is no such function in tranlib.cpp. The program should handle such cases too. Once the user has selected two allowed values of (j, k) the program should call the corresponding function in tranlib.cpp. We may use the selection structure to do that, as in the following pseudo-code: if ((j==1) && (k==1)){ // RC, Dirac read R, C; call RC dirac(R,C,Np); } else { if (…..){ …. } The use of nested if(){…}else{…} can be quite complex. When multiple selections are possible it is better to use only the if(){…} structure, as in the following pseudo-code: check=0; if ((j==1) && (k==1)){ // RC, Dirac read R, C; call RC dirac(R,C,Np); 14 check=1; } if ((j==1) && (k==2)){ // RC, Step read R, C, Vf; call RC step(R,C,Vf,Np); check=1; } ………. The variable check is used to know if one of the correct possible choices has been selected. At the end of the if structures check may be 0 or 1: if check is 0 it means the user’s selection doesn’t correspond to any function in tranlib.cpp, and the program may display: “sorry, I’m not able to calculate the transient response you requested”; if check is 1 it means the program already calculated the requested transient response and the program can exit without any warning. However, C provides a much simpler structure to deal with multiple selections: the switch(){case: …} structure. It works like this: switch(expression){ case value1: sequence of instructions 1; // break; // if not commented the program exits the switch after sequence of instructions 1 execution case value2: sequence of instructions 2; // break; // if not commented the program exits the switch after sequence of instructions 2 execution default: sequence of default instructions; } If the expression integer value is equal to one of the values in the case clause then the program starts executing all the instructions following that case clause. For instance, in the example above if expression is equal to value2 the program starts to execute the sequence of instructions2 and all the following included the default one. The break instructions in each case clause should be used when only one sequence of instructions is to be executed. Can we use this structure in our program? The answer is yes, but we need to translate our two user inputs (j and k) into a single integer expression. To this purpose we may define a new integer variable, jk=j*10+k. When (j,k)=(1,1) then jk=11 and we will call RCdirac() function; when (j,k)=(1,2) then jk=12 and we will call RCstep() function, and so on. If jk value does not correspond to any function in tranlib.cpp then we’ll print the following on the PC screen: “Sorry but you selected a not existing function” in the default case. Note that since for each selection we need to call only one function, we’ll use the break instruction in each case of the switch structure. Here’s the complete C program: /*** linear circuits transient responses - alltran.cpp *** This program calculates a linear circuit transient response based on the functions contained in library tranlib.cpp. Data inputs (user defined): j defines the kind of circuit, k defines the kind of stimulus depending on the j k user’s selection the program will ask the required circuit and stimuli parameters Other Parameters (program defined): Npoints, the number of data points Data elaboration: it is performed by the routines in tranlib.cpp library Data Outputs: file containing Np data points reporting circuit output voltages versus time */ 15 // ANSI-C libraries included by the program #include <stdio.h> // User defined libraries included by the program - with full library path #include "C:\Scuola\ANNO 2010-2011\CLIL IV SISTEMI\tranlib.cpp" // program defined functions void readpar(bool bR, bool bL, bool bC, bool bVf, bool bP); // program defined parameters #define Npoints 200 // number of data points to be plotted in the output file // program variables definition int j, k, jk; char risp; float R, C, L, Vf, P; int main (){ do{ //outer cycle to enable the calculation of many transients with only one program call // reading of user’s defined input data printf("\nPlease insert the kind of circuit whose transient response you want to calculate "); printf("\n1 for RC\n2 for CR\n3 for LR\n4 for RL\n5 for LC\n6 for CL\n7 for RCL series "); printf("\nA different number corresponds to the default selection: RC circuit "); scanf("%d",&j); fflush(stdin); if ((j<0)||(j>7)) j=1; // RC circuit is default printf("\nYou chose j=%d\n",j); printf("\nPlease insert the kind of stimulus "); printf("\n1 for Dirac pulse\n2 for step input\n3 for ramp input "); printf("\nA different number corresponds to the default selection: step input "); scanf("%d",&k); fflush(stdin); if ((k<0)||(k>3)) k=2; // step input is default printf("\nYou chose k=%d\n",k); jk=j*10+k; switch (jk){ case(11): printf("\nYou chose RC circuit with Dirac stimulus, RCdirac.txt is your output file\n"); readpar(1,0,1,0,0); // read R and C values RCdirac(R,C,Npoints); // calculation and generation of output file break; case(12): printf("\nYou chose RC circuit with step stimulus, RCstep.txt is your output file\n"); readpar(1,0,1,1,0); // read R, C and Vf values RCstep(R,C,Vf,Npoints); // calculation and generation of output file break; case(13): printf("\nYou chose RC circuit with ramp stimulus, RCramp.txt is your output file\n"); readpar(1,0,1,0,1); // read R, C and P values RCramp(R,C,P,Npoints); // calculation and generation of output file break; case(22): printf("\nYou chose CR circuit with step stimulus, CRstep.txt is your output file\n"); readpar(1,0,1,1,0); // read R, C and Vf values CRstep(R,C,Vf,Npoints); // calculation and generation of output file break; case(23): printf("\nYou chose CR circuit with ramp stimulus, CRramp.txt is your output file\n"); readpar(1,0,1,0,1); // read R, C and P values CRramp(R,C,P,Npoints); // calculation and generation of output file break; case(31): printf("\nYou chose LR circuit with Dirac pulse stimulus, LRdirac.txt is your output file\n"); readpar(1,1,0,0,0); // read R and L values LRdirac(R,L,Npoints); // calculation and generation of output file break; 16 case(32): printf("\nYou chose LR circuit with step stimulus, LRstep.txt is your output file\n"); readpar(1,1,0,1,0); // read R, L and Vf values LRstep(R,L,Vf,Npoints); // calculation and generation of output file break; case(33): printf("\nYou chose LR circuit with ramp stimulus, LRramp.txt is your output file\n"); readpar(1,1,0,0,1); // read R, L and P values LRramp(R,L,P,Npoints); // calculation and generation of output file break; case(42): printf("\nYou chose RL circuit with step stimulus, RLstep.txt is your output file\n"); readpar(1,1,0,1,0); // read R, L and Vf values RLstep(R,L,Vf,Npoints); // calculation and generation of output file break; case(43): printf("\nYou chose RL circuit with ramp stimulus, RLramp.txt is your output file\n"); readpar(1,1,0,0,1); // read R, L and P values RLramp(R,L,P,Npoints); // calculation and generation of output file break; case(51): printf("\nYou chose LC circuit with Dirac pulse stimulus, LCdirac.txt is your output file\n"); readpar(0,1,1,0,0); // read L and C values LCdirac(L,C,Npoints); // calculation and generation of output file break; case(52): printf("\nYou chose LC circuit with step stimulus, LCstep.txt is your output file\n"); readpar(0,1,1,1,0); // read L, C and Vf values LCstep(L,C,Vf,Npoints); // calculation and generation of output file break; case(62): printf("\nYou chose CL circuit with step stimulus, CLstep.txt is your output file\n"); readpar(0,1,1,1,0); // read L, C and Vf values CLstep(L,C,Vf,Npoints); // calculation and generation of output file break; case(63): printf("\nYou chose CL circuit with ramp stimulus, CLramp.txt is your output file\n"); readpar(0,1,1,0,1); // read L, C and P values CLramp(L,C,P,Npoints); // calculation and generation of output file break; case(72): printf("\nYou chose RCL series circuit with step stimulus, RCLstep.txt is your output file\n"); readpar(1,1,1,1,0); // read R, C, L and P values RCLstep(R,L,C,Vf,Npoints); // calculation and generation of output file break; default: printf("\nSorry, there is no function for the combination of circuit/stimulus you chose\n"); } printf("\n\nWould You like to calculate the transient response of another system? (Y/N)"); scanf("%c",&risp); fflush(stdin); }while((risp=='y')||(risp=='Y')); printf("\nPress any key to exit... "); getchar(); } void readpar(bool bR, bool bL, bool bC, bool bVf, bool bP){ if(bR){ printf("\nPlease insert circuit resistor value R in Ohm (1E3 default): "); risp=scanf("%f",&R); fflush(stdin); 17 if (!risp) R=1E3; printf("Circuit resistor value is %g Ohm\n",R); } if(bC){ printf("\nPlease insert circuit capacitor value C in F (100E-9 default): "); risp=scanf("%f",&C); fflush(stdin); if (!risp) C=100E-9; printf("Circuit capacitor value is %gF\n",C); } if(bL){ printf("\nPlease insert circuit inductor value L in H (500E-6 default): "); risp=scanf("%f",&L); fflush(stdin); if (!risp) L=500E-6; printf("Circuit inductor value is %gH\n",L); } if(bVf){ printf("\nPlease insert step waveform final voltage in V (5 default): "); risp=scanf("%f",&Vf); fflush(stdin); if (!risp) Vf=5; printf("Step waveform final voltage is %.2fV\n",Vf); } if(bP){ printf("\nPlease insert ramp waveform slope in V/s (1E5 default): "); risp=scanf("%f",&P); fflush(stdin); if (!risp) P=1E5; printf("Ramp waveform slope is %gV/s\n",P); } } In addition to the explanation provided above, the program proposed contains an external do{…}while cycle to allow an unlimited number of transient responses calculations just with a single program call. In fact, with only one program call all waveforms of Appendix A have been calculated and then imported into an MS Excel worksheet. Another important feature of the program is the internal function readpar(), used to read circuit and stimuli variables. In fact, the number and kind of circuit and stimuli variables to enter as inputs depends on the user’s choice. readpar() has 5 input parameters of Boolean type (bool), namely bR, bL, bC, bVf, bP. When one of these Boolean parameters is true (i.e. value 1) readpar() reads the corresponding input variable, otherwise the corresponding input variable is skipped. For instance, the function call readpar(1,0,1,1,0) asks the user to insert R value (bR=1), C value (bC=1) and Vf value (bVf=1), while it skips L and P values (bL=0 and bP=0) - note R, C, L, Vf and P variables are global variables. Hence, depending on user’s input, it is sufficient to call readpar() with the required set of Boolean parameters values to read the required stimuli and circuit variables. 18 SECTION 3 Finite state machines – questions and exercises 1) Explain all the optimization performed to pass from the C program of Figure 37 to the one of Figure 38. - The first optimization is the use of a single variable q (Boolean type) to identify the two possible states S1 and S2 of the system. Each transition of state can then be done with a single instruction, q=0 to pass from S1 to S2 and q=1 to pass from S2 to S1. The second optimization is to merge two consecutive if structures in a single if structure: if (S1){ if (x1){ … } } if(q && x1){ … } The third and last optimization is similar to the second one with the additional simplification of removing a redundant condition: if (S2){ if (!x1){ … } } if((!q) && (!x1)){ … } if(!x1){ … } In fact, when x1 is 0 we need to pass to state S1 whatever the state we are in. 2) With your PC simulate a finite state machine able to recognize one name made of four letters, such as for instance MARY. In practice the system should recognize a sequence of characters (for instance ‘M’, ‘A’, ‘R’ and ‘Y’) and then print Hello Mary! on screen. - Since the name to be recognized can be anyone, there could also be cases where the same character is found two consecutive times, as for instance in “Anne”. So we must be sure each character is processed only once: whenever function _kbhit() returns 1 a character is read and only 1 state transition is performed; then the next character is read and so on. If one of the characters is not in the sequence, the machine goes back to the initial state. Note the characters are case sensitive, i.e. it makes a difference if they are upper or lower case. For instance, if the name to be recognized is “Anne”, and the sequence of input characters is anneanAnneanneanAnnean, Hello Anne! will be printed only twice on the screen. Here follows the State Graph of the machine: ch!=name[3]/ch=name[0]/cls ch=name[1]/- ch!=name[0]/S1 S2 ch=name[2]/S3 S4 ch!=name[1]/ch!=name[2]/ch=name[3]/print ”Hello name!” 19 A Mealy State Graph has been preferred: each state transition is associated with an action (or no action when the symbol – is used). There are only two possible actions: cls means clear screen, print is the instruction to display the greeting on the screen. The name to be recognized is defined as a constant string in the program (name). Within the infinite for cycle, a while(){…} cycle with break instructions has been used in order to allow only a single state transition for each character. Here’s the program code: // Program to recognize a sequence of 4 characters – namerecognition.cpp #include <stdio.h> #include <conio.h> #include <iostream> // 4 characters sequence to be recognized #define name "Anne" // program variables definition char ch; bool S1=1, S2=0, S3=0, S4=0; // initial state is S1 int main (){ for(;;){ // finite state machine working cycle while (_kbhit()){ // the state machine processes only 1 character at a time ch=_getch(); // read the character removing it from the input buffer if (S1){ if(ch==name[0]){ system("cls"); // clear screen instruction S1=0, S2=1; } break; // only 1 state transition for each character } if (S2){ if(ch==name[1]){ S2=0, S3=1; } else { S2=0, S1=1; } break; // only 1 state transition for each character } if (S3){ if (ch==name[2]){ S3=0, S4=1; } else { S3=0, S1=1; } // only 1 state transition for each character break; } if (S4){ if (ch==name[3]) printf("\nHello %s!",name); S4=0, S1=1; // go to initial state break; } // only 1 state transition for each character } // close while } // close for cycle } // close main 3) With your PC simulate a finite state machine able to control the automatic gate of your house. - The system digital inputs are: x1 – corresponding to the remote control button; x2 – corresponding to the gate fully open sensor signal; x3 – corresponding to the gate fully closed sensor signal; x4 – corresponding to the “someone passing” sensor signal. There is 20 another digital input, namely x5, corresponding to the end of the wait time and whose meaning will be explained later. System initial state S1 is when the gate is still and fully closed. The system can move from this state only if the button of the remote control is pushed (x1=1): the gate starts opening. In our system the only way to stop the opening of the gate is the x2 signal coming from the proximity sensor detecting the gate fully open condition (so the gate always reaches the fully open state S2). When x2 becomes 1 the gate stops and a timer starts. There are two possible inputs that may force the gate closure: the timer expires (x5 input becomes 1) or the remote control button is pushed (x1 becomes 1). However, in both cases the gate starts closing only if no one is passing through the gate (x4=0). While the gate is closing, the gate stops closing if someone is passing through the gate (x4=1), and returns to the initial state where it waits for x1=1 (remote control button pressure) to re-open again. This is the Mealy State Graph for our system: 10xxx/open 0xxxx/- x1,x2,x3,x4,x5/actions S2 S1 x0xxx/Si xxx1x/stop 0x1xx/stop 01xxx/stop,set timer 1xx0x/close xx00x/- S4 S3 0xx00/timer-- xxx01/close xxx1x/set timer Again, in our PC simulation we cannot handle cases where inputs can be changed simultaneously because we are forced by _kbhit() instruction to handle a character at a time. This simplifies our design considerably, while in actual life we may have a gate fully open signal simultaneously with a remote control button pressure. However, the State Graph of the system is able to handle these situations, too. This is the C program that simulates our State Graph: // automatic gate simulation - automaticgate.cpp #include <stdio.h> #include <conio.h> // program parameters #define WAITCYCLES 300000 // number of cycles to wait before closing the gate // program variables definition unsigned long int timer; // counter variable defining the gate open wait time bool x1=0, x2=0, x3=0, x4=0, S1=1, S2=0, S3=0, S4=0; char ch; int main (){ printf("\nMEANINGS OF KEYS:"); printf("\nB or b is the remote control button"); // x1 input printf("\nO or o is the gate fully open sensor signal"); // x2 input printf("\nC or c is the gate fully closed sensor signal"); // x3 input printf("\nP or p is the 'someone passing' sensor signal\n"); // x4 input for(;;){ // finite state machine working cycle if (_kbhit()){ 21 ch=_getch(); // read the character and clear the input buffer if((ch=='B')||(ch=='b')) x1=1, x2=0, x3=0, x4=0; // remote control button pushed if((ch=='O')||(ch=='o')) x1=0, x2=1, x3=0, x4=0; // gate fully open if((ch=='C')||(ch=='c')) x1=0, x2=0, x3=1, x4=0; // gate fully closed if((ch=='P')||(ch=='p')) x1=0, x2=0, x3=0, x4=1; // someone passing } else x1=0, x2=0, x3=0, x4=0; // nothing happens if (S1){ if(x1 && (!x2)){ printf("\nThe gate is OPENING"); S1=0, S2=1; } } if (S2){ if((!x1) && x2){ printf("\nThe gate is STILL AND FULLY OPEN"); timer=WAITCYCLES, S2=0, S3=1; } } if (S3){ if((x1 && (!x4))||((timer==0) && (!x4))){ // timer==0 corresponds to x5=1 printf("\nThe gate is CLOSING"); S3=0, S4=1; } if(x4) timer=WAITCYCLES; else if ((!x1) && (timer!=0)) timer--; } if (S4){ if((!x1) && x3){ printf("\nThe gate is STILL AND FULLY CLOSED"); S4=0, S1=1; } if(x4){ if (!x3) printf("\nSomeone passing: The gate is STILL but NOT FULLY CLOSED"); else printf("\nSomeone passing: The gate is STILL and FULLY CLOSED"); S4=0, S1=1; } } } // close for cycle } // close main 4) With your PC simulate a finite state machine able to control the stop and go light of a car park. The car park can host a maximum of N cars. When a car enters the park a sensor provides the digital signal x1=1 in output; when no car is entering the park x1=0. When a car goes out another sensor provides the digital signal x2=1 in output; when no car goes out of the park x2=0. When the number of cars in the park is N the park light should be red, otherwise green. When green the number of vacancies should be displayed, too. - There are two digital inputs from two sensors: x1 and x2. An internal system variable cont is used to count the number of cars present in the park; hence N-cont is the number of vacancies. When cont==N the light should become green. When cont==0 there are no cars in the park. Again, in our simulation we can handle only one input signal at a time, but the State Graph of the system is consistent even when input signals are changed simultaneously. A Mealy State Graph with only two states is sufficient to describe our system. S1 is the initial state where the number of cars is always less than N. Therefore, when a car enters and no car goes out there is a transition from S1 to S2 during which cont is incremented and if it is less than 100 the green light is updated with the number of vacancies, otherwise the red light is displayed. In state S2 whenever a car enters (and no 22 one goes out) cont is incremented unless it is already equal to N. When a car goes out and no car enters, there is a transition from S2 to S1 during which cont is decremented, the light is green and the number of vacancies is updated. 10/cont++, (cont!=N)?N-cont:Red; S2 S1 01/(cont!=0)?cont--,N-cont:N-cont; 10/if(cont!=N)cont++; (cont!=N)?N-cont:Red; 01/cont--, N-cont When inputs (x1,x2)=(0,0) or (x1,x2)=(1,1) no action is performed; this is the reason why these cases are not shown in the State Graph of the system. Also note some actions are written using the C instruction (cont!=100)?action1:action2; whose meaning is: if (cont!=100){ action1; } else { action2; } Here follows the C code implementing the State Graph: // car park stop and go light management - carpark.cpp #include <stdio.h> #include <conio.h> #include <iostream> // number of places available in the park #define N 20 // program variables definition int cont=0; // current number of cars in the park bool x1=0, x2=0, S1=1, S2=0; char ch; int main (){ printf("\nMEANINGS OF KEYS:"); printf("\nI or i is the car entering signal"); // x1 input printf("\nO or o is the car going out signal\n\n"); // x2 input printf("\nGREEN LIGHT: %d VACANCIES",N-cont); for(;;){ // finite state machine working cycle while(_kbhit()){ x1=0, x2=0; ch=_getch(); // read the character and clear the input buffer if((ch=='I')||(ch=='i')) x1=1, x2=0; // a car enters if((ch=='O')||(ch=='o')) x2=1, x1=0; // a car goes out if (S1){ if(x1 && (!x2)){ cont++, system("cls"); (cont!=N)?printf("\nGREEN LIGHT: %d VACANCIES",N-cont):printf("\nRED LIGHT: NO VACANCIES"); S1=0, S2=1; } if((!x1) && x2){ if(cont!=0) cont--; system("cls"); printf("\nGREEN LIGHT: %d VACANCIES",N-cont); } break; } if (S2){ if((!x1) && x2){ cont--, system("cls"); printf("\nGREEN LIGHT: %d VACANCIES",N-cont); S2=0, S1=1; } 23 if(x1 && (!x2)){ if(cont!=N) cont++; system("cls"); (cont!=N)?printf("\nGREEN LIGHT: %d VACANCIES",N-cont):printf("\nRED LIGHT: NO VACANCIES"); } break; } } // close while cycle } // close for cycle } // close main Note a while(){…} cycle with break instructions has been used in order to perform a single state transition for each key pressed. x1=1 corresponds to a single pressure of the key ‘I’ or ‘i’, while x2=1 to a single pressure of the key ‘O’ or ‘o’. 24