Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion pdnkit/pi/CavityModel.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "pi/CavityModel.h"
#include "pi/Roughness.h"

#include <Eigen/Dense>

Expand All @@ -21,7 +22,16 @@ std::complex<double> cavity_impedance(

const double mu = cfg.mu_r * kMu0;
// Complex permittivity: eps = eps_r eps_0 (1 - j tan_delta).
const cd eps = cfg.eps_r * kEps0 * cd(1.0, -cfg.tan_delta);
cd eps = cfg.eps_r * kEps0 * cd(1.0, -cfg.tan_delta);
// Optional conductor surface loss (HJ roughness x delta_s / d).
if (cfg.conductor_roughness_rq_m > 0.0 && cfg.d > 0.0) {
const double f_hz = omega / (2.0 * std::numbers::pi);
const double delta_s = skin_depth_copper(omega);
const double k_hj = hj_roughness_multiplier(
cfg.conductor_roughness_rq_m, f_hz);
const double tan_delta_cond = k_hj * delta_s / cfg.d;
eps -= cd(0.0, 1.0) * cfg.eps_r * kEps0 * tan_delta_cond;
}
const cd k_squared = omega * omega * mu * eps;

cd sum(0.0, 0.0);
Expand Down
9 changes: 9 additions & 0 deletions pdnkit/pi/CavityModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ struct CavityConfig {
double mu_r = 1.0; // relative permeability (~1 for PCB dielectrics)
double tan_delta = 0.020; // dielectric loss tangent (FR-4 default)
int max_modes = 30; // m, n each summed 0..max_modes inclusive

// Optional conductor surface roughness contribution. When > 0 the
// effective dielectric loss tangent is augmented per-frequency with
// K_HJ * (delta_s / d) -- the surface-loss term for a parallel-plate
// cavity, multiplied by the Hammerstad-Jensen roughness factor.
// Default 0 = smooth, preserves existing behavior.
// Typical values: 0.4e-6 (smooth ED foil), 1.0e-6 (standard rolled),
// 2.0-5.0e-6 (black-oxide treated).
double conductor_roughness_rq_m = 0.0;
};

// Self/transfer impedance at angular frequency omega (rad/s) between ports
Expand Down
1 change: 1 addition & 0 deletions pdnkit/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_executable(pdnkit_tests
ir_solver_test.cpp
ir_result_mesh_test.cpp
cavity_model_test.cpp
cavity_hj_test.cpp
cavity_mount_l_test.cpp
decap_optimizer_test.cpp
transient_test.cpp
Expand Down
64 changes: 64 additions & 0 deletions pdnkit/tests/cavity_hj_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>

#include <cmath>
#include <complex>
#include <numbers>

#include "pi/CavityModel.h"

using namespace pdnkit::pi;
using Catch::Approx;

namespace {
CavityConfig fr4() {
CavityConfig cfg;
cfg.a = 0.100;
cfg.b = 0.080;
cfg.d = 1.6e-3;
cfg.eps_r = 4.3;
cfg.tan_delta = 0.020;
cfg.max_modes = 15;
return cfg;
}
} // namespace

TEST_CASE("cavity-hj: zero roughness is identical to default",
"[cavity-hj][validation]") {
CavityConfig a = fr4();
a.conductor_roughness_rq_m = 0.0;
CavityConfig b = fr4();
const double f = 1.0e8;
const double w = 2.0 * std::numbers::pi * f;
auto za = cavity_impedance(a, 0.020, 0.020, 0.080, 0.060, w);
auto zb = cavity_impedance(b, 0.020, 0.020, 0.080, 0.060, w);
REQUIRE(za.real() == Approx(zb.real()));
REQUIRE(za.imag() == Approx(zb.imag()));
}

TEST_CASE("cavity-hj: roughness damps the resonance peak",
"[cavity-hj][validation]") {
const double f = 723.0e6;
const double w = 2.0 * std::numbers::pi * f;
CavityConfig smooth = fr4();
CavityConfig rough = fr4();
rough.conductor_roughness_rq_m = 5.0e-6;
auto z_smooth = cavity_impedance(smooth, 0.020, 0.020, 0.080, 0.060, w);
auto z_rough = cavity_impedance(rough, 0.020, 0.020, 0.080, 0.060, w);
INFO("|Z_smooth| = " << std::abs(z_smooth)
<< " |Z_rough| = " << std::abs(z_rough));
REQUIRE(std::abs(z_rough) < std::abs(z_smooth));
}

TEST_CASE("cavity-hj: off-resonance change is small", "[cavity-hj]") {
const double f = 50.0e6;
const double w = 2.0 * std::numbers::pi * f;
CavityConfig smooth = fr4();
CavityConfig rough = fr4();
rough.conductor_roughness_rq_m = 5.0e-6;
auto z_smooth = cavity_impedance(smooth, 0.020, 0.020, 0.080, 0.060, w);
auto z_rough = cavity_impedance(rough, 0.020, 0.020, 0.080, 0.060, w);
const double rel = std::abs(std::abs(z_rough) - std::abs(z_smooth))
/ std::abs(z_smooth);
REQUIRE(rel < 0.05);
}
Loading