44#include < SensorDebug/SensorDebugTypeIds.h>
55
66#include < AzCore/Serialization/SerializeContext.h>
7-
7+ # include < AzFramework/Components/ConsoleBus.h >
88namespace SensorDebug
99{
1010 AZ_COMPONENT_IMPL (SensorDebugSystemComponent, " SensorDebugSystemComponent" , SensorDebugSystemComponentTypeId);
@@ -20,10 +20,12 @@ namespace SensorDebug
2020 void SensorDebugSystemComponent::Activate ()
2121 {
2222 ImGui::ImGuiUpdateListenerBus::Handler::BusConnect ();
23+ AZ::TickBus::Handler::BusConnect ();
2324 }
2425
2526 void SensorDebugSystemComponent::Deactivate ()
2627 {
28+ AZ::TickBus::Handler::BusDisconnect ();
2729 ImGui::ImGuiUpdateListenerBus::Handler::BusDisconnect ();
2830 }
2931
@@ -129,6 +131,41 @@ namespace SensorDebug
129131 void SensorDebugSystemComponent::OnImGuiUpdate ()
130132 {
131133 ImGui::Begin (" ROS2 SensorDebugger" );
134+
135+ ImGui::InputFloat (" Application Max FPS" , &m_maxFPS);
136+ ImGui::SameLine ();
137+ if (ImGui::Button (" Set sys_MaxFPS" ))
138+ {
139+ // disable vsync
140+ AZStd::string commandVsync = AZStd::string::format (" vsync_interval=0" );
141+ AzFramework::ConsoleRequestBus::Broadcast (&AzFramework::ConsoleRequests::ExecuteConsoleCommand, commandVsync.c_str ());
142+ AZStd::string commandMaxFps = AZStd::string::format (" sys_MaxFPS=%f" , m_maxFPS);
143+ AzFramework::ConsoleRequestBus::Broadcast (&AzFramework::ConsoleRequests::ExecuteConsoleCommand, commandMaxFps.c_str ());
144+ m_appFrequencies.clear ();
145+ }
146+
147+ float freqencySum = 0 .0f ;
148+ for (const auto & freq : m_appFrequencies)
149+ {
150+ freqencySum += freq;
151+ }
152+ const float averageFrequency = freqencySum / static_cast <float >(m_appFrequencies.size ());
153+ // compute std deviation
154+ float variance = 0 .0f ;
155+ for (const auto & freq : m_appFrequencies)
156+ {
157+ variance += (freq - averageFrequency) * (freq - averageFrequency);
158+ }
159+ float stdDeviation = sqrt (variance / static_cast <float >(m_appFrequencies.size ()));
160+ ImGui::Separator ();
161+ ImGui::PlotHistogram (" App Actual Frequency" , m_appFrequencies.data (), static_cast <int >(m_appFrequencies.size ()), 0 );
162+ ImGui::Text (" App Actual Frequency: %.2f Hz [ std_dev = %.2f ]" , averageFrequency, stdDeviation);
163+ ImGui::SameLine ();
164+ if (ImGui::Button (" reset stats" ))
165+ {
166+ m_appFrequencies.clear ();
167+ }
168+ ImGui::Separator ();
132169 if (ImGui::Button (" Refresh with EnumerateHandlers(o3de bus API)" ))
133170 {
134171 FindSensorsWithBusAPI ();
@@ -178,7 +215,7 @@ namespace SensorDebug
178215 {
179216 FindSensorsWithGivenType (ROS2::ROS2OdometrySensorComponent);
180217 }
181-
218+ ImGui::InputInt ( " History Size " , &m_historySize);
182219 for (auto & sensorEntity : m_sensorEntities)
183220 {
184221 ImGui::Separator ();
@@ -189,7 +226,42 @@ namespace SensorDebug
189226 float frequency = 0 .0f ;
190227 ROS2::SensorConfigurationRequestBus::EventResult (
191228 frequency, sensorEntity, &ROS2::SensorConfigurationRequest::GetEffectiveFrequency);
192- ImGui::Text (" %s : %s effective Freq: %f Hz" , entityName.c_str (), sensorName.c_str (), frequency);
229+
230+ m_sensorFrequencyHistory[sensorEntity].push_back (frequency);
231+ auto &sensorFrequencyHistory = m_sensorFrequencyHistory[sensorEntity];
232+ if (sensorFrequencyHistory.size () > m_historySize)
233+ {
234+ sensorFrequencyHistory.erase (sensorFrequencyHistory.begin ());
235+ }
236+ float freqencySum = 0 .0f ;
237+ for (const auto & freq : sensorFrequencyHistory)
238+ {
239+ freqencySum += freq;
240+ }
241+ const float averageFrequency = freqencySum / static_cast <float >(sensorFrequencyHistory.size ());
242+ // compute std deviation
243+ float variance = 0 .0f ;
244+ for (const auto & freq : sensorFrequencyHistory)
245+ {
246+ variance += (freq - averageFrequency) * (freq - averageFrequency);
247+ }
248+ float stdDeviation = sqrt (variance / static_cast <float >(sensorFrequencyHistory.size ()));
249+ const AZStd::string histogramNameWithCookie = AZStd::string::format (" Histogram%s" , cookie.c_str ());
250+
251+ ImGui::PlotHistogram (
252+ histogramNameWithCookie.c_str (), sensorFrequencyHistory.data (), static_cast <int >(sensorFrequencyHistory.size ()), 0 );
253+ ImGui::SameLine ();
254+ const AZStd::string resetButton = AZStd::string::format (" reset stats%s" , cookie.c_str ());
255+ if (ImGui::Button (resetButton.c_str ()))
256+ {
257+ sensorFrequencyHistory.clear ();
258+ }
259+ ImGui::Text (
260+ " %s : %s effective Freq: %.2f Hz [ std_dev = %.2f ]" ,
261+ entityName.c_str (),
262+ sensorName.c_str (),
263+ averageFrequency,
264+ stdDeviation);
193265
194266 AZStd::string buttonNameEna = AZStd::string::format (" Enable%s" , cookie.c_str ());
195267 AZStd::string buttonNameDis = AZStd::string::format (" Disable%s" , cookie.c_str ());
@@ -230,7 +302,7 @@ namespace SensorDebug
230302 ROS2::SensorConfigurationRequestBus::Event (sensorEntity, &ROS2::SensorConfigurationRequest::SetVisualizeEnabled, false );
231303 }
232304 AZStd::string freqName = AZStd::string::format (" Frequency%s" , cookie.c_str ());
233- ImGui::DragFloat (freqName.c_str (), &m_sensorFrequencies[sensorEntity], 0 . 1f , 0 . 1f , 500 . 0f );
305+ ImGui::InputFloat (freqName.c_str (), &m_sensorFrequencies[sensorEntity]);
234306 ImGui::SameLine ();
235307 AZStd::string buttonSetFreq = AZStd::string::format (" Set Frequency%s" , cookie.c_str ());
236308 if (ImGui::Button (buttonSetFreq.c_str ()))
@@ -242,4 +314,13 @@ namespace SensorDebug
242314
243315 ImGui::End ();
244316 }
317+
318+ void SensorDebugSystemComponent::OnTick (float deltaTime, AZ::ScriptTimePoint time)
319+ {
320+ m_appFrequencies.push_back (1 .0f / deltaTime);
321+ if (m_appFrequencies.size () > m_historySize)
322+ {
323+ m_appFrequencies.erase (m_appFrequencies.begin ());
324+ }
325+ }
245326} // namespace SensorDebug
0 commit comments