Privacy and Security Notice

Hall A current monitor WEB page - State Sequencer


State Sequencer Program

The state sequencer program is loaded into the IOC, and used to perform the Current monitor calibration.

program calibrate

This state sequencer program is designed to peform the Hall A Beam Current Monitor Calibration.
To compile it, type "snc calib.st" (this converts it into a .c file)
then you have to type "make" to have it compile and ready to be loaded
The program is loaded into the IOC Hallasc5 memory and executed by Epics
All files are located in: "/hac_epics/ioc/hallasc5/epics/seq/".
Written in 1997 by:
Yves Roblin
Geraud Laveissiere

INCLUDE LIBRARIES
%% #include
%% #include

INTEGER DECLARATIONS
u corresponds to the Unser monitor
1 corresponds to the Upstream BCM
2 corresponds to the Downstream BCM
o corresponds to the Unser monitor offset

Step Variables
indexes of current values
int i; Unser,bcm1,bcm2
int io; Unser offset
numbers of stored values
int j; Unser,bcm1,bcm2
int jo; Unser offset

int k;

Step time limit = 1minute
int timelimit;

position in step 0=offset 1=top
int position;

uncrash variable ?????
int machin;

number of steps
int step;

autorize computation of coefficients 0=yes 1=no
int compute;

autorize update of date 0=no 1=yes
int update;

Control Button
0 = Calibration OFF
1 = Calibration ON
int done;

Alarm variable: is set if the time since last calibration is more than 12h
0 = Calibration still good
1 = Calibration bad; time has elapsed
int uncalibrated;

Blinking signal
0 = Message not visible
1 = Message visible
int blicky;

stopwatch used to measure the time since last calibration
int swsec;
int swmin;
int swhr;
int swday;
int swblicky;

# of correction needed for each bcm
int correct1;
int correct2;

FLOATING POINTS DECLARATIONS
u corresponds to the Unser monitor
1 corresponds to the Upstream BCM
2 corresponds to the Downstream BCM
o corresponds to the Unser monitor offset

Low threshold that defines offset computation
It is set at the beginning of the program.
float threshold_b;

sum of all stored values during a step
float s1;
float s2;
float su;
float so;

coefficients modifications for the 2 bcms
float modif1;
float modif2;

stored values during a step *
float top1[70];
float top2[70];
float topu[70];
float offset[70];

list of all steps coefficients
float values1[20];
float values2[20];

List of steps that need correction
0 = value OK
1 = need correction
float correction1[20];
float correction2[20];

Unser,BCM1,BCM2 readings
float bcm1;
float bcm2;
float unser;

Final coefficients and standard deviations
float A1;
float A2;
float sdev1;
float sdev2;

high threshold that defines Unser and bcms computation. It is defined by user through another screen.
float threshold_t;

FILES POINTERS DECLARATIONS

%% FILE *fpcoef;
%% FILE *fpdate;
%% FILE *fpthres;

ASSIGN VARIABLES TO CHANNELS

assign done to "hac_bcm_done";
assign uncalibrated to "hac_bcm_uncalibrated";
assign blicky to "hac_bcm_blicky";
assign bcm1 to "hac_bcm_dvm1_read";
assign bcm2 to "hac_bcm_dvm2_read";
assign unser to "hac_unser_current";
assign A1 to "hac_bcm_A1";
assign A2 to "hac_bcm_A2";
assign sdev1 to "hac_bcm_A1sdev";
assign sdev2 to "hac_bcm_A2sdev";
assign step to "hac_bcm_count";
assign swmin to "hac_bcm_swmin";
assign swhr to "hac_bcm_swhr";
assign swday to "hac_bcm_swday";
assign threshold_t to "hac_bcm_threshold_t";

CHANNEL ACCESS MONITORING

monitor unser;
monitor done;
monitor bcm1;
monitor bcm2;
monitor threshold_t;

BEGINNING OF PROGRAM

