DECLARE SUB vtoffsetcorr2 (n%, vt!(), vtn!) DECLARE SUB vtlogoffset2 (logfile$, n%, b!, vt0!, vtn!, vtmin!, vtmax!) DECLARE SUB pdivtrotenc (c$, g%, d$, np%, ns%, n%, vt!(), vtn!) DECLARE SUB cm2100avdst (a!, v!, d!) DECLARE SUB cm2100avdend (d!) DECLARE SUB vtcheckdata (n%, vt!(), ok$) DECLARE SUB vtcheckpar (ok$) DECLARE SUB vtgetvt (rotdir$, n%, vt!()) DECLARE SUB vtgetvthar (rotdir$, nh%, harm!(), harp!()) DECLARE SUB vtlogoffset (logfile$, n%, vt0!, vtn!, vtmin!, vtmax!) DECLARE SUB vtlogvthar1 (logfile$, rotdir$, vtmag!, vtphase!) DECLARE SUB vtoffsetcorr (n%, vt!(), vtn!) DECLARE SUB pdivtrotencrd (c$, n%, vt!(), vtn!) DECLARE SUB pdivtrotencst (c$, g%, d$, np%, ns%, n%) DECLARE SUB cm2100avd (a!, v!, d!) DECLARE SUB spcalcfft (ns%, samp!(), fftm!(), fftp!()) DECLARE SUB spcalchar (ns%, fftm!(), fftp!(), nfun%, nh%, harm!(), harp!()) DECLARE SUB spplotfft (ns%, fftm!(), fftp!()) DECLARE SUB spplothar (nh%, harm!(), harp!()) DECLARE SUB spplotsamp (ns%, samp!()) '**************************************************************************** 'Module VTCOIL.BAS 'The subroutines in this module perform integrated voltage measurements 'using the Metrolab PDI-5025 integrator. The Compumotor CM2100 rotates 'either the coil or the magnet. ' 'Zachary Wolf '9/12/95 '**************************************************************************** 'Common block containing parameters for this module COMMON SHARED /vtcoil/ logfileP$, vtchanP$, vtgainP%, vtnpulseperrevP%, vtnsampperrevP%, vtnrevpermeasP%, vtaccP!, vtvelP!, vtdisP! SUB vtcheckdata (n%, vt!(), ok$) '**************************************************************************** 'This subroutine checks the data for missing data points or large noise. ' 'Input/Output: ' n%, the number of samples ' vt!(0 to n%-1), the integrated voltage samples, a few points may be corrected ' 'Output: ' ok$, "y" if the data is smooth, "n" otherwise ' 'Zachary Wolf '1/9/96 '**************************************************************************** 'Initialize ok$ = "y" 'Find the peak value vtpeak! = 0! FOR i% = 0 TO n% - 1 IF ABS(vt!(i%)) > vtpeak! THEN vtpeak! = ABS(vt!(i%)) NEXT i% 'Check that each data point is near the value of a linear fit between neighboring points nbad% = 0 FOR i% = 2 TO n% - 2 vtexpect! = vt!(i% - 1) + (vt!(i% - 1) - vt!(i% - 2)) vtfit! = (vt!(i% + 1) + vt!(i% - 1)) / 2! IF (ABS(vtexpect!) > .1 * vtpeak!) AND (ABS(vt!(i%) - vtexpect!) > ABS(.3 * vtexpect!)) THEN PRINT "i = "; i%; "vt(i) = "; vt!(i%); ", vtexptect = "; vtexpect!; ", vtfit = "; vtfit! vt!(i%) = vtfit! nbad% = nbad% + 1 IF nbad% > 4 THEN ok$ = "n" 'bad value PRINT "VTCHECKDATA: bad data, writing values to checkvt.dat" filenum% = FREEFILE 'save the values for analysis OPEN "checkvt.dat" FOR OUTPUT AS filenum% FOR j% = 0 TO n% - 1 PRINT #filenum%, vt!(j%) NEXT j% CLOSE filenum% EXIT SUB 'exit with ok$ = "n" END IF END IF NEXT i% END SUB SUB vtcheckpar (ok$) '**************************************************************************** 'This subroutine checks that all required VT parameters have been assigned 'values. ' 'Output: ' ok$, "y" if parameter assignments are ok, "n" otherwise ' 'Zachary Wolf '9/18/95 '**************************************************************************** 'Default value ok$ = "n" 'Logfile IF logfileP$ = "" THEN PRINT "VT: Log file not defined" EXIT SUB END IF 'Integrator channel IF (vtchanP$ <> "A" AND vtchanP$ <> "B") THEN PRINT "VT: PDI channel not defined: "; vtchanP$ EXIT SUB END IF 'Integrator gain IF (vtgainP% <= 0 OR vtgainP% > 1000) THEN PRINT "VT: PDI gain has improper value: "; vtgainP% EXIT SUB END IF 'Number of encoder pulses per revolution IF (vtnpulseperrevP% <= 0 OR vtnpulseperrevP% > 10000) THEN PRINT "VT: #encoder pulses per revolution has improper value: "; vtnpulseperrevP% EXIT SUB END IF 'Number of VT samples per revolution IF (vtnsampperrevP% <= 0 OR vtnsampperrevP% > vtnpulseperrevP%) THEN PRINT "VT: #samples per revolution has improper value: "; vtnsampperrevP% EXIT SUB END IF 'Number of revolutions per measurement IF (vtnrevpermeasP% <= 0 OR vtnrevpermeasP% > 25) THEN PRINT "VT: #revolutions per measurement has improper value: "; vtnrevpermeasP% EXIT SUB END IF 'Motor acceleration IF (vtaccP! <= 0 OR vtaccP! > 30) THEN PRINT "VT: motor acceleration has improper value: "; vtaccP! EXIT SUB END IF 'Motor velocity IF (vtvelP! <= 0 OR vtvelP! > 30) THEN PRINT "VT: motor velocity has improper value: "; vtvelP! EXIT SUB END IF 'Distance motor turns IF (vtdisP! <= 0 OR vtdisP! > 50) THEN PRINT "VT: motor distance has improper value: "; vtdisP! EXIT SUB END IF 'If we made it this far, all parameters have values ok$ = "y" END SUB SUB vtgetvt (rotdir$, n%, vt!()) '**************************************************************************** 'This subroutine gets triggered integrated voltage measurements from a coil. 'The triggers come from a rotary encoder. ' 'Input: ' rotdir$, rotation direction, "+" = CW, "-" = CCW ' n%, the number of integrated voltage samples ' 'Output: ' vt!(0 to n%-1), the integrated voltage at each sample point ' 'Zachary Wolf '9/12/95 '**************************************************************************** 'Make sure all required parameters have been defined CALL vtcheckpar(ok$) IF ok$ <> "y" THEN FOR i% = 0 TO n% - 1 vt!(i%) = 0! NEXT i% EXIT SUB END IF 'Simplify the notation pm$ = rotdir$ c$ = vtchanP$ g% = vtgainP% np% = vtnpulseperrevP% ns% = vtnsampperrevP% nr% = vtnrevpermeasP% a! = vtaccP! v! = vtvelP! d! = vtdisP! IF (pm$ = "-") THEN d! = -d! 'Check that we sample over a complete number of rotations IF n% <> ns% * nr% THEN PRINT "VTGETVT: N problem" EXIT SUB END IF remeasure: 'Start the motor turning CALL cm2100avdst(a!, v!, d!) 'Wait until the motor is up to speed, 3 revolutions sleeptime% = 3 / v! IF sleeptime% >= 1 THEN SLEEP sleeptime% 'Perform the integrator measurement CALL pdivtrotenc(c$, g%, pm$, np%, ns%, n%, vt!(), vtn!) 'Wait until the motor is done turning to continue CALL cm2100avdend(d!) '*****************Alternate Approach********************** 'Start the integrator measurement 'CALL pdivtrotencst(c$, g%, pm$, np%, ns%, n%) 'Turn the motor 'CALL cm2100avd(a!, v!, d!) 'Get the data 'CALL pdivtrotencrd(c$, n%, vt!(), vtn!) '********************************************************** 'Correct the data for integrator drift CALL vtoffsetcorr(n%, vt!(), vtn!) 'CALL vtoffsetcorr2(n%, vt!(), vtn!) 'Check the data for missing points and excessive noise 'CALL vtcheckdata(n%, vt!(), ok$) 'IF ok$ <> "y" THEN ' PRINT "Noisy data, remeasuring..." ' GOTO remeasure 'END IF END SUB SUB vtgetvthar (rotdir$, nh%, harm!(), harp!()) '**************************************************************************** 'This subroutine performs an integrated voltage measurement and returns the 'signals at the harmonics of the rotation frequency. ' 'Input: ' rotdir$, rotation direction, "+" = CW, "-" = CCW ' nh%, the number of harmonics to return ' 'Output: ' harm!(1 to nh%), voltage magnitude at each harmonic ' harp!(1 to nh%), voltage phase in degrees at each harmonic ' 'Zachary Wolf '9/13/95 '**************************************************************************** 'Make sure all required parameters have been defined CALL vtcheckpar(ok$) IF ok$ <> "y" THEN FOR i% = 1 TO nh% harm!(i%) = 0! harp!(i%) = 0! NEXT i% EXIT SUB END IF 'Simplify the notation ns% = vtnsampperrevP% nr% = vtnrevpermeasP% 'Compute the required number of samples n% = ns% * nr% 'Initialize data arrays DIM vt!(0 TO n% - 1) DIM fftm!(0 TO n% / 2) DIM fftp!(0 TO n% / 2) 'Sample the voltage from the coil CALL vtgetvt(rotdir$, n%, vt!()) 'Calculate the FFT of the voltage sample CALL spcalcfft(n%, vt!(), fftm!(), fftp!()) 'Calculate the signal harmonics of the rotation frequency CALL spcalchar(n%, fftm!(), fftp!(), nr%, nh%, harm!(), harp!()) 'Plot the data when debugging 'PRINT "DEBUG, VTGETVTHAR: writing samples using spplotxxx" CALL spplotsamp(n%, vt!()) CALL spplotfft(n%, fftm!(), fftp!()) CALL spplothar(nh%, harm!(), harp!()) END SUB SUB vtgetvthar1 (rotdir$, vtmag!, vtphase!) '**************************************************************************** 'This subroutine performs an integrated voltage measurement and returns the 'signals at the fundamental harmonic of the rotation frequency. ' 'Input: ' rotdir$, rotation direction, "+" = CW, "-" = "CCW" ' 'Output: ' vtmag!, magnitude of the component of vt at the fundamental frequency ' vtphase!, phase of the component of vt at the fundamental frequency ' 'Zachary Wolf '9/13/95 '**************************************************************************** 'Make sure all required parameters have been defined CALL vtcheckpar(ok$) IF ok$ <> "y" THEN vtmag! = 0! vtphase! = 0! EXIT SUB END IF 'Initialize arrays nh% = 1 DIM harm!(1 TO nh%) DIM harp!(1 TO nh%) 'Get the integrated voltage harmonics CALL vtgetvthar(rotdir$, nh%, harm!(), harp!()) 'Save the magnitude and phase of the fundamental vtmag! = harm!(1) vtphase! = harp!(1) 'Log the result CALL vtlogvthar1(logfileP$, rotdir$, vtmag!, vtphase!) END SUB SUB vtlogoffset (logfile$, n%, vt0!, vtn!, vtmin!, vtmax!) '**************************************************************************** 'This subroutine logs an offset correction. ' 'Input: ' logfile$, the name of the log file ' n%, the number of samples ' vt0!, the 0'th sample ' vtn!, the n'th sample, with no offset will equal vt0! ' vtmin!, minimum of the corrected vt samples ' vtmax!, maximum of the corrected vt samples ' 'Zachary Wolf '11/5/95 '**************************************************************************** 'Open the log file filenum% = FREEFILE OPEN logfile$ FOR APPEND AS filenum% 'Print the results PRINT #filenum%, TIME$; " VT Offset Correction:" PRINT #filenum%, " n = "; n%; ", VT0 = "; vt0!; ", VTn = "; vtn! PRINT #filenum%, " VTmin = "; vtmin!; ", VTmax = "; vtmax!; ", Rel Corr = "; ABS(vtn! - vt0!) / (vtmax! - vtmin!) 'Close the log file CLOSE filenum% END SUB SUB vtlogoffset2 (logfile$, n%, b!, vt0!, vtn!, vtmin!, vtmax!) '**************************************************************************** 'This subroutine logs an offset correction. ' 'Input: ' logfile$, the name of the log file ' n%, the number of samples ' b!, the slope of the offset correction ' vt0!, the 0'th sample ' vtn!, the n'th sample, with no offset will equal vt0! ' vtmin!, minimum of the corrected vt samples ' vtmax!, maximum of the corrected vt samples ' 'Zachary Wolf '11/5/95 '**************************************************************************** 'Open the log file filenum% = FREEFILE OPEN logfile$ FOR APPEND AS filenum% 'Print the results PRINT #filenum%, TIME$; " VT Offset Correction:" PRINT #filenum%, " n = "; n%; ", b = "; b!; ", n*b = "; n% * b! PRINT #filenum%, " VT0 = "; vt0!; ", VTn = "; vtn! PRINT #filenum%, " VTmin = "; vtmin!; ", VTmax = "; vtmax! PRINT #filenum%, " Rel Corr = "; ABS(n% * b!) / (vtmax! - vtmin!) 'Close the log file CLOSE filenum% END SUB SUB vtlogvthar1 (logfile$, rotdir$, vtmag!, vtphase!) '**************************************************************************** 'This subroutine writes to the log file the results of an integrated voltage 'measurement. ' 'Input: ' logfile$, the name of the log file ' rotdir$, rotation direction, "+" = CW, "-" = CCW ' vtmag!, vt magnitude ' vtphase!, vt phase ' 'Zachary Wolf '11/5/95 '**************************************************************************** 'Open the log file filenum% = FREEFILE OPEN logfile$ FOR APPEND AS filenum% 'Print the results PRINT #filenum%, TIME$; " VT Fundamental Measurement:" PRINT #filenum%, " Rotation direction: "; rotdir$ PRINT #filenum%, " vtmag1 = "; vtmag!; ", vtphase1 = "; vtphase! 'Close the log file CLOSE filenum% END SUB SUB vtoffsetcorr (n%, vt!(), vtn!) '**************************************************************************** 'This subroutine corrects for a voltage offset in an integrator. This 'produces a linear ramp in the integrator output. The linear ramp 'is subtracted from the vt samples. The subroutine assumes a periodic 'integrator input so the n'th sample is the same as the 0'th sample. ' 'Input/Output ' n%, the number of samples ' vt!(0 to n%-1), the integrated voltage samples ' 'Zachary Wolf '1/8/96 '**************************************************************************** 'Get the initial sample value samp0! = vt!(0) 'Get the n'th sample value 'With no drift and a periodic signal, this is the same as the initial sample sampn! = vtn! 'Compute a linear ramp from the 0'th to the n-1'th sample DIM ramp!(0 TO n% - 1) FOR i% = 0 TO n% - 1 ramp!(i%) = (sampn! - samp0!) * i% / n% NEXT i% 'Subtract the ramp from the measured samples FOR i% = 0 TO n% - 1 vt!(i%) = vt!(i%) - ramp!(i%) NEXT i% 'Get the minimum and maximum value from the corrected data to log the relative size of the correction vtmin! = 100! vtmax! = -100! FOR i% = 0 TO n% - 1 IF vt!(i%) < vtmin! THEN vtmin! = vt!(i%) IF vt!(i%) > vtmax! THEN vtmax! = vt!(i%) NEXT i% 'Log the correction CALL vtlogoffset(logfileP$, n%, samp0!, sampn!, vtmin!, vtmax!) END SUB SUB vtoffsetcorr2 (n%, vt!(), vtn!) '**************************************************************************** 'This subroutine corrects for a voltage offset in an integrator. This 'produces a linear ramp in the integrator output. The linear ramp 'is subtracted from the vt samples. This subroutine assumes a signal 'of the form ' vt(i) = a + b*i + c*cos(2*pi*n*i/ns + phin), n = 1 to ..., 0 <= i <= ns 'It takes the derivative of the samples and then averages to get b. 'It uses b to calculate the linear ramp. ' 'Input/Output ' n%, the number of samples ' vt!(0 to n%-1), the integrated voltage samples ' vtn!, the n'th sample ' 'Zachary Wolf '1/8/96 '**************************************************************************** 'First take the derivative of the samples DIM deriv!(0 TO n% - 1) FOR i% = 0 TO n% - 2 deriv!(i%) = vt!(i% + 1) - vt!(i%) NEXT i% deriv!(n% - 1) = vtn! - vt!(n% - 1) 'The average of the derivative is the slope of the linear offset 'The sinusoidal terms average to zero b! = 0! FOR i% = 0 TO n% - 1 b! = b! + deriv!(i%) NEXT i% b! = b! / n% 'Compute a linear ramp from the 0'th to the n-1'th sample DIM ramp!(0 TO n% - 1) FOR i% = 0 TO n% - 1 ramp!(i%) = b! * i% NEXT i% 'Subtract the ramp from the measured samples FOR i% = 0 TO n% - 1 vt!(i%) = vt!(i%) - ramp!(i%) NEXT i% 'Get the minimum and maximum value from the corrected data to log the relative size of the correction vtmin! = 100! vtmax! = -100! FOR i% = 0 TO n% - 1 IF vt!(i%) < vtmin! THEN vtmin! = vt!(i%) IF vt!(i%) > vtmax! THEN vtmax! = vt!(i%) NEXT i% 'Log the correction CALL vtlogoffset2(logfileP$, n%, b!, vt!(0), vtn!, vtmin!, vtmax!) END SUB SUB vtsetpar (logfile$, vtchan$, vtgain%, vtnpulseperrev%, vtnsampperrev%, vtnrevpermeas%, vtacc!, vtvel!, vtdis!) '**************************************************************************** 'This subroutine sets all required VT parameters for a Helmholtz coil 'measurement. ' 'Input: ' logfile$, path and name of the log file ' vtchan$, PDI5025 channel A or B ' vtgain%, PDI5025 gain ' vtnpulseperrev%, # encoder pulses per revolution ' vtnsampperrev%, # vt samples per revolution ' vtnrevpermeas%, # revolutions per measurement ' vtacc!, CM2100 acceleration (rev/sec/sec) ' vtvel!, CM2100 velocity (rev/sec) ' vtdis!, CM2100 distance to move (rev) 'Zachary Wolf '11/5/95 '**************************************************************************** 'Put all parameters in a common area for later use logfileP$ = logfile$ vtchanP$ = vtchan$ vtgainP% = vtgain% vtnpulseperrevP% = vtnpulseperrev% vtnsampperrevP% = vtnsampperrev% vtnrevpermeasP% = vtnrevpermeas% vtaccP! = vtacc! vtvelP! = vtvel! vtdisP! = vtdis! 'Print the values 'PRINT 'PRINT "VTCOIL parameters" 'PRINT "logfileP$ = "; logfileP$ 'PRINT "vtchanP$ = "; vtchanP$ 'PRINT "vtgainP% = "; vtgainP% 'PRINT "vtnpulseperrevP% = "; vtnpulseperrevP% 'PRINT "vtnsampperrevP% = "; vtnsampperrevP% 'PRINT "vtnrevpermeasP% = "; vtnrevpermeasP% 'PRINT "vtaccP! = "; vtaccP! 'PRINT "vtvelP! = "; vtvelP! 'PRINT "vtdisP! = "; vtdisP! 'INPUT "Press ENTER to continue.", a$ END SUB