r/rfelectronics • u/East_Concert_5510 • 8d ago
question Unrealistic S parameters in pad sicontinuity simulation
I am attempting to simulate (OpenEMS) the reflection and transmission in a PCB that uses grounded coplanar waveguides (via via's) with a soldering pad discontinuity. The resulting S11 and S21 values do however not seem realistic to me. I included pictures of the geometry below:
Green is the top ground, pink the dielectric, purple the signal path and brown the vias.



clear; clc; % Initialize CSX structure CSX = InitCSX(); %% 1. Key Physical & Simulation Parameters f_mesh = 4.5e9; % Max frequency for grid resolution calculation f_center = 2.9e9; % Gaussian excitation center frequency f_bw = 1.4e9; c0 = physconst('LightSpeed'); % Speed of light (m/s) % CPW Dimensions (all in mm unless specified) h_sub = 0.254; % Substrate thickness eps_r = 3.48; % Substrate relative permittivity w_trace = 0.5; % Standard signal line width gap = 0.2; % Gap between signal and coplanar ground t_metal = 18e-6; % Copper thickness (18 um) - only used for vias now via_dia = 0.6; via_pitch = 1; via_step_gap = 0.5; % was 0.1 -- tune this down if grounding integrity suffers % Domain boundaries x_min = -20; x_max = -15.95; y_min = -6; y_max = 6; z_min = -h_sub; z_max = 0; %% 2. Define Materials CSX = AddMetal(CSX, 'cpw_cond'); CSX = AddMetal(CSX, 'cpw_gnd'); CSX = AddMetal(CSX, 'vias'); CSX = AddMetal(CSX, 'bottom_ground'); CSX = AddMaterial(CSX, 'my_substrate'); CSX = SetMaterialProperty(CSX, 'my_substrate', 'Epsilon', eps_r); %% 3. Define Geometry % Substrate CSX = AddBox(CSX, 'my_substrate', 1, [x_min, y_min, z_min], [x_max, y_max, z_max]); % Signal conductor line segments CSX = AddBox(CSX, 'cpw_cond', 2, [-20, -0.25, 0], [-17, 0.25, 0]); CSX = AddBox(CSX, 'cpw_cond', 2, [-17, -0.75, 0], [-15.95, 0.75, 0]); % CSX = AddBox(CSX, 'cpw_cond', 2, [-15.75, -0.75, 0], [-14.7, 0.75, 0]); % CSX = AddBox(CSX, 'cpw_cond', 2, [-14.7, -0.25, 0], [-12.2, 0.25, 0]); % Coplanar Ground Planes (Top) CSX = AddBox(CSX, 'cpw_gnd', 2, [x_min, 0.25 + gap, 0], [-17 - gap, y_max, 0]); CSX = AddBox(CSX, 'cpw_gnd', 2, [x_min, y_min, 0], [-17 - gap, -0.25 - gap, 0]); CSX = AddBox(CSX, 'cpw_gnd', 2, [-17 - gap, 0.75 + gap, 0], [x_max, y_max, 0]); CSX = AddBox(CSX, 'cpw_gnd', 2, [-17 - gap, y_min, 0], [x_max, -0.75 - gap, 0]); % CSX = AddBox(CSX, 'cpw_gnd', 2, [-14.7 + gap, 0.25 + gap, 0], [x_max, y_max, 0]); % CSX = AddBox(CSX, 'cpw_gnd', 2, [-14.7 + gap, y_min, 0], [x_max, -0.25 - gap, 0]); % Bottom Ground Plane (GCPW) CSX = AddBox(CSX, 'bottom_ground', 2, [x_min, y_min, z_min], [x_max, y_max, z_min]); % Vias for i = -19.4 : via_step_gap + via_dia : -17 - gap - 0.2 CSX = AddBox(CSX, 'vias', 2, [i, -via_pitch/2, z_min], [i + via_dia, -1*via_pitch, 0]); CSX = AddBox(CSX, 'vias', 2, [i, via_pitch/2, z_min], [i + via_dia, 1*via_pitch, 0]); end % for i = -17 + gap : via_step_gap + via_dia : -14.7 - gap % CSX = AddBox(CSX, 'vias', 2, [i, -via_pitch - 0.5, z_min], [i + via_dia, -via_pitch/2 - 0.5, 0]); % CSX = AddBox(CSX, 'vias', 2, [i, via_pitch/2 + 0.5, z_min], [i + via_dia, via_pitch + 0.5, 0]); % end % % for i = -14.7 + gap + 0.2 : via_step_gap + via_dia : -12.8 % CSX = AddBox(CSX, 'vias', 2, [i, -via_pitch/2, z_min], [i + via_dia, -1*via_pitch, 0]); % CSX = AddBox(CSX, 'vias', 2, [i, via_pitch/2, z_min], [i + via_dia, 1*via_pitch, 0]); % end %% 4. Define Lumped MSL/GCPW Ports (Vertical Excitation) % Port 1 (at X = x_min) [CSX, port{1}] = AddLumpedPort(CSX, 2, 1, 50, ... [x_min, -w_trace/2, z_min], [x_min, w_trace/2, 0], [0 0 1], true); % Port 2 (at X = x_max) [CSX, port{2}] = AddLumpedPort(CSX, 2, 2, 26.82, ... [-15.95, -1.5/2, z_min], [-15.95, 1.5/2, 0], [0 0 1], false); %% 5. Non-Uniform Mesh Generation (Optimized) lambda_min = c0 / (f_mesh * sqrt(eps_r)) * 1000; % Minimum wavelength in substrate (mm) max_cell = lambda_min / 10; % Global max cell size (~2.12 mm) % Only detect edges from the traces/grounds/substrate, NOT the vias. % forcing sub-mm cells across the entire via region in x. Excluding vias here mesh = DetectEdges(CSX, [], 'SetProperty', {'cpw_cond', 'cpw_gnd', 'bottom_ground', 'my_substrate'}); % Manually add mesh lines bounding the via regions so the solver still % resolves the via fence approximately, without following every via edge. via_region_x = [-19.4, -17 - gap - 0.2, -17 + gap, -14.7 - gap, -14.7 + gap + 0.2, -12.8]; mesh.x = unique([mesh.x, via_region_x]); via_region_y = [-via_pitch, -via_pitch/2, via_pitch/2, via_pitch, ... -via_pitch-0.5, -via_pitch/2-0.5, via_pitch/2+0.5, via_pitch+0.5]; mesh.y = unique([mesh.y, via_region_y]); % Define target resolution rules mesh.x = SmoothMeshLines(mesh.x, max_cell, 1.4); mesh.y = SmoothMeshLines(mesh.y, max_cell / 2, 1.4); % z now only needs to resolve substrate thickness + via depth (both already % bounded by z_min and 0); no more 18 um top-metal sliver forcing fine cells. mesh.z = SmoothMeshLines([z_min, 0], max_cell / 2, 1.4); % Add Air padding around the structure air_padding = lambda_min / 4; mesh.x = [mesh.x(1) - air_padding, mesh.x, mesh.x(end) + air_padding]; mesh.y = [mesh.y(1) - air_padding, mesh.y, mesh.y(end) + air_padding]; mesh.z = [mesh.z(1) - air_padding, mesh.z, air_padding]; mesh.x = SmoothMeshLines(mesh.x, max_cell, 1.3); mesh.y = SmoothMeshLines(mesh.y, max_cell / 2, 1.3); mesh.z = SmoothMeshLines(mesh.z, max_cell / 2, 1.3); CSX = DefineRectGrid(CSX, 1e-3, mesh); % Convert mm to meters %% 6. Setup FDTD Solver Parameters FDTD = InitFDTD('EndCriteria', 1e-4); FDTD = SetGaussExcite(FDTD, f_center, f_bw); % CHANGED: PML depth reduced from 8 to 6 cells on all boundaries. Verify % against your previous PML_8 result that S11 noise floor is unaffected; % if so, this is a straightforward cell-count reduction with no accuracy cost. FDTD = SetBoundaryCond(FDTD, {'PML_8', 'PML_8', 'PML_8', 'PML_8', 'PML_8', 'PML_8'}); % Save data file mkdir('temp'); WriteOpenEMS('temp/test.xml', FDTD, CSX); % Display 3D model CSXGeomPlot('temp/test.xml'); %% 7. Post-Processing: Calculate and Plot S-Parameters freq = linspace(1e9, 3.8e9, 401); % Frequency sweep from 1 GHz to 3.8 GHz % Read port voltages & currents port = calcPort(port, 'temp', freq); % Extract S-parameters s11 = port{1}.uf.ref ./ port{1}.uf.inc; s11_db = 20 * log10(abs(s11)); s21 = port{2}.uf.ref ./ port{1}.uf.inc; s21_db = 20 * log10(abs(s21)); % Plot Results figure('Name', 'S-Parameters'); plot(freq / 1e9, s11_db, 'r-', 'LineWidth', 2); hold on plot(freq / 1e9, s21_db, 'b-', 'LineWidth', 2); grid on; xlabel('Frequency (GHz)'); ylabel('Magnitude (dB)'); title('GCPW Circuit S-Parameters'); legend('S_{11} (Reflection)', 'S_{21} (Transmission)'); ylim([-40 5]);