Welcome to EnviroDIY, a community for do-it-yourself environmental science and monitoring. EnviroDIY is part of WikiWatershed, an initiative of Stroud Water Research Center designed to help people advance knowledge and stewardship of fresh water.
New to EnviroDIY? Start here
Tips & Pointers

Evaluating Maxbotix Ultrasonic Sensors for Monitoring Stream Base Flow

Evaluation by the Save our Water, Watershed Hydrologic Analysis Team, Marion Waggoner and Dave Yake.

Background

Broad Run drains a 10 km2 watershed straddling southeastern Pennsylvania and northwest Delaware. Commercial groundwater withdrawal from the aquifer underlying the Broad Run watershed has been approved, but questions about the effect of this withdrawal on Broad Run flow and water quality remain. To address these questions, our organization (Save Our Water) started a stream monitoring program on Broad Run in late 2014.

Our primary objective was to establish a baseline of stream discharge throughout the year that could be used to evaluate the effect of commercial pumping when it begins.

We used an acoustic doppler velocimeter (ADV) to measure the velocity of water flow and calculate discharge. We then developed a stream rating curve to relate water stage (depth, an easy-to-continuously-measure parameter) to water discharge (volume per time, a more difficult to measure parameter but more relevant to our objective).

Our rating curve allows us to continuously predict water discharge from water stage. Multiple rating curves were developed at several locations with particular emphasis on the low flow periods because these periods are when the effect of commercial pumping from the aquifer is expected to be most apparent.

Real-time continuous data from New Garden Township’s EnviroDIY monitoring station allows us to convert stream depth measurements to discharge using our rating curve, but this site is upstream from the commercial well. We needed additional stream flow data from further downstream but did not have money for a submerged pressure (depth) sensor.

We decided to evaluate the Maxbotix ultrasonic sensors for possible monitoring of baseflow stream levels.

Equipment List and Setup

We selected the MB7389 sensor for distance resolution and weather resistance. We initially tested just one sensor but added another when unexpected issues surfaced.

The MB7389 sensors were tested by pointing them downward at a stationary dry target. In the stream, sensors were mounted on standpipes and, later, on a boom extending over open water. We limited the standpipe diameter to 4 inches because a larger standpipe would have been too disruptive to flow in a small stream and would catch lots of debris.

Reviewing the Results

The Positives

Delivers stable data: The two sensors delivered very stable distance data on test stands indoors — stationary plates as targets — at a constant ambient temperature. Generally, over many hours and at a distance near 1 meter, the values varied only about +/- 1 to 2 millimeters.

Functionally impeccable: Both sensors continued to function after extensive time outdoors in operation at temperatures from below 0 degrees Celsius to as high as 39 degrees Celsius.

Extremely rugged: One sensor was washed away during a huge flood on August 7, 2020. A couple of days later we found the sensor and the mounting washed up on the bank in a pile of debris. In spite of the prolonged immersion, the sensor was completely functional and still very accurate.

Remarkable performance: After mounting the sensors over open air above the water, one sensor has operated for nine months, taking ten data points (for averaging) at each 5 minute interval, without returning a single “bad” data value. This is remarkable performance compared to the earlier erratic problems with “bad” data when mounted in standpipes.

Low cost: The sensors cost about $125 each.

Very good depth change performance: During a runoff event where the temperature changes are minor, the Maxbotix sensor delivers very good depth change performance as illustrated in the chart below. At peak flow there is about a 21 millimeter average difference between the Maxbotix and Onset Depth sensors out of a 370 millimeter rise in depth (or about 5.7%). The Onset depth sensor was located on the side of a large stake and could have detected some depth depression at higher peak flow compared to the Maxbotix which was located 2 feet downstream where there was less surface turbulence. Therefore, the 5.7% difference at peak flow is likely a real detected difference in stream depth. Overall, when the Maxbotix is used to measure stream surface height changes using a boom configuration performance is excellent. However, using the Maxbotix as an absolute measure of distance is complicated by a strong temperature variance bias.

During a runoff event where the temperature changes are minor, the Maxbotix sensor delivers very good depth change performance.

The Negatives

“Bad” distance data: When mounted in standpipes, the Maxbotix MB7389 sensors sometimes delivered “bad” distance data — generating values of 300 millimeters when the range was much larger than 300. On rare occasions, the distances might be intermediate between 300 and the real value. Note that these MB7389 sensors are not very accurate below 500 millimeters (50 centimeters) but range well out to about 5 meters. The lower cutoff is approximately 300 millimeters.

We noted that the “bad” data seemed to occur at times when the temperature was dropping and believe that the issue was condensation on the walls of the standpipes. Therefore, the situation should have improved when we insulated the exterior of the standpipes with bubble wrap (would not waterlog) which was over-wrapped with foil. Unfortunately, this helped only marginally. The “bad” data might occur for a single interval or might occur for many consecutive intervals for long time periods (up to a few hours).

We tried adding delays between startup and taking data (to allow the sensor to stabilize) and start to average/integrate distances with built-in software. No improvement was seen.

We had to go to a boom mount of the sensor in open air to eliminate bad data.

Whether mounted over a standpipe or boom-mounted in open air in a stable test stand at a fixed distance to the target, the sensors show large changes in reported distances (as much as +/- 1 centimeter or more) with normal ambient temperature cycling. In fact, we observed this in three conditions:

  • Using the sensor’s internal temperature monitor/ correction for temperature.
  • Using the Maxbotix external temperature sensor for temperature compensation.
  • Attempting to correlate the Maxbotix temperature compensated data with either the Mayfly board temperature or a DHT temperature and % RH sensor. Those results will be discussed along with data in the next section.

Test Data versus Temperature

The issue with temperature seen with the MB7389 sensors is well illustrated in the three figures below. The results are from a stable test stand outdoor mounting over a stationary plate target when the weather was warm/sunny days and cooler nights. The MB7389 was equipped with the Maxbotix external temperature sensor (HR-Maxtemp sensor) which was mounted in the shade under the logger box. The logger box was covered with foil to minimize solar heating of the logger box interior.

Note the +/- spread of the distance data above at any given temperature and % RH. (Click on an image to enlarge.)

A “Multiple Regression Analysis” of the distance vs. Mayfly board temperature or DHT temperature, and percent relative humidity delivered a root squared error the same as using only board temperature: 37%. As would be expected from theory, the relative humidity has very low significance.

Conclusions

  • If used in a boom mounting to eliminate issues associated with condensation inside standpipes, the MB7389 sensors reliably deliver distance data over a wide temperature range and other weather conditions. Furthermore, the sensor delivered excellent stream depth change performance because the temperature change during the rain event and runoff was minor.
  • In spite of using the Maxbotix external temperature sensor for better temperature compensation, the distance data (fixed test stand) vary significantly with changes in ambient temperature — as much as +/- 1 centimeter or more. It is questionable whether the Maxbotix temperature compensation software can be considered worthwhile since the same results were seen for both ultrasonic sensors.
  • Work to correlate the distance changes with other measures of temperature (Mayfly board temperature or an independent temperature as from the DHT digital temperature and humidity sensor) could account for at most 40% of the changes.
  • We recommend careful consideration of these results before deploying these sensors if the objective is to have an absolute measure of depth/distance. However, the sensor is excellent for measuring changes in depth over a time frame where the temperature is not changing significantly.
#include <SoftwareSerial_PCINT12.h>

#include <Sodaq_PcInt_PCINT0.h>



//sketch to log sonar data on Mayfly
//this one can use  digital pin intermittent power or continuous power from board +rail 
//or a battery pack to power Maxbotix
//serialSonar begin and end empty buffer between each read so all data is new each time
//this also solves problems with the interrupts not allowing sleep code
#include <Wire.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

#include <SPI.h>
#include <SdFat.h>
SdFat SD;

#include <RTCTimer.h>
#include <Sodaq_DS3231.h>



SoftwareSerial sonarSerial(11, -1);        

boolean stringComplete = false;

#define READ_DELAY 1

//RTC Timer
RTCTimer timer;

String dataRec = "";
int currentminute;
long currentepochtime = 0;
float boardtemp = 0.0;

int batteryPin = A6;    // select the input pin for the potentiometer
int batterysenseValue = 0;  // variable to store the value coming from the sensor
float batteryvoltage;

int range_mm1;
int range_mm2;
int range_mm3;
int range_mm4;
int range_mm5;
int range_mm6;
int range_mm7;
int range_mm8;
int range_mm9;
int range_mm10;
int range_mm; 
int attempts;
int average_mm;
int total;
//RTC Interrupt pin
#define RTC_PIN A7
#define RTC_INT_PERIOD EveryMinute

#define SD_SS_PIN 12

//The data log file
#define FILE_NAME "SonicLog.txt"

//Data header
#define LOGGERNAME "Ultrasonic Maxbotix Sensor Datalogger"
#define DATA_HEADER "DateTime,Loggertime,BoardTemp,Battery_V,SonarRange_mm 1 to 10"
     

void setup() 
{
  
  
  rtc.begin();
  delay(100);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  
  pinMode(10, OUTPUT);
  
  

  greenred4flash();   //blink the LEDs to show the board is on

  setupLogFile();

  //Setup timer events
  setupTimer();
  
  //Setup sleep mode
  setupSleep();
  
  ///Serial.println("Power On, running: ultrasonic_logger_example_1.ino");
  ///Serial.println("Power On, running: ultrasonic_logger_example_1.ino");
          digitalWrite(8, HIGH);  
          digitalWrite(10, HIGH);
          stringComplete = false; 
           
          delay(5000);//wait for board to stabilize
          sonarSerial.begin(9600);
          range_mm = SonarRead();//does not add data to a string, included only for debugging
                    
          sonarSerial.end();
           attempts = 0;
           if (range_mm <= 300 || range_mm >= 2000 )
          {
            
            do {
               
              sonarSerial.begin(9600);
              delay (250);
              
              range_mm = SonarRead();
              stringComplete = false;
              attempts++;
              sonarSerial.end();
              delay (50);
            }
            while (attempts <21 && (range_mm == 300 || range_mm == 0));
          }
  
          average_mm = range_mm;  //sets initial average for trapping on first reading
         digitalWrite(10, LOW);          
          digitalWrite(8,LOW);           
          
  delay (1000);//added to show blink of led before loop.
}

