00001 /* 00002 * Copyright 2016 The Cartographer Authors 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #ifndef CARTOGRAPHER_COMMON_RATE_TIMER_H_ 00018 #define CARTOGRAPHER_COMMON_RATE_TIMER_H_ 00019 00020 #include <chrono> 00021 #include <deque> 00022 #include <iomanip> 00023 #include <numeric> 00024 #include <sstream> 00025 #include <string> 00026 #include <vector> 00027 00028 #include "cartographer/common/math.h" 00029 #include "cartographer/common/port.h" 00030 #include "cartographer/common/time.h" 00031 00032 namespace cartographer { 00033 namespace common { 00034 00035 // Computes the rate at which pulses come in. 00036 template <typename ClockType = std::chrono::steady_clock> 00037 class RateTimer { 00038 public: 00039 // Computes the rate at which pulses come in over 'window_duration' in wall 00040 // time. 00041 explicit RateTimer(const common::Duration window_duration) 00042 : window_duration_(window_duration) {} 00043 ~RateTimer() {} 00044 00045 RateTimer(const RateTimer&) = delete; 00046 RateTimer& operator=(const RateTimer&) = delete; 00047 00048 // Returns the pulse rate in Hz. 00049 double ComputeRate() const { 00050 if (events_.empty()) { 00051 return 0.; 00052 } 00053 return static_cast<double>(events_.size() - 1) / 00054 common::ToSeconds((events_.back().time - events_.front().time)); 00055 } 00056 00057 // Returns the ratio of the pulse rate (with supplied times) to the wall time 00058 // rate. For example, if a sensor produces pulses at 10 Hz, but we call Pulse 00059 // at 20 Hz wall time, this will return 2. 00060 double ComputeWallTimeRateRatio() const { 00061 if (events_.empty()) { 00062 return 0.; 00063 } 00064 return common::ToSeconds((events_.back().time - events_.front().time)) / 00065 common::ToSeconds(events_.back().wall_time - 00066 events_.front().wall_time); 00067 } 00068 00069 // Records an event that will contribute to the computed rate. 00070 void Pulse(common::Time time) { 00071 events_.push_back(Event{time, ClockType::now()}); 00072 while (events_.size() > 2 && 00073 (events_.back().wall_time - events_.front().wall_time) > 00074 window_duration_) { 00075 events_.pop_front(); 00076 } 00077 } 00078 00079 // Returns a debug string representation. 00080 std::string DebugString() const { 00081 if (events_.size() < 2) { 00082 return "unknown"; 00083 } 00084 std::ostringstream out; 00085 out << std::fixed << std::setprecision(2) << ComputeRate() << " Hz " 00086 << DeltasDebugString() << " (pulsed at " 00087 << ComputeWallTimeRateRatio() * 100. << "% real time)"; 00088 return out.str(); 00089 } 00090 00091 private: 00092 struct Event { 00093 common::Time time; 00094 typename ClockType::time_point wall_time; 00095 }; 00096 00097 // Computes all differences in seconds between consecutive pulses. 00098 std::vector<double> ComputeDeltasInSeconds() const { 00099 CHECK_GT(events_.size(), 1); 00100 const size_t count = events_.size() - 1; 00101 std::vector<double> result; 00102 result.reserve(count); 00103 for (size_t i = 0; i != count; ++i) { 00104 result.push_back( 00105 common::ToSeconds(events_[i + 1].time - events_[i].time)); 00106 } 00107 return result; 00108 } 00109 00110 // Returns the average and standard deviation of the deltas. 00111 std::string DeltasDebugString() const { 00112 const auto deltas = ComputeDeltasInSeconds(); 00113 const double sum = std::accumulate(deltas.begin(), deltas.end(), 0.); 00114 const double mean = sum / deltas.size(); 00115 00116 double squared_sum = 0.; 00117 for (const double x : deltas) { 00118 squared_sum += common::Pow2(x - mean); 00119 } 00120 const double sigma = std::sqrt(squared_sum / (deltas.size() - 1)); 00121 00122 std::ostringstream out; 00123 out << std::scientific << std::setprecision(2) << mean << " s +/- " << sigma 00124 << " s"; 00125 return out.str(); 00126 } 00127 00128 std::deque<Event> events_; 00129 const common::Duration window_duration_; 00130 }; 00131 00132 } // namespace common 00133 } // namespace cartographer 00134 00135 #endif // CARTOGRAPHER_COMMON_RATE_TIMER_H_