ss calibrate {



LOADING STATE:
In this State, the program loads the data stored into file:
FILE NAME VARIABLES
"calib_threshold_file" threshold_t
"calib_coef_file" A1 A2 sdev1 sdev2
"calib_date_file" swday swhr swsmin
and then inserts them into Epics, on the screen. It also initializes the lower threshold, which never changes. It also initializes the blinking variable, so that it starts blinking if the "time since last calibration" is more than 12hr.

state load {
when () {
threshold_b=0.0015;
this corresponds to 1.5mV
%% fpthres = fopen("/hac_epics/ioc/hallasc5/epics/seq/calib_threshold_file", "r");
%% fscanf(fpthres,"%f",&threshold_t);
%% fclose(fpthres);
pvPut(threshold_t);

%% fpcoef = fopen("/hac_epics/ioc/hallasc5/epics/seq/calib_coef_file", "r");
%% fscanf(fpcoef,"%f %f %f %f",&A1,&sdev1,&A2,&sdev2);
%% fclose(fpcoef);
pvPut(A1);
pvPut(A2);
pvPut(sdev1);
pvPut(sdev2);

%% fpdate = fopen("/hac_epics/ioc/hallasc5/epics/seq/calib_date_file", "r");
%% fscanf(fpdate,"%d %d %d",&swday,&swhr,&swmin);
%% fclose(fpdate);
pvPut(swday);
pvPut(swhr);
pvPut(swmin);

swsec=0;
update=0;
if (swday>0) | (swhr>12) uncalibrated=1;
} state init
}



CLOCK INITIALIZATION STATE:
After the calibration process (when STOP is pressed), in case the number of steps is not zero (actual calibration), the program resets the clock that gives you the time elapsed since the last calibration.

state clockinit {
when () {
if (step>0) {
swsec=0;
swmin=0;
swhr=0;
swday=0;
pvPut(swmin);
pvPut(swhr);
pvPut(swday);
}
} state init
}



INITIALIZATION STATE:
The sequencer checks continuously the value of the button "done" and updates the clock every second. Every 9/10 second, it also updates the blinking signal by switching the value of "blicky" from 0 to 1.
Every minute, the program writes the present time into the file "calib_date_file".
In case the START button is pressed (done=1) the program starts the calibration process. In order:
- initialize A1,A2,sdev1,sdev2
- initialize values1,values2,correction1,correction2
- initialize correct1,correct2
- initialize step
- initialize position
- initialize compute
then it goes to beam state.

state init {
when (done==1) {
printf("starting calibration\n");
A1=0.0;
A2=0.0;
sdev1=0.0;
sdev2=0.0;
for (k = 1;k <= 15;k++) values1[k]=0.0;
for (k = 1;k <= 15;k++) values2[k]=0.0;
for (k = 1;k <= 15;k++) correction1[k]=0.0;
for (k = 1;k <= 15;k++) correction2[k]=0.0;
correct1=0;
correct2=0;
step=0;
printf("step #%d\n",step);
pvPut(step);
position=2;
compute=1;
} state beam

when (delay(0.1)) {
swsec++;

/* start blinking process */
if (uncalibrated==1) {
swblicky++;
if (swblicky==9) {
swblicky=0;
if (blicky==0) blicky=1;
else blicky=0;
pvPut(blicky);
}
}

if (swsec==546) {
swmin++;
swsec=0;
pvPut(swmin);
update=0;
}
if (swmin==60) {
swhr++;
swmin=0;
pvPut(swhr);
pvPut(swmin);
update=0;
}
if (swhr==12) {
uncalibrated=1;
pvPut(uncalibrated);
}
if (swhr==24) {
swday++;
swhr=0;
pvPut(swday);
pvPut(swhr);
update=0;
}
if (update==0) {
%% fpdate = fopen("/hac_epics/ioc/hallasc5/epics/seq/calib_date_file", "w");
%% fprintf(fpdate,"%d %d %d",swday,swhr,swmin);
%% fclose(fpdate);
update=1;
}
} state init
}



WAITING STATE: This makes the program check its loop every 0.2 seconds; also duration of the present step is updated (this is used to know when the step time limit is reached).

state wait {
when (delay(0.2)) {
timelimit = timelimit + 1;
} state beam
}



BEAM STATE:
This state actually performs the coefficients computation. See detailed description below for each operation.
Every 0.2 seconds the program loops again, and performs one of the following operations.
You need to understand the principle of the calibration process in order to understand this part of the program.

state beam {

USER PUSHES STOP BUTTON:
First the program checks whether the number of steps is more than zero, because you don't want to perform anything in case of a phantom calibration.
Then it computes the last step (update of values1 & 2) and updates the coefficients and their standard deviations on the screen.
Finally, it resets the variables uncalibrated and blicky, and jumps into the last state: correct.

when(done==0) {
printf("calibration stopped\n");
compute A1 and A2 coefficients
if (step>0) {
values1[step] = modif1;
values2[step] = modif2;
printf("modif1=%f modif2=%f",modif1,modif2);
printf(" bcm1=%f bcm2=%f\n",A1 * bcm1,A2 * bcm2);
printf("computing coefficients\n");
updating coefficients
A1=A1/step;
A2=A2/step;
pvPut(A1);
pvPut(A2);
for (k = 1;k <= step;k++) {
sdev1 = sdev1 + (values1[k]-A1)*(values1[k]-A1);
sdev2 = sdev2 + (values2[k]-A2)*(values2[k]-A2);
}
sdev1 = sqrt( sdev1/step );
sdev2 = sqrt( sdev2/step );
pvPut(sdev1);
pvPut(sdev2);
printf("A1=%f +/-%f A2=%f +/-%f\n",A1,sdev1,A2,sdev2);
uncalibrated=0;
pvPut(uncalibrated);
blicky=0;
pvPut(blicky);
}
printf("end of process\n");
} state correct

BEAM IS PRESENT (Faraday Cup 2 is OUT):
First the program determines whether:
- we are at the beginning of the calibration (position=2) In this case, the program just resets all the variables i,j,s1,s2,su,top1,top2,topu,modif1,modif2,timelimit and sets the variable position to "1". Number of step also gets increased by 1.
- or we are at the beginning of a new step (position=0) Here the program performa the same initialization as in the first case, and also computes the previous step: it updates the variables values1 & 2 and A1 & 2.
- or beam was already present (position=1)
Then the program starts or goes on computing the step.

when ( (bcm1>threshold_t) & (bcm2>threshold_t) ) {
we are with beam

new step -> initialization of every variable
if (position!=1) {
if (position!=2) {
compute=0;
don't compute if first step
if (step>0) {
A1=A1/step;
A2=A2/step;
values1[step] = modif1;
values2[step] = modif2;
printf("modif1=%f modif2=%f",modif1,modif2);
pvPut(A1);
pvPut(A2);
printf(" bcm1=%f bcm2=%f ",A1 * bcm1,A2 * bcm2);
A1=A1*step;
A2=A2*step;
}
step++;
printf("step #%d\n",step);
pvPut(step);
}
position=1;
i=0;
j=0;
s1=0;
s2=0;
su=0;
for (k = 1;k <= 70;k++) top1[k]=0.0;
for (k = 1;k <= 70;k++) top2[k]=0.0;
for (k = 1;k <= 70;k++) topu[k]=0.0;
modif1=0.0;
modif2=0.0;
timelimit=0.0;
}

The program then checks whether the values have been updated (Unser): if yes, then if the duration of the step has not reached the time limit yet, the program increments the indexes and updates the current variables arrays top1, top2,topu, and also their sums s1,s2,su.
Then if we are still in the middle of a step, the program UPDATES the coefficients.
Note: the program doesn't make any computation if the step is made only by 1 measurement.
For each bcm the actual calculation is made by:
- first substracting the Unser Offset (calculated during last step) from the Unser measurement
- dividing the average of the Unser measurements during the step by the average of the BCM measurements during the step.


check if values changed
if (unser!= topu[i]) {

don't compute if more than one minute has ellapsed
if (timelimit>280) {
if (i==j) i=2;
else i++;
compute=1;
}
else {
i++;
j=i;
}

calculate new values
s1=s1 - top1[i];
s2=s2 - top2[i];
su=su - topu[i];
if (i!=1) {
top1[i]=bcm1;
top2[i]=bcm2;
topu[i]=unser;
}
s1=s1 + top1[i];
s2=s2 + top2[i];
su=su + topu[i];
}

compute new coefficient
if ( (compute==0) & (i!=1) ) {
A1=A1 - modif1;
A2=A2 - modif2;
modif1=( (su/(j - 1))-(so/jo) ) / (s1/(j - 1));
modif2=( (su/(j - 1))-(so/jo) ) / (s2/(j - 1));
A1=A1 + modif1;
A2=A2 + modif2;
}
if (timelimit==280) printf("stop computing\n");
} state wait

BEAM IS NOT DETECTED (Faraday cup 2 is IN):
First the program determines whether:
- we are at the beginning of the calibration (position=2) In this case, the program just resets all the variables i,j,s1,s2,su,top1,top2,topu,modif1,modif2,timelimit and sets the variable position to "0". Number of step also gets increased by 1.
- or we are at the beginning of a new step (position=1) Here the program performa the same initialization as in the first case, and also computes the previous step: it updates the variables values1 & 2 and A1 & 2.
- or beam was already present (position=0)
Then the program starts or goes on computing the step.

when ( (bcm1<threshold_b) & (bcm2<threshold_b) ) {
we are with no beam

new step -> initialization of every variable
if (position>0) {
if (position!=2) {
compute=0;

don't compute if first step
if (step>0) {
A1=A1/step;
A2=A2/step;
values1[step] = modif1;
values2[step] = modif2;
printf("modif1=%f modif2=%f",modif1,modif2);
pvPut(A1);
pvPut(A2);
printf(" bcm1=%f bcm2=%f ",A1 * bcm1,A2 * bcm2);
A1=A1*step;
A2=A2*step;
}
step++;
printf("step #%d\n",step);
pvPut(step);
}
position=0;
io=0;
jo=0;
so=0;
for (k = 1;k <= 70;k++) offset[k]=0.0;
modif1=0.0;
modif2=0.0;
timelimit=0.0;
}

The program then checks whether the values have been updated (Unser): if yes, then if the duration of the step has not reached the time limit yet, the program increments the indexes and updates the current variable array topo and also its sum so.
Then if we are still in the middle of a step, the program UPDATES the coefficients.
Note: the program doesn't make any computation if the step is made only by 1 measurement.
For each bcm the actual calculation is made by:
- first substracting the Unser Offset from the Unser measurement (calculated during last step)
- dividing the average of the Unser measurements during the step by the average of the BCM measurements during the step.

check if values changed
if (unser != offset[io]) {

don't compute if more than one minute has ellapsed
if (timelimit>280) {
if (io==jo) io=1;
else io++;
compute=1;
}
else {
io++;
jo=io;
}

calculate new values
so=so - offset[io];
offset[io]=unser;
so=so + offset[io];
}

compute new coefficient
if (compute==0) {
A1=A1 - modif1;
A2=A2 - modif2;
modif1=( (su/(j - 1))-(so/jo) ) / (s1/(j - 1));
modif2=( (su/(j - 1))-(so/jo) ) / (s2/(j - 1));
A1=A1 + modif1;
A2=A2 + modif2;
}
if (timelimit==280) printf("stop computing\n");
} state wait
}



CORRECTION STATE:
At the end of the Calibration, the program reviews all the intermediate coefficients, checks them, and if necessary redoes the final computation for A1,A2,sdev1,sdev2, taking off the bad steps.

state correct {
when () {
if (step>0) {

Here it checks whether the intermediate steps belongs to some confidence interval:
[19 27] for the Upstream BCM
[20 28] for the Downstream BCM
For each bcm, in case one coefficient is bad, the corresponding value of the variable correction1 (or 2) is set to 1 (instead of 0); also the value of correct1 (or 2) is not 0 anymore.
Finally, we know which coefficients are bad by the variable correction1 (or 2).

for (k = 1;k <= step;k++) {
if (values1[k] < 19) {
correction1[k] = 1;
correct1++;
}
if (values1[k] > 27) {
correction1[k] = 1;
correct1++;
}
if (values2[k] < 20) {
correction2[k] = 1;
correct2++;
}
if (values2[k] > 28) {
correction2[k] = 1;
correct2++;
}
}

If some correction has to be made, the program recomputes A1 and/or A2.

if (correct1!=0) {
A1=0;
for (k = 1;k <= step;k++) {
if (correction1[k] != 1) A1=A1+values1[k];
}
A1=A1/(step-correct1);
pvPut(A1);
}

if (correct2!=0) {
A2=0;
for (k = 1;k <= step;k++) {
if (correction2[k] != 1) A2=A2+values2[k];
}
A2=A2/(step-correct2);
pvPut(A2);
}

If some correction has to be made, the program recomputes sdev1 and/or sdev2.

if (correct1!=0) {
sdev1=0;
for (k = 1;k <= step;k++) {
if (correction1[k] != 1) sdev1=sdev1+(values1[k]-A1)*(values1[k]-A1);
}
sdev1=sqrt( sdev1/(step-correct1) );
pvPut(sdev1);
}

if (correct2!=0) {
sdev2=0;
for (k = 1;k <= step;k++) {
if (correction2[k] != 1) sdev2=sdev2+(values2[k]-A2)*(values2[k]-A2);
}
sdev2=sqrt( sdev2/(step-correct2) );
pvPut(sdev2);
}

Finally the program updates the file that contains A1,A2, sdev1,sdev2, and the file that contains threshold_t.

%% fpcoef = fopen("/hac_epics/ioc/hallasc5/epics/seq/calib_coef_file", "w");
%% fprintf(fpcoef,"%f %f %f %f",A1,sdev1,A2,sdev2);
%% fclose(fpcoef);
%% fpthres = fopen("/hac_epics/ioc/hallasc5/epics/seq/calib_threshold_file", "w");
%% fprintf(fpthres,"%f",threshold_t);
%% fclose(fpthres);
}
} state clockinit
}

}

END OF PROGRAM


Last update: October 27th 1997