def gcpw(trace_width: float): """ """ sim = Simulation(freq=freq, unit=1e-3) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), ) box = Box2( Coordinate2(-pcb_len / 2, -trace_width / 2), Coordinate2(pcb_len / 2, trace_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=box.width(), propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, gnd_gap=(gap, gap), port_number=1, ref_impedance=50, excite=True, ) ViaWall( pcb=pcb, position=Coordinate2(0, trace_width / 2 + gap + via_gap), length=pcb_len, width=via_gap / 2, ) ViaWall( pcb=pcb, position=Coordinate2(0, -trace_width / 2 - gap - via_gap), length=pcb_len, width=via_gap / 2, ) Mesh( sim=sim, metal_res=1 / 120, nonmetal_res=1 / 40, smooth=(1.1, 1.5, 1.5), min_lines=25, expand_bounds=((0, 0), (24, 24), (24, 24)), ) sim.run(csx=False) return np.average(np.abs(np.abs(sim.ports[0].impedance()) - 50))
def func(min_lines: int): sim = Simulation(freq=freq, unit=unit, reference_frequency=ref_freq, sim_dir=None) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) Microstrip( pcb=pcb, position=Coordinate2(0, 0), length=pcb_len, width=trace_width, propagation_axis=Axis("x"), port_number=1, excite=True, ) Mesh( sim=sim, metal_res=1 / 80, nonmetal_res=1 / 10, smooth=(1.1, 1.5, 1.5), min_lines=min_lines, expand_bounds=((0, 0), (0, 0), (10, 40)), ) sim.run(csx=False) return sim.ports[0].impedance()
def z0_for_width(width: float) -> float: """ """ sim = Simulation(freq=freq, unit=1e-3, reference_frequency=ref_freq, sim_dir=None) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) Microstrip( pcb=pcb, position=Coordinate2(0, 0), length=pcb_len, width=width, propagation_axis=Axis("x"), port_number=1, excite=True, ref_impedance=50, ) Mesh( sim=sim, metal_res=1 / 80, nonmetal_res=1 / 10, min_lines=5, expand_bounds=((0, 0), (0, 0), (10, 40)), ) sim.run(csx=False) return np.abs(sim.ports[0].impedance(freq=ref_freq))
def func(gnd_gap: float): sim = Simulation(freq=freq, unit=unit, reference_frequency=ref_freq, sim_dir=None) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), ) Microstrip( pcb=pcb, position=Coordinate2(0, 0), length=pcb_len, width=trace_width, propagation_axis=Axis("x"), gnd_gap=(gnd_gap, gnd_gap), port_number=1, excite=True, ref_impedance=50, ) Mesh( sim=sim, metal_res=1 / 80, nonmetal_res=1 / 10, min_lines=9, expand_bounds=((0, 0), (0, 0), (10, 40)), ) sim.run(csx=False) return np.abs(sim.ports[0].impedance(freq=ref_freq))
def prim_coords2(prim: CSPrimitives) -> List[Coordinate2]: """ Retrieve a 2D xy projection of all coordinates from a primitive. """ coords3 = prim_coords(prim) coords2 = [Coordinate2(coord.x, coord.y) for coord in coords3] return _remove_prim_coord_dups(coords2)
def gen_sim(width: float) -> Simulation: """ Create simulation objects to sweep over. :param width: Top layer trace width. This is the parameter we sweep over. """ sim = Simulation(freq=freq, unit=1e-3) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), ) box = Box2( Coordinate2(-pcb_len / 2, -width / 2), Coordinate2(pcb_len / 2, width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=box.width(), propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, gnd_gap=(gap, gap), port_number=1, feed_shift=0.3, ref_impedance=50, excite=True, ) Mesh( sim=sim, metal_res=1 / 80, nonmetal_res=1 / 40, smooth=(1.2, 1.5, 1.5), min_lines=25, expand_bounds=((0, 0), (8, 8), (8, 20)), ) return sim_impedance(sim)
def func(width: float): sim = Simulation(freq=freq, unit=unit, reference_frequency=ref_freq, sim_dir=None) pcb_prop = common_pcbs["oshpark4"] pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) DifferentialMicrostrip( pcb=pcb, position=Coordinate2(0, 0), length=pcb_len, width=width, gap=trace_gap, propagation_axis=Axis("x"), port_number=1, excite=True, ref_impedance=50, ) Mesh( sim=sim, metal_res=1 / 80, nonmetal_res=1 / 10, min_lines=9, expand_bounds=((0, 0), (0, 0), (10, 40)), ) FieldDump( sim=sim, box=Box3( Coordinate3(-pcb_len / 2, -pcb_width / 2, 0), Coordinate3(pcb_len / 2, pcb_width / 2, 0), ), dump_type=DumpType.current_density_time, ) sim.run(csx=False) return np.abs(sim.ports[0].impedance(freq=ref_freq))
def _circle_points( center: C3Tuple, radius: float, normal: Axis, poly_faces: int ) -> List[Coordinate2]: """ """ pts1 = np.multiply(radius, np.cos(np.linspace(0, 2 * np.pi, poly_faces))) pts2 = np.multiply(radius, np.sin(np.linspace(0, 2 * np.pi, poly_faces))) if normal.intval() == 0: pts1 += center.y pts2 += center.z elif normal.intval() == 1: pts1 += center.x pts2 += center.z else: pts1 += center.x pts2 += center.y lst = [] for pt1, pt2 in zip(pts1, pts2): lst.append(Coordinate2(pt1, pt2)) return lst
def sim_func(taper_angle: float): """ :param taper_angle: Linear taper angle in degrees. """ angle_rad = taper_angle * np.pi / 180 dy = np.abs(trace_width - microstrip_discontinuity_width) / 2 dx = dy / np.tan(angle_rad) taper_middle = microstrip_discontinuity_length / 2 + dx / 2 taper_end = microstrip_discontinuity_length / 2 + dx sim = Simulation(freq=freq, unit=unit, sim_dir=None) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) Microstrip( pcb=pcb, position=Coordinate2(0, 0), length=microstrip_discontinuity_length, width=microstrip_discontinuity_width, propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, ) Taper( pcb=pcb, position=Coordinate2(-taper_middle, 0), pcb_layer=0, width1=trace_width, width2=microstrip_discontinuity_width, length=dx, ) Taper( pcb=pcb, position=Coordinate2(taper_middle, 0), pcb_layer=0, width1=microstrip_discontinuity_width, width2=trace_width, length=dx, ) box = Box2( Coordinate2(-pcb_len / 2, -trace_width / 2), Coordinate2(-taper_end, trace_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=trace_width, propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, port_number=1, excite=True, feed_shift=0.35, ref_impedance=50, ) box = Box2( Coordinate2(taper_end, -trace_width / 2), Coordinate2(pcb_len / 2, trace_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=trace_width, propagation_axis=Axis("x", direction=-1), trace_layer=0, gnd_layer=1, port_number=2, ref_impedance=50, ) Mesh( sim=sim, metal_res=1 / 120, nonmetal_res=1 / 40, min_lines=5, expand_bounds=((0, 0), (0, 0), (10, 40)), ) # sim.run(csx=False) sim.run() return sim.s_param(1, 1)
pcb_prop = common_pcbs["oshpark4"] pcb_len = 20 pcb_width = 5 trace_width = 0.34 gap = mil_to_mm(6) via_gap = 0.4 pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), ) box = Box2( Coordinate2(-pcb_len / 2, -trace_width / 2), Coordinate2(pcb_len / 2, trace_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=box.width(), propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, gnd_gap=(gap, gap), port_number=1, ref_impedance=50, excite=True, )
pcb_len = 10 pcb_width = 2 * sma_rect_width pcb_prop = common_pcbs["oshpark4"] pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) Microstrip( pcb=pcb, position=Coordinate2(0, 0), length=pcb_len, width=trace_width, propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, port_number=1, ref_impedance=50, excite=True, ) # Mueller BU-1420701851 edge mount SMA pad = add_conducting_sheet( csx=sim.csx, name="pad", conductivity=pcb_prop.metal_conductivity(),
microstrip_discontinuity_width = 0.5 microstrip_discontinuity_length = 1 sim = Simulation(freq=freq, unit=unit, reference_frequency=5.6e9) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) Microstrip( pcb=pcb, position=Coordinate2(0, 0), length=microstrip_discontinuity_length, width=microstrip_discontinuity_width, propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, ) box = Box2( Coordinate2(-pcb_len / 2, -trace_width / 2), Coordinate2(-microstrip_discontinuity_length / 2, trace_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(),
def func(params: List[float]): """ """ cutout_width = params[0] sim = Simulation(freq=freq, unit=unit, sim_dir=None) pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) box = Box2( Coordinate2(-pcb_len / 2, -trace_width / 2), Coordinate2(-(cap_dim.length / 2) - (pad_length / 2), trace_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=box.width(), propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, port_number=1, excite=True, feed_shift=0.35, ref_impedance=z0_ref, ) SMDPassive( pcb=pcb, position=Coordinate2(0, 0), axis=Axis("x"), dimensions=cap_dim, pad_width=pad_width, pad_length=pad_length, c=10e-12, pcb_layer=0, gnd_cutout_width=cutout_width, gnd_cutout_length=1, ) box = Box2( Coordinate2(pcb_len / 2, trace_width / 2), Coordinate2((cap_dim.length / 2) + (pad_length / 2), -trace_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=box.width(), propagation_axis=Axis("x", direction=-1), trace_layer=0, gnd_layer=1, port_number=2, excite=False, ref_impedance=z0_ref, ) Mesh( sim=sim, metal_res=1 / 120, nonmetal_res=1 / 40, smooth=(1.2, 1.2, 1.2), min_lines=5, expand_bounds=((0, 0), (0, 0), (10, 20)), ) sim.run(csx=False) print_table( data=[sim.freq / 1e9, sim.s_param(1, 1), sim.s_param(2, 1)], col_names=["freq", "s11", "s21"], prec=[4, 4, 4], ) return np.sum(sim.s_param(1, 1))
pad_length = 0.6 pad_width = trace_width pcb_prop = common_pcbs["oshpark4"] pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), ) DifferentialMicrostrip( pcb=pcb, position=Coordinate2( (-pcb_len / 2 - cap_dim.length / 2 - pad_length / 2) / 2, 0 ), length=pcb_len / 2 - cap_dim.length / 2 - pad_length / 2, width=trace_width, gap=trace_gap, propagation_axis=Axis("x"), gnd_gap=(gnd_gap, gnd_gap), via_gap=(via_gap, via_gap), port_number=1, excite=True, ref_impedance=50, ) # values based on Murata GJM1555C1H100FB01 (ESR at 6GHz) SMDPassive( pcb=pcb,
gcpw_width = 0.34 gcpw_gap = mil_to_mm(6) via_gap = 0.4 # drill_radius = gcpw_width / 2 - pcb_prop.via_plating_thickness(unit) drill_radius = 0.13 drill_diam = 2 * drill_radius annular_width = 0.145 antipad = gcpw_gap keepout_radius = drill_radius + annular_width + antipad via_sep = 0.76 via_fence_sep = via_sep * 2 sim = Simulation(freq=freq, unit=unit) pcb = PCB(sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width) box = Box2( Coordinate2(-pcb_len / 2, -gcpw_width / 2), Coordinate2(pcb_len / 4, gcpw_width / 2), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=box.width(), propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, gnd_gap=(gcpw_gap, gcpw_gap), via_gap=(via_gap, via_gap), via=None, port_number=1, feed_shift=0.2,
coupler_length = phase_shift_length(90, eeff, ref_freq) print("coupler_length: {:.4f}".format(coupler_length)) pcb_len = 2 * coupler_length pcb_width = 0.5 * pcb_len pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) coupler = MicrostripCoupler( pcb=pcb, position=Coordinate2(0, 0), trace_layer=0, gnd_layer=1, trace_width=trace_width, trace_gap=trace_spacing, length=coupler_length, miter=None, ) coupler_port_positions = coupler.port_positions() port0_x = coupler_port_positions[0].x port0_y = coupler_port_positions[0].y Microstrip( pcb=pcb, position=Coordinate2(np.average([port0_x, -pcb_len / 2]), port0_y),
trace_width = 0.34 gap = mil_to_mm(6) via_gap = 0.4 pcb_prop = common_pcbs["oshpark4"] pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), ) Microstrip( pcb=pcb, position=Coordinate2(-pcb_len / 4, 0), length=pcb_len / 2, width=trace_width, propagation_axis=Axis("x"), gnd_gap=(gap, gap), port_number=1, excite=True, ref_impedance=50, ) cap_0402 = common_smd_passives["0402C"] cap_0402.set_unit(unit) # values based on Murata GJM1555C1HR50BB01 (ESR at 12GHz) SMDPassive( pcb=pcb,
freq = np.linspace(4e9, 8e9, 501) sim = Simulation(freq=freq, unit=1e-3) pcb_prop = common_pcbs["oshpark4"] pcb_len = 10 trace_width = 0.34 gap = mil_to_mm(6) via_gap = 0.4 pcb = PCB(sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_len, layers=range(3)) box = Box2( Coordinate2(-pcb_len / 2, pcb_len / 4 - (trace_width / 2)), Coordinate2(pcb_len / 4, pcb_len / 4 + (trace_width / 2)), ) Microstrip( pcb=pcb, position=box.center(), length=box.max_corner.x - box.min_corner.x, width=trace_width, propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, gnd_gap=(gap, gap), port_number=1, feed_shift=0.4, excite=True, )
def sim_func(cutout_width: float): """ """ sim = Simulation(freq=freq, unit=unit, reference_frequency=ref_freq) core_rad = (coax_core_diameter( 2 * coax_rad, coax_dielectric.epsr_at_freq(sim.reference_frequency)) / 2) pcb_prop = common_pcbs["oshpark4"] pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) Microstrip( pcb=pcb, position=Coordinate2(0, 0), length=pcb_len, width=trace_width, propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, port_number=1, ref_impedance=50, excite=True, ) # Mueller BU-1420701851 edge mount SMA pad = sim.csx.AddConductingSheet( "pad", conductivity=pcb_prop.metal_conductivity(), thickness=pcb_prop.copper_thickness(0), ) pad.AddBox( priority=priorities["trace"], start=[pcb_len / 2 - sma_lead_len / 2, -sma_lead_width / 2, 0], stop=[pcb_len / 2, sma_lead_width / 2, 0], ) pad_cutout = sim.csx.AddMaterial( "gnd_cutout", epsilon=pcb_prop.substrate.epsr_at_freq(ref_freq), kappa=pcb_prop.substrate.kappa_at_freq(ref_freq), ) pad_cutout.AddBox( priority=priorities["keepout"], start=[ pcb_len / 2 - sma_lead_len / 2, -cutout_width / 2, pcb.copper_layer_elevation(1), ], stop=[pcb_len / 2, cutout_width / 2, pcb.copper_layer_elevation(1)], ) sma_box = sim.csx.AddMetal("sma_box") sma_box.AddBox( priority=priorities["ground"], start=[ pcb_len / 2, -sma_rect_width / 2, -sma_rect_height / 2 + sma_lead_height / 2, ], stop=[ pcb_len / 2 + sma_rect_length, sma_rect_width / 2, sma_rect_height / 2 + sma_lead_height / 2, ], ) sma_keepout = sim.csx.AddMaterial( "sma_keepout", epsilon=coax_dielectric.epsr_at_freq(ref_freq), kappa=coax_dielectric.kappa_at_freq(ref_freq), ) sma_keepout.AddCylinder( priority=priorities["keepout"], start=[pcb_len / 2, 0, sma_lead_height / 2], stop=[pcb_len / 2 + sma_rect_length, 0, sma_lead_height / 2], radius=coax_rad, ) for ypos in [ -sma_rect_width / 2, sma_rect_width / 2 - sma_gnd_prong_width, ]: # sma_box.AddBox( # priority=priorities["ground"], # start=[pcb_len / 2 - sma_gnd_prong_len, ypos, 0], # stop=[ # pcb_len / 2, # ypos + sma_gnd_prong_width, # sma_gnd_prong_height # ], # ) # sma_box.AddBox( # priority=priorities["ground"], # start=[ # pcb_len / 2 - sma_gnd_prong_len, # ypos, # pcb.copper_layer_elevation(1) # ], # stop=[ # pcb_len / 2, # ypos + sma_gnd_prong_width, # pcb.copper_layer_elevation(1) - sma_gnd_prong_height, # ], # ) sma_box.AddBox( priority=priorities["ground"], start=[ pcb_len / 2 - sma_gnd_prong_len, ypos, pcb.copper_layer_elevation(1) - sma_gnd_prong_height, ], stop=[ pcb_len / 2, ypos + sma_gnd_prong_width, sma_gnd_prong_height, ], ) lead = sim.csx.AddMetal("lead") lead.AddBox( priority=priorities["trace"], start=[pcb_len / 2 - sma_lead_len / 2, -sma_lead_width / 2, 0], stop=[ pcb_len / 2 + sma_rect_length, sma_lead_width / 2, sma_lead_height, ], ) # coax port Coax( sim=sim, position=Coordinate3( pcb_len / 2 + sma_rect_length + coax_len / 2, 0, sma_lead_height / 2, ), length=coax_len, radius=coax_rad, core_radius=core_rad, shield_thickness=mil_to_mm(5), dielectric=coax_dielectric, propagation_axis=Axis("x", direction=-1), port_number=2, ref_impedance=50, ) mesh = Mesh( sim=sim, metal_res=1 / 120, nonmetal_res=1 / 10, min_lines=5, expand_bounds=((0, 0), (0, 0), (10, 10)), ) box = mesh.sim_box(include_pml=False) sim.run(csx=False) s11 = sim.s_param(1, 1) s21 = sim.s_param(2, 1) print("cutout width: {}".format(cutout_width)) print_table( data=[sim.freq / 1e9, s11, s21], col_names=["freq", "s11", "s21"], prec=[4, 4, 4], ) return np.sum(s11)
pad_length = cap_dim.width # taper_length = pad_length / 4 taper_length = 0 # taper_length = 0.1501806 pcb = PCB( sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_width, layers=range(3), omit_copper=[0], ) box = Box2( Coordinate2(-pcb_len / 2, -trace_width / 2), Coordinate2( -(cap_dim.length / 2) - (pad_length / 2) - taper_length, trace_width / 2, ), ) Microstrip( pcb=pcb, position=box.center(), length=box.length(), width=box.width(), propagation_axis=Axis("x"), trace_layer=0, gnd_layer=1, port_number=1, excite=True,
freq = np.linspace(4e9, 8e9, 501) sim = Simulation(freq=freq, unit=1e-3) pcb_prop = common_pcbs["oshpark4"] pcb_len = 10 trace_width = 0.38 gap = mil_to_mm(6) via_gap = 0.4 pcb = PCB(sim=sim, pcb_prop=pcb_prop, length=pcb_len, width=pcb_len, layers=range(3)) box = Box2( Coordinate2(-pcb_len / 2, pcb_len / 4 - (trace_width / 2)), Coordinate2(pcb_len / 4, pcb_len / 4 + (trace_width / 2)), ) miter = Miter( pcb=pcb, position=Coordinate2(pcb_len / 4, pcb_len / 4), pcb_layer=0, gnd_layer=1, trace_width=trace_width, gap=gap, ) print("miter: {:.4f}mm ({:.2f}%)".format( miter.miter, 100 * miter.miter / (trace_width * np.sqrt(2)))) Microstrip(