/* ************************************************************** */ /* * Module IMAG * This module contains functions to set and read the magnet current. * * Zachary Wolf * 8/10/98 */ /* ************************************************************** */ /* INCLUDES */ #include #include #include #include #include #include "imag.h" #include "imagui.h" #include "hp3457.h" #include "dac488.h" #include "dac488hr.h" /* ************************************************************** */ /* PRIVATE PARAMETERS */ static char log_file[100]; static struct imag_param_struct imag_param; /* ************************************************************** */ /* PRIVATE GLOBAL VARIABLES */ static int dac488_ID; static int dac488hr_ID; static int hp3457_ID; static double present_nominal_current; static char msg[80]; static double zero_current_meas = 0.; /* ************************************************************** */ /* PRIVATE FUNCTIONS */ int imag_check_param(void); void imag_error(char* message); void imag_message(char* message); void imag_log_init_zero_current_meas(double zero_current); void imag_log_current(double voltage, double zero_current_meas, double current); void imag_log_ave_current(double ave_current, double sig_current); void imag_log_ramp(double current); void imag_supervise_ramp(double desired_current, double ramp_rate); void imag_perform_ramp(double desired_current, double ramp_rate); void idac488_perform_ramp(double delta_t, int N_points, double ramp[]); void idac488hr_perform_ramp(double delta_t, int N_points, double ramp[]); void iman_perform_ramp(double delta_t, int N_points, double ramp[]); void imag_calculate_linear_ramp(double I_ini, double I_fin, double rate, double delta_t, int* N_points, double ramp[]); void imag_calculate_three_linear_ramp(double I_ini, double I_fin, double rate, double delta_t, int* N_points, double ramp[]); void imag_calculate_cosine_ramp(double I_ini, double I_fin, double rate, double delta_t, int* N_points, double ramp[]); /* ************************************************************** */ /* PUBLIC FUNCTIONS */ /* ************************************************************** */ /* * imag_init * This function is used to initialize the magnet current system. * * Zachary Wolf * 8/10/98 */ void imag_init(char log_file_in[], struct imag_param_struct imag_param_in) { /* Declare variables */ int err; int result; /* Save parameters for future use */ strcpy(log_file, log_file_in); imag_param = imag_param_in; /* Check all parameter values to find any problems early */ err = imag_check_param(); if (err != 0) { imag_error("Problem with parameter values"); return; } /* Initialize the required hardware */ if (imag_param.config == IMAG_DAC488_HP3457) { dac488_init(imag_param.board_addr, imag_param.dac488_addr, &dac488_ID); hp3457_init(imag_param.board_addr, imag_param.hp3457_addr, &hp3457_ID); } else if (imag_param.config == IMAG_DAC488HR_HP3457) { dac488hr_init(imag_param.board_addr, imag_param.dac488hr_addr, &dac488hr_ID); hp3457_init(imag_param.board_addr, imag_param.hp3457_addr, &hp3457_ID); } else if (imag_param.config == IMAG_MANUAL_HP3457) { hp3457_init(imag_param.board_addr, imag_param.hp3457_addr, &hp3457_ID); } else if (imag_param.config == IMAG_NONE) { /* No hardware initialization required */ } else { imag_error("Unknown magnet current configuration"); /* Problem */ return; } /* Initial zero current measurement */ imag_init_zero_current_meas(); /* Initial power supply turn on */ imag_init_turn_on(); /* Done */ return; } /* ************************************************************** */ /* * imag_init_zero_current_meas * This function is used to determine offsets in the current measurement * system. The measured current with zero actual current is subtracted * from future current measurements. * * Output (global): * zero_current_meas, measured current with zero actual current (A) * * Zachary Wolf * 4/7/00 */ void imag_init_zero_current_meas(void) { /* Declare variables */ int err; char buf[80]; double imag_ave, imag_rms; /* Check all parameter values */ err = imag_check_param(); if (err != 0) { imag_error("Problem with parameter values"); return; } /* Exit if there is no magnet current configuration */ if (imag_param.config == IMAG_NONE) return; /* Measure the current with zero actual current */ if (imag_param.init_zero_current_meas == IMAG_TRUE) { printf("\nInitial zero current measurement to determine system offsets...\n"); printf("Please turn the current off.\n"); printf("Press ENTER when ready."); Beep(); fgets(buf, 80, stdin); zero_current_meas = 0.; imag_get_ave_current(&imag_ave, &imag_rms); zero_current_meas = imag_ave; printf("\nThe zero current measurement is complete.\n"); printf("Please turn on the power supply and press ENTER to continue."); Beep(); fgets(buf, 80, stdin); } /* Log the result */ imag_log_init_zero_current_meas(zero_current_meas); /* Done */ return; } /* ************************************************************** */ /* * imag_init_turn_on * This function is used to initially turn on the magnet current system. * * Zachary Wolf * 12/13/99 */ void imag_init_turn_on(void) { /* Declare variables */ int err; /* Check all parameter values */ err = imag_check_param(); if (err != 0) { imag_error("Problem with parameter values"); return; } /* Exit if there is no magnet current configuration */ if (imag_param.config == IMAG_NONE) return; /* Initial power supply turn on */ if (imag_param.init_turn_on == IMAG_TRUE) { printf("\nInitial power supply turn on...\n"); imag_ramp(imag_param.init_turn_on_current); printf("Wait 20 seconds for the power supply to stabilize..."); Delay(20.); printf("Done\n"); } /* Done */ return; } /* ************************************************************** */ /* * imag_write_header * This function writes a header to the specified file describing * the standardization and test currents. * * Input: * file_name, file name including the directory path and extension * num_stand_cycles, number of standardization cycles * istand_max, maximum standardization current (A) * istand_min, minimum standardization current (A) * num_test_currents, number of test currents * test_currents, array of test currents (A) * * Zachary Wolf * 11/19/99 */ void imag_write_header(char* file_name, int num_stand_cycles, double istand_max, double istand_min, int num_test_currents, double test_currents[]) { /* Declare variables */ FILE* file_ptr; int i; /* Open the file */ file_ptr = fopen(file_name, "a"); if (file_ptr == NULL) imag_error("Problem opening a file to write a header"); /* Write the standardization information */ if (num_stand_cycles > 0) { fprintf(file_ptr, "\n"); fprintf(file_ptr, "Standardization:\n"); fprintf(file_ptr, " %2i cycles from %6.1f A to %6.1f A to %6.1f A\n", num_stand_cycles, istand_min, istand_max, istand_min); } /* Write the test current information */ fprintf(file_ptr, "\n"); fprintf(file_ptr, "Test Currents (A):\n"); for (i = 0; i < num_test_currents; i++) { fprintf(file_ptr, " %6.1f", test_currents[i]); if ((i + 1) % 5 == 0) fprintf(file_ptr, "\n"); } fprintf(file_ptr, "\n\n"); /* Close the file */ fclose(file_ptr); /* Done */ return; } /* ************************************************************** */ /* * imag_ramp * This function is used to ramp the current in the magnet to the * requested value. The setting ramp rate is used. * (This function can not replace imag_supervise_ramp because of * other ramp rates, ie. standardization ramp rate.) * * Input: * desired_current, current to ramp to (A) * * Zachary Wolf * 8/12/98 */ void imag_ramp(double desired_current) { /* Exit if there is no magnet current configuration */ if (imag_param.config == IMAG_NONE) return; /* Let the ramp supervisor perform the ramp */ imag_supervise_ramp(desired_current, imag_param.ramp_rate); /* Wait for things to settle after the ramp */ Delay(imag_param.wait_after_ramp); /* Done */ return; } /* ************************************************************** */ /* * imag_standardize * This function is used to standardize the magnet. * It leaves the power supply at the minimum standardization current. * * Input: * stand_max_current, max current to ramp to (A) * stand_min_current, min current to ramp to (A) * num_cycles, number of standardization cycles * * Zachary Wolf * 8/19/98 */ void imag_standardize(double stand_max_current, double stand_min_current, int num_cycles) { /* Declare variables */ int i; /* Exit if there is no magnet current configuration */ if (imag_param.config == IMAG_NONE) return; /* Loop over standardization cycles */ for (i = 1; i <= num_cycles; i++) { /* Ramp to the maximum current */ imag_supervise_ramp(stand_max_current, imag_param.stand_ramp_rate); /* Wait for things to settle after the ramp */ Delay(imag_param.wait_after_stand_ramp); /* Ramp to the minimum current */ imag_supervise_ramp(stand_min_current, imag_param.stand_ramp_rate); /* Wait for things to settle after the ramp */ Delay(imag_param.wait_after_stand_ramp); /* End loop over standardization cycles */ } /* Done */ return; } /* ************************************************************** */ /* * imag_get_current * This function measures the magnet current. * * Output: * current, magnet current (A) * * Zachary Wolf * 8/12/98 */ void imag_get_current(double* current) { /* Declare variables */ double voltage; double current_without_offset_corr; /* Measure the transductor voltage */ if (imag_param.config == IMAG_DAC488_HP3457) { hp3457_get_chan_voltage(hp3457_ID, imag_param.hp3457_chan, &voltage); } else if (imag_param.config == IMAG_DAC488HR_HP3457) { hp3457_get_chan_voltage(hp3457_ID, imag_param.hp3457_chan, &voltage); } else if (imag_param.config == IMAG_MANUAL_HP3457) { hp3457_get_chan_voltage(hp3457_ID, imag_param.hp3457_chan, &voltage); } else if (imag_param.config == IMAG_NONE) { *current = 0.; return; } else { imag_error("Unknown magnet current configuration"); /* Problem */ return; } /* Calculate the magnet current */ *current = voltage / imag_param.trans_volts_per_amp - zero_current_meas; /* Log the measured current */ imag_log_current(voltage, zero_current_meas, *current); /* Done */ return; } /* ************************************************************** */ /* * imag_get_ave_current * This function measures the magnet current several times and * computes the average and standard deviation. * * Output: * ave_current, average of magnet current measurements (A) * sig_current, rms variation of magnet current measurements (A) * * Zachary Wolf * 8/12/98 */ void imag_get_ave_current(double* ave_current, double* sig_current) { /* Declare variables */ double current[IMAG_NUM_MEAS_AVE]; int i; /* Loop over current measurements */ for (i = 0; i < IMAG_NUM_MEAS_AVE; i++) { imag_get_current(¤t[i]); } /* Compute the average and rms variation */ StdDev(current, IMAG_NUM_MEAS_AVE, ave_current, sig_current); /* Log the measured current */ imag_log_ave_current(*ave_current, *sig_current); /* Message */ printf("\nMagnet Current Measurement:\n"); printf("Imag = %f +- %f Amps\n", *ave_current, *sig_current); /* Done */ return; } /* ************************************************************** */ /* * imag_get_present_nominal_current * This function returns the nominal magnet current. * * Output: * present_nominal_current, nominal magnet current (A) * * Zachary Wolf * 8/12/98 */ void imag_get_present_nominal_current(double* current) { /* Return the present nominal current */ *current = present_nominal_current; /* Done */ return; } /* ************************************************************** */ /* * imag_set_ramp_rate * This function sets the ramp rate. * * Input: * ramp_rate, ramp rate (A/s) * * Zachary Wolf * 6/17/99 */ void imag_set_ramp_rate(double ramp_rate) { /* Set the ramp rate */ imag_param.ramp_rate = ramp_rate; /* Done */ return; } /* ************************************************************** */ /* * imag_monitor * This function allows the operator to monitor the transductor * voltage on the HP3457. * * Zachary Wolf * 8/13/98 */ void imag_monitor(void) { /* Use the HP3457 to monitor the transductor voltage */ if (imag_param.config == IMAG_DAC488_HP3457) { hp3457_monitor_chan_voltage(hp3457_ID, imag_param.hp3457_chan); } else if (imag_param.config == IMAG_DAC488HR_HP3457) { hp3457_monitor_chan_voltage(hp3457_ID, imag_param.hp3457_chan); } else if (imag_param.config == IMAG_MANUAL_HP3457) { hp3457_monitor_chan_voltage(hp3457_ID, imag_param.hp3457_chan); } else if (imag_param.config == IMAG_NONE) { return; } else { imag_error("Unknown magnet current configuration"); /* Problem */ return; } /* Done */ return; } /* ************************************************************** */ /* * imag_exit * This function is used to exit the magnet current system. * * Zachary Wolf * 8/13/98 */ void imag_exit(void) { /* Ramp the power supply to 0 */ imag_supervise_ramp(0., imag_param.stand_ramp_rate); /* Exit all devices */ if (imag_param.config == IMAG_DAC488_HP3457) { dac488_exit(dac488_ID); hp3457_exit(hp3457_ID); } else if (imag_param.config == IMAG_DAC488HR_HP3457) { dac488hr_exit(dac488hr_ID); hp3457_exit(hp3457_ID); } else if (imag_param.config == IMAG_MANUAL_HP3457) { hp3457_exit(hp3457_ID); } else if (imag_param.config == IMAG_NONE) { /* No hardware closing required */ } else { imag_error("Unknown magnet current configuration"); return; } /* Done */ return; } /* ************************************************************** */ /* INTERNAL FUNCTIONS */ /* ************************************************************** */ /* * imag_error * This function handles errors for the IMAG module. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 10/11/98 */ void imag_error(char* message) { /* Declare variables */ char buf[80]; /* Notify the operator of the error */ printf("\nIMAG ERROR: %s\n", message); Beep(); Delay(.5); Beep(); /* Terminate the program if the operator desires */ printf("Press ENTER to continue.\nPress any key then ENTER to terminate program.\n"); fgets(buf, 80, stdin); if (buf[0] == '\n') return; else exit(0); } /* ************************************************************** */ /* * imag_message * This function handles messages for the IMAG module. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 10/12/98 */ void imag_message(char* message) { /* Print the message */ printf("%s\n", message); /* Done */ return; } /* ************************************************************** */ /* * imag_check_param * This function checks that all required parameters have been assigned * appropriate values. * * Output: * err, 0 = no error, non-zero = error * * Zachary Wolf * 8/11/98 */ int imag_check_param() { /* log_file */ if (CompareStrings(log_file, 0, "", 0, 0) == 0) { imag_error("Log file not defined."); return -1; } /* imag_param.config, OK, enum */ /* imag_param.bipolar, OK, enum */ /* imag_param.dac488_addr */ if (imag_param.dac488_addr <= 0 || imag_param.dac488_addr > 30) { Fmt(msg, "%s 4) { Fmt(msg, "%s 30) { Fmt(msg, "%s 2) { Fmt(msg, "%s 1000.) { Fmt(msg, "%s 30) { Fmt(msg, "%s 10) { Fmt(msg, "%s 10.) { Fmt(msg, "%s 3100.) { Fmt(msg, "%s 0.) { Fmt(msg, "%s 100.) { Fmt(msg, "%s 200.) { Fmt(msg, "%s 100.) { Fmt(msg, "%s 200.) { Fmt(msg, "%s imag_param.max_curr_limit || desired_current < imag_param.min_curr_limit) { imag_error("imag_supervise_ramp, desired current past current limit"); return; } /* If the power supply is bipolar, perform the ramp and return */ if (imag_param.bipolar == IMAG_TRUE) { imag_perform_ramp(desired_current, ramp_rate); return; } /* Otherwise, things are a little more complicated */ /* Compute the sign of the present and desired current */ if (present_nominal_current >= 0) sign_present = 1; else sign_present = -1; if (desired_current >= 0) sign_desired = 1; else sign_desired = -1; /* If the signs are the same, perform the ramp and return */ if (sign_present == sign_desired) { imag_perform_ramp(desired_current, ramp_rate); return; } /* At this point, the power supply is not bipolar and the sign of the * current needs to change. * Ramp to zero, * ask the operator to turn the supply off and reverse the leads, * then turn the supply on and press ENTER, * finally, ramp to the desired current */ imag_perform_ramp(0., ramp_rate); printf("\nPlease turn off the power supply and reverse the leads.\n"); printf("Then turn the power supply back on.\n"); printf("Press ENTER when ready."); Beep(); fgets(buf, 80, stdin); imag_perform_ramp(desired_current, ramp_rate); /* Done */ return; } /* ************************************************************** */ /* * imag_perform_ramp * This function is used to carry out the ramp of the current. * * Input: * desired_current, current to ramp to (A) * ramp_rate, ramp rate (A/s) * * Zachary Wolf * 8/12/98 */ void imag_perform_ramp(double desired_current, double ramp_rate) { /* Declare variables */ double ramp[IMAG_MAX_NUM_RAMP_POINTS]; int num_ramp_points; /* Exit if there is no magnet current configuration */ if (imag_param.config == IMAG_NONE) return; /* Message */ Fmt(msg, "%s<\nRamping to %f Amps...", desired_current); imag_message(msg); /* Log the ramp */ imag_log_ramp(desired_current); /* Set the DMM so the transductor can be monitored */ imag_monitor(); /* Calculate the ramp */ if (imag_param.ramp_style == IMAG_LINEAR) { imag_calculate_linear_ramp(present_nominal_current, desired_current, ramp_rate, IMAG_TIME_BETWEEN_CURRENT_STEPS, &num_ramp_points, ramp); } else if (imag_param.ramp_style == IMAG_THREE_LINEAR) { imag_calculate_three_linear_ramp(present_nominal_current, desired_current, ramp_rate, IMAG_TIME_BETWEEN_CURRENT_STEPS, &num_ramp_points, ramp); } else if (imag_param.ramp_style == IMAG_COSINE) { imag_calculate_cosine_ramp(present_nominal_current, desired_current, ramp_rate, IMAG_TIME_BETWEEN_CURRENT_STEPS, &num_ramp_points, ramp); } else { imag_error("Unknown ramp style requested"); } /* Ramp the magnet */ if (imag_param.config == IMAG_DAC488_HP3457) { idac488_perform_ramp(IMAG_TIME_BETWEEN_CURRENT_STEPS, num_ramp_points, ramp); } else if (imag_param.config == IMAG_DAC488HR_HP3457) { idac488hr_perform_ramp(IMAG_TIME_BETWEEN_CURRENT_STEPS, num_ramp_points, ramp); } else if (imag_param.config == IMAG_MANUAL_HP3457) { iman_perform_ramp(IMAG_TIME_BETWEEN_CURRENT_STEPS, num_ramp_points, ramp); } else if (imag_param.config == IMAG_NONE) { } else { imag_error("Unknown magnet current configuration"); return; } /* Done */ return; } /* ************************************************************** */ /* * idac488_perform_ramp * This function uses the IOtech DAC488 to perform a current ramp. * * Input: * delta_t, time between current steps (s) * N_points, number of points in the ramp * ramp[0 to N_points - 1], currents making up the ramp (A) * * Zachary Wolf * 8/12/98 */ void idac488_perform_ramp(double delta_t, int N_points, double ramp[]) { /* Loop over currents */ /* Save the new nominal current setting */ /* Update the user interface with the new nominal current */ /* Convert currents to DAC voltages */ /* Have the DAC output the correct voltage */ int i; double voltage; double t0; for (i = 0; i < N_points; i++) { t0 = Timer(); present_nominal_current = ramp[i]; imagui_update(present_nominal_current); voltage = ramp[i] / imag_param.ps_amps_per_dac_volt; if (imag_param.bipolar == IMAG_TRUE) dac488_set_port_voltage(dac488_ID, imag_param.dac488_port, voltage); else dac488_set_port_voltage(dac488_ID, imag_param.dac488_port, fabs(voltage)); while (Timer() - t0 < delta_t); } } /* ************************************************************** */ /* * idac488hr_perform_ramp * This function uses the IOtech DAC488HR to perform a current ramp. * * Input: * delta_t, time between current steps (s) * N_points, number of points in the ramp * ramp[0 to N_points - 1], currents making up the ramp (A) * * Zachary Wolf * 8/12/98 */ void idac488hr_perform_ramp(double delta_t, int N_points, double ramp[]) { /* Loop over currents */ /* Save the new nominal current setting */ /* Update the user interface with the new nominal current */ /* Convert currents to DAC voltages */ /* Have the DAC output the correct voltage */ int i; double voltage; double t0; for (i = 0; i < N_points; i++) { t0 = Timer(); present_nominal_current = ramp[i]; imagui_update(present_nominal_current); voltage = ramp[i] / imag_param.ps_amps_per_dac_volt; if (imag_param.bipolar == IMAG_TRUE) dac488hr_set_port_voltage(dac488hr_ID, imag_param.dac488hr_port, voltage); else dac488hr_set_port_voltage(dac488hr_ID, imag_param.dac488hr_port, fabs(voltage)); while (Timer() - t0 < delta_t); } } /* ************************************************************** */ /* * iman_perform_ramp * This function uses the operator to perform a current ramp. * * Input: * delta_t, time between current steps (s) * N_points, number of points in the ramp * ramp[0 to N_points - 1], currents making up the ramp (A) * * Zachary Wolf * 8/12/98 */ void iman_perform_ramp(double delta_t, int N_points, double ramp[]) { /* Declare variables */ double desired_current; char buf[81]; /* Have the operator ramp to the desired current */ desired_current = ramp[N_points - 1]; printf("\nPlease ramp to %.2f amps. Press ENTER when finished.", desired_current); Beep(); fgets(buf, 80, stdin); printf("\n"); /* Save the new nominal current setting */ present_nominal_current = desired_current; /* Update the user interface */ if (imag_param.show_ui == IMAG_TRUE) imagui_update(present_nominal_current); /* Done */ return; } /* ************************************************************** */ /* * imag_calculate_linear_ramp * This function calculates a linear ramp from an initial current * to a final current. * * Input: * I_ini, initial current (A) * I_fin, final current (A) * rate, ramp rate (A/s) * delta_t, time between current steps (s) * * Output: * N_points, number of points in the ramp * ramp[0 to N_points - 1], currents making up the ramp (A) * * Zachary Wolf * 8/12/98 */ void imag_calculate_linear_ramp(double I_ini, double I_fin, double rate, double delta_t, int* N_points, double ramp[]) { /* Declare variables */ double abs_I_step; long int num_steps; int i; double I_step; /* Determine the absolute value of the current step size */ abs_I_step = rate * delta_t; /* Check */ if (abs_I_step <= 0) { Fmt(msg, "%s IMAG_MAX_NUM_RAMP_POINTS) { Fmt(msg, "%s IMAG_MAX_NUM_RAMP_POINTS) { Fmt(msg, "%s IMAG_MAX_NUM_RAMP_POINTS) { Fmt(msg, "%s