

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Amazon Braket 上的脈衝控制
<a name="braket-pulse-control"></a>

脈衝是控制量子電腦中 qubit 的類比訊號。透過 Amazon Braket 上的特定裝置，您可以存取脈衝控制功能，以使用脈衝提交電路。您可以透過 Braket SDK、使用 OpenQASM 3.0 或直接透過 Braket APIs 存取脈衝控制。首先，介紹在 Braket 中用於脈衝控制的一些關鍵概念。

**Topics**
+ [

## 影格
](#braket-frame)
+ [

## 連接埠
](#braket-port)
+ [

## 波形
](#braket-waveform)
+ [

# 使用 Hello Pulse
](braket-hello-pulse.md)
+ [

# 使用脈衝存取原生閘道
](braket-native-gate-pulse.md)

## 影格
<a name="braket-frame"></a>

框架是一種軟體抽象，可同時做為量子程式和階段中的時鐘。每個用量的時鐘時間和由頻率定義的具狀態電信業者訊號都會遞增。將訊號傳輸到 qubit 時，影格會決定 qubit 的載波頻率、相位移，以及發出波形信封的時間。在 Braket Pulse 中，建構影格取決於裝置、頻率和階段。視裝置而定，您可以選擇預先定義的影格，或提供連接埠來執行個體化新的影格。

```
from braket.aws import AwsDevice
from braket.pulse import Frame, Port

# Predefined frame from a device
device = AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-3")
drive_frame = device.frames["Transmon_5_charge_tx"]

# Create a custom frame
readout_frame = Frame(frame_id="r0_measure", port=Port("channel_0", dt=1e-9), frequency=5e9, phase=0)
```

## 連接埠
<a name="braket-port"></a>

連接埠是一種軟體抽象，代表控制 qubit 的任何輸入/輸出硬體元件。它有助於硬體供應商提供一個界面，使用者可以與之互動以操作和觀察 qubit。連接埠的特徵是代表連接器名稱的單一字串。此字串也會公開最小時間增量，指定我們可以定義波形的精細程度。

```
from braket.pulse import Port

Port0 = Port("channel_0", dt=1e-9)
```

## 波形
<a name="braket-waveform"></a>

波形是一種時間相依的信封，可用來在輸出連接埠上發出訊號，或透過輸入連接埠擷取訊號。您可以透過複雜數字清單或使用波形範本從硬體提供者產生清單，直接指定您的波形。

```
from braket.pulse import ArbitraryWaveform, ConstantWaveform
import numpy as np

cst_wfm = ConstantWaveform(length=1e-7, iq=0.1)
arb_wf = ArbitraryWaveform(amplitudes=np.linspace(0, 100))
```

 Braket Pulse 提供標準的波形程式庫，包括常數波形、高斯波形，以及依二軸閘道 (DRAG) 波形的衍生移除。您可以透過 `sample`函數擷取波形資料，以繪製波形的形狀，如下列範例所示。

```
from braket.pulse import GaussianWaveform
import numpy as np
import matplotlib.pyplot as plt

zero_at_edge1 = GaussianWaveform(1e-7, 25e-9, 0.1, True)
# or zero_at_edge1 = GaussianWaveform(1e-7, 25e-9, 0.1)
zero_at_edge2 = GaussianWaveform(1e-7, 25e-9, 0.1, False)

times_1 = np.arange(0, zero_at_edge1.length, drive_frame.port.dt)
times_2 = np.arange(0, zero_at_edge2.length, drive_frame.port.dt)

plt.plot(times_1, zero_at_edge1.sample(drive_frame.port.dt))
plt.plot(times_2, zero_at_edge2.sample(drive_frame.port.dt))
```

![\[顯示兩個案例隨時間變化幅度的圖表：ZaE = True （曲線較低） 和 ZaE = False （曲線上方）。曲線的鐘形峰值約為 0.5 秒，振幅為 0.10 a. u.\]](http://docs.aws.amazon.com/zh_tw/braket/latest/developerguide/images/gaussianwaveform.png)


上圖描述從 建立的高斯波形`GaussianWaveform`。我們選擇 100 ns 的脈衝長度、25 ns 的寬度，以及 0.1 的振幅 （任意單位）。波形以脈衝視窗為中心。 `GaussianWaveform`接受布林引數 `zero_at_edges`（圖例中的 ZaE)。設為 時`True`，此引數會偏移高斯波形，讓 t=0 和 t=`length` 的點位於零，並重新調整其振幅，讓最大值對應至`amplitude`引數。

# 使用 Hello Pulse
<a name="braket-hello-pulse"></a>

在本節中，您將了解如何直接使用Rigetti裝置上的脈衝來描述和建構單一 qubit 閘道。將電磁欄位套用至 qubit 會導致 Rabi 振盪，並在其 0 狀態和 1 狀態之間切換 qubit。使用經過校正的脈衝長度和階段，Rabi 振盪可以計算單一 qubit 閘道。在這裡，我們將決定測量 pi/2 脈衝的最佳脈衝長度，這是用來建置更複雜脈衝序列的基本區塊。

首先，若要建置脈衝序列，請匯入 `PulseSequence`類別。

```
from braket.aws import AwsDevice
from braket.circuits import FreeParameter
from braket.devices import Devices
from braket.pulse import PulseSequence, GaussianWaveform

import numpy as np
```

接著，使用 QPU 的 Amazon Resource Name(ARN) 執行個體化新的 Braket 裝置。下列程式碼區塊使用 Rigetti Ankaa-3。

```
device = AwsDevice(Devices.Rigetti.Ankaa3)
```

下列脈衝序列包含兩個元件：播放波形和測量 qubit。脈衝序列通常可以套用至影格。除了一些例外狀況，例如障礙和延遲，這些例外狀況可以套用至 qubit。在建構脈衝序列之前，您必須擷取可用的影格。驅動框架用於套用 Rabi 振盪的脈衝，而讀取框架用於測量 qubit 狀態。此範例使用 qubit 25 的影格。

```
drive_frame = device.frames["Transmon_25_charge_tx"]
readout_frame = device.frames["Transmon_25_readout_rx"]
```

現在，建立將在驅動影格中播放的波形。目標是描述不同脈衝長度的 qubit 行為。您每次都會播放不同長度的波形。使用脈衝序列`FreeParameter`中支援的 Braket，而不是每次執行個體化新波形。您可以使用免費參數建立波形和脈衝序列一次，然後使用不同的輸入值執行相同的脈衝序列。

```
waveform = GaussianWaveform(FreeParameter("length"), FreeParameter("length") * 0.25, 0.2, False)
```

最後，將它們放在一起做為脈衝序列。在脈衝序列中， 會在驅動影格上`play`播放指定的波形，並從讀取影格`capture_v0`測量狀態。

```
pulse_sequence = (
    PulseSequence()
    .play(drive_frame, waveform)
    .capture_v0(readout_frame)
)
```

掃描各種脈衝長度，並將其提交至 QPU。在 QPU 上執行脈衝序列之前，請先繫結可用參數的值。

```
start_length = 12e-9
end_length = 2e-7
lengths = np.arange(start_length, end_length, 12e-9)
N_shots = 100

tasks = [
    device.run(pulse_sequence(length=length), shots=N_shots)
    for length in lengths
]

probability_of_zero = [
    task.result().measurement_counts['0']/N_shots
    for task in tasks
]
```

qubit 測量的統計資料會顯示在 0 狀態和 1 狀態之間振盪的 qubit 振盪動態。從測量資料中，您可以擷取 Rabi 頻率，並微調脈波的長度，以實作特定的 1-qubit 閘道。例如，根據下圖中的資料，週期性約為 154 ns。因此，pi/2 輪換閘道會對應至長度 = 38.5ns 的脈衝序列。

![\[顯示以秒為單位的脈衝持續時間人口數量的折線圖。圖形中有兩個峰值和一個波谷。\]](http://docs.aws.amazon.com/zh_tw/braket/latest/developerguide/images/Rabi-frequency.png)


## 使用 OpenPulse 的 Hello Pulse
<a name="braket-hello-pulse-openpulse"></a>

 [OpenPulse](https://openqasm.com/language/openpulse.html) 是一種語言，用於指定一般量子裝置的脈衝層級控制，並且是 OpenQASM 3.0 規格的一部分。Amazon Braket 支援使用 OpenQASM 3.0 表示法OpenPulse直接程式設計脈衝。

 Braket 使用 OpenPulse做為基礎中繼表示法，以在原生指示中表達脈衝。 OpenPulse支援以 `defcal`(「定義校正」的簡稱） 宣告形式新增指令校正。透過這些宣告，您可以在較低層級的控制文法中指定閘道指令的實作。

您可以使用`PulseSequence`下列命令檢視 Braket 的 OpenPulse 程式。

```
print(pulse_sequence.to_ir())
```

您也可以直接建構 OpenPulse 程式。

```
from braket.ir.openqasm import Program
 
openpulse_script = """
OPENQASM 3.0;
cal {
    bit[1] psb;
    waveform my_waveform = gaussian(12.0ns, 3.0ns, 0.2, false);
    play(Transmon_25_charge_tx, my_waveform);
    psb[0] = capture_v0(Transmon_25_readout_rx);
}
"""
```

使用指令碼建立`Program`物件。然後，將程式提交至 QPU。

```
from braket.aws import AwsDevice
from braket.devices import Devices
from braket.ir.openqasm import Program

program = Program(source=openpulse_script)

device = AwsDevice(Devices.Rigetti.Ankaa3)
task = device.run(program, shots=100)
```

# 使用脈衝存取原生閘道
<a name="braket-native-gate-pulse"></a>

研究人員通常需要確切知道特定 QPU 支援的*原生*閘道如何實作為脈衝。脈衝序列由硬體提供者仔細校正，但存取它們可讓研究人員有機會設計更好的閘道，或探索錯誤緩解的通訊協定，例如延伸特定閘道的脈衝進行零雜訊外推。

Amazon Braket 支援從 Rigetti 以程式設計方式存取原生閘道。

```
import math
from braket.aws import AwsDevice
from braket.circuits import Circuit, GateCalibrations, QubitSet
from braket.circuits.gates import Rx

device = AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-3")

calibrations = device.gate_calibrations
print(f"Downloaded {len(calibrations)} calibrations.")
```

**注意**  
硬體供應商會定期校正 QPU，通常每天不只一次。Braket SDK 可讓您取得最新的閘道校正。

```
device.refresh_gate_calibrations()
```

若要擷取指定的原生閘道，例如 RX 或 XY 閘道，您需要傳遞`Gate`物件和感興趣的 qubit。例如，您可以檢查套用至 0 的 RX(π/2) qubit 的脈衝實作。

```
rx_pi_2_q0 = (Rx(math.pi/2), QubitSet(0))

pulse_sequence_rx_pi_2_q0 = calibrations.pulse_sequences[rx_pi_2_q0]
```

您可以使用 `filter`函數建立一組篩選後的校正。您可以傳遞閘道清單或 清單`QubitSet`。下列程式碼會建立兩組，其中包含 RX(π/2) 和 0 qubit 的所有校正。

```
rx_calibrations = calibrations.filter(gates=[Rx(math.pi/2)])
q0_calibrations = calibrations.filter(qubits=QubitSet([0]))
```

現在，您可以透過連接自訂校正集來提供或修改原生閘道的動作。例如，請考慮下列電路。

```
bell_circuit = (
    Circuit()
    .rx(0, math.pi/2)
    .rx(1, math.pi/2)
    .iswap(0, 1)
    .rx(1, -math.pi/2)
)
```

您可以透過將`PulseSequence`物件字典傳遞至`gate_definitions`關鍵字引數`qubit 0`，以閘道 的自訂`rx`閘道校正來執行它。您可以從 `GateCalibrations` 物件`pulse_sequences`的 屬性建構字典。所有未指定的閘道都會以量子硬體提供者的脈衝校正取代。

```
nb_shots = 50
custom_calibration = GateCalibrations({rx_pi_2_q0: pulse_sequence_rx_pi_2_q0})
task = device.run(bell_circuit, gate_definitions=custom_calibration.pulse_sequences, shots=nb_shots)
```