def test_yz(self): tinyfloat = 1e-12 ntwk = rf.Network() ntwk.z0 = npy.array([28,75+3j]) ntwk.f = npy.array([1000, 2000]) ntwk.s = rf.z2s(npy.array([[[1+1j,5,11],[40,5,3],[16,8,9+8j]], [[1,20,3],[14,10,16],[27,18,-19-2j]]])) self.assertTrue((abs(rf.y2z(ntwk.y)-ntwk.z) < tinyfloat).all()) self.assertTrue((abs(rf.y2s(ntwk.y, ntwk.z0)-ntwk.s) < tinyfloat).all()) self.assertTrue((abs(rf.z2y(ntwk.z)-ntwk.y) < tinyfloat).all()) self.assertTrue((abs(rf.z2s(ntwk.z, ntwk.z0)-ntwk.s) < tinyfloat).all())
def test_network_from_z_or_y(self): ' Construct a network from its z or y parameters ' # test for both real and complex char. impedance # and for 2 frequencies z0 = [npy.random.rand(), npy.random.rand() + 1j * npy.random.rand()] freqs = npy.array([1, 2]) # generate arbitrary complex z and y z_ref = npy.random.rand(2, 3, 3) + 1j * npy.random.rand(2, 3, 3) y_ref = npy.random.rand(2, 3, 3) + 1j * npy.random.rand(2, 3, 3) # create networks from z or y and compare ntw.z to the reference # check that the conversions work for all s-param definitions for s_def in S_DEFINITIONS: ntwk = rf.Network(s_def=s_def) ntwk.z0 = rf.fix_z0_shape(z0, 2, 3) ntwk.f = freqs # test #1: define the network directly from z ntwk.z = z_ref npy.testing.assert_allclose(ntwk.z, z_ref) # test #2: define the network from s, after z -> s (s_def is important) ntwk.s = rf.z2s(z_ref, z0, s_def=s_def) npy.testing.assert_allclose(ntwk.z, z_ref) # test #3: define the network directly from y ntwk.y = y_ref npy.testing.assert_allclose(ntwk.y, y_ref) # test #4: define the network from s, after y -> s (s_def is important) ntwk.s = rf.y2s(y_ref, z0, s_def=s_def) npy.testing.assert_allclose(ntwk.y, y_ref)
def test_sparam_conversion_with_complex_char_impedance(self): ''' Renormalize a 2-port network wrt to complex characteristic impedances using power-waves definition of s-param Example based on scikit-rf issue #313 ''' f0 = rf.Frequency(75.8, npoints=1, unit='GHz') s0 = npy.array([[-0.194 - 0.228j, -0.721 + 0.160j], [-0.721 + 0.160j, +0.071 - 0.204j]]) ntw = rf.Network(frequency=f0, s=s0, z0=50, name='dut') # complex characteristic impedance to renormalize to zdut = 100 + 10j # reference solutions obtained from ANSYS Circuit or ADS (same res) # case 1: z0=[50, zdut] s_ref = npy.array( [[[-0.01629813 - 0.29764199j, -0.6726785 + 0.24747539j], [-0.6726785 + 0.24747539j, -0.30104687 - 0.10693578j]]]) npy.testing.assert_allclose(rf.z2s(ntw.z, z0=[50, zdut]), s_ref) npy.testing.assert_allclose( rf.renormalize_s(ntw.s, [50, 50], [50, zdut]), s_ref) # case 2: z0=[zdut, zdut] s_ref = npy.array([[[ -0.402829859501534 - 0.165007172677339j, -0.586542065592524 + 0.336098534178339j ], [ -0.586542065592524 + 0.336098534178339j, -0.164707376748782 - 0.21617153431756j ]]]) npy.testing.assert_allclose(rf.z2s(ntw.z, z0=[zdut, zdut]), s_ref) npy.testing.assert_allclose( rf.renormalize_s(ntw.s, [50, 50], [zdut, zdut]), s_ref) # Compararing Z and Y matrices from reference ones (from ADS) # Z or Y matrices do not depend of characteristic impedances. # Precision is 1e-4 due to rounded results in ADS export files z_ref = npy.array([[[34.1507 - 65.6786j, -37.7994 + 73.7669j], [-37.7994 + 73.7669j, 55.2001 - 86.8618j]]]) npy.testing.assert_allclose(ntw.z, z_ref, atol=1e-4) y_ref = npy.array([[[0.0926 + 0.0368j, 0.0770 + 0.0226j], [0.0770 + 0.0226j, 0.0686 + 0.0206j]]]) npy.testing.assert_allclose(ntw.y, y_ref, atol=1e-4)
def test_conversions(self): #Converting to other format and back to S-parameters should return the original network tinyfloat = 1e-12 for test_z0 in (50, 10, 90+10j, 4-100j): for test_ntwk in (self.ntwk1, self.ntwk2, self.ntwk3): ntwk = rf.Network(s=test_ntwk.s, f=test_ntwk.f, z0=test_z0) self.assertTrue((abs(rf.a2s(rf.s2a(ntwk.s, test_z0), test_z0)-ntwk.s) < tinyfloat).all()) self.assertTrue((abs(rf.z2s(rf.s2z(ntwk.s, test_z0), test_z0)-ntwk.s) < tinyfloat).all()) self.assertTrue((abs(rf.y2s(rf.s2y(ntwk.s, test_z0), test_z0)-ntwk.s) < tinyfloat).all()) self.assertTrue((abs(rf.t2s(rf.s2t(ntwk.s))-ntwk.s) < tinyfloat).all())
def test_conversions(self): #Converting to other format and back to S-parameters should return the original network for test_z0 in (50, 10, 90+10j, 4-100j): for test_ntwk in (self.ntwk1, self.ntwk2, self.ntwk3): ntwk = rf.Network(s=test_ntwk.s, f=test_ntwk.f, z0=test_z0) npy.testing.assert_allclose(rf.a2s(rf.s2a(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.z2s(rf.s2z(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.y2s(rf.s2y(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.h2s(rf.s2h(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.t2s(rf.s2t(ntwk.s)), ntwk.s) npy.testing.assert_allclose(rf.t2s(rf.s2t(self.Fix.s)), self.Fix.s)
def test_conversions(self): #Converting to other format and back to S-parameters should return the original network s_random = npy.random.uniform(-10, 10, (self.freq.npoints, 2, 2)) + 1j * npy.random.uniform(-10, 10, (self.freq.npoints, 2, 2)) ntwk_random = rf.Network(s=s_random, frequency=self.freq) for test_z0 in (50, 10, 90+10j, 4-100j): for test_ntwk in (self.ntwk1, self.ntwk2, self.ntwk3, ntwk_random): ntwk = rf.Network(s=test_ntwk.s, f=test_ntwk.f, z0=test_z0) npy.testing.assert_allclose(rf.a2s(rf.s2a(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.z2s(rf.s2z(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.y2s(rf.s2y(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.h2s(rf.s2h(ntwk.s, test_z0), test_z0), ntwk.s) npy.testing.assert_allclose(rf.t2s(rf.s2t(ntwk.s)), ntwk.s) npy.testing.assert_allclose(rf.t2s(rf.s2t(self.Fix.s)), self.Fix.s)
def s(self) -> np.ndarray: """Get the scattering parameters as an NxN array, N being the number of ports. Does NOT take into account possible deembbeding. Returns ------- s : :class:`numpy.ndarray` of shape n x n scattering parameters of the TOPICA result """ # Zref = np.diag(np.repeat(self.z0, self.nbPorts)) # G = 1/np.sqrt(np.real(self.z0)) # Gref = np.diag(np.repeat(G, self.nbPorts)) # # Z to S formulae # s = Gref @ (self.z - Zref) @ (np.linalg.inv(self.z + Zref)) @ (np.linalg.inv(Gref)) _z = self.z.reshape(1, self.nbPorts, self.nbPorts) s = rf.z2s(_z, z0=self.z0) return (s)
def short_deembed(data, data_open, data_short, datadir=None): ''' Subtracts admittance of open from that of device and short, then subtracts dembeded short impedance from device and saves results in new network n. If save_deembedded is defined, saves a copy of the deembedded short and device networks in snp format. ''' d = open_deembed(data, data_open, datadir) # s = open_deembed(data_short, data_open, datadir) s = open_Network(data_short) n = rf.Network() n.frequency = d.frequency n.z0 = d.z0 n.name = d.name n.z = d.z - s.z n.s = rf.z2s(n.z) n.y = rf.y2z(n.z) if datadir: savedir = os.path.join(datadir, 'deembedded_openshort') if not os.path.isfile(os.path.join(savedir, n.name)): n.write_touchstone(dir=savedir) return n