Skip to content

Commit

Permalink
Combine x and y signals
Browse files Browse the repository at this point in the history
  • Loading branch information
chunyu-li committed Feb 26, 2023
1 parent dc8481b commit 6fee633
Show file tree
Hide file tree
Showing 29 changed files with 196 additions and 193 deletions.
45 changes: 22 additions & 23 deletions example.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

# 首先产生发射端X/Y双偏振信号

data_x, data_y = phot.gen_bits(num_symbols * bits_per_symbol) # 生成两列随机二进制序列
bits = phot.gen_bits(num_symbols * bits_per_symbol) # 生成两列随机二进制序列

# QAM调制器
symbols_x, symbols_y = phot.qam_modulate(data_x, data_y, bits_per_symbol)
symbols = phot.qam_modulate(bits, bits_per_symbol)

# 此处先存储发射端原始发送信号,作为最后比较BER
prev_symbols_x, prev_symbols_y = symbols_x, symbols_y
prev_symbols = symbols

RRC_ROLL_OFF = 0.02 # RRC脉冲整形滚降系数
shaper = phot.PulseShaper(
Expand All @@ -34,22 +34,22 @@
fs=sampling_rate,
)

signal_x, signal_y = shaper.tx_shape(symbols_x, symbols_y)
signals = shaper.tx_shape(symbols)

""" 加入AWG中DAC的量化噪声 """
sampling_rate_awg = 96e9 # DAC采样率
dac_resolution_bits = 8 # DAC的bit位数

signal_x, signal_y = phot.dac_noise(signal_x, signal_y, sampling_rate_awg, sampling_rate, dac_resolution_bits)
signals = phot.dac_noise(signals, sampling_rate_awg, sampling_rate, dac_resolution_bits)

""" 加入发射端激光器产生的相位噪声 """
linewidth_tx = 150e3 # 激光器线宽
signal_x, signal_y = phot.phase_noise(signal_x, signal_y, sampling_rate / total_baud, linewidth_tx, total_baud)
signals = phot.phase_noise(signals, sampling_rate / total_baud, linewidth_tx, total_baud)

""" 根据设置的OSNR来加入高斯白噪声 """

osnr_db = 50 # 设置系统OSNR,也就是光信号功率与噪声功率的比值,此处单位为dB
signal_x, signal_y = phot.gaussian_noise(signal_x, signal_y, osnr_db, sampling_rate)
signals = phot.gaussian_noise(signals, osnr_db, sampling_rate)

""" 发射端代码此处截止 """

Expand All @@ -64,42 +64,42 @@
beta2 = 21.6676e-24
gamma = 1.3