void loop() 
{   
  
  //Update the timer 
  timer.update();
  
  
  if(currentminute % 5 == 0)   
     {
          digitalWrite(8, HIGH);  
          dataRec = createDataRecord();
          stringComplete = false; 
          delay(100);    
          digitalWrite(10, HIGH);//turns on  power to sonar
          delay(10000);//wait 10 sec for sonar to stabilize after startup
          sonarSerial.begin(9600);//open to allow data from sonar to enter input serial buffer
          //also clears buffer of old data
          delay(250);
          range_mm1 = SonarRead();
          stringComplete = false; 
          sonarSerial.end();//closes serial and stops input to buffer
          delay(50);
          attempts = 0;  
          if (range_mm1 <= 300 || range_mm1 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay (250);
              range_mm1 = SonarRead();
              stringComplete = false;
              attempts++;
              sonarSerial.end();
              delay (50);
            }
            while (attempts <11 && (range_mm1 <= 300 || range_mm1 >= 2000));
          }
  
          delay (200);
          sonarSerial.begin(9600);
          delay(250);
          range_mm2 = SonarRead();
          stringComplete = false; 
          sonarSerial.end();
          attempts = 0;  
          delay(50);
          if (range_mm2 <= 300 || range_mm2 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay (250);
              range_mm2 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm2 <= 300 || range_mm2 >= 2000));
          }
 
            
          delay (200);
          sonarSerial.begin(9600);
          delay(250);
          range_mm3 = SonarRead();
          stringComplete = false; 
          sonarSerial.end();
          delay(50);
          attempts = 0;  
          if (range_mm3 <= 300 || range_mm3 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm3 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm3 <= 300 || range_mm3 >= 2000));
          }
     
            
          delay (200);
          sonarSerial.begin(9600);
          delay (250);
          range_mm4 = SonarRead();
          stringComplete = false;
          sonarSerial.end();
          attempts = 0; 
          delay (50); 
          if (range_mm4 <= 300 || range_mm4 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm4 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm4 <= 300 || range_mm4 >= 2000));
          }


             
          
           
          delay (200);
          sonarSerial.begin(9600);
          delay (250);
          range_mm5 = SonarRead();
          stringComplete = false;
          sonarSerial.end(); 
          delay(50);
          attempts = 0;  
          if (range_mm5 <= 300 || range_mm5 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm5 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm5 <= 300 || range_mm5 >= 2000));
          }  
          
           
          delay (200);
          sonarSerial.begin(9600);
          delay(250);
          range_mm6 = SonarRead();
          stringComplete = false;
          sonarSerial.end(); 
          delay(50);  
          attempts = 0;  
          if (range_mm6 <= 300 || range_mm6 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm6 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm6 <= 300 || range_mm6 >= 2000));
          }
          
          delay (200);
          sonarSerial.begin(9600);
          delay(250);
          range_mm7 = SonarRead();
          stringComplete = false;
          sonarSerial.end();
          delay(50);  
          attempts = 0;  
          if (range_mm7 <= 300 || range_mm7 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm7 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm7 <= 300 || range_mm7 >= 2000));
          }
            
          delay (200);
          sonarSerial.begin(9600);
          delay(250);
          range_mm8 = SonarRead();
          stringComplete = false; 
          sonarSerial.end();
          delay(50);  
          attempts = 0;  
          if (range_mm8 <= 300 || range_mm8 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm8 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm8 <= 300 || range_mm8 >= 2000));
          }
            
          delay (200);
          sonarSerial.begin(9600);
          delay(250);
          range_mm9 = SonarRead();
          stringComplete = false; 
          sonarSerial.end();
          delay(50);  
          attempts = 0;  
          if (range_mm9 <= 300 || range_mm9 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm9 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm9 <= 300 || range_mm9 >= 2000));
          }
           
          delay (200);
          sonarSerial.begin(9600);
          delay(250);
          range_mm10 = SonarRead();
          stringComplete = false;
          sonarSerial.end(); 
          delay(50);  
          attempts = 0;  
          if (range_mm10 <= 300 || range_mm10 >= 2000 )
          {
            do {
              sonarSerial.begin(9600);
              delay(250);
              range_mm10 = SonarRead();
              stringComplete = false;
              sonarSerial.end();
              attempts++;
              delay (50);
            }
            while (attempts <11 && (range_mm10 <= 300 || range_mm10 >= 2000));
          }
          
          delay (100);
                                                                                             
          digitalWrite(8, LOW);
          digitalWrite(10, LOW);
          //following records ten data reads.  
      dataRec += ",";
      dataRec += range_mm1;  
      dataRec += ",";
      dataRec += range_mm2;  
      dataRec += ",";
      dataRec += range_mm3;  
      dataRec += ",";
      dataRec += range_mm4;  
      dataRec += ",";
      dataRec += range_mm5;  
      dataRec += ",";
      dataRec += range_mm6;  
      dataRec += ",";
      dataRec += range_mm7;  
      dataRec += ",";
      dataRec += range_mm8;  
      dataRec += ",";
      dataRec += range_mm9;  
      dataRec += ",";
      dataRec += range_mm10;
       
          if (range_mm1 <= 300 || range_mm1 >= 2000)
          { 
            range_mm1 = average_mm;
          }
          if (range_mm2 <= 300 || range_mm2 >= 2000)
          { 
            range_mm2 = average_mm;
          }
          if (range_mm3 <= 300 || range_mm3 >= 2000)
          { 
            range_mm3 = average_mm;
          }
          if (range_mm4 <= 300 || range_mm4 >= 2000)
          { 
            range_mm4 = average_mm;
          }
          if (range_mm5 <= 300 || range_mm5 >= 2000)
          { 
            range_mm5 = average_mm;
          }
          if (range_mm6 <= 300 || range_mm6 >= 2000)
          { 
            range_mm6 = average_mm;
          }
          if (range_mm7 <= 300 || range_mm7 >= 2000)
          { 
            range_mm7 = average_mm;
          }
          if (range_mm8 == 300 || range_mm8 >= 2000)
          { 
            range_mm8 = average_mm;
          }
          if (range_mm9 <= 300 || range_mm9 >= 2000)
          { 
            range_mm9 = average_mm;
          }
          if (range_mm10 <= 300 || range_mm10  >= 2000)
          { 
            range_mm10 = average_mm;
          }
          
      
          total = (range_mm1 + range_mm2 + range_mm3 + range_mm4 + range_mm5 + range_mm6 + range_mm7 + range_mm8 + range_mm9 + range_mm10); 
          average_mm = (total/10);
          
       
      dataRec += ",avg= ";
      dataRec+= average_mm; 
     
      
      
          //Save the data record to the log file
          logData(dataRec);
 
          //Echo the data to the serial connection
          //Serial.println();
          //Serial.print("Data Record: ");
          //Serial.println(dataRec);      
   
   
          String dataRec = "";   
     }
     
     systemSleep();
     } 
  


void showTime(uint32_t ts)
{
  //Retrieve and display the current date/time
  String dateTime = getDateTime();
  //Serial.println(dateTime);
}

void setupTimer()
{
  
  //Schedule the wakeup every minute
  timer.every(READ_DELAY, showTime);
  
  //Instruct the RTCTimer how to get the current time reading
  timer.setNowCallback(getNow);


}

void wakeISR()
{
  //Leave this blank
}

void setupSleep()
{
  pinMode(RTC_PIN, INPUT_PULLUP);
  PcInt::attachInterrupt(RTC_PIN, wakeISR);

  //Setup the RTC in interrupt mode
  rtc.enableInterrupts(RTC_INT_PERIOD);
  
  //Set the sleep mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}

void systemSleep()
{  
  //Wait until the serial ports have finished transmitting
  Serial.flush();
  Serial1.flush();
  
  //The next timed interrupt will not be sent until this is cleared
  rtc.clearINTStatus();
    
  //Disable ADC
  ADCSRA &= ~_BV(ADEN);
  
  //Sleep time
  noInterrupts();
  sleep_enable();
  interrupts();
  sleep_cpu();
  sleep_disable();
 
  //Enbale ADC
  ADCSRA |= _BV(ADEN);
  
}

String getDateTime()
{
  String dateTimeStr;
  
  //Create a DateTime object from the current time
  DateTime dt(rtc.makeDateTime(rtc.now().getEpoch()));

  currentepochtime = (dt.get());    //Unix time in seconds 

  currentminute = (dt.minute());
  //Convert it to a String
  dt.addToString(dateTimeStr); 
  return dateTimeStr;  
}

uint32_t getNow()
{
  currentepochtime = rtc.now().getEpoch();
  return currentepochtime;
}

void greenred4flash()
{
  for (int i=1; i <= 4; i++){
  digitalWrite(8, HIGH);   
  digitalWrite(9, LOW);
  delay(50);
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  delay(50);
  }
  digitalWrite(9, LOW);
}

void setupLogFile()
{
  // initialize the SD card at SPI_FULL_SPEED for best performance.
  // try SPI_HALF_SPEED if bus errors occur.
  if (!SD.begin(SD_SS_PIN, SPI_HALF_SPEED)) {
    SD.initErrorHalt();
  }
  //Check if the file already exists
  bool oldFile = SD.exists(FILE_NAME);  
  
  //Open the file in write mode
  File logFile = SD.open(FILE_NAME, FILE_WRITE);
  
  //Add header information if the file did not already exist
  if (!oldFile)
  {
    logFile.println(LOGGERNAME);
    logFile.println(DATA_HEADER);
  }
  
  //Close the file to save it
  logFile.close();  
}

void logData(String rec)
{
  //Re-open the file
  File logFile = SD.open(FILE_NAME, FILE_WRITE);
  
  //Write the CSV data
  logFile.println(rec);
  
  //Close the file to save it
  logFile.close();  
}

String createDataRecord()
{
    //Create a String type data record in csv format
    //TimeDate, Loggertime,Temp_DS, Diff1, Diff2, boardtemp
    String data = getDateTime();
    data += ",";  
  
    rtc.convertTemperature();          //convert current temperature into registers
    boardtemp = rtc.getTemperature(); //Read temperature sensor value
    
    batterysenseValue = analogRead(batteryPin);
    batteryvoltage = (3.3/1023.) * (12.7/2.7) * batterysenseValue;
    
    data += currentepochtime;
    data += ",";

    addFloatToString(data, boardtemp, 3, 1);    //float   
    data += ",";  
    addFloatToString(data, batteryvoltage, 4, 2);
  
    return data;
}


static void addFloatToString(String & str, float val, char width, unsigned char precision)
{
  char buffer[10];
  dtostrf(val, width, precision, buffer);
  str += buffer;
}


int SonarRead() 
{

  int result;
  char inData[5];                                          //char array to read data into
  int index = 0;
  
  while (sonarSerial.read() != -1) {}
   
  while (stringComplete == false) {

      if (sonarSerial.available())
    {
      
      char rByte = sonarSerial.read();                     //read serial input for "R" to mark start of data
      if(rByte == 'R')
      {
        //Serial.println("rByte set");
        while (index < 4)                                  //read next three character for range from sensor
        {
          if (sonarSerial.available())
          {
            delay(50);
            inData[index] = sonarSerial.read(); 
            //Serial.println(inData[index]);               //Debug line

            index++;                                       // Increment where to write next
          }  
        }
        inData[index] = 0x00;                              //add a padding byte at end for atoi() function
      }

      rByte = 0;                                           //reset the rByte ready for next reading

      index = 0;                                           // Reset index ready for next reading
      stringComplete = true;                               // Set completion of read to true
      result = atoi(inData); // Changes string data into an integer for use
      
    }
    
    
    }
    
  
      
      
  return result;
}

6 Comments

  1. Thankyou so much for doing such detailed work. I’d been thinking of a boom situation for some measurements. However the atmospheric temperature will vary.

  2. Great work guys. We are also interested in these sensors and have also been considering a boom-type setup.
    I think it might be worth getting one of these to see if it’s fit for our purpose.

  3. Hey Dave,
    As part of my technical institute’s graduation requirements, I’m currently designing a project to test the accuracy of MaxBotix’s sensors (as well as a $75 vented pressure transducer) to determine their applicability for streamflow monitoring. I’m also a hydrometric tech so do put a lot of thought into collecting accurate data.

    With that said, I do have a couple of thoughts to consider in regards to how your test was designed.

    Here they are in point form for brevity’s sake:

    • The U20-001-04’s (13 ft range) accuracy is 3-6 mm, so that needs to be considered. It also needs to be compensated with barrometric pressure (not mentioned in the report) which adds additional inaccuracies.
    • When measuring water in a stilling well with a pressure transducer, and the surface of the water with an ultrasonic sensor, you can’t consider the two data sets as reporting the same values. In high-velocity situations, you can get positive or negative pressure, thus lowering or raising the water level, in your stilling well depending on how it is designed.
    • And most importantly, in your on-ground test, the image shows that the sensor is on a metal boom. This is problematic as long metal objects deform/bend with temperature. You metnioned that you also did this test with the sensor at the top of a stilling well, but I didn’t see those images.

    Anyhow, I don’t mean to be a downer. I basically just listed these points as I’ll be critiquing your work in a literature review as part of my project.

    Really though I think it’s great that you’ve gone to all this work to test the sensor. I learned a few ideas from reading this that I’ll be incorporating into my tests.

    Give me a shout at gallaugher.consulting@gmail.com if you are up to chatting about your tests and helping me to design mine.

    • Rory,

      I have copied the comments from our email so that others can view them… thanks again.

      dave

      The U20-001-04’s (13 ft range) accuracy is 3-6 mm, so that needs to be considered. It also needs to be compensated with barrometric pressure (not mentioned in the report) which adds additional inaccuracies.

      With respect to the barometric pressure: a. Pressure sensor for depth: Remember that we are compensating for barometric pressure changes in the Onset logger by having a parallel sensor following barometric pressure. Not sure he understood that.  b. Also, with respect to the ultrasonic sensor, the barometric pressure has a very minimal effect on the speed of sound in air. Marion remembers that it is 2 orders of magnitude below the effect of both temperature and relative humidity (which is much lower than the temp effect.) So, really the only important effect is the temperature effect on speed of sound. 

      </li><li>When measuring water in a stilling well with a pressure transducer, and the surface of the water with an ultrasonic sensor, you can’t consider the two data sets as reporting the same values. In high-velocity situations, you can get positive or negative pressure, thus lowering or raising the water level, in your stilling well depending on how it is designed.

      We discarded using the ultrasonic sensor on a stilling well due to the signal dropouts which were somewhat erratic as to when they occurred, but clearly were connected to temp changes from high to low which induced some kind of condensation on the walls (that caused deflection of the wave). Similarly, we actually dispensed with the stilling well on the Onset depth logger just for convenience. So, stilling well experience is not something where got comparison data. The Final result comparisons were not data from stilling wells..

      </li><li>And most importantly, in your on-ground test, the image shows that the sensor is on a metal boom. This is problematic as long metal objects deform/bend with temperature.

      We don’t believe your comments about the metal boom having a significant impact on correct. If you calculate the change in dimension for a uniform metal (ie..
      no bimetallic effect) that is heated on only one side (eg. sun) while the other side is cool (shady side) then you can see that the metal is much less than wood. For example, CTE’s for metal will run around 1 * 10**-5 while wood will be at least 10X higher. Still, neither will show much bending with temperature differentials that we see in outside testing. That said, however, it is a concern for planned experiments, and easy to manually measure the separate distance from the boom to the target over the temp range..

      We would be interested in your results if/when available…. In particular, it would be helpful to see what the temperature effect (water temp) has on a pressure sensor logger (such as the Onset or the CTD sensor used in the Stroud logger stations..

  4. Hi David,

    Just to follow up on your comments, and then provide the report that I wrapped up last month where I tested the Maxbotix sensor.

    Just a quick reply to each comment here:
    1) yep, definitely understand that barometric pressure is only relevant to the pressure transducer and that the ultrasonic sensor is mostly affected by air temp.
    2) stilling well placement is finicky, and so thought I would just comment on that. It’s not where I would have placed the well but to each their own.
    3) Interesting to learn that wood would bend more than metal. I had not done the calculations but was told by Water Survey Canada that they accidentally collected errored water level data because they had an ultrasonic sensor on a metal boom that fluctuated with temp.

    I should mention too that my comments were in preparation for a literature review that I was preparing for my report. There isn’t much material available on the accuracy of Maxbotix sensors, and so was overly critical of what I did find to show my professors that I have my own thoughts on the current research. In reality, though I really enjoyed your work and found it quite helpful.

    I’ll post my research on this blog shortly, but in the meantime, it can be downloaded at the following link:
    https://drive.google.com/file/d/1TwziM5uK7JQWOxKAlAWntKWqhyg-bLit/view?usp=sharing

    • @roryg I need some assistance testing my maxbotix MB-7386 and I posted my issues in the forum…can you please assist?

Leave a Reply