# How to Configure Control Frequency vs Simulation Frequency in Peng

> Learn how to configure control frequency vs simulation frequency in Peng by editing the quad.yaml file. Optimize your simulation performance efficiently.

- Repository: [Yang Zhou/peng](https://github.com/makeecat/peng)
- Tags: how-to-guide
- Published: 2026-03-06

---

**In Peng, you configure control frequency and simulation frequency in [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml) under the `simulation` section; the control loop executes every `simulation_frequency / control_frequency` physics steps as implemented in the main simulation loop.**

Peng is an open-source quadrotor physics simulator written in Rust that decouples high-rate physics updates from lower-rate control evaluations. The relationship between these frequencies is defined in YAML configuration and enforced through integer division in the main simulation loop. Understanding how to configure control frequency vs simulation frequency in Peng allows you to balance computational load against controller responsiveness.

## Understanding the Frequency Architecture

The frequency relationship is defined in the `SimulationConfig` struct declared in [`src/config.rs`](https://github.com/makeecat/peng/blob/main/src/config.rs) at lines 54–59. This structure stores both the physics update rate and the control evaluation rate as discrete integer values representing hertz.

The fields are:

- `control_frequency`: How many times per second the PID controller computes actuator commands
- `simulation_frequency`: How many times per second the physics engine updates the vehicle state

## Where to Configure Frequencies

Peng loads runtime parameters from [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml) using the `Config::from_yaml` method called at startup in [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) (lines 20–21). To modify the timing behavior:

1. Open [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml)
2. Locate the `simulation` block
3. Adjust `control_frequency` and `simulation_frequency` values

Example configuration:

```yaml
simulation:
  # Number of control loop executions per second (Hz)

  control_frequency: 250   # e.g., 250 Hz

  # Number of physics simulation steps per second (Hz)

  simulation_frequency: 2000   # e.g., 2000 Hz

  log_frequency: 20
  duration: 90.0

```

## How the Simulation Loop Applies Control

The main simulation loop in [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) (specifically at line 38) implements a decoupled update strategy using modulo arithmetic. The control step triggers only when the current step index satisfies:

```rust
i % (config.simulation.simulation_frequency / config.simulation.control_frequency) == 0

```

This means the PID controller runs only once every N physics ticks, where N is the integer ratio of `simulation_frequency` divided by `control_frequency`. For example, with a 2000 Hz simulation and 250 Hz control, the controller updates every 8 physics steps.

### Calculating the Step Interval Programmatically

You can verify the effective control interval in Rust:

```rust
let control_interval = config.simulation.simulation_frequency
                    / config.simulation.control_frequency;
println!("Apply control every {} simulation steps", control_interval);

```

### Logging Runtime Frequencies

To confirm the configuration at runtime:

```rust
let sim_hz = config.simulation.simulation_frequency;
let ctrl_hz = config.simulation.control_frequency;
log::info!(
    "Simulation running at {} Hz, control loop at {} Hz (ratio {}:1)",
    sim_hz,
    ctrl_hz,
    sim_hz / ctrl_hz
);

```

## Summary

- **Configuration location**: Edit `control_frequency` and `simulation_frequency` in [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml) under the `simulation` section
- **Source definitions**: The `SimulationConfig` struct in [`src/config.rs`](https://github.com/makeecat/peng/blob/main/src/config.rs) (lines 54–59) declares the frequency fields
- **Runtime logic**: The main loop in [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) (line 38) applies control using modulo arithmetic with the ratio `simulation_frequency / control_frequency`
- **Loading mechanism**: `Config::from_yaml` parses the YAML at startup in [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) (lines 20–21)
- **Ratio constraint**: The control frequency should evenly divide the simulation frequency for consistent timing intervals

## Frequently Asked Questions

### What happens if control_frequency does not divide evenly into simulation_frequency?

When the ratio produces a remainder, the control loop executes at irregular intervals due to integer truncation in the modulo operation at line 38 of [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs). For consistent controller behavior, ensure `simulation_frequency % control_frequency == 0`.

### Can I set control_frequency higher than simulation_frequency?

Technically the YAML accepts any value, but setting `control_frequency` higher than `simulation_frequency` causes the modulo expression to evaluate to 0 or 1, resulting in control updates every step or causing division errors. The control loop should always run at or below the physics rate.

### Where does Peng load the YAML configuration?

Peng loads [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml) at startup through the `Config::from_yaml` function call in [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) at lines 20–21. Changes to the configuration file require a restart to take effect; there is no hot-reload mechanism.

### How do I verify the actual frequencies at runtime?

Log the configuration values using the code snippet shown in the examples above, or inspect the initialization logs. The `SimulationConfig` struct values defined in [`src/config.rs`](https://github.com/makeecat/peng/blob/main/src/config.rs) are accessible throughout the application after loading.