signal_x, signal_y, power_x, power_y = phot.optical_fiber_channel(
signal_x, signal_y, sampling_rate, span, num_steps, beta2, delta_z, gamma, alpha, L
signals, signals_power = phot.optical_fiber_channel(
signals, sampling_rate, span, num_steps, beta2, delta_z, gamma, alpha, L
)

""" 添加接收端激光器产生的相位噪声 """
linewidth_rx = 150e3 # 激光器线宽
signal_x, signal_y = phot.phase_noise(signal_x, signal_y, sampling_rate / total_baud, linewidth_rx, total_baud)
signals = phot.phase_noise(signals, sampling_rate / total_baud, linewidth_rx, total_baud)

""" 添加收发端激光器造成的频偏,就是发射端激光器和接收端激光器的中心频率的偏移差 """

frequency_offset = 2e9 # 设置频偏,一般激光器的频偏范围为 -3G~3G Hz

signal_x, signal_y = phot.add_freq_offset(signal_x, signal_y, frequency_offset, sampling_rate)
signals = phot.add_freq_offset(signals, frequency_offset, sampling_rate)

""" 模拟接收机造成的I/Q失衡,主要考虑幅度失衡和相位失衡,这里将两者都加在虚部上 """

signal_x, signal_y = phot.add_iq_imbalance(signal_x, signal_y)
signals = phot.add_iq_imbalance(signals)

""" 加入ADC的量化噪声 """
adc_sample_rate = 160e9 # ADC采样率
adc_resolution_bits = 8 # ADC的bit位数

signal_x, signal_y = phot.add_adc_noise(signal_x, signal_y, sampling_rate, adc_sample_rate, adc_resolution_bits)
signals = phot.adc_noise(signals, sampling_rate, adc_sample_rate, adc_resolution_bits)

""" IQ正交化补偿,就是将之前的I/Q失衡的损伤补偿回来 """

signal_x, signal_y = phot.iq_freq_offset_and_compensation(
signal_x, signal_y, power_x, power_y, sampling_rate, beta2, span, L
signals = phot.iq_freq_offset_and_compensation(
signals, signals_power, sampling_rate, beta2, span, L
)

""" 接收端相应的RRC脉冲整形,具体的参数代码与发射端的RRC滤波器是一致的 """
signal_x, signal_y = shaper.rx_shape(signal_x, signal_y)
signals = shaper.rx_shape(signals)

""" 帧同步,寻找与发射端原始信号头部对应的符号 """
signal_x, signal_y, prev_symbols_x, prev_symbols_y = phot.sync_frame(
signal_x, signal_y, prev_symbols_x, prev_symbols_y, up_sampling_factor
signals, prev_symbols = phot.sync_frame(
signals, prev_symbols, up_sampling_factor
)

""" 自适应均衡,此处采用恒模算法(CMA)对收敛系数进行预收敛,再拿收敛后的滤波器系数对正式的信号使用半径定向算法(RDE)进行均衡收敛,总的思想采用梯度下降法 """
Expand All @@ -110,9 +110,8 @@
step_size_cma = 1e-9 # CMA的更新步长,梯度下降法的步长
step_size_rde = 1e-9 # RDE的更新步长,梯度下降法的步长,%% CMA和RDE主要就是损失函数不同

signal_x, signal_y = phot.adaptive_equalize(
signal_x,
signal_y,
signals = phot.adaptive_equalize(
signals,
num_tap,
cma_convergence,
ref_power_cma,
Expand All @@ -128,8 +127,8 @@
num_test_angle = 64 # BPS算法的测试角数目,具体算法原理可以参考函数内部给的参考文献
block_size = 100 # BPS算法的块长设置

signal_x, signal_y = phot.bps_restore(signal_x, signal_y, num_test_angle, block_size, bits_per_symbol)
signals = phot.bps_restore(signals, num_test_angle, block_size, bits_per_symbol)

""" 此处开始计算误码率 """

phot.bits_error_count(signal_x, signal_y, prev_symbols_x, prev_symbols_y, bits_per_symbol)
phot.bits_error_count(signals, prev_symbols, bits_per_symbol)
2 changes: 1 addition & 1 deletion phot/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@
from .bps import bps_restore
from .ber import bits_error_count
from .modem import qam_modulate
from .rx_simple import add_freq_offset, add_iq_imbalance, add_adc_noise, iq_freq_offset_and_compensation
from .rx_simple import add_freq_offset, add_iq_imbalance, adc_noise, iq_freq_offset_and_compensation
7 changes: 4 additions & 3 deletions phot/components/adaptive_equalizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@


def adaptive_equalize(
signal_x,
signal_y,
signals,
num_tap,
cma_convergence,
ref_power_cma,
Expand All @@ -33,6 +32,8 @@ def adaptive_equalize(
bits_per_symbol,
total_baud,
):
signal_x = signals[0]
signal_y = signals[1]
input_x_i = np.real(signal_x) # 求出接收端X偏振的实部信号
input_x_q = np.imag(signal_x) # 求出接收端X偏振的虚部信号
input_y_i = np.real(signal_y) # 求出接收端Y偏振的实部信号
Expand Down Expand Up @@ -64,4 +65,4 @@ def adaptive_equalize(
)
logger.info("Estimated Accurate Frequency offset: {}".format(fre_offset))

return equalization_matrix_x, equalization_matrix_y
return [equalization_matrix_x, equalization_matrix_y]
22 changes: 14 additions & 8 deletions phot/components/ber.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,43 @@
from phot import logger


def bits_error_count(signal_x, signal_y, prev_signal_x, prev_signal_y, bits_per_symbol):
def bits_error_count(signals, prev_symbols, bits_per_symbol):
"""计算误码率"""

signal_x = signals[0]
signal_y = signals[1]

prev_symbols_x = prev_symbols[0]
prev_symbols_y = prev_symbols[1]

""" 再进行一个帧同步,因为经过均衡器会存在符号的一些舍弃,因此在计算误码率(BER)之前需要再一次帧同步 """

# 对发射端信号跟均衡后信号进行同步
start_index_x_1 = fine_synchronize(prev_signal_x[:, 0].T, signal_x[0:10000, 0].reshape((1, -1)))
start_index_x_1 = fine_synchronize(prev_symbols_x[:, 0].T, signal_x[0:10000, 0].reshape((1, -1)))

# 对发射端信号利用自带函数进行移动
prev_signal_x = np.roll(prev_signal_x, -start_index_x_1)
prev_signal_y = np.roll(prev_signal_y, -start_index_x_1)
prev_symbols_x = np.roll(prev_symbols_x, -start_index_x_1)
prev_symbols_y = np.roll(prev_symbols_y, -start_index_x_1)

# 变为16的倍数
signal_x = signal_x[:-1]
signal_y = signal_y[:-1]

# 使得均衡后信号与发射端信号一样长度
prev_signal_x = prev_signal_x[0 : len(signal_x), :]
prev_signal_y = prev_signal_y[0 : len(signal_y), :]
prev_symbols_x = prev_symbols_x[0 : len(signal_x), :]
prev_symbols_y = prev_symbols_y[0 : len(signal_y), :]

""" BER COUNT 对信号进行误码率计算,将接收信号与发射信号转化为格雷编码,比较各个码元的正确率 """

ber, q_db = ber_estimate(prev_signal_y, signal_y, bits_per_symbol)
ber, q_db = ber_estimate(prev_symbols_y, signal_y, bits_per_symbol)
logger.info("Estimated overall bits error is {:.5f}".format(ber))
logger.info("Estimated Q factor is {:.5f}".format(q_db))

# 下面是遗弃版本
# modem = QAMModem(2**bits_per_symbol)

# tx_bits = modem.demodulate(
# np.concatenate((np.reshape(prev_signal_x, (-1, 1)), np.reshape(prev_signal_y, (-1, 1))), axis=0).ravel(),
# np.concatenate((np.reshape(prev_symbols_x, (-1, 1)), np.reshape(prev_symbols_y, (-1, 1))), axis=0).ravel(),
# demod_type="hard",
# )
# rx_bits = modem.demodulate(
Expand Down
7 changes: 5 additions & 2 deletions phot/components/bps.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import numpy as np


def bps_restore(signal_x, signal_y, num_test_angle, block_size, bits_per_symbol):
def bps_restore(signals, num_test_angle, block_size, bits_per_symbol):
signal_x = signals[0]
signal_y = signals[1]

# BPS算法
equalization_matrix_x, phase_x = bps_hybrid_qam(
np.real(signal_x), np.imag(signal_x), num_test_angle, block_size, bits_per_symbol
Expand All @@ -44,4 +47,4 @@ def bps_restore(signal_x, signal_y, num_test_angle, block_size, bits_per_symbol)

plot_scatter(equalization_matrix_x)

return equalization_matrix_x, equalization_matrix_y
return [equalization_matrix_x, equalization_matrix_y]
27 changes: 13 additions & 14 deletions phot/components/dac_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,22 @@
import numpy as np


def _dac_noise(signal, sampling_rate_awg, sampling_rate, dac_resolution_bits):
# 重采样信号采样率为DAC的采样率,模拟进入DAC
signal = resample_poly(signal, int(sampling_rate_awg), int(sampling_rate))
def dac_noise(signals, sampling_rate_awg, sampling_rate, dac_resolution_bits):

# 对信号进行量化,模拟加入量化噪声
signal = dac_resolution(signal, dac_resolution_bits)
return_signals = []
for signal in signals:
# 重采样信号采样率为DAC的采样率,模拟进入DAC
signal = resample_poly(signal, int(sampling_rate_awg), int(sampling_rate))

# 减去信号量化后的直流,也就是均值
signal = signal - np.mean(signal)
# 对信号进行量化,模拟加入量化噪声
signal = dac_resolution(signal, dac_resolution_bits)

# 重采样信号采样率为原来的采样率,模拟出DAC后采样率,resample_poly 为SciPy库的函数
signal = resample_poly(signal, int(sampling_rate), int(sampling_rate_awg)).reshape((-1, 1))
# 减去信号量化后的直流,也就是均值
signal = signal - np.mean(signal)

return signal
# 重采样信号采样率为原来的采样率,模拟出DAC后采样率,resample_poly 为SciPy库的函数
signal = resample_poly(signal, int(sampling_rate), int(sampling_rate_awg)).reshape((-1, 1))

return_signals.append(signal)

def dac_noise(signal_x, signal_y, sampling_rate_awg, sampling_rate, dac_resolution_bits):
return _dac_noise(signal_x, sampling_rate_awg, sampling_rate, dac_resolution_bits), _dac_noise(
signal_y, sampling_rate_awg, sampling_rate, dac_resolution_bits
)
return return_signals
20 changes: 13 additions & 7 deletions phot/components/frame_syncer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,22 @@
from phot import logger


def sync_frame(signal_x, signal_y, prev_signal_x, prev_signal_y, up_sampling_factor):
def sync_frame(signals, prev_symbols, up_sampling_factor):
"""帧同步,寻找与发射端原始信号头部对应的符号"""

signal_x = signals[0]
signal_y = signals[1]

prev_symbols_x = prev_symbols[0]
prev_symbols_y = prev_symbols[1]

# 对信号进行帧同步,找出接收信号与发射信号对准的开头
start_index_x_1 = fine_synchronize(
signal_x[0 : 10000 * up_sampling_factor : up_sampling_factor].T, prev_signal_x[0:4000].T
signal_x[0 : 10000 * up_sampling_factor : up_sampling_factor].T, prev_symbols_x[0:4000].T
)

start_index_y_1 = fine_synchronize(
signal_y[0 : 10000 * up_sampling_factor : up_sampling_factor].T, prev_signal_y[0:4000].T
signal_y[0 : 10000 * up_sampling_factor : up_sampling_factor].T, prev_symbols_y[0:4000].T
)

logger.info("两个偏振第一次对准的帧头")
Expand All @@ -44,7 +50,7 @@ def sync_frame(signal_x, signal_y, prev_signal_x, prev_signal_y, up_sampling_fac
signal_y = signal_y[:-1000]

# 调整发射端信号与接收端信号的长度
prev_signal_x = prev_signal_x[0 : int(np.floor(len(signal_x) / up_sampling_factor))]
prev_signal_y = prev_signal_y[0 : int(np.floor(len(signal_y) / up_sampling_factor))]
prev_symbols_x = prev_symbols_x[0 : int(np.floor(len(signal_x) / up_sampling_factor))]
prev_symbols_y = prev_symbols_y[0 : int(np.floor(len(signal_y) / up_sampling_factor))]

return signal_x, signal_y, prev_signal_x, prev_signal_y
return [signal_x, signal_y], [prev_symbols_x, prev_symbols_y]
7 changes: 5 additions & 2 deletions phot/components/gaussian_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import numpy as np


def gaussian_noise(signal_x, signal_y, osnr, sampling_rate):
def gaussian_noise(signals, osnr, sampling_rate):
signal_x = signals[0]
signal_y = signals[1]

# 生成均值为0,方差为1的随机噪声,此处直接产生两个偏振的噪声
noise_x, noise_y, noise_power = load_awgn(len(signal_x))

Expand All @@ -39,4 +42,4 @@ def gaussian_noise(signal_x, signal_y, osnr, sampling_rate):
signal_x = noise_x + signal_x
signal_y = noise_y + signal_y

return signal_x, signal_y
return [signal_x, signal_y]
10 changes: 6 additions & 4 deletions phot/components/modem.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from commpy.modulation import QAMModem


def qam_modulate(data_x, data_y, bits_per_symbol):
def qam_modulate(bits, bits_per_symbol):
"""QAM modulate
Args:
Expand All @@ -27,6 +27,8 @@ def qam_modulate(data_x, data_y, bits_per_symbol):
bits_per_symbol (int/float): Bits per symbol
"""
modem = QAMModem(2**bits_per_symbol)
symbols_x = modem.modulate(data_x).reshape((-1, 1)) # X偏振信号
symbols_y = modem.modulate(data_y).reshape((-1, 1)) # Y偏振信号
return symbols_x, symbols_y
symbols = []
for sequence in bits:
symbols_sequence = modem.modulate(sequence).reshape((-1, 1)) # 调制一列偏振信号
symbols.append(symbols_sequence)
return symbols
12 changes: 7 additions & 5 deletions phot/components/phase_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
from ..optical import linewidth_induced_noise


def phase_noise(signal_x, signal_y, over_sampling_rate, linewidth, symbol_rate):
phase_noise = linewidth_induced_noise(len(signal_x), over_sampling_rate, linewidth, symbol_rate)
def phase_noise(signals, over_sampling_rate, linewidth, symbol_rate):
phase_noise = linewidth_induced_noise(len(signals[0]), over_sampling_rate, linewidth, symbol_rate)

# 添加相位噪声
signal_x = signal_x * np.exp(1j * phase_noise)
signal_y = signal_y * np.exp(1j * phase_noise)
return signal_x, signal_y
return_signals = []
for signal in signals:
signal = signal * np.exp(1j * phase_noise)
return_signals.append(signal)
return return_signals
34 changes: 20 additions & 14 deletions phot/components/pulse_shaping.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,23 @@ def __init__(self, up_sampling_factor, len_filter, alpha, ts, fs):
) # up_sampling_factor*128为滤波器的长度
self.rrc_filter = rrc_filter * np.sqrt(2)

def tx_shape(self, signal_x, signal_y):
# 先进行插0上采样,上采样倍数为 up_sampling_factor
up_sampled_signal_x = upsample(signal_x, self.up_sampling_factor)
up_sampled_signal_y = upsample(signal_y, self.up_sampling_factor)

# 对信号使用RRC滤波器脉冲整形
rrc_signal_x = lfilter(self.rrc_filter, 1, up_sampled_signal_x, axis=0)
rrc_signal_y = lfilter(self.rrc_filter, 1, up_sampled_signal_y, axis=0)
return rrc_signal_x, rrc_signal_y

def rx_shape(self, signal_x, signal_y):
signal_x = lfilter(self.rrc_filter, 1, signal_x, axis=0)
signal_y = lfilter(self.rrc_filter, 1, signal_y, axis=0)
return signal_x, signal_y
def tx_shape(self, symbols):

signals = []
for item in symbols:
# 先进行插0上采样,上采样倍数为 up_sampling_factor
up_sampled_signal = upsample(item, self.up_sampling_factor)

# 对信号使用RRC滤波器脉冲整形
rrc_signal = lfilter(self.rrc_filter, 1, up_sampled_signal, axis=0)
signals.append(rrc_signal)

return signals

def rx_shape(self, signals):

return_signals = []
for signal in signals:
signal = lfilter(self.rrc_filter, 1, signal, axis=0)
return_signals.append(signal)
return return_signals
Loading

0 comments on commit 6fee633

Please sign in to comment.