-
Notifications
You must be signed in to change notification settings - Fork 0
/
Flow-based_Sampling-eTape_and_0-5V_Output_Module.CR8
280 lines (234 loc) · 10.6 KB
/
Flow-based_Sampling-eTape_and_0-5V_Output_Module.CR8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
' Event-based ISCO Sampling Triggered via a Standard eTape Assembly with 0-5V
' Output Module
' Author: Joe Shannon
' Last Modified: 2018-09-20
'
' Summary:
' --------
' This program is designed for a CR800 datalogger to connected to a standard
' assembly eTape from Milone Technologies with the 0-5V Output Module. The
' purpose of the program is to trigger sampling on an ISCO autosampler whenever
' a storm event is detected and every 24 hours if a storm event is not
' detected. It calculates a rolling mean hourly water level change (2-hr, 6-hr,
' and 24-hr), and a rolling standard deviation of the change in 24-hr mean
' water level. An event is triggered when the change in 24-hr mean water level
' is greater than the mean change plus a 99.5% confidence interval (2.58 * SD).
' The 6-hr rolling mean water level must be greater than minimum_event_size (cm)
' for an event to be triggered. The hydrograph limb is set to "rising" and hourly
' sampling begins. When the 2-hr rolling mean water level change is less than 0 the
' rising limib is set to "falling". Hourly sampling continues until the water
' level returns to a user-defined percentage of the water level at the start of
' the event (see non-event_interval constant and set as decimal value, i.e.
' 1.0 = 100%).
' The program can be recompiled without losing existing data by using the command
' REBOOT in the terminal emulator when communicating with the datalogger. When
' the program is recompiled on the datalogger most existing variable values
' a retained, only the bottle number is reset to zero.
' Notes:
' ------
' No sample will be taken during the first 24 hours after initial deployment. This
' is because the mean and standard deviation calculations include zeroes. This is not
' the case when REBOOT is used, the existing values are retained then and sampling
' can be triggered immediately.
' This calibration is for the eTape currently deployed at 113. It is fitted with
' a 0-5 V output converter rather than a voltage divider. The latter probably the
' better option as the voltage divider is more robust than the output converter.
' Speaking with Chris Milone he said there is no chip in the voltage divider,
' which means a wiring error will not destroy the eTape. However, measurement
' resolution is lost when using a voltage divider due to the reduced range of
' the output, 2.5V - 5V rather than 0-5V
' The linear regression used to convert eTape measurements (mV) to water level (cm)
' was taken from ...
' Water Level (cm) = 0.009891 * eTape (mv) + 0.498129
' Set-up:
' -------
' The program is controlled via a table of constants that can be set manually
' in this code before sending to the datalogger or can be accessed and adjusted
' using the Terminal Emulator (function 'C') in Campbell Scientific's Loggernet
' or PC200W software.
' falling_limb_threshold - The water level used to signal the end of an event,
' defined as a proportion of the water level at the start of an event.
' non-event_interval - The number of hours between samples during non-event flow
' eTape_intercept - The slope of the eTape calibration curve
' eTape_slope - The intercept of the eTape calibration curve
' pre-event_period - The number of hours of data to capture before checking for
' events. This helps prevent false positives.
' minimum_event_size - The minimum change in the 6-hour rolling mean that would
' be considered an event. This is to avoid vey small changes from triggering an
' event after a long period of no flow
' Wiring:
' -------
' eTape | CR800
' ---------------
' Vin | 12V
' Vout | 1H
' Gnd | Ground
' ISCO | CR800
' ---------------
' Pin A | SDI 12V
' Pin C | SDI C1
' -----------------------------------------------------------------------------
' Set mode
SequentialMode
ConstTable (Setup_Parameters)
Const falling_limb_threshold = 1.05
Const nonevent_interval = 24
Const eTape_intercept = 0.498129
Const eTape_slope = 0.009891
Const interval_sampling = true
Const preevent_period = 12
Const minimum_event_size = 0.1
EndConstTable
' Declare Variables and Units
Public battery_voltage As FLOAT
Public bottle_number As LONG
Public counter As LONG
Public delta_daily_WL As FLOAT ' meanDailyDeltaWL = meanDailyWL_cm - lag(meanDailyWL_cm, 1)
Public delta_daily_WL_array(24) As FLOAT
Public delta_hourly_WL As FLOAT ' deltaWL_1hr = hourlyWL_cm - lag(hourlyWL_cm, 1)
Public eTape As FLOAT
Public hourly_index As LONG
Public hours_after_sample As LONG
Public hydrograph_limb As STRING
Public logger_temp As FLOAT
Public lagged_mean_WL_24hr As FLOAT ' lag(meanDailyWL_cm, 1)
Public lagged_water_level As FLOAT ' lag(hourlyWL_cm, 1)
Public mean_delta_daily_WL_24hr As FLOAT
Public mean_delta_WL_2hr As FLOAT
Public mean_delta_WL_6hr As FLOAT ' mean_delta_WL_6hr = roll_meanr(deltaWL_1hr, 6)
Public mean_WL_24hr As FLOAT ' meanDailyWL_cm = roll_meanr(hourlyWL_cm, 24)
Public preevent_water_level As FLOAT
Public sampling_event As BOOLEAN
Public sample_threshold As FLOAT
Public sd_delta_daily_WL_24hr As FLOAT
Public water_level As FLOAT ' hourlyWL_cm
Units battery_voltage = Volts
Units logger_temp = Celsius
Units eTape = mV
'Units water_level = cm
Units lagged_water_level = cm
Units delta_hourly_WL = cm
Units mean_delta_WL_2hr = cm
Units mean_delta_WL_6hr = cm
Units mean_WL_24hr = cm
Units lagged_mean_WL_24hr = cm
Units delta_daily_WL = cm
Units preevent_water_level = cm
Units hours_after_sample = hours
'Define Data Tables.
DataTable (Diagnostics, 1, -1)
Sample (1, battery_voltage, FLOAT)
Sample (1, logger_temp, FLOAT)
EndTable
DataTable (Water_Level, 1, -1) 'Set table size to # of records, or -1 to autoallocate.
Sample(1, bottle_number, LONG)
Sample(1, eTape, FLOAT)
Sample(1, water_level, FLOAT)
Sample(1, lagged_water_level, FLOAT)
Sample(1, delta_hourly_WL, FLOAT)
Sample(1, mean_delta_WL_2hr, FLOAT)
Sample(1, mean_delta_WL_6hr, FLOAT)
Sample(1, mean_WL_24hr, FLOAT)
Sample(1, mean_delta_daily_WL_24hr, FLOAT)
Sample(1, sd_delta_daily_WL_24hr, FLOAT)
Sample(1, lagged_mean_WL_24hr, FLOAT)
Sample(1, delta_daily_WL, FLOAT)
Sample(1, sampling_event, FLOAT)
Sample(1, hydrograph_limb, STRING)
Sample(1, preevent_water_level, FLOAT)
Sample(1, hours_after_sample, LONG)
EndTable
DataTable (ISCO, 1, -1)
Sample(1, bottle_number, LONG)
Sample(1, water_level, FLOAT)
Sample(1, hydrograph_limb, STRING)
EndTable
' Main Program
BeginProg
' Preserve the variables so that when the program is recompiled to reset the bottle_number the running
' means and standard deviation will be retained.
PreserveVariables()
' Reset the bottle number and counter number
bottle_number = 0
Scan(60, min, 1, 0)
hours_after_sample = hours_after_sample + 1
hourly_index = (counter MOD 24) + 1
counter = counter + 1
' Default Datalogger Battery Voltage measurement BattV
Battery(battery_voltage)
PanelTemp(logger_temp, _60Hz)
' Measure eTape and calculate water level from eTape calibration. Use running average to calculate the mean daily water level
VoltSE(eTape, 1, mV5000, 1, True, 0, _60Hz, 1, 0)
'Temperature probe used for in-lab testing:
'Therm107(water_level,1,1,1,0,_60Hz,1,0)
water_level = (eTape_slope * eTape) + eTape_intercept
AvgRun(mean_WL_24hr, 1, water_level, 24)
' Calculate change in hourly and daily water levels and a 6 hour running mean hourly change in water level
delta_hourly_WL = water_level - lagged_water_level
delta_daily_WL = mean_WL_24hr - lagged_mean_WL_24hr
AvgRun(mean_delta_WL_2hr, 1, delta_hourly_WL, 2)
AvgRun(mean_delta_WL_6hr, 1, delta_hourly_WL, 6)
' During non-event flow calculate the mean and standard deviation of the
' daily water level over a 24 hour period. Then compare the current change in
' daily water level to the sampling threshold.
If sampling_event = false Then
delta_daily_WL_array(hourly_index) = delta_daily_WL
AvgSpa(mean_delta_daily_WL_24hr, 24, delta_daily_WL_array)
StdDevSpa(sd_delta_daily_WL_24hr, 24, delta_daily_WL_array)
sample_threshold = mean_delta_daily_WL_24hr + 2.575829 * sd_delta_daily_WL_24hr
If counter > 24 Then
sampling_event = delta_daily_WL >= sample_threshold AND mean_delta_WL_6hr > minimum_event_size
End If
hydrograph_limb = "NA"
End If
If sampling_event = true Then
' If this is the start of an event then store the starting water level and
' remove the last delta_daily_WL as that was the one large enough to trigger
' an event
If preevent_water_level = 0 Then
preevent_water_level = lagged_water_level
delta_daily_WL_array(hourly_index) = delta_daily_WL_array(hourly_index - 1)
hydrograph_limb = "rising"
' Else check if the two-hour change in water level is negative, if it is change
' the hydrograph limb to falling
Else
If mean_delta_WL_2hr < 0 Then
hydrograph_limb = "falling"
End If
End If
' For each hour write in the previous change in daily water level (starting with the
' pre-event value) plus some noise within the standard deviation of daily water level
' changes. Continue to calculate the average and standard deviations. Within an event
' the standard deviation can become so large from the event flows that triggering
' another event less than 24 hours after the original event is essentialy impossible.
delta_daily_WL_array(hourly_index) = delta_daily_WL_array + (RND > 0.5) * RND * sd_delta_daily_WL_24hr
AvgSpa(mean_delta_daily_WL_24hr, 24, delta_daily_WL_array)
StdDevSpa(sd_delta_daily_WL_24hr, 24, delta_daily_WL_array)
sample_threshold = mean_delta_daily_WL_24hr + 2.575829 * sd_delta_daily_WL_24hr
' Check the bottle number and then sample, updating the bottle number record and resetting the time since last sample
If bottle_number < 24 Then
PulsePort(1, 25000)
hours_after_sample = 0
bottle_number = bottle_number + 1
CallTable(ISCO)
EndIf
' At the end of an event reset the starting water level and the hydrograph limb
If hydrograph_limb = "falling" AND water_level <= preevent_water_level * falling_limb_threshold Then
sampling_event = false
preevent_water_level = 0
hydrograph_limb = "NA"
EndIf
EndIf
' If interval sampling is occurring then check the bottle number and then sample, updating the bottle number record and resetting the time since last sample
If interval_sampling AND hours_after_sample = nonevent_interval AND bottle_number < 24 Then
PulsePort(1, 25000)
hours_after_sample = 0
bottle_number = bottle_number + 1
CallTable(ISCO)
EndIf
lagged_water_level = water_level
lagged_mean_WL_24hr = mean_WL_24hr
CallTable(Diagnostics)
CallTable(Water_Level)
NextScan
EndProg