PeteS said:
I have a perl script I posted some time ago that calculates
differential impedance (there's a bug I have never fixed in the
propagation velocity, though).
I've used this a number of times and empirically it agrees with the
board manufacturer's data when they calculate the requirements for me.
Once I get home, I'll post it again.
Cheers
PeteS
# top-level options
# Globals
$Pi = 3.1415926535;
# main
print "\n\n";
print "Impedance calculator\n\n";
print "Source material:\n Johnson & Graham, ";
print "\"High-Speed Digital Design.\" 1993. Appendix C.\n";
print "Differential impedance calculations based on empirical data\n";
{
my ($choice);
do {
print "\nEnter S for stripline, M for microstrip, X to exit
<$choice>: ";
$entry = <>;
chomp $entry;
$choice = uc $entry unless $entry eq "";
print "\n";
if ($choice eq "S") {
STRIPLINE();
}
if ($choice eq "M") {
MICROSTRIP();
}
} until ($choice eq "X")
}
# Subroutines
BEGIN {
sub E_skny($$$) {
local ($h,$w,$Er) = @_;
return ($Er + 1) / 2 + ($Er - 1) / 2 * ((1 + 12 * $h / $w) ** -0.5 +
0.04*(1-$w/$h)**2);
}
sub E_wide($$$) {
local ($h,$w,$Er) = @_;
return ($Er + 1) / 2 + ($Er - 1) / 2 * (1 + 12 * $h / $w) ** -0.5;
}
sub E_temp($$$) {
local ($h, $w, $Er) = @_;
return ( $w > $h ? E_wide($h, $w, $Er) : E_skny($h, $w, $Er));
}
sub EEFF($$$$) {
local ($h, $w, $t, $Er) = @_;
return E_temp($h, $w, $Er) - (($Er - 1) * $t / $h) / 4.6 * ($w / $h) **
0.5;
}
sub WE_skny($$$) {
local ($h, $w, $t) = @_;
return $w + (1.25 * $t)/$Pi * (1 + log(4 * $Pi * $w / $t));
}
sub WE_wide($$$) {
local ($h, $w, $t) = @_;
return $w + (1.25 * $t)/$Pi * (1 + log(2 * $h / $t));
}
sub WE($$$) {
local ($h, $w, $t) = @_;
return ($w > $h / (2 * $Pi) ? WE_wide($h, $w, $t) : WE_skny($h, $w, $t));
}
sub ZMS_skny($$$) {
local ($h, $w, $t) = @_;
return 60 * log((8 * $h / WE($h, $w, $t)) + (WE($h, $w, $t) / (4 * $h)));
}
sub ZMS_wide($$$) {
local ($h, $w, $t) = @_;
return 120 * $Pi / (WE($h, $w, $t) / $h + 1.393 + 0.667 *
log(WE($h, $w, $t) / $h + 1.444));
}
sub ZMSTRIP($$$$) {
local ($h, $w, $t, $Er) = @_;
return ($w > $h ? ZMS_wide($h, $w, $t) : ZMS_skny($h, $w, $t)) /
EEFF($h, $w, $t, $Er) ** 0.5;
}
sub PMSTRIP($$$$) {
local ($h, $w, $t, $Er) = @_;
return 84.72e-12 * EEFF($h, $w, $t, $Er) ** 0.5;
}
sub LMSTRIP($$$$) {
local ($h, $w, $t, $x) = @_;
return PMSTRIP($h, $w, $t, 1) * ZMSTRIP($h, $w, $t, 1) * $x;
}
sub CMSTRIP($$$$$) {
local ($h, $w, $t, $Er, $x) = @_;
return PMSTRIP($h, $w, $t, $Er) / ZMSTRIP($h, $w, $t, $Er) * $x;
}
{ # this block makes the "my" below permanent
my ($h, $w, $t, $s);
sub MICROSTRIP {
print "\nMicrostrip configuration\n";
$h *= 1000;
$w *= 1000;
$t *= 1000;
$s *= 1000;
print "Enter height to reference plane (mil) <$h>: ";
$input = <>;
$h = $input unless $input eq "\n";
print "Enter width of track (mil) <$w>: ";
$input = <>;
$w = $input unless $input eq "\n";
print "Enter separation of diff traces <$s>: ";
$input = <>;
$s = $input unless $input eq "\n";
print "Enter thickness of trace (mil) (1oz = 1.37) <$t>: ";
$input = <>;
$t = $input unless $input eq "\n";
print "Enter dielectric constant <$Er>: ";
$input = <>;
$Er = $input unless $input eq "\n";
$h /= 1000;
$w /= 1000;
$t /= 1000;
$s /= 1000;
chomp $Er;
$hi_accuracy = 0;
if (($t / $h > 0) && ($t / $h < 0.2)) {
if (($w / $h > 0.1) && ($w / $h < 20)) {
if (($Er > 0) && ($Er < 16)) {
$hi_accuracy = 1;
}
}
}
print "\n";
$Zo = ZMSTRIP($h, $w, $t, $Er);
printf "Calculated impedance (ohm): %6.2f ", $Zo;
print ($hi_accuracy ? "(accuracy > 98%)" : "(accuracy undefined)");
print "\n";
printf "Differential impedance (ohm): %6.2f (+/-10%)\n",
ZMDIFF ($Zo, $s, $h);
printf "Calculated prop delay (in/ns): %6.2f\n", 1e-9 /
PMSTRIP($h, $w, $t, $Er);
printf "Calculated inductance (nH/in): %6.2f\n", 1e9 *
LMSTRIP($h, $w, $t, 1);
printf "Calculated capacitance (pF/in): %6.2f\n", 1e12 *
CMSTRIP($h, $w, $t, $Er, 1);
}
}
sub ZSTR_K1 ($$) {
local ($w, $t) = @_;
local ($tmp1, $tmp2, $tmp3) = 0;
$tmp1 = 1 + log(4 * $Pi * $w / $t);
$tmp2 = 1 + $t * $tmp1 / ($Pi * $w);
$tmp3 = $tmp2 + 0.255 * ($t / $w) ** 2;
return $w * $tmp3 / 2;
}
sub ZSTR_skny ($$$$) {
local ($b, $w, $t, $Er) = @_;
return 60 / ($Er ** 0.5) * log (4 * $b / ($Pi * ZSTR_K1($w, $t)));
}
sub ZSTR_K2 ($$) {
local ($b, $t) = @_;
local ($tmp1) = 0;
$tmp1 = 1 - $t / $b;
return 2 / $tmp1 * log(1 / $tmp1 + 1) - (1 / $tmp1 - 1) *
log(1 / $tmp1 ** 2 - 1);
}
sub ZSTR_wide ($$$$) {
local ($b, $w, $t, $Er) = @_;
return 94.15 / $Er ** 0.5 / ( ($w / $b) / (1 - $t / $b) +
ZSTR_K2 ($b, $t) / $Pi);
}
sub ZSTRIP ($$$$) {
local ($b, $w, $t, $Er) = @_;
return ($w > 0.35 * $b ? ZSTR_wide($b, $w, $t, $Er) :
ZSTR_skny ($b, $w, $t, $Er));
}
sub ZOFFSET ($$$$$) {
local ($h1, $h2, $w, $t, $Er) = @_;
return (2 * ZSTRIP(2 * $h1 + $t, $w, $t, $Er) *
ZSTRIP(2 * $h2 + $t, $w, $t, $Er)) /
(ZSTRIP(2 * $h1 + $t, $w, $t, $Er) +
ZSTRIP(2 * $h2 + $t, $w, $t, $Er));
}
sub PSTRIP($) {
local $Er = @_;
return 84.72e-12 * $Er ** 0.5;
}
sub LSTRIP($$$$) {
local ($b, $w, $t, $x) = @_;
return PSTRIP(1) * ZSTRIP($b, $w, $t, 1) * $x;
}
sub LOSTRIP($$$$$) {
local ($h1, $h2, $w, $t, $x) = @_;
return PSTRIP(1) * ZOFFSET($h1, $h2, $w, $t, 1) * $x;
}
sub CSTRIP($$$$$) {
local ($b, $w, $t, $Er, $x) = @_;
return PSTRIP($Er) / ZSTRIP($b, $w, $t, $Er);
}
sub COSTRIP($$$$$$) {
local ($h1, $h2, $w, $t, $Er, $x) = @_;
return PSTRIP($Er) / ZOFFSET($h1, $h2, $w, $t, $Er);
}
{ # this line makes the "my" below permanent
my ($h1, $h2, $w, $t, $s);
sub STRIPLINE {
print "\nStripline configuration\n";
$h1 *= 1000;
$h2 *= 1000;
$w *= 1000;
$t *= 1000;
$s *= 1000;
print "Enter distance to reference plane above (mil) <$h1>: ";
$input = <>;
$h1 = $input unless $input eq "\n";
print "Enter distance to reference plane below (mil) <$h2>: ";
$input = <>;
$h2 = $input unless $input eq "\n";
print "Enter width of track (mil) <$w>: ";
$input = <>;
$w = $input unless $input eq "\n";
print "Enter separation of diff traces <$s>: ";
$input = <>;
$s = $input unless $input eq "\n";
print "Enter thickness of trace (mil) (1oz = 1.37) <$t>: ";
$input = <>;
$t = $input unless $input eq "\n";
print "Enter dielectric constant <$Er>: ";
$input = <>;
$Er = $input unless $input eq "\n";
$h1 /= 1000;
$h2 /= 1000;
$w /= 1000;
$t /= 1000;
$s /= 1000;
chomp $Er;
$b = $h1 + $h2 + $t;
$hi_accuracy = 0;
if ($h1 == $h2) {
print "Symmetric stripline configuration\n\n";
if (($t / $b < 0.25) && ($t / $w < 0.11)) { $hi_accuracy = 1 }
$symmetric = 1;
}
else {
print "Asymmetric stripline configuration\n\n";
$symmetric = 0;
}
$Zo = ($symmetric ? ZSTRIP($b,$w,$t,$Er) : ZOFFSET($h1, $h2, $w,
$t, $Er));
printf "Calculated impedance (ohm): %6.2f ", $Zo;
print ($hi_accuracy ? "(accuracy > 98.7%)" : "(accuracy undefined)");
print "\n";
printf "Differential impedance (ohm): %6.2f (+/-10%)\n",
ZSDIFF($Zo, $s, $h1, $h2);
printf "Calculated prop delay (in/ns): %6.2f\n", 1e-9 /
PSTRIP($Er);
printf "Calculated inductance (nH/in): %6.2f\n", 1e9 *
($symmetric ? LSTRIP($b, $w, $t, 1) : LOSTRIP($h1, $h2, $w, $t, 1));
printf "Calculated capacitance (pF/in): %6.2f\n", 1e12 *
($symmetric ? CSTRIP($b, $w, $t, $Er, 1) :
COSTRIP($h1, $h2, $w, $t, $Er, 1));
}
}
sub ZMDIFF ($$$) {
my ($Zo, $s, $h) = @_;
return 2*$Zo*(1-0.48*exp(-.96*$s/$h));
}
sub ZSDIFF ($$$$) {
my ($Zo, $s, $h1, $h2) = @_;
return 2*$Zo*(1-0.374*exp(-2.9*$s/($h1+$h2)));
}
}