Last active
December 11, 2025 11:32
-
-
Save rezamarzban/379337326ae86d0d0d06b26c987606db to your computer and use it in GitHub Desktop.
Local vswr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import cmath | |
| import math | |
| # Define the chain as a simple list of tuples: ('type', value, 'unit') | |
| # Types: 'R' for resistor, 'L' for inductor, 'C' for capacitor, 'Source' for AC Source | |
| # Units for R/Source: 'ohm', 'kohm', 'mohm' | |
| # Units for L: 'nH', 'uH', 'mH', 'H' | |
| # Units for C: 'fF', 'pF', 'nF', 'uF', 'F' | |
| # Example (AC Source with 0 impedance included as first element): | |
| chain = [ | |
| ('Source', 0, 'ohm'), # AC Source with no impedance | |
| ('R', 100, 'ohm'), # 100 ohms | |
| ('R', 50, 'ohm'), # 50 ohms | |
| ('L', 1, 'uH'), # 1 uH | |
| ('C', 100, 'pF'), # 100 pF | |
| ('R', 33, 'ohm'), # 33 ohms | |
| # Add more: ('L', 2.5, 'mH'), ('C', 0.1, 'uF'), etc. | |
| ] | |
| # Get scale factor for units | |
| def get_scale(unit, comp_type): | |
| unit = unit.lower() | |
| if comp_type in ['R', 'Source']: | |
| scales = {'ohm': 1, 'kohm': 1e3, 'mohm': 1e6} | |
| elif comp_type == 'L': | |
| scales = {'nh': 1e-9, 'uh': 1e-6, 'mh': 1e-3, 'h': 1} | |
| elif comp_type == 'C': | |
| scales = {'ff': 1e-15, 'pf': 1e-12, 'nf': 1e-9, 'uf': 1e-6, 'f': 1} | |
| return scales.get(unit, 1) # Default 1 if unknown | |
| # Component impedance calculator | |
| def get_impedance(comp_type, value, unit, omega): | |
| scale = get_scale(unit, comp_type) | |
| base_value = value * scale | |
| if comp_type in ['R', 'Source']: | |
| return base_value + 0j | |
| elif comp_type == 'L': | |
| return 1j * omega * base_value | |
| elif comp_type == 'C': | |
| if omega * base_value == 0: | |
| return 0j | |
| return -1j / (omega * base_value) | |
| else: | |
| raise ValueError("Unknown type: use 'R', 'L', 'C', or 'Source'") | |
| # Z_right (toward GND) at each node | |
| def compute_z_right(chain, omega): | |
| z_right = [0j] * (len(chain) + 1) | |
| z = 0j | |
| z_right[len(chain)] = z | |
| for i in range(len(chain) - 1, -1, -1): | |
| comp_type, value, unit = chain[i] | |
| z_comp = get_impedance(comp_type, value, unit, omega) | |
| z = z_comp + z | |
| z_right[i] = z | |
| return z_right | |
| # Z_left (toward source) at each node | |
| def compute_z_left(chain, omega): | |
| z_left = [0j] * (len(chain) + 1) | |
| z = 0j # Start with 0 since source is now in chain | |
| z_left[0] = z | |
| for i in range(len(chain)): | |
| comp_type, value, unit = chain[i] | |
| z_comp = get_impedance(comp_type, value, unit, omega) | |
| z = z + z_comp | |
| z_left[i + 1] = z | |
| return z_left | |
| # Reflection coefficient Gamma | |
| def compute_gamma(z_left, z_right): | |
| if z_left + z_right == 0: | |
| return 0 | |
| return (z_right - z_left) / (z_right + z_left) | |
| # VSWR from |Gamma| | |
| def compute_vswr(gamma): | |
| mag_gamma = abs(gamma) | |
| if mag_gamma >= 1: | |
| return float('inf') | |
| return (1 + mag_gamma) / (1 - mag_gamma) | |
| # Get frequency scale | |
| def get_freq_scale(unit): | |
| unit = unit.lower() | |
| scales = {'hz': 1, 'khz': 1e3, 'mhz': 1e6, 'ghz': 1e9} | |
| return scales.get(unit, 1e6) # Default MHz | |
| # Print used equations | |
| def print_equations(): | |
| print("\nUsed Equations (in LaTeX format):") | |
| print(r"\omega = 2 \pi f") | |
| print(r"Z_R = R") | |
| print(r"Z_L = j \omega L") | |
| print(r"Z_C = -j / (\omega C)") | |
| print(r"Z_{series} = Z_1 + Z_2 + \dots") | |
| print(r"\Gamma = \frac{Z_{right} - Z_{left}}{Z_{right} + Z_{left}}") | |
| print(r"VSWR = \frac{1 + |\Gamma|}{1 - |\Gamma|}") | |
| # Main calculator function | |
| def calculate_local_vswr(node_index, freq_value, freq_unit='MHz'): | |
| if node_index < 0 or node_index > len(chain): | |
| raise ValueError(f"Node must be 0 to {len(chain)}") | |
| freq_scale = get_freq_scale(freq_unit) | |
| f = freq_value * freq_scale | |
| omega = 2 * math.pi * f | |
| z_right_list = compute_z_right(chain, omega) | |
| z_left_list = compute_z_left(chain, omega) | |
| z_l = z_left_list[node_index] | |
| z_r = z_right_list[node_index] | |
| gamma = compute_gamma(z_l, z_r) | |
| vswr = compute_vswr(gamma) | |
| print(f"\nResults for Node {node_index} at {freq_value} {freq_unit}:") | |
| print(f"Z_left: {z_l.real:.2f} {'+' if z_l.imag >= 0 else ''}{z_l.imag:.2f}j Ω") | |
| print(f"Z_right: {z_r.real:.2f} {'+' if z_r.imag >= 0 else ''}{z_r.imag:.2f}j Ω") | |
| print(f"|Γ|: {abs(gamma):.3f}") | |
| print(f"VSWR: {vswr:.2f}") | |
| print_equations() | |
| # Edit these to run: | |
| node = 2 # Node index (0 is before first component after source, up to len(chain)) | |
| freq_value = 10.0 # Frequency value | |
| freq_unit = 'MHz' # Can be 'Hz', 'kHz', 'MHz', 'GHz' | |
| calculate_local_vswr(node, freq_value, freq_unit) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import cmath | |
| import math | |
| # Define the chain as a simple list of tuples or Parallel branches: | |
| # Single components: ('Type', value, 'unit') where Type in {'R','L','C','Source'} | |
| # Parallel branch: ('Parallel', [ element1, element2, ... ]) | |
| # Each element in a Parallel list can be: | |
| # - a single component tuple ('R', 10, 'ohm') | |
| # - a list of component tuples representing series components [ ('R',10,'ohm'), ('C',1,'pF') ] | |
| chain = [ | |
| ('Source', 0, 'ohm'), # AC Source with no impedance | |
| ('R', 100, 'ohm'), # 100 ohms | |
| ('Parallel', [ # Parallel branch with multiple series groups and single components | |
| ('L', 1, 'uH'), | |
| [('R', 10, 'ohm'), ('C', 100, 'pF')], # series group: R in series with C | |
| ('C', 200, 'pF'), | |
| [('L', 2, 'uH'), ('R', 5, 'ohm'), ('C', 50, 'pF')] # longer series group | |
| ]), | |
| ('R', 50, 'ohm'), # 50 ohms | |
| ('R', 33, 'ohm'), # 33 ohms | |
| ] | |
| # Get scale factor for units | |
| def get_scale(unit, comp_type): | |
| if unit is None: | |
| return 1 | |
| unit = unit.lower() | |
| if comp_type in ['R', 'Source']: | |
| scales = {'ohm': 1, 'kohm': 1e3, 'mohm': 1e6} | |
| elif comp_type == 'L': | |
| scales = {'nh': 1e-9, 'uh': 1e-6, 'mh': 1e-3, 'h': 1} | |
| elif comp_type == 'C': | |
| scales = {'ff': 1e-15, 'pf': 1e-12, 'nf': 1e-9, 'uf': 1e-6, 'f': 1} | |
| else: | |
| scales = {} | |
| return scales.get(unit, 1) # Default 1 if unknown | |
| # Compute impedance of a series group (list of component tuples) | |
| def get_series_impedance(series_list, omega): | |
| z_total = 0+0j | |
| for comp in series_list: | |
| if len(comp) != 3: | |
| raise ValueError("Series group components must be tuples of (Type, value, unit)") | |
| c_type, c_value, c_unit = comp | |
| z_comp = get_impedance(c_type, c_value, c_unit, omega) | |
| # If any series element is infinite (open), the series total is infinite | |
| if z_comp == complex(float('inf'), 0): | |
| return complex(float('inf'), 0) | |
| z_total += z_comp | |
| return z_total | |
| # Compute impedance of a parallel branch (branch is a list of elements) | |
| # Each element can be a tuple (single component) or a list (series group) | |
| def get_parallel_impedance(branch, omega): | |
| admittance = 0+0j | |
| for elem in branch: | |
| # element is a series group (list) | |
| if isinstance(elem, list): | |
| z_comp = get_series_impedance(elem, omega) | |
| # element is a single component tuple | |
| elif isinstance(elem, tuple): | |
| if len(elem) != 3: | |
| raise ValueError("Parallel branch component tuples must be (Type, value, unit)") | |
| c_type, c_value, c_unit = elem | |
| z_comp = get_impedance(c_type, c_value, c_unit, omega) | |
| else: | |
| raise ValueError("Parallel branch elements must be tuples or lists of tuples") | |
| # If element is open (inf), it contributes 0 admittance | |
| if z_comp == complex(float('inf'), 0): | |
| continue | |
| # If element is short (0), total parallel impedance is 0 | |
| if z_comp == 0: | |
| return 0+0j | |
| admittance += 1 / z_comp | |
| if admittance == 0: | |
| return complex(float('inf'), 0) # open circuit | |
| return 1 / admittance | |
| # Component impedance calculator (handles Parallel specially) | |
| def get_impedance(comp_type, value, unit, omega): | |
| if comp_type == 'Parallel': | |
| # value is expected to be the branch list | |
| return get_parallel_impedance(value, omega) | |
| scale = get_scale(unit, comp_type) | |
| base_value = value * scale | |
| if comp_type in ['R', 'Source']: | |
| return complex(base_value, 0) | |
| elif comp_type == 'L': | |
| return 1j * omega * base_value | |
| elif comp_type == 'C': | |
| # If C == 0 or omega == 0, treat as open circuit (infinite impedance) | |
| if base_value == 0 or omega == 0: | |
| return complex(float('inf'), 0) | |
| return complex(0, -1 / (omega * base_value)) | |
| else: | |
| raise ValueError("Unknown type: use 'R', 'L', 'C', 'Source', or 'Parallel'") | |
| # Z_right (toward GND) at each node | |
| def compute_z_right(chain, omega): | |
| z_right = [0j] * (len(chain) + 1) | |
| z = 0j | |
| z_right[len(chain)] = z | |
| for i in range(len(chain) - 1, -1, -1): | |
| comp = chain[i] | |
| comp_type = comp[0] | |
| if comp_type == 'Parallel': | |
| z_comp = get_impedance('Parallel', comp[1], None, omega) | |
| else: | |
| if len(comp) != 3: | |
| raise ValueError(f"Component at index {i} must be ('Type', value, 'unit')") | |
| _, value, unit = comp | |
| z_comp = get_impedance(comp_type, value, unit, omega) | |
| # handle infinities gracefully | |
| if z == complex(float('inf'), 0) or z_comp == complex(float('inf'), 0): | |
| # if either is infinite, series sum is infinite | |
| z = complex(float('inf'), 0) | |
| else: | |
| z = z_comp + z | |
| z_right[i] = z | |
| return z_right | |
| # Z_left (toward source) at each node | |
| def compute_z_left(chain, omega): | |
| z_left = [0j] * (len(chain) + 1) | |
| z = 0j # Start with 0 since source is now in chain | |
| z_left[0] = z | |
| for i in range(len(chain)): | |
| comp = chain[i] | |
| comp_type = comp[0] | |
| if comp_type == 'Parallel': | |
| z_comp = get_impedance('Parallel', comp[1], None, omega) | |
| else: | |
| if len(comp) != 3: | |
| raise ValueError(f"Component at index {i} must be ('Type', value, 'unit')") | |
| _, value, unit = comp | |
| z_comp = get_impedance(comp_type, value, unit, omega) | |
| if z == complex(float('inf'), 0) or z_comp == complex(float('inf'), 0): | |
| z = complex(float('inf'), 0) | |
| else: | |
| z = z + z_comp | |
| z_left[i + 1] = z | |
| return z_left | |
| # Reflection coefficient Gamma | |
| def compute_gamma(z_left, z_right): | |
| # Handle infinite impedances: if both infinite, treat as matched (Gamma=0) | |
| if (z_left == complex(float('inf'), 0)) and (z_right == complex(float('inf'), 0)): | |
| return 0+0j | |
| denom = z_right + z_left | |
| if denom == 0: | |
| return 0+0j | |
| return (z_right - z_left) / denom | |
| # VSWR from |Gamma| | |
| def compute_vswr(gamma): | |
| mag_gamma = abs(gamma) | |
| if mag_gamma >= 1: | |
| return float('inf') | |
| return (1 + mag_gamma) / (1 - mag_gamma) | |
| # Get frequency scale | |
| def get_freq_scale(unit): | |
| if unit is None: | |
| return 1e6 | |
| unit = unit.lower() | |
| scales = {'hz': 1, 'khz': 1e3, 'mhz': 1e6, 'ghz': 1e9} | |
| return scales.get(unit, 1e6) # Default MHz | |
| # Print used equations in plain math expression format (not LaTeX) | |
| def print_equations(): | |
| print("\nUsed Equations (math expression format):") | |
| print("omega = 2 * pi * f") | |
| print("Z_R = R") | |
| print("Z_L = j * omega * L") | |
| print("Z_C = -j / (omega * C)") | |
| print("Z_series = Z1 + Z2 + ...") | |
| print("Z_parallel = 1 / (1/Z1 + 1/Z2 + ...)") | |
| print("Gamma = (Z_right - Z_left) / (Z_right + Z_left)") | |
| print("VSWR = (1 + |Gamma|) / (1 - |Gamma|)") | |
| # Print node map with support for series groups inside parallel branches | |
| def print_node_map(chain): | |
| print("\nNode Map (index : components):") | |
| for i, comp in enumerate(chain): | |
| comp_type = comp[0] | |
| if comp_type == 'Parallel': | |
| branch = comp[1] | |
| elem_descs = [] | |
| for elem in branch: | |
| if isinstance(elem, list): | |
| # series group | |
| parts = [] | |
| for c in elem: | |
| parts.append(f"{c[0]} {c[1]} {c[2]}") | |
| elem_descs.append("(" + " + ".join(parts) + ")") | |
| else: | |
| # single component tuple | |
| elem_descs.append(f"{elem[0]} {elem[1]} {elem[2]}") | |
| branch_desc = " || ".join(elem_descs) | |
| print(f"Node {i}: Parallel[{branch_desc}]") | |
| else: | |
| if len(comp) == 3: | |
| print(f"Node {i}: {comp[0]} {comp[1]} {comp[2]}") | |
| else: | |
| print(f"Node {i}: {comp}") | |
| # Calculate and print local VSWR for all nodes | |
| def calculate_all_vswr(freq_value, freq_unit='MHz'): | |
| print_node_map(chain) | |
| freq_scale = get_freq_scale(freq_unit) | |
| f = freq_value * freq_scale | |
| omega = 2 * math.pi * f | |
| z_right_list = compute_z_right(chain, omega) | |
| z_left_list = compute_z_left(chain, omega) | |
| def fmt_z(z): | |
| if z == complex(float('inf'), 0): | |
| return "inf" | |
| return f"{z.real:.6g} {'+' if z.imag >= 0 else ''}{z.imag:.6g}j" | |
| print(f"\nCalculations at {freq_value} {freq_unit} (omega = {omega:.6g} rad/s):") | |
| for node_index in range(0, len(chain) + 1): | |
| z_l = z_left_list[node_index] | |
| z_r = z_right_list[node_index] | |
| gamma = compute_gamma(z_l, z_r) | |
| vswr = compute_vswr(gamma) | |
| print(f"\nNode {node_index}:") | |
| print(f" Z_left : {fmt_z(z_l)} Ω") | |
| print(f" Z_right: {fmt_z(z_r)} Ω") | |
| print(f" |Gamma|: {abs(gamma):.6f}") | |
| if vswr == float('inf'): | |
| print(" VSWR : inf") | |
| else: | |
| print(f" VSWR : {vswr:.6f}") | |
| print_equations() | |
| # Edit these to run: | |
| freq_value = 10.0 # Frequency value | |
| freq_unit = 'MHz' # Can be 'Hz', 'kHz', 'MHz', 'GHz' | |
| if __name__ == "__main__": | |
| calculate_all_vswr(freq_value, freq_unit) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment