def find_f_res(): # Secant method root finding algorithm # Loosely based upon http://www.see.ed.ac.uk/~jwp/JavaScript/programming/chop2.html x_1 = c_0 / l_w_eff / 40 x_2 = x_1 * 100 max_tries = 40 for tries in range(-1, max_tries + 1): # <= max if tries == -1: x = x_1 if tries == 0: x = x_2 if tries > 0: x = (x_1 + x_2) / 2 # First, solve the sheath helix dispersion function for tau at frequency x. omega = 2 * pi * x k_0 = omega / c_0 F = lambda tau: K1(tau * a) * I1(tau * a) / K0(tau * a) / I0( tau * a) - (tau / k_0 * tan(psi))**2 tau_1 = k_0 * cot(psi)**2 - k_0**2 # an estimate tau_2 = k_0 # another estimate zero = fzero(F, tau_1, tau_2) if zero['error_code'] == 2: alert( 'An error occurred when solving for the resonant frequency.\n' + 'However, all shown results are useable.\n\n' + zero['error_msg']) document['f_res'].value = '' tau = zero['zero'] # Then, check for resonance. # β² = k_0² + τ² # βℓ → π/2 fx = sqrt(k_0**2 + tau**2) * l - pi / 2 if tries == -1: fx_1 = fx if tries == 0: fx_2 = fx if tries <= 0: continue if fx * fx_1 > 0: fx_1 = fx x_1 = x else: fx_2 = fx x_2 = x return x
def myCalculate(D, N, l, d, f, plating_nr='hard-drawn copper'): try: rho = plating[plating_nr].rho * 1E-9 mu_r_w = plating[plating_nr].mu_r print('rho = {:.2f}'.format(rho * 1E9)) print('mu_r_w = {:.2f}'.format(mu_r_w)) l = float(l) * 1E-3 p = l / N D = float(D) * 1E-3 d = float(d) * 1E-3 Phi = lookup_Phi(l, D, p, d) D_eff = D - d * (1 - 1 / sqrt(Phi)) # Correction factors if l <= D_eff: # The short coil expression gives a value that agrees better with the AGM result. k_L = 1 + 0.383901 * (l / D_eff)**2 + 0.017108 * (l / D_eff)**4 k_L /= 1 + 0.258952 * (l / D_eff)**2 k_L *= log(4 * D_eff / l) - 0.5 k_L += 0.093842 * (l / D_eff)**2 + 0.002029 * ( l / D_eff)**4 - 0.000801 * (l / D_eff)**6 k_L *= 2 / pi * l / D_eff else: k_L = 1 + 0.383901 * (D_eff / l)**2 + 0.017108 * (D_eff / l)**4 k_L /= 1 + 0.258952 * (D_eff / l)**2 k_L -= 4 / 3 / pi * D_eff / l k_s = 5 / 4 - log(2 * p / d) c_9 = -log(2 * pi) + 3 / 2 + 0.33084236 + 1 / 120 - 1 / 504 + 0.0011925 k_m = log(2 * pi) - 3 / 2 - log(N) / 6 / N - 0.33084236 / N - 1 / ( 120 * N**3) + 1 / (504 * N**5) - 0.0011925 / N**7 + c_9 / N**9 # Effective series AC resistance l_w_phys = sqrt((N * pi * D)**2 + l**2) l_w_eff = sqrt((N * pi * D_eff)**2 + l**2) f = float(f) * 1E6 delta_i = sqrt(rho / pi / f / mu_0 / mu_r_w) R_eff_s = rho * l_w_eff R_eff_s /= pi * (d * delta_i - delta_i**2) R_eff_s *= Phi if (N > 1): R_eff_s *= (N - 1) / N # Corrected current-sheet geometrical formula mu_r_core = 1 L_s = pi * (D_eff * N)**2 / 4 / l * k_L L_s -= D_eff * N * (k_s + k_m) / 2 L_s *= mu_r_core * mu_0 psi = atan(p / pi / D_eff) # Copy & paste text field offset = 28 print('{:{offset}} D = {:3.1f} mm'.format('mean diameter of the coil', D / 1e-3, offset=offset)) print('{:{offset}} N = {:4.1f}'.format('number of turns', N, offset=offset)) print('{:{offset}} ℓ = {:3.1f} mm'.format('length of the coil', l / 1e-3, offset=offset)) print('{:{offset}} d = {:3.1f} mm'.format('wire or tubing diameter', d / 1e-3, offset=offset)) print('{:{offset}} f = {:3.1f} MHz'.format('design frequency', f / 1e6, offset=offset)) print(' The (plating) material is {}.\n'.format( plating[plating_nr].description)) print('\nINTERMEDIATE RESULTS') print(' {:{offset}} p = {:3.1f} mm'.format('winding pitch', p / 1e-3, offset=offset)) print(' {:{offset}} ℓ_w_phys = {:3.1f} mm'.format( 'physical conductor length', l_w_phys / 1e-3, offset=offset)) print(' {:{offset}} ψ = {:3.1f}°'.format('effective pitch angle', psi, offset=offset)) # Characteristic impedance of the sheath helix waveguide mode offset = 55 try: omega = 2 * pi * f k_0 = omega / c_0 a = D_eff / 2 # Sheath helix dispersion function F = lambda tau: K1(tau * a) * I1(tau * a) / (K0(tau * a) * I0( tau * a)) - (tau / k_0 * tan(psi))**2 tau_1 = k_0 # smallest tau estimate tau_2 = k_0 * cot(psi)**2 # largest tau estimate zero = fzero(F, tau_1, tau_2) tau = zero['zero'] beta = sqrt(k_0**2 + tau**2) Z_c = 60 * beta / k_0 * I0(tau * a) * K0(tau * a) # Effective equivalent circuit # Corrected sheath helix waveguide formula L_eff_s = Z_c / omega * tan(beta * l) * k_L L_eff_s -= mu_0 * D_eff * N * (k_s + k_m) / 2 X_eff_s = omega * L_eff_s Q_eff = X_eff_s / R_eff_s # Effective circuit results in copy & paste text field print('\nEffective equivalent circuit ') print('{:{offset}} L_eff_s = {:1.3e} H'.format( 'effective series inductance @ design frequency', L_eff_s, offset=offset)) print('{:{offset}} X_eff_s = {:1.3e} Ω'.format( 'effective series reactance @ design frequency', X_eff_s, offset=offset)) print('{:{offset}} R_eff_s = {:3.3e} Ω'.format( 'effective series AC resistance @ design frequency', R_eff_s, offset=offset)) print('{:{offset}} Q_eff = {:3.1f}'.format( 'effective unloaded quality factor @ design frequency', Q_eff, offset=offset)) except: print('\nLumped circuit equivalent') print(' {:{offset}} L_s = {:1.3e} Hy'.format( 'f-independent series inductance; geometrical formula', L_s / 1e-6, offset=offset)) print( ' An error occurred when solving the dispersion function!') print(' However, all shown results are useable.') try: # Lumped equivalent circuit R_p = (Q_eff**2 + 1) * R_eff_s X_L_s = omega * L_s # https://en.wikipedia.org/wiki/Quadratic_equation#Reduced_quadratic_equation P = R_p / (2 * X_L_s) Q_L = P + sqrt(P**2 - 1) R_s = X_L_s / Q_L X_eff_p = (Q_eff**2 + 1) / Q_eff**2 * X_eff_s X_L_p = (Q_L**2 + 1) / Q_L**2 * X_L_s L_p = X_L_p / omega X_C_p = X_eff_p * X_L_p / (X_L_p - X_eff_p) C_p = -1 / omega / X_C_p # Lumped circuit results in copy & paste text field print('\nLumped circuit equivalent (serie)') print(' {:{offset}} L_s = {:1.3e} Hy'.format( 'f-independent series inductance; geometrical formula', L_s, offset=offset)) print(' {:{offset}} R_s = {:1.3e} Ω'.format( 'series AC resistance @ design frequency', R_s, offset=offset)) print(' {:{offset}} C_p = {:1.3e} F'.format( 'parallel stray capacitance @ design frequency', C_p, offset=offset)) print('\nLumped circuit equivalent (paralelo)') print(' {:{offset}} L_p = {:1.3e} Hy'.format( 'f-independent series inductance; geometrical formula', L_s, offset=offset)) print(' {:{offset}} R_p = {:1.3e} Ω'.format( 'series AC resistance @ design frequency', R_p, offset=offset)) print(' {:{offset}} C_p = {:1.3e} F'.format( 'parallel stray capacitance @ design frequency', C_p, offset=offset)) except: print('\nLumped circuit equivalent') print(' {:{offset}} L_s = {:1.3e} Hy\n'.format( 'f-independent series inductance; geometrical formula', L_s, offset=offset)) print(' No lumped circuit equivalent is available!\n') print(' However, all shown results are useable.\n') offset = 40 try: # Self‑resonant frequency f_res = find_f_res(l_w_eff, a, l, psi) # Resonant frequency in copy & paste text field print('{:{offset}} f_res = {:1.3e} Hz\n'.format( 'Self-resonant frequency', f_res, offset=offset)) except: print( ' An error occurred when solving for the self-resonant frequency!\n' ) print(' However, all shown results are useable.\n') except: #document['txt'].clear() # COMMENT THIS LINE FOR TESTING PROGRESS outputs = [ 'p', 'Phi', 'D_eff', 'k_L', 'k_s', 'k_m', 'l_w_phys', 'l_w_eff', 'delta_i', 'R_eff_s', 'L_s', 'psi' ] outputs += [ 'beta', 'Z_c', 'L_eff_s', 'X_eff_s', 'Q_eff', 'R_s', 'C_p', 'f_res' ]
def calculate(event): document['txt'].clear() try: plating_nr = int(document['plating'].value) rho = plating[plating_nr].rho * 1E-9 mu_r_w = plating[plating_nr].mu_r document['rho'].value = '%.2f' % (rho * 1E9) document['mu_r_w'].value = '%.8f' % mu_r_w N = float(document['N'].value) global l l = float(document['l'].value) * 1E-3 p = l / N document['p'].value = '%.2f' % round(p * 1E3, 2) D = float(document['D'].value) * 1E-3 d = float(document['d'].value) * 1E-3 Phi = lookup_Phi(l, D, p, d) document['Phi'].value = '%.2f' % round(Phi, 2) D_eff = D - d * (1 - 1 / sqrt(Phi)) document['D_eff'].value = '%.2f' % round(D_eff * 1E3, 2) # Correction factors if l <= D_eff: # The short coil expression gives a value that agrees better with the AGM result. k_L = 1 + 0.383901 * (l / D_eff)**2 + 0.017108 * (l / D_eff)**4 k_L /= 1 + 0.258952 * (l / D_eff)**2 k_L *= log(4 * D_eff / l) - 0.5 k_L += 0.093842 * (l / D_eff)**2 + 0.002029 * ( l / D_eff)**4 - 0.000801 * (l / D_eff)**6 k_L *= 2 / pi * l / D_eff else: k_L = 1 + 0.383901 * (D_eff / l)**2 + 0.017108 * (D_eff / l)**4 k_L /= 1 + 0.258952 * (D_eff / l)**2 k_L -= 4 / 3 / pi * D_eff / l document['k_L'].value = '%.6f' % round(k_L, 6) k_s = 5 / 4 - log(2 * p / d) document['k_s'].value = '%.6f' % round(k_s, 6) c_9 = -log(2 * pi) + 3 / 2 + 0.33084236 + 1 / 120 - 1 / 504 + 0.0011925 k_m = log(2 * pi) - 3 / 2 - log(N) / 6 / N - 0.33084236 / N - 1 / ( 120 * N**3) + 1 / (504 * N**5) - 0.0011925 / N**7 + c_9 / N**9 document['k_m'].value = '%.8f' % round(k_m, 8) # Effective series AC resistance l_w_phys = sqrt((N * pi * D)**2 + l**2) document['l_w_phys'].value = '%.1f' % round(l_w_phys * 1E3, 1) global l_w_eff l_w_eff = sqrt((N * pi * D_eff)**2 + l**2) document['l_w_eff'].value = '%.1f' % round(l_w_eff * 1E3, 1) f = float(document['f'].value) * 1E6 delta_i = sqrt(rho / pi / f / mu_0 / mu_r_w) document['delta_i'].value = '%.2f' % round(delta_i * 1E6, 2) R_eff_s = rho * l_w_eff R_eff_s /= pi * (d * delta_i - delta_i**2) R_eff_s *= Phi if (N > 1): R_eff_s *= (N - 1) / N document['R_eff_s'].value = '%.3f' % round(R_eff_s, 3) # Corrected current-sheet geometrical formula mu_r_core = 1 L_s = pi * (D_eff * N)**2 / 4 / l * k_L L_s -= D_eff * N * (k_s + k_m) / 2 L_s *= mu_r_core * mu_0 document['L_s'].value = '%.3f' % round(L_s * 1E6, 3) global psi psi = atan(p / pi / D_eff) document['psi'].value = '%.2f' % round(psi / pi * 180, 2) # Copy & paste text field t = time.time() document['txt'] <= 'QOIL™ — https://hamwaves.com/qoil/ — v{}\n'.format( VERSION) document['txt'] <= time.strftime(' Coil design %Y-%m-%d %H:%M\n', time.localtime(t)) offset = 28 document['txt'] <= '\nINPUT\n' document['txt'] <= ' {:{offset}} D = {} mm\n'.format( 'mean diameter of the coil', document['D'].value, offset=offset) document['txt'] <= ' {:{offset}} N = {}\n'.format( 'number of turns', document['N'].value, offset=offset) document['txt'] <= ' {:{offset}} ℓ = {} mm\n'.format( 'length of the coil', document['l'].value, offset=offset) document['txt'] <= ' {:{offset}} d = {} mm\n'.format( 'wire or tubing diameter', document['d'].value, offset=offset) document['txt'] <= ' {:{offset}} f = {} MHz\n'.format( 'design frequency', document['f'].value, offset=offset) document['txt'] <= ' The (plating) material is {}.\n'.format( plating[plating_nr].description) document['txt'] <= '\nINTERMEDIATE RESULTS\n' document['txt'] <= ' {:{offset}} p = {} mm\n'.format( 'winding pitch', document['p'].value, offset=offset) document['txt'] <= ' {:{offset}} ℓ_w_phys = {} mm\n'.format( 'physical conductor length', document['l_w_phys'].value, offset=offset) document['txt'] <= ' {:{offset}} ψ = {}°\n'.format( 'effective pitch angle', document['psi'].value, offset=offset) # Characteristic impedance of the sheath helix waveguide mode offset = 55 try: omega = 2 * pi * f k_0 = omega / c_0 global a a = D_eff / 2 # Sheath helix dispersion function F = lambda tau: K1(tau * a) * I1(tau * a) / (K0(tau * a) * I0( tau * a)) - (tau / k_0 * tan(psi))**2 tau_1 = k_0 # smallest tau estimate tau_2 = k_0 * cot(psi)**2 # largest tau estimate zero = fzero(F, tau_1, tau_2) tau = zero['zero'] beta = sqrt(k_0**2 + tau**2) document['beta'].value = '%.4f' % round(beta, 4) Z_c = 60 * beta / k_0 * I0(tau * a) * K0(tau * a) document['Z_c'].value = '%.1f' % round(Z_c, 1) # Effective equivalent circuit # Corrected sheath helix waveguide formula L_eff_s = Z_c / omega * tan(beta * l) * k_L L_eff_s -= mu_0 * D_eff * N * (k_s + k_m) / 2 document['L_eff_s'].value = '%.3f' % round(L_eff_s * 1E6, 3) X_eff_s = omega * L_eff_s document['X_eff_s'].value = '%.1f' % round(X_eff_s, 1) Q_eff = X_eff_s / R_eff_s document['Q_eff'].value = '%d' % int(Q_eff) # Effective circuit results in copy & paste text field document['txt'] <= '\nRESULTS\n' document['txt'] <= ' Effective equivalent circuit\n' document['txt'] <= ' {:{offset}} L_eff_s = {} μH\n'.format( 'effective series inductance @ design frequency', document['L_eff_s'].value, offset=offset) document['txt'] <= ' {:{offset}} X_eff_s = {} Ω\n'.format( 'effective series reactance @ design frequency', document['X_eff_s'].value, offset=offset) document['txt'] <= ' {:{offset}} R_eff_s = {} Ω\n'.format( 'effective series AC resistance @ design frequency', document['R_eff_s'].value, offset=offset) document['txt'] <= ' {:{offset}} Q_eff = {}\n'.format( 'effective unloaded quality factor @ design frequency', document['Q_eff'].value, offset=offset) except: document['txt'] <= ' Lumped circuit equivalent\n' document['txt'] <= ' {:{offset}} L_s = {} μH\n'.format( 'f-independent series inductance; geometrical formula', document['L_s'].value, offset=offset) document[ 'txt'] <= ' An error occurred when solving the dispersion function!\n' document['txt'] <= ' However, all shown results are useable.\n' outputs = [ 'beta', 'Z_c', 'L_eff_s', 'X_eff_s', 'Q_eff', 'R_s', 'C_p', 'f_res' ] for i in range(len(outputs)): document[outputs[i]].value = '' try: # Lumped equivalent circuit R_p = (Q_eff**2 + 1) * R_eff_s X_L_s = omega * L_s # https://en.wikipedia.org/wiki/Quadratic_equation#Reduced_quadratic_equation P = R_p / (2 * X_L_s) Q_L = P + sqrt(P**2 - 1) R_s = X_L_s / Q_L document['R_s'].value = '%.3f' % round(R_s, 3) X_eff_p = (Q_eff**2 + 1) / Q_eff**2 * X_eff_s X_L_p = (Q_L**2 + 1) / Q_L**2 * X_L_s X_C_p = X_eff_p * X_L_p / (X_L_p - X_eff_p) C_p = -1 / omega / X_C_p document['C_p'].value = '%.1f' % round(C_p * 1E12, 1) # Lumped circuit results in copy & paste text field document['txt'] <= ' Lumped circuit equivalent\n' document['txt'] <= ' {:{offset}} L_s = {} μH\n'.format( 'f-independent series inductance; geometrical formula', document['L_s'].value, offset=offset) document['txt'] <= ' {:{offset}} R_s = {} Ω\n'.format( 'series AC resistance @ design frequency', document['R_s'].value, offset=offset) document['txt'] <= ' {:{offset}} C_p = {} pF\n'.format( 'parallel stray capacitance @ design frequency', document['C_p'].value, offset=offset) except: document['txt'] <= ' Lumped circuit equivalent\n' document['txt'] <= ' {:{offset}} L_s = {} μH\n'.format( 'f-independent series inductance; geometrical formula', document['L_s'].value, offset=offset) document[ 'txt'] <= ' No lumped circuit equivalent is available!\n' document['txt'] <= ' However, all shown results are useable.\n' outputs = ['R_s', 'C_p', 'f_res'] for i in range(len(outputs)): document[outputs[i]].value = '' offset = 57 try: # Self‑resonant frequency f_res = find_f_res() document['f_res'].value = '%.3f' % round(f_res * 1E-6, 3) # Resonant frequency in copy & paste text field document['txt'] <= ' {:{offset}} f_res = {} MHz\n'.format( 'Self-resonant frequency', document['f_res'].value, offset=offset) except: document[ 'txt'] <= ' An error occurred when solving for the self-resonant frequency!\n' document['txt'] <= ' However, all shown results are useable.\n' document['f_res'].value = '' document['txt'] <= '\nDONATE\n' document['txt'] <= ' If this calculator proved any useful to you,\n' document['txt'] <= ' please, consider making a one-off donation\n' document[ 'txt'] <= ' towards keeping me and the server up and running.\n' document['txt'] <= ' Thank you!' except: document['txt'].clear() # COMMENT THIS LINE FOR TESTING PROGRESS outputs = [ 'p', 'Phi', 'D_eff', 'k_L', 'k_s', 'k_m', 'l_w_phys', 'l_w_eff', 'delta_i', 'R_eff_s', 'L_s', 'psi' ] outputs += [ 'beta', 'Z_c', 'L_eff_s', 'X_eff_s', 'Q_eff', 'R_s', 'C_p', 'f_res' ] for i in range(len(outputs)): document[outputs[i]].value = ''