calc.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # from cmath import atan
  2. import numpy as np
  3. def open_file(path):
  4. """depends on the format of file we open"""
  5. freq, re, im = [], [], []
  6. with open(path) as f:
  7. for line in f:
  8. temp = line[:-1].split(' ')
  9. for i in range(3):
  10. temp[i] = temp[i].replace(" ", "")
  11. freq.append(float(temp[0]))
  12. re.append(float(temp[1]))
  13. im.append(float(temp[2]))
  14. return freq, re, im
  15. def prepare_data(freq, re, im, fl=None):
  16. """the function takes raw data and gives vectors of eq (8)"""
  17. # finding fl from the point with smallest magnitude if argument not provided
  18. if fl is None:
  19. s = abs(np.array(re) + np.array(im) * 1j)
  20. # frequency of loaded resonance
  21. fl = freq[list(abs(s)).index(min(abs(s)))]
  22. # frequency of unloaded resonance.
  23. f0 = fl
  24. # f0 = fl does not decrease the accuracy if Q >> 100
  25. e1, e2, e3, gamma, p = [], [], [], [], []
  26. for i in range(0, len(freq)):
  27. # filling vectors
  28. t = 2 * (freq[i] - fl) / f0
  29. g = re[i] + im[i] * 1j
  30. e1.append(t)
  31. e2.append(1)
  32. e3.append(-t * g)
  33. gamma.append(g)
  34. p.append(1 / (1 + t ** 2 * (1 + re[i] ** 2 + im[i] ** 2)))
  35. data = np.array([e1, e2, e3, gamma, p], dtype=np.cdouble)
  36. return data, fl
  37. def solution(data):
  38. """ takes projections of equation (8) on vectors e1, e2, e3 and solves the equations.
  39. It is also gives matrix of equation"""
  40. c = [] # matrix of the system
  41. b = [] # matrix extension
  42. for i in range(3):
  43. c1 = np.vdot(data[i], data[4] * data[0])
  44. c2 = np.vdot(data[i], data[4] * data[1])
  45. c3 = np.vdot(data[i], data[4] * data[2])
  46. c.append([c1, c2, c3])
  47. b.append(np.vdot(data[i], data[4] * data[3]))
  48. c = np.array(c)
  49. a = np.linalg.solve(c, b)
  50. d = np.linalg.inv(c) # inverse of matrix c
  51. return a, c, d
  52. def q_factor(a):
  53. """calculation of result"""
  54. Ql = a[2].imag # Q-factor of loaded resonator
  55. diam = abs(a[1] - a[0] / a[2]) # diameter of circle
  56. k = 1 / (2 / diam - 1)
  57. Q = Ql * (1 + k) # Q-factor = result
  58. return Ql, diam, k, Q
  59. def recalculation_of_data(data, a, c, d, error=False):
  60. """preparation data for the next iteration of solving system"""
  61. # data = np.array([e1, e2, e3, gamma, p], dtype=complex), t = e1, 1 = e2
  62. eps = np.array(a[0] * data[0] + a[1] * data[1] - a[2] * data[0] * data[3] - data[3], dtype=complex)
  63. # eps is eq(7) line's errors
  64. S2 = np.dot(abs(data[4]), abs(eps) * abs(eps)) # the weighted squared sum of errors
  65. sigma2A = [] # the square of standart deviation coefficients a
  66. temp = c[0][0] * d[0][0] + c[1][1] * d[1][1] + c[2][2] * d[2][2]
  67. for i in range(3):
  68. sigma2A.append(d[i][i] * S2 / temp)
  69. for i in range(len(data[4])): # recalculation of weight coefficients P
  70. data[4][i] = 1 / (
  71. data[0][i] ** 2 * sigma2A[0] + sigma2A[1] + data[0][i] ** 2 * sigma2A[2] * (abs(data[3][i]) ** 2))
  72. if error:
  73. return abs(np.array(sigma2A))
  74. else:
  75. return data
  76. def recalculating(data, a, c, d, n, printing=False):
  77. for i in range(2, n):
  78. data = recalculation_of_data(data, a, c, d)
  79. a, c, d = solution(data)
  80. Ql, diam, k, Q = q_factor(a)
  81. sigma2A = recalculation_of_data(data, a, c, d, error=True)
  82. sigmaQ0, sigmaQl = random_deviation(a, sigma2A, diam, k, Ql)
  83. if printing:
  84. print(f"Q = {Q} +- {sigmaQ0}, if i == {i}")
  85. return a, c, d, Ql, diam, k, Q, sigma2A, sigmaQ0, sigmaQl, data
  86. def random_deviation(a, sigma2A, diam, k, Ql):
  87. """defines standart deviations of values"""
  88. sigmaQl = sigma2A[2] ** 0.5
  89. sigmaDiam = (sigma2A[0] / (abs(a[2]) ** 2) + sigma2A[1] + abs(a[0] / a[2] / a[2]) ** 2 * sigma2A[2]) ** 0.5
  90. sigmaK = 2 * sigmaDiam / ((2 - diam) ** 2)
  91. sigmaQ0 = ((1 + k) ** 2 * sigma2A[2] + Ql ** 2 * sigmaK ** 2) ** 0.5
  92. return sigmaQ0, sigmaQl
  93. def apply(filename):
  94. freq, re, im = open_file(filename)
  95. data = prepare_data(freq, re, im)
  96. a, c, d = solution(data)
  97. a, c, d, Ql, diam, k, Q, sigma2A, sigmaQ0, sigmaQl, data = recalculating(data, a, c, d, 10, printing=True)
  98. def fl_fitting(freq, re, im, correction):
  99. """providing an option to find actual fl"""
  100. data, fl = prepare_data(freq, re, im)
  101. a, c, d = solution(data)
  102. Ql, Q, sigmaQ0, sigmaQl = None, None, None, None
  103. # Repeated curve fitting
  104. # 1.189 of Qfactor Matlab
  105. # fl2 = 0
  106. # g_d=0
  107. # g_c=0
  108. for x in range(0, 3):
  109. g_c = (np.conj(a[2]) * a[1] - a[0]) / (np.conj(a[2]) - a[2])
  110. g_d = a[0] / a[2]
  111. g_2 = 2 * g_c - g_d
  112. dt = (a[1] - g_2) / (g_2 * a[2] - a[0])
  113. fl2 = fl * (1 + np.real(dt) / 2)
  114. data, fl = prepare_data(freq, re, im, fl2)
  115. a, c, d = solution(data)
  116. a, c, d, Ql, diam, k, Q, sigma2A, sigmaQ0, sigmaQl, data = recalculating(data, a, c, d, 20)
  117. # taking into account coupling losses on page 69 of Qfactor Matlab
  118. # to get results similar to example program
  119. if correction:
  120. phi1=np.arctan(np.double(g_d.imag/g_d.real)) # 1.239
  121. phi2=np.arctan(np.double((g_c.imag-g_d.imag)/(g_c.real-g_d.real)))
  122. phi=-phi1+phi2
  123. d_s=(1-np.abs(g_d)**2)/(1-np.abs(g_d)*np.cos(phi))
  124. diam = abs(a[1] - a[0] / a[2])
  125. qk=1/(d_s/diam-1)
  126. sigma2A = recalculation_of_data(data, a, c, d, error=True)
  127. sigmaQ0, sigmaQl = random_deviation(a, sigma2A, diam, k, Ql)
  128. Q = Ql * (1 + qk) # Q-factor = result
  129. # print(f"Q0 = {Q} +- {sigmaQ0}")
  130. return Q, sigmaQ0, Ql, sigmaQl, a