'--------------------------------------------------------------------------- 'NAME: ' FluxQB version 1.0 ' 'PURPOSE: ' Operate the Relaxed Eddy Accumulation (REA) system by collecting data ' from a sonic anemometer/thermometer at 10 hz, controlling the on/off ' status of 2 valves, and writing data to a disk. ' 'CALLING SEQUENCE: ' rea3c ' 'INPUTS: ' Sonic data stream (verbose mode with A/D channels a-h enabled) using ' an RS-232C (serial) cable connected with the computer's COM1 port. ' Data from digital isoprene analyzer. ' A menu on the computer screen allows the manual changing of ' default operating parameters. ' 'OUTPUTS: ' three file types are produced: *.f15, errors.txt (where ' * is date and time). *.txt ' ' *.f15 contains 30 minutes of sonic output in binary integer format: ' ' U, V, W, T, A, B, C, D, E, F, G, H, Wmean, thresh, time ' ' U-H are constant sonic channels; Wmean is a 30 minute moving average ' of vertical wind velocity; thresh is the REA threshold; time is seconds ' after 1200 h ' ' Errors.txt is an ascii text file that contains information on any ' errors that may have occurred during the program execution. ' It contains the cycle number, the error code (see MS QB45 manual), ' date, and time. This file is created during every program execution ' and is empty if no errors occur. Errors are appended to this file ' so that it will be a permanent record of recurring errors. ' 'SUBROUTINES: ' ' 'NOTES: ' Sonic channels u,v,w,t are converted from floating point to integer ' by this program so that the output file will be composed of ' only integer values. This simplifies future reading of the files ' by spreadsheet programs. ' ' 'MODIFICATION HISTORY: ' B. Baugh January 22, 1996 - Adapted from REA 1.0g and SON_RD 6.2 ' A. Guenther May 1, 1996 - Adapted program to work with cartridge REA ' B. Baugh May 14, 1996 - Added a Timer display to printed screen ' A. Guenther May 28, 1996 - set 9999 error to vent, use 8 A/D channels ' A. Guenther May 1996 - change output file extension, ventfactor is output ' A. Guenther September 1996: allow rea or not, cartridge or bags, include digital isoprene '--------------------------------------------------------------------------- '=========================================================================== 'Declarations: settings, variables '=========================================================================== '--------- Declare the NI-DAQ functions in the NI-DAQ library ------------ REM $INCLUDE: 'c:\nidaqdos\basic_ex\nidaq.inc' '--------- Allocate memory for NI-DAQ library use ------------------------ heap.size = SETMEM(-4096) '--------- Variable to hold numeric sonic data --------------------------- TYPE numdata uval AS INTEGER vval AS INTEGER wval AS INTEGER tval AS INTEGER aval AS INTEGER bval AS INTEGER cval AS INTEGER dval AS INTEGER eval AS INTEGER fval AS INTEGER gval AS INTEGER hval AS INTEGER ival AS INTEGER Wmean AS INTEGER thresh AS INTEGER secs AS INTEGER END TYPE '--------- Variables ----------------------------------------------------- DIM BagPair AS INTEGER 'Toggles between bag pairs A(0) and B(1) DIM BuffMax AS INTEGER 'Maximum buffer filling DIM character AS STRING * 1 'Holds individual character from sonic DIM CircularBuffer1(18000) AS INTEGER 'Circular buffer for stats, integer status reduces size, divide by 100 DIM count11 AS INTEGER 'Counter from 1-11, for print to screen timing DIM Cycle AS LONG 'Sonic cycle (10/sec., 864,000/24 hours) DIM Delay AS INTEGER '15 cycle delay to help file open/close timing DIM Errors AS INTEGER 'Total number of errors DIM HalfHour AS INTEGER 'Holds seconds after the hour for half hour after start time DIM increment AS INTEGER 'Increments the Circular Buffer DIM OM(3) AS INTEGER 'Operational Mode, stores the mode for screen display of "system status" DIM OpenDate AS STRING 'Month:day:hour:minute.version used for the binary output filename DIM path AS STRING 'Output file path, let user alter default DIM Port AS INTEGER 'Switch positions (1-8) sent to NIDAQ DIM raw AS STRING 'Holds string of raw data from sonic DIM raw2 AS STRING 'Holds string of raw data from sonic DIM sonvar AS STRING 'Holds string of raw data from sonic DIM sonic AS numdata 'Holds numeric data from sonic DIM Timebase AS INTEGER 'Holds seconds after the hour of start time DIM TimeSum AS LONG 'Keeps sum of seconds since start of run DIM TimeSumTemp AS INTEGER 'Holds seconds from previous cycle to compare w/current seconds to keep a 1 sec. timer DIM TimeToStart AS STRING 'Time to start initialization DIM ValvePrint(4) AS STRING * 3 'String variable used to print valve on/off status DIM Valvestatus(4) AS INTEGER 'Number (0-255) representing valve positions DIM Ventfactor AS SINGLE 'Factor used to determine cutoffs for sampling of up/down eddies or venting DIM W AS SINGLE 'Floating point version of W value for use in computing stats DIM Wmean AS SINGLE 'Floating point holder for 10 minute mean of vertical wind velocity DIM Wsig AS SINGLE 'Floating point holder for standard deviation of vertical wind velocity DIM Wsqrsum AS SINGLE 'Sum of W squares, used to find standard deviation '--------- Initialize constants ------------------------------------------ CLS 'Clear the screen BagPair = 0 'Set Bag Pair 'A' to current increment = 1 'Increments circular buffer Delay = 100 'Delay to moderate file open/close path = "c:\data" 'Output path TimeToStart = "IMMEDIATELY" 'Time to start initialization 'Set all valve positions to off: Valvestatus(1) = 1: Valvestatus(2) = 1: Valvestatus(3) = 1: Valvestatus(4) = 1 Ventfactor = .6 'Factor used to determine up/down sampling or venting Wsig = .2 'Initial standard deviation value sonic.thresh = CINT(Ventfactor * Wsig * 100) 'Integer representation of Wsig textouttime = 50: textout = 0: digisoprene = 0: bags = 1: enableREA = 0 '=========================================================================== 'Print Setup Screen '=========================================================================== CLS PRINT TAB(30); "REA Hardware Setup" PRINT TAB(30); "******************" PRINT PRINT "1) Connect sonic 'digital' port to computer COM1 port with an RS-232 cable." PRINT PRINT "2) Connect sonic probe cable to sonic box." PRINT PRINT "3) Turn sonic on (verbose mode with A/D channels a-h enabled)." PRINT PRINT "4) Connect the REA output channels to the sonic A/D ports:" PRINT "a= co2 #1, b=h2o#1, c=co2 #2, d= h2o #2," PRINT "e=slow O3, f=fast O3, g=ozonizer, h=analog isoprene"; "" PRINT PRINT "5) Press 'Enter' to continue." DO: LOOP WHILE INKEY$ = "" '=========================================================================== 'Get User Input '=========================================================================== DO 'Start user input DO loop CLS LOCATE 2, 1: PRINT "Current system values are shown." PRINT "Choose the number of any value you wish to change," PRINT "or choose zero to accept these values and continue." PRINT STRING$(52, "*") LOCATE 8, 1 PRINT " 0) Accept these values and continue" PRINT " 1) Path = "; path PRINT " 2) Time to begin this job = "; TimeToStart PRINT " 3) Factor used in determining vent/sample thresholds ="; Ventfactor PRINT " 4) enable digital isoprene (1=yes)"; digisoprene PRINT " 5) bags (1) or cartridges (0)"; bags PRINT " 6) enableREA (1)"; enableREA PRINT " 7) enable text output and number of seconds between output"; textout; textouttime PRINT " 8) Exit program" INPUT "", choice% SELECT CASE choice% CASE 0 Temp1$ = "done" CASE 1 ON ERROR GOTO FileErr CLS LOCATE 8, 1 PRINT "Enter the complete path for the output file (ie. c:\data)." PRINT "If the directory does not exist you will be given the option" PRINT "to create it. An invalid drive letter will cause an error." INPUT "", path OPEN path + "\errors.txt" FOR APPEND AS #3 CLOSE #3 CASE 3 CLS LOCATE 8, 1 PRINT "The standard deviation of the mean vertical wind velocity is multiplied by this" PRINT "factor to determine the thresholds for sampling up/down eddies or venting." PRINT INPUT "Enter a new factor: ", Ventfactor CASE 2 CLS LOCATE 8, 1 PRINT "The current time is "; TIME$ PRINT PRINT "Enter the time to start initialization based on a 24 hour clock." PRINT "Use the format shown above (hh:mm:ss). Include colons (:), and" PRINT "zeros for values less than 10 (ie. 6 = 06)." INPUT "", TimeToStart DO UNTIL MID$(TimeToStart, 3, 1) = ":" AND MID$(TimeToStart, 6, 1) = ":" INPUT "Format not correct (hh:mm:ss), try again", TimeToStart LOOP CASE 4 PRINT INPUT "Enter 0 if digital isoprene not on com2 ", digisoprene CASE 5 PRINT INPUT "Enter 1 for bags, 0 for cartridges ", bags CASE 6 PRINT INPUT "Enter 1 to enable REA, 0 otherwise ", enableREA CASE 7 PRINT INPUT "Enter 1 to enable text output, 0 otherwise ", textout INPUT "Enter number of seconds betwen text output ", textouttime CASE 8 END 'End program CASE ELSE CLS LOCATE 10, 1 PRINT "Invalid entry, try again. Press any key to continue." DO LOOP WHILE INKEY$ = "" END SELECT LOOP WHILE Temp1$ <> "done" 'Complete DO loop to continue IF enableREA THEN status1% = DIG.Out.Port(1, 0, 254) 'Initialize valves 2-8 to off, S1 on to vent status2% = ICTR.Reset(1, 1, 1) 'Initialize valve #9 to off status3% = ICTR.Reset(1, 2, 1) 'Initialize valve #10 to off END IF '--------- Wait until specified start time ------------------------------- IF TimeToStart <> "IMMEDIATELY" THEN DO temp3! = TIMER DO: LOOP WHILE TIMER < temp3! + .4 'Slow down the loop so that the screen refreshes only once every .5 seconds CLS LOCATE 10, 5: PRINT "Start time = "; TimeToStart LOCATE 11, 5: PRINT "Current time = "; TIME$ LOCATE 14, 5: PRINT "Enter '!' to start now." LOOP UNTIL TimeToStart = TIME$ OR INKEY$ = CHR$(33) END IF '=========================================================================== 'Open com port and files for output, prepare to receive data, initialize '=========================================================================== ON ERROR GOTO ErrorHandler 'Enable error handler (see gosub at end of program) OpenDate = MID$(DATE$, 1, 2) + MID$(DATE$, 4, 2) + MID$(TIME$, 1, 2) + MID$(TIME$, 4, 2) OPEN path + "\" + OpenDate + ".f15" FOR BINARY AS #2 IF textout THEN OPEN path + "\" + OpenDate + ".txt" FOR OUTPUT AS #5 OPEN "com1:9600,e,7,1,cs0,ds0,cd0,rb2048" FOR INPUT AS #1 '--------- Check for sonic data ------------------------------------------ temp3! = TIMER DO WHILE LOC(1) = 0 IF TIMER > temp3! + 5 THEN CLS LOCATE 8, 24: PRINT "** ERROR - No Data from Sonic **" LOCATE 9, 14: PRINT " Check sonic and data cables and restart program" END END IF LOOP '--------- Check for digital isoprene data ------------------------------------------ IF digisoprene THEN OPEN "com2:9600,n,8,1,cs,ds" FOR RANDOM AS #4 integrate = 9 '90 ms byte = 2 'expect 2 byte ackowledgement PRINT #4, "P" + CHR$(integrate) temp3! = TIMER DO WHILE LOC(4) = 0 IF TIMER > temp3! + 5 THEN CLS LOCATE 8, 24: PRINT "** ERROR - No Data from digital isoprene analyzer" LOCATE 9, 14: PRINT " Check sonic and data cables and restart program" END END IF LOOP GOSUB acquire PRINT #4, "D" 'set operating high voltage to default value GOSUB acquire PRINT #4, "C" + "CR" 'set continuous data mode GOSUB acquire byte = 4 firstloop = 1 END IF '--------- Set start time baseline --------------------------------------- Timebase = (TIMER MOD 3600) 'Get seconds after the hour IF Timebase < 1800 THEN HalfHour = Timebase + 1800 'Get seconds after the hour for next half hour BagPair = 0 'Set Bag Pair 'A' to current ELSEIF Timebase >= 1800 THEN HalfHour = Timebase - 1800 BagPair = 1 'Set Bag Pair 'B' to current END IF '--------------------------------------------------------------------------- 'Find the end of a line of sonic data by looking for the linefeed character '--------------------------------------------------------------------------- Restart: 'Error handler returns control at this point DO character = INPUT$(1, #1) LOOP WHILE character <> "a" DO character = INPUT$(1, #1) LOOP WHILE character <> CHR$(10) '=========================================================================== 'Begin sonic-controlled sampling loop: 'Read a line of sonic string data into 'raw' and then convert the numeric 'values to integers, get stats, switch valves, store data, print to screen. '=========================================================================== temp3! = TIMER DO WHILE INKEY$ <> CHR$(33) '-------- Slow program cycle to at least 1 per 0.05 seconds -------------- DO: LOOP WHILE (TIMER - temp3!) >= 0 AND TIMER < temp3! + .05 temp3! = TIMER IF LOC(1) > BuffMax THEN BuffMax = LOC(1) 'Monitor maximum buffer filling LINE INPUT #1, raw Cycle = Cycle + 1 'Increment counters: cycle & count11 count11 = count11 + 1 sonic.uval = CINT(100 * VAL(MID$(raw, 3, 6))): sonic.vval = CINT(100 * VAL(MID$(raw, 12, 6))) sonic.wval = CINT(100 * VAL(MID$(raw, 21, 6))): sonic.tval = CINT(100 * VAL(MID$(raw, 30, 6))) sonic.aval = VAL(MID$(raw, 39, 5)): sonic.bval = VAL(MID$(raw, 47, 5)) sonic.cval = VAL(MID$(raw, 55, 5)): sonic.dval = VAL(MID$(raw, 63, 5)) sonic.eval = VAL(MID$(raw, 71, 5)): sonic.fval = VAL(MID$(raw, 79, 5)) sonic.gval = VAL(MID$(raw, 87, 5)): sonic.hval = VAL(MID$(raw, 95, 5)) '--------------------------------------------------------------------------- 'Compute statistics for wind and temperature. Skip wind if the sonic 'output is out of bounds. '--------------------------------------------------------------------------- IF sonic.wval < 9000 AND sonic.wval > -9000 THEN W = sonic.wval / 100 Wsum = Wsum + W - (CircularBuffer1(increment) / 100) CircularBuffer1(increment) = sonic.wval Wsqrsum = Wsqrsum + (W * W) Wmean = Wsum / 18000 sonic.Wmean = CINT(Wmean * 100) IF increment < 18000 THEN increment = increment + 1 ELSE increment = 1 END IF END IF '--------------------------------------------------------------------------- 'Evaluate vertical wind velocity & determine valve positions 'to sample into bags or cartridges. '--------------------------------------------------------------------------- IF bags THEN IF W > (Wmean + Ventfactor * Wsig) THEN 'No valves on OM2: None - Bag 1 OM(2) = 1 ELSEIF W < (Wmean - Ventfactor * Wsig) THEN Valvestatus(2) = 0 'OM3: S2 - Bag 2 OM(3) = 1 ELSE Valvestatus(1) = 0 'OM1: S1 - Vent OM(1) = 1 END IF ELSE '-----cartridges---------------------------------------------------------------- IF W > (Wmean + Ventfactor * Wsig) AND W < 90 THEN 'No valves on up OM(2) = 1 ELSEIF W < (Wmean - Ventfactor * Wsig) AND W > -90 THEN Valvestatus(2) = 0 'down Valvestatus(1) = 0 ' OM(3) = 1 ELSE Valvestatus(1) = 0 'OM1: S1 - Vent OM(1) = 1 END IF END IF SELECT CASE BagPair CASE 0 Valvestatus(3) = 1 'Toggle to bag pair A Valvestatus(4) = 1 CASE 1 Valvestatus(3) = 0 'Toggle to bag pair B Valvestatus(4) = 0 CASE ELSE PRINT "Bag Pair Variable Error" END END SELECT '--------- Control REA segregator valves --------------------------------- IF enableREA THEN '--------- Combine binary switch positions into single number ------------ Port = 2 * Valvestatus(2) + Valvestatus(1) + 252 'Add 252 to set valves 3-8 off for safety '--------- Call NIDAQ functions to control Digital Output ports ---------- status1% = DIG.Out.Port(1, 0, Port) status2% = ICTR.Reset(1, 1, Valvestatus(3)) status3% = ICTR.Reset(1, 2, Valvestatus(4)) END IF '--------- Get digital isoprene data -------------------------------------- IF digisoprene THEN IF firstloop THEN CLS PRINT #4, "S" firstloop = 0 ELSE GOSUB acquire: GOSUB convert ' get result and convert to binary PRINT #4, "S" END IF END IF '--------- Output to files ----------------------------------------------- sonic.secs = TIMER MOD 43200 'store time PUT #2, , sonic ' ------- store to file ---------------------------------- IF textout AND ((TIMER MOD textouttime) = 0) THEN PRINT #5, USING "######"; TIMER; PRINT #5, USING " ##.##"; sonic.uval / 100; sonic.vval / 100; sonic.wval / 100; sonic.tval / 100; PRINT #5, USING " ####"; sonic.aval; sonic.bval; sonic.cval; sonic.dval; sonic.eval; sonic.fval; sonic.gval; sonic.hval END IF '--------- Print formatted output to screen once every 11 cycles --------- IF count11 = 11 THEN CLS LOCATE 2, 24: PRINT "** RUNNING - Enter '!' to stop **" LOCATE 4, 1: PRINT " U V W T A B C D E F G H" PRINT USING " ##.##"; sonic.uval / 100; sonic.vval / 100; sonic.wval / 100; sonic.tval / 100; PRINT USING " ####"; sonic.aval; sonic.bval; sonic.cval; sonic.dval; sonic.eval; sonic.fval; sonic.gval; sonic.hval IF digisoprene THEN PRINT "---------- Isoprene counts ="; sonic.ival LOCATE 7, 1: PRINT "Timer ="; TAB(20); "Clock = "; TIME$; TAB(40); "Buffer="; LOC(1); TAB(60); "Cycle ="; Cycle LOCATE 7, 8: PRINT LTRIM$(STR$(TimeSum \ 3600)); ":"; LTRIM$(STR$((TimeSum MOD 3600) \ 60)); ":"; LTRIM$(STR$(TimeSum MOD 60)) LOCATE 8, 1: PRINT "Wmean ="; TAB(20); "threshold ="; TAB(40); "Buff Max ="; BuffMax LOCATE 8, 8: PRINT USING "###.##"; Wmean; LOCATE 8, 27: PRINT USING "###.##"; sonic.thresh * .01 LOCATE 16, 43 IF OM(1) THEN PRINT TAB(43); "Vent" IF bags THEN IF BagPair THEN PRINT TAB(43); "Current Bag Pair = B" ELSE PRINT TAB(43); "Current Bag Pair = A" IF OM(2) THEN PRINT TAB(43); "Sample up eddies into bag 1" IF OM(3) THEN PRINT TAB(43); "Sample down eddies into bag 2" ELSE IF OM(2) THEN PRINT TAB(43); "Sample up eddies into cartridge 1" IF OM(3) THEN PRINT TAB(43); "Sample down eddies into cartridge 2" END IF '--------- Swap valve states prior to printing & print valve positions --- FOR i = 1 TO 4 IF Valvestatus(i) = 1 THEN ValvePrint(i) = "Off" ELSE ValvePrint(i) = " On" NEXT i LOCATE 15, 1: PRINT "Valve Status:"; TAB(40); "System Status:" PRINT " S1 = "; ValvePrint(1) PRINT " S2 = "; ValvePrint(2) PRINT " S9 = "; ValvePrint(3) PRINT "S10 = "; ValvePrint(4) LOCATE 21, 1 IF Errors THEN PRINT "Number of errors ="; Errors IF status1% THEN PRINT "NIDAQ Error Code = "; status1% IF status2% THEN PRINT "NIDAQ Error Code = "; status2% IF status3% THEN PRINT "NIDAQ Error Code = "; status3% END IF '--------------------------------------------------------------------------- 'Reset all variables as necessary '--------------------------------------------------------------------------- Temp1% = (TIMER MOD 3600) IF Delay = 0 AND Timebase = Temp1% OR HalfHour = Temp1% THEN 'Do half hour tasks: ' ------- Close Data File & reset variables ----------------------------- OpenDate = MID$(DATE$, 1, 2) + MID$(DATE$, 4, 2) + MID$(TIME$, 1, 2) + MID$(TIME$, 4, 2) ' ------- Reset variables and counters ---------------------------------- Delay = 100 Wsig = SQR(ABS(Wsqrsum) / Cycle) 'Compute standard deviation sonic.thresh = CINT(Ventfactor * Wsig * 100) Cycle = 0 Wsqrsum = 0 IF Temp1% < 1800 THEN BagPair = 0 ELSE BagPair = 1 'Toggle bag pair ' ------- Close file & open a new one ----------------------------- CLOSE #2 OPEN path + "\" + OpenDate + ".f15" FOR BINARY AS #2 END IF '--------- Increment TimeSum once per second for display as a Timer ------ IF Temp1% > TimeSumTemp THEN TimeSum = TimeSum + 1 TimeSumTemp = Temp1% FOR i = 1 TO 4 Valvestatus(i) = 1 NEXT i FOR i = 1 TO 3 OM(i) = 0 NEXT i IF count11 >= 11 THEN count11 = 0 IF Delay > 0 THEN Delay = Delay - 1 Port = 0 LOOP '========= End of sonic-controlled loop ================================== '--------- Set REA to vent mode before quitting -------------------------- IF enableREA THEN status1% = DIG.Out.Port(1, 0, 254) 'Set valves 2-8 to off, leave S1 on to vent status2% = ICTR.Reset(1, 1, 1) 'Set valve #9 to off status3% = ICTR.Reset(1, 2, 1) 'Set valve #10 to off END IF CLOSE #1, #2 IF digisoprene THEN CLOSE #4 IF textout THEN CLOSE #5 PRINT "DONE!" END '--------- End program IF (B3 < 128) THEN 'Calculate the count sonic.ival = (B3 * 256 ^ 3 + B2 * 256 ^ 2 + B1 * 256 + B0) ELSE COLOR 4: PRINT " OVERFLOW !!!": BEEP: COLOR 7 'Overflow Detected CNT = &HFFFF 'Display -1 in data file END IF RETURN