Restrict mixer calibration to target qubits' channels - #1581
Conversation
Previously calibrate_mixers configured and calibrated every channel in the platform regardless of `targets`. Now only the drive/probe channels of the requested qubits are touched (all targets together, to preserve intermodulation products), the report table is split per qubit, and offset_i/offset_q updates propagate to sibling channels sharing a frequency-multiplexed readout port, since those get recalibrated in hardware too.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1581 +/- ##
==========================================
- Coverage 91.84% 91.54% -0.30%
==========================================
Files 147 147
Lines 11635 11679 +44
==========================================
+ Hits 10686 10692 +6
- Misses 949 987 +38
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
How I handle the update is a bit dummy running first in a reduced version of the hardware (only the target channels) and later in the full cluster to update offsets (and make sure all mixers that share an LO get the same offset update). |
|
Hi @jevillegasd, to for me to understand, what is the main motivation for this? Is it the time saved or something else? |
Hey @RoyStegeman , you may recall we talked about needing this when you have more pulses than sequencers. This may happen for example if in a platform we defined the ge, ef, and cr pulses, for two qubits, this already exhausts the available sequencers, even if they are not used simultaneously in a practical application. The mixer calibration would fail in such cases because it loads by default all existing sequencers. Additionally, when you re-calibrate the mixer in practice you need to re-calibrate your pulse amplitudes and drag coefficients, so so it does make sense to have some level of control of which ports are being re calibrated. |
| sequencer.sideband_cal() | ||
|
|
||
|
|
||
| def _target_channels(platform: CalibrationPlatform, targets: list[str]) -> set[str]: |
There was a problem hiding this comment.
| def _target_channels(platform: CalibrationPlatform, targets: list[str]) -> set[str]: | |
| def _target_channels(platform: CalibrationPlatform, targets: list[QubitId]) -> set[ChannelId]: |
Using these type aliases improves readability. I point out just here, but of course it should be done for all instances where there is now str that can be a more specific type alias.
|
|
||
|
|
||
| def _acquisition( | ||
| params: CalibrateMixersParameters, |
There was a problem hiding this comment.
| params: CalibrateMixersParameters, | |
| _params: CalibrateMixersParameters, |
to indicate it's not consumed
| ``Cluster.configure`` always configures every channel in | ||
| ``Cluster._channels_by_module`` (the whole platform, by default), so the map is | ||
| narrowed temporarily and restored right after, to avoid touching unrelated modules | ||
| or leaking the restriction into later experiments. |
There was a problem hiding this comment.
Please mention that this handling is needed because Cluster._channels_by_module is a cached property.
Also mention that try is there not because you expect it to fail, but just to be absolutely certain that if it does then the previous cluster._channels_by_module is still restored. Or if there is some other reason, explain that one.
| target_channels = _target_channels(platform, [target]) | ||
| mapping[target] = sorted( | ||
| { | ||
| cluster._modules[slot].short_name |
There was a problem hiding this comment.
cluster._modules is not cached so you're generating the same dict it for each target, it can be moved out of the loop.
| # round2 | ||
| # offset_i/offset_q are per physical port, shared by every qubit multiplexed on it | ||
| # Calibrating one recalibrates all of them in hardware, so propagate the update to | ||
| # update to every channel on a sahred calibrated port, not just the targets. |
There was a problem hiding this comment.
| # update to every channel on a sahred calibrated port, not just the targets. | |
| # update to every channel on a shared calibrated port, not just the targets. |
| cal = final_cal[mod_name] | ||
| for ch_id, seq_id in channels.items(): | ||
| ch = channel_mixer(ch_id) | ||
| port = PortAddress.from_path(cluster.channels[ch_id].path).ports[0] - 1 |
There was a problem hiding this comment.
| port = PortAddress.from_path(cluster.channels[ch_id].path).ports[0] - 1 | |
| port = PortAddress.from_path(ch.path).ports[0] - 1 |
| for slot, channels in results.sequencer_map.items(): | ||
| mod_name = cluster._modules[slot].short_name | ||
| if mod_name not in final_cal: | ||
| continue # Skip if no calibration data for this module |
There was a problem hiding this comment.
This is duplicated in the second round. The mod_name handling can be done only once
| data: Acquisition data | ||
|
|
||
| Returns: | ||
| Empty results |
There was a problem hiding this comment.
Pull request overview
Restricts Qblox mixer calibration and reporting to channels associated with requested qubits.
Changes:
- Filters configured channels by target.
- Produces per-target module reports.
- Propagates port-level offsets to multiplexed sibling channels.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Roy Stegeman <roystegeman@live.nl>
Co-authored-by: Roy Stegeman <roystegeman@live.nl>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
for more information, see https://pre-commit.ci
Previously calibrate_mixers configured and calibrated every channel in the platform regardless of
targets. Now only the drive/probe channels of the requested qubits are touched (all targets together, to preserve intermodulation products), the report table is split per qubit, and offset_i/offset_q updates propagate to sibling channels sharing a frequency-multiplexed readout port, since those get recalibrated in hardware too.To do this I patch the
_channels_by_modulemethod fromqibolab.instruments.qblox.clusterto keep only the channels associated to the target qubit(s).