供应商提供了两个产品的S参数文件(s4p 格式),需要对这两个S参数文件进行处理,提取出SDD21插损值,并与IEEE标准进行比较。
Python 对该 s4p 格式的S-parameters 文件进行处理,通过单端转差分的公式,获取SDD21参数
这个s4p 文件表明,这是4端口的16个S参数。通过标准Touchstone 格式可知,该文件里 #HZ S RI R 50, 表示第一列是单位为Hz的频率,后面的参数是S参数,用实部,虚部表示,参考阻抗是50欧姆
从touchstone file format 可以得知,这个s4p 里是4端口网络的单端S参数。
因为Port 1 与 Port 3 组成一对差分线,Port 2 与 Port 4 组成一对差分线,则有
SDD11=0.5*(S11-S13-S31+S33)
SDD12=0.5*(S12-S14-S32+S34)
SDD21=0.5*(S21-S23-S41+S43)
SDD22=0.5*(S22-S24-S42+S44)
在这里SDD11是输入端回损,SDD12是差分线的反向隔离系数, SDD21是正向增益/插损,这里称为差分线的插入损耗特性,SDD22是输出端回损
(1)由于S 参数是以 实部+虚部方式表示,因此S参数的加减法遵循实数域的加法规则,即 实部与实部相加,虚部与虚部相加
(2)将实部与虚部转换为幅度(dB)与相位,则是通过:
magnitude[dB] = 20 * log(sqr(ReRe+ ImIm))
phase = arctan(Im / Re)
在这里插入代码片
import numpy as np
import matplotlib.pyplot as plt
import math
Data_SFP = open("SFP+_HCB_wo_conn_18p5in_M_SMA_RevA.s4p").readlines()
Data_SFP28 = open("SFP28_HCB_wo_conn_12in_M_SMA_RevA.s4p").readlines()
with open('SFP_SDD21_data.txt',mode='w') as SFP_SDD21_data:
for i in range(9,len(Data_SFP),5):
Freq = float(Data_SFP[i].split()[0])/1000000
SFP_SDD21_data.write(str(Freq))
SFP_SDD21_data.write(" ")
S21_R = Data_SFP[i+1].split()[0]
S21_I = Data_SFP[i+1].split()[1]
S23_R = Data_SFP[i+1].split()[4]
S23_I = Data_SFP[i+1].split()[5]
S41_R = Data_SFP[i+3].split()[0]
S41_I = Data_SFP[i+3].split()[1]
S43_R = Data_SFP[i+3].split()[4]
S43_I = Data_SFP[i+3].split()[5]
SDD21_R=0.5*(float(S21_R)-float(S23_R)-float(S41_R)+float(S43_R))
SDD21_I=0.5*(float(S21_I)-float(S23_I)-float(S41_I)+float(S43_I))
SDD21=20*math.log10(math.sqrt(float(SDD21_R)*float(SDD21_R) + float(SDD21_I)*float(SDD21_I)))
# print(Freq,S12_R, type(S12_R),S12_I, type(S12_I))
SFP_SDD21_data.write(str(SDD21))
SFP_SDD21_data.write("\n")
with open('SFP28_SDD21_data.txt',mode='w') as SFP28_SDD21_data:
for i in range(9,len(Data_SFP28),5):
Freq = float(Data_SFP28[i].split()[0])/1000000
SFP28_SDD21_data.write(str(Freq))
SFP28_SDD21_data.write(" ")
SDD21_R=0.5*(float(Data_SFP28[i+1].split()[0])-float(Data_SFP28[i+1].split()[4])-float(Data_SFP28[i+3].split()[0])+float(Data_SFP28[i+3].split()[4]))
SDD21_I=0.5*(float(Data_SFP28[i+1].split()[1])-float(Data_SFP28[i+1].split()[5])-float(Data_SFP28[i+3].split()[1])+float(Data_SFP28[i+3].split()[5]))
SDD21=20*math.log10(math.sqrt(float(SDD21_R)*float(SDD21_R) + float(SDD21_I)*float(SDD21_I)))
SFP28_SDD21_data.write(str(SDD21))
SFP28_SDD21_data.write("\n")
SFP_SDD21_plot = np.loadtxt("SFP_SDD21_data.txt")
SFP28_SDD21_plot = np.loadtxt("SFP28_SDD21_data.txt")
SDD21_x=SFP_SDD21_plot[0:2500,0]
SFP_SDD21_y=SFP_SDD21_plot[0:2500,1]
SFP28_SDD21_y=SFP28_SDD21_plot[:,1]
IEEE_86A_y=[]
IEEE_86A_ymax=[]
IEEE_86A_ymin=[]
for i in range(0,1500):
IEEE_86A_y.append(float(-0.01-0.25*math.sqrt(float(SDD21_x[i])/1000)-0.0916*float(SDD21_x[i])/1000))
if i<1110:
IEEE_86A_ymax.append(float(-0.01-0.25*math.sqrt(float(SDD21_x[i])/1000)-0.0916*float(SDD21_x[i])/1000)*1.15)
IEEE_86A_ymin.append(float(-0.01-0.25*math.sqrt(float(SDD21_x[i])/1000)-0.0916*float(SDD21_x[i])/1000)*0.85)
else:
IEEE_86A_ymax.append(float(-0.01-0.25*math.sqrt(float(SDD21_x[i])/1000)-0.0916*float(SDD21_x[i])/1000)*1.25)
IEEE_86A_ymin.append(float(-0.01-0.25*math.sqrt(float(SDD21_x[i])/1000)-0.0916*float(SDD21_x[i])/1000)*0.75)
plt.plot(SDD21_x,SFP_SDD21_y,linewidth = 1,label='SFP+ HCB')
plt.plot(SDD21_x,SFP28_SDD21_y,linewidth = 1,label='SFP28 HCB')
plt.plot(SDD21_x[0:1500],IEEE_86A_y,linewidth = 1,label='SFF8431_Spec_Recomamnd')
plt.plot(SDD21_x[0:1500],IEEE_86A_ymax,linewidth = 1,label='SFF8431_Spec_Max',color="red")
plt.plot(SDD21_x[0:1500],IEEE_86A_ymin,linewidth = 1,label='SFF8431_Spec_Min',color="red")
plt.xlabel('Frequency (MHZ)', fontsize=12)
plt.ylabel(' SDD21(dB)', fontsize=12)
plt.xticks(fontsize = 12)
plt.yticks(fontsize = 12)
plt.legend()
plt.show()