I use the following perl code for diff pairs (when I need to calculate stuff - mostly I tell the board fabricator what I need and let them tell me what the track widths and inter layer thicknesses are).
Note that a diff pair should be length matched to a certain degree (to prevent differential to common mode conversion; i.e. to make sure your differential signal is still differential). In your case, that's not necessarily too important. The numbers of consequence to you are t(prop) ~ 160psec/inch on FR4
Code follows: # 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 : "; $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) : "; $input = ; $h = $input unless $input eq "\\n"; print "Enter width of track (mil) : "; $input = ; $w = $input unless $input eq "\\n"; print "Enter separation of diff traces : "; $input = ; $s = $input unless $input eq "\\n"; print "Enter thickness of trace (mil) (1oz = 1.37) : "; $input = ; $t = $input unless $input eq "\\n"; print "Enter dielectric constant : "; $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) : "; $input = ; $h1 = $input unless $input eq "\\n"; print "Enter distance to reference plane below (mil) : "; $input = ; $h2 = $input unless $input eq "\\n"; print "Enter width of track (mil) : "; $input = ; $w = $input unless $input eq "\\n"; print "Enter separation of diff traces : "; $input = ; $s = $input unless $input eq "\\n"; print "Enter thickness of trace (mil) (1oz = 1.37) : "; $input = ; $t = $input unless $input eq "\\n"; print "Enter dielectric constant : "; $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))); } }