I'm using version 2.7.4 of the robot_localization package for ROS Noetic.

I'm currently utilizing two nodes of the package:
- EKF Local Node: Fuses data from an IMU (100Hz) and wheel encoders (4Hz).
- EKF Global Node: Fuses the output of the EKF Local Node with GPS data (4Hz).

Despite these frequencies, the ekf_global node's frequency appears bounded between 60-65 Hz (asking for 100). And the ekf_local node's frequency appears bounded between 80-85 Hz(asking for 100). This restriction remains even when altering the input frequencies. with a lot of "Failed to meet update rate! Took 0.02000X" warnings in the console.

**Configuration:**

_launch file:_
```
        <launch>
            <arg name="namespace" default="fjcruiser" />
            <arg name="base_link_frame" value="$(arg namespace)/base_footprint" />
            <arg name="use_legacy_odom" default="false" />

            <!-- Load conf and parameters from yaml files -->
            <rosparam command="load" file="$(find ugv_odometry)/config/origins.yaml"/>
            <rosparam command="load" file="$(find ugv_odometry)/params/$(arg namespace)/localization.yaml" />

            <!-- Set the origin as a rosparam -->
            <node pkg="ugv_odometry" type="initializer_node" name="initializer_node" output="screen" />
            <!-- GNSS velocity converter-->
            <node name="gnss_velocity_converter" pkg="ugv_odometry" type="gnss_velocity_converter" output="screen" />
            
            <!-- EKF LOCAL-->
            <node pkg="robot_localization" type="ekf_localization_node" name="ekf_local" respawn="false" output="screen">
                <rosparam command="load" file="$(find ugv_odometry)/config/$(arg namespace)/ekf_local.yaml"/>
                <param name="base_link_frame" value="$(arg base_link_frame)"/>
                <remap from="odometry/filtered" to="relative_odom"/>
            </node>

            <!-- EKF Global -->
            <node pkg="robot_localization" type="ekf_localization_node" name="ekf_global" respawn="true" output="screen">
                <rosparam command="load" file="$(find ugv_odometry)/config/common/ekf_global.yaml"/>
                <param name="base_link_frame" value="$(arg base_link_frame)" />
                <param name="odom0" value="/$(arg namespace)/relative_odom" />
                <param name="odom1" value="/$(arg namespace)/navsat/odometry" />
                <remap from="odometry/filtered" to="odom" />
            </node>

            <!-- Navsat Transform Node -->
            <node pkg="robot_localization" type="navsat_transform_node" name="navsat_transform_node" respawn="true">
                <rosparam command="load" file="$(find ugv_odometry)/config/common/navsat_transform.yaml"/>
                <remap from="imu/data" to="imu" />
                <remap from="gps/fix" to="fix" />
                <remap from="odometry/filtered" to="odom" />
                <remap from="odometry/gps" to="navsat/odometry" />
            </node>
         <launch>
```

_ekf_local.yaml_

```
frequency: 100
sensor_timeout: 0.1
two_d_mode: true
world_frame: odom
odom_frame: odom
debug: false
debug_out_file: /home/developer/workspace/rosbag/ekf_local_debug_file
reset_on_time_jump: true
publish_tf: true
dynamic_process_noise_covariance: true
#transform_time_offset: 0.05

# -------------------------------------
# IMU configuration:
# -------------------------------------

imu0: /fjcruiser/imu
imu0_config: [false, false, false,
                false,  false,  false,
                false, false, false,
                false, false, true,
                false, false, false]
imu0_differential: false
imu0_queue_size: 50 
imu0_remove_gravitational_acceleration: true
imu0_nodelay: true
# -------------------------------------
# GNSS Doppler velocity configuration:
# -------------------------------------

odom0: /fjcruiser/converted_gnss_velocity
odom0_config: [false, false, false,
                       false, false, false,
                       true, true, false,
                       false, false, false,
                       false, false, false]
odom0_differential: false
odom0_queue_size: 4
odom0_nodelay: true

# [ADVANCED] This matrix represents the noise we add to the total error after each prediction step.

process_noise_covariance: [0.005, 0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                           0,    0.005, 0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                           0,    0,    0.006, 0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                           0,    0,    0,    0.03,  0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                           0,    0,    0,    0,    0.03,  0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                           0,    0,    0,    0,    0,    0.06,  0,     0,     0,    0,    0,    0,    0,    0,    0,
                           0,    0,    0,    0,    0,    0,    0.5,    0,     0,    0,    0,    0,    0,    0,    0,
                           0,    0,    0,    0,    0,    0,    0,     0.5,    0,    0,    0,    0,    0,    0,    0,
                           0,    0,    0,    0,    0,    0,    0,     0,     0.5,   0,    0,    0,    0,    0,    0,
                           0,    0,    0,    0,    0,    0,    0,     0,     0,    0.01,  0,    0,    0,    0,    0,
                           0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0.01,  0,    0,    0,    0,
                           0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0.02,  0,    0,    0,
                           0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0.01,  0,    0,
                           0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0.01,  0,
                           0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0.015]

# [ADVANCED] This represents the initial value for the state estimate error covariance matrix.

initial_estimate_covariance: [0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    1e-9, 0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    1e-9, 0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    1e-9, 0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    1e-9, 0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    1e-9, 0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    1e-9, 0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    1e-9,  0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     1e-9,  0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     1e-9,  0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     1e-9, 0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    1e-9, 0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    1e-9]
```


_ekf_global.yaml_

```
# The frequency of the output
frequency: 50
sensor_timeout: 0.1
two_d_mode: true
debug: false
debug_out_file: /home/developer/workspace/rosbag/ekf_global_debug_file
reset_on_time_jump: true
publish_tf: true
dynamic_process_noise_covariance: true
#transform_time_offset: 0.05

# The frame IDs
map_frame: map
odom_frame: odom
world_frame: map

# Sensor configurations
# Local EKF odometry settings
odom0_config: [false, false, false,
               false, false, false,
               true, true, false,
               false, false, true,
               false, false, false]
odom0_differential: false
odom0_queue_size: 50
odom0_nodelay: true

# GNSS settings
odom1_config: [true, true, false,
                 false, false, false,
                 false, false, false,
                 false, false, false,
                 false, false, false]
odom1_differential: false
odom1_queue_size: 4
odom1_nodelay: true

# [ADVANCED] This matrix represents the noise we add to the total error after each prediction step.

process_noise_covariance: [0.005, 0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                          0,    0.005, 0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                          0,    0,    0.006, 0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                          0,    0,    0,    0.03, 0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                          0,    0,    0,    0,    0.03, 0,    0,     0,     0,    0,    0,    0,    0,    0,    0,
                          0,    0,    0,    0,    0,    0.01, 0,     0,     0,    0,    0,    0,    0,    0,    0,
                          0,    0,    0,    0,    0,    0,    0.025, 0,     0,    0,    0,    0,    0,    0,    0,
                          0,    0,    0,    0,    0,    0,    0,     0.025, 0,    0,    0,    0,    0,    0,    0,
                          0,    0,    0,    0,    0,    0,    0,     0,     0.04, 0,    0,    0,    0,    0,    0,
                          0,    0,    0,    0,    0,    0,    0,     0,     0,    0.01, 0,    0,    0,    0,    0,
                          0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0.01, 0,    0,    0,    0,
                          0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0.02, 0,    0,    0,
                          0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0.01, 0,    0,
                          0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0.01, 0,
                          0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0.015]

# [ADVANCED] This represents the initial value for the state estimate error covariance matrix.

initial_estimate_covariance: [1,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    1,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    1,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    1e-9, 0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    1e-9, 0,    0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    1, 0,    0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    1e-9, 0,    0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    1e-9, 0,    0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    1e-9, 0,     0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    1e-9,  0,     0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     1e-9,  0,     0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     1e-9,  0,    0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     1e-9, 0,    0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    1e-9, 0,
                              0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    1e-9]
```




**Observations and Testing:**

- CPU Load: Always remains below 10% across all cores.
- EKF local Frequency: The limiting frequency of around 80/85 hz remains consistent, even when input frequencies are varied.
- Compilation and Debugging: The package is compiled in release mode, and the debug parameter is set to false.
- Input Queue Sizes: Altering the sizes doesn't have a discernable impact on frequency.
- EKF Dependency: The frequency of ekf_global always matches the maximum frequency of ekf_local. If I set the ekf_local to 10 Hz, I will have also 10Hz on the ekf_global regardless of the asked frequency. 
- TF Frequency: The frequency of the /tf topic is the combined frequency of the odom and relative_odom topics.
- TF Interactions: Both EKF nodes have interdependent TF requirements. However, when I replaced the TF produced by ekf_global with a static TF, there was no improvement on frequency.


**Request:**
I'm keen on understanding the reasons behind the frequency limitation of the ekf_local nodes and any potential solutions or workarounds that can be recommended.
thank you.