* bondwire.cpp - bondwire class implementation
*
* Copyright (C) 2006 Bastien Roucaries <roucaries.bastien@gmail.com>
* Copyright (C) 2007, 2008 Stefan Jahn <stefan@lkcc.org>
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this package; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* $Id$
*
*/
\brief Implement a bondwire model
Bibliography:
[1] Microwave Solid State Circuit Design,
Inder Bahl and Prakash Barthia -- 2nd edition
2003 - Wiley interscience
ISBN 9-471-20755-1
[2] Wikibook Electronics/Inductors
http://en.wikibooks.org/w/index.php?title=Electronics/Inductors&oldid=497883
online 2006/11/02
[3] Physical and electrical modeling of bonding wires up to 110 GHz,
Descharles, C. Algani, C. Mercier, B. Alquie, G.
Microwave Conference, 2003. 33rd European
Volume: 2, On page(s): 639- 642 vol.2
ISBN: 1-58053-834-7
INSPEC Accession Number: 1262971
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "component.h"
#include "substrate.h"
#include "bondwire.h"
using namespace qucs;
bondwire::bondwire () : circuit (2) {
type = CIR_BONDWIRE;
}
#define TABLE(x) { #x, x }
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
enum bondwiremodel {
FREESPACE,
MIRROR,
DESCHARLES
};
struct modeltable_t {
const char * name;
int model;
};
static const modeltable_t modeltable[] = {
TABLE(FREESPACE),
TABLE(MIRROR),
};
* Get properties and fill the class.
*
* \todo check values
*/
void bondwire::getProperties (void) {
unsigned int i;
R = 0;
l = getPropertyDouble ("L");
d = getPropertyDouble ("D");
h = getPropertyDouble ("H");
rho = getPropertyDouble ("rho");
mur = getPropertyDouble ("mur");
const char * Model = getPropertyString ("Model");
if (Model == NULL) {
model = FREESPACE;
logprint (LOG_STATUS, "Model is not specified force FREESPACE\n");
} else {
model = (enum bondwiremodel) -1;
for (i = 0 ; i < ARRAY_SIZE (modeltable); i++) {
if (!strcasecmp (modeltable[i].name, Model))
model = modeltable[i].model;
}
if (model == -1)
logprint (LOG_ERROR, "Model %s not defined\n", Model);
}
temp = getPropertyDouble ("Temp");
substrate * subst = getSubstrate ();
nr_double_t er = subst->getPropertyDouble ("er");
nr_double_t h = subst->getPropertyDouble ("h");
nr_double_t t = subst->getPropertyDouble ("t");
(void) er;
(void) h;
(void) t;
}
* \todo Factorize the compution of skin depth in a header file.
*
* \param f frequency
* \param rho bond wire resistivity
* \param mur relative magnetic permeabillity
*/
static nr_double_t skindepth (const nr_double_t f,
const nr_double_t rho, const nr_double_t mur) {
return std::sqrt (rho / (pi * f * MU0 * mur));
}
* Resitance of the wire is computed using classical
* tube model enhanced for case where tube is greater
* than conductor (i.e. low frequency case).
*
* \todo Offer other resistance model for
* instance exponential decay and bessel function exact
* computation. But I do not know it is worth the effort.
*
* \todo Factorise the resistance model.
*/
nr_double_t bondwire::resistance (const nr_double_t f) const {
nr_double_t delta, rout, rin;
rout = d / 2;
if (f > 0.0) {
delta = skindepth (f, rho, mur);
rin = rout - delta;
if (rin < 0.0)
rin = 0.0;
}
else
rin = 0.0;
return (rho * one_over_pi * l) / (rout * rout - rin * rin);
}
* According to [1] pp63 (2.30a-b) correction factor
* is such as:
* \f[
* C = 0.25 \tanh \frac{4\delta}{d}
* \f]
* where \f$\delta\f$ is the well known skin depth.
*
* \param f frequency
* \param d bond wire diameter
* \param rho bond wire resistivity
* \param mur relative magnetic permeabillity
*
* However according to [2] it seems that the author of [1] do the
* assumption of \f$\mu_r=1\f$ therefore rewrite the equation such as:
*
* \f[
* C = \frac{\mu_r}{4} \tanh \frac{4\delta}{d}
* \f]
*
* \return mur/4 if rho is zero, otherwise C
* \todo Check domain validity for round C factor.
*/
static nr_double_t correctionfactor (const nr_double_t f,
const nr_double_t d,
const nr_double_t rho,
const nr_double_t mur) {
nr_double_t delta;
if (f > 0.0 && rho > 0.0) {
delta = skindepth (f, rho, mur);
if (delta / d < 1e-2)
return delta / d;
else
return (mur / 4) * std::tanh ((4 * delta) / d);
}
return mur / 4;
}
According to [1] pp63 (2.29) free space inductance (in nH)
is such as (\f$l\f$ in micrometers):
\f[
L = 2\times10^{-4} l \left[
\ln\left\{ \frac{2l}{d}
+ \sqrt{1 + \left(\frac{2l}{d}\right)^2} \right\}
+ \frac{d}{2l} - \sqrt{1+\left(\frac{d}{2l}\right)^2}
+ C \right]
\f]
According to [2] self inductance is (in H with l in m):
\f[
L = \frac{\mu_0}{2\pi} l\left[
\ln\left\{ \frac{2l}{d}
+ \sqrt{1 + \left(\frac{2l}{d}\right)^2} \right\}
+ \frac{d}{2l} - \sqrt{1+\left(\frac{d}{2l}\right)^2}
+ \frac{\mu_r}{4} \right]
\f]
Finally we will use (in H with l in m):
\f[
L = \frac{\mu_0}{2\pi} l\left[
\ln\left\{ \frac{2l}{d}
+ \sqrt{1 + \left(\frac{2l}{d}\right)^2} \right\}
+ \frac{d}{2l} - \sqrt{1+\left(\frac{d}{2l}\right)^2}
+ C \right]
\f]
\param f frequency
\param d bond wire diameter
\param l bond wire length (in meters)
\param rho bond wire resistivity
\param mur relative magnetic permeabillity
*/
nr_double_t bondwire::Lfreespace (const nr_double_t f) const {
nr_double_t _2ld = (2.0 * l) / d;
nr_double_t d2l = d / (2.0 * l);
nr_double_t tmp;
tmp = std::log (_2ld + std::sqrt (1 + _2ld * _2ld));
tmp += d2l - std::sqrt (1 + d2l * d2l);
tmp += correctionfactor (f, d, rho, mur);
return MU0 * (one_over_pi / 2) * l * tmp;
}
According to [1] pp64 (2.32) inductance (in nH)
is such as (\f$l\f$ in micrometers):
\f[
L = 2\times10^{-4} l \left[
\ln \frac{4h}{d}
+ \ln \frac{l+\sqrt{l^2+d^2/4}}{l+\sqrt{l^2+4h^2}}
+ \sqrt{1+\frac{4h^2}{l^2}} - \sqrt{1+\frac{d^2}{4l^2}}
- 2 \frac{h}{l} + \frac{d}{2l}
\right]
\f]
Finally we will use (in H with l in m):
\f[
L = \frac{\mu_0}{2\pi} l \left[
\ln \frac{4h}{d}
+ \ln \frac{l+\sqrt{l^2+d^2/4}}{l+\sqrt{l^2+4h^2}}
+ \sqrt{1+\frac{4h^2}{l^2}} - \sqrt{1+\frac{d^2}{4l^2}}
- 2 \frac{h}{l} + \frac{d}{2l}
\right]
\f]
\note Mirror is a strange model that is frequency independent.
Whereas computations are valid, hypothesis are arguable.
Indeed, they did the assumption that the ground plane is
perfect that is really a zero order model in the high
frequency domain.
*/
nr_double_t bondwire::Lmirror (void) const {
nr_double_t tmp;
tmp = std::log ((l + std::sqrt (l * l + d * d / 4)) / (l + std::sqrt (l * l + 4 * h * h)));
tmp += std::log (4 * h / d);
tmp += std::sqrt (1 + 4 * h * h / (l * l));
tmp -= std::sqrt (1 + d * d / (4 * l * l));
tmp -= 2 * h / l;
tmp += d / (2 * l);
return MU0 * (one_over_pi / 2) * l * tmp;
}
*/
matrix bondwire::calcMatrixY (const nr_double_t f) {
nr_double_t Lw;
L = 0;
switch (model) {
case MIRROR:
L = Lmirror ();
R = resistance (f);
break;
case FREESPACE:
L = Lfreespace (f);
R = resistance (f);
break;
default:
break;
}
Lw = L * 2 * pi * f;
nr_complex_t yL = 1.0 / nr_complex_t (R, Lw);
matrix Y (2);
Y.set (NODE_1, NODE_1, +yL);
Y.set (NODE_1, NODE_2, -yL);
Y.set (NODE_2, NODE_1, -yL);
Y.set (NODE_2, NODE_2, +yL);
return Y;
}
void bondwire::initSP (void) {
allocMatrixS ();
getProperties ();
}
*! Reuse computed Y matrix.
*/
void bondwire::calcSP (const nr_double_t frequency) {
setMatrixS (ytos (calcMatrixY (frequency)));
}
void bondwire::saveCharacteristics (nr_double_t) {
setCharacteristic ("L", L);
setCharacteristic ("R", R);
}
*! DC model of a bondwire is a resistance.
*/
void bondwire::initDC (void) {
nr_double_t g;
getProperties ();
if (rho != 0.0) {
g = 1.0 / resistance (0);
setVoltageSources (0);
allocMatrixMNA ();
setY (NODE_1, NODE_1, +g); setY (NODE_2, NODE_2, +g);
setY (NODE_1, NODE_2, -g); setY (NODE_2, NODE_1, -g);
}
else {
setVoltageSources (1);
setInternalVoltageSource (1);
allocMatrixMNA ();
clearY ();
voltageSource (VSRC_1, NODE_1, NODE_2);
}
}
void bondwire::initTR (void)
{
initDC();
}
void bondwire::initAC (void) {
getProperties ();
setVoltageSources (0);
allocMatrixMNA ();
}
*! Use serial LR model (Y matrix).
*/
void bondwire::calcAC (const nr_double_t frequency) {
setMatrixY (calcMatrixY (frequency));
}
void bondwire::calcDC(void)
{
if (rho != 0.0) {
nr_double_t g = 1.0 / resistance (0);
setY (NODE_1, NODE_1, +g); setY (NODE_2, NODE_2, +g);
setY (NODE_1, NODE_2, -g); setY (NODE_2, NODE_1, -g);
}
}
void bondwire::calcTR(nr_double_t t)
{
calcDC();
}
void bondwire::calcNoiseSP (nr_double_t) {
nr_double_t T = getPropertyDouble ("Temp");
nr_double_t f = celsius2kelvin (T) * 4.0 * R * z0 / norm (4.0 * z0 + R) / T0;
setN (NODE_1, NODE_1, +f); setN (NODE_2, NODE_2, +f);
setN (NODE_1, NODE_2, -f); setN (NODE_2, NODE_1, -f);
}
void bondwire::calcNoiseAC (nr_double_t) {
nr_double_t y = 1 / R;
nr_double_t T = getPropertyDouble ("Temp");
nr_double_t f = celsius2kelvin (T) / T0 * 4.0 * y;
setN (NODE_1, NODE_1, +f); setN (NODE_2, NODE_2, +f);
setN (NODE_1, NODE_2, -f); setN (NODE_2, NODE_1, -f);
}
PROP_REQ [] = {
{ "D", PROP_REAL, { 25e-6, PROP_NO_STR }, PROP_POS_RANGE },
{ "L", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_POS_RANGE },
{ "H", PROP_REAL, { 1e-3, PROP_NO_STR }, PROP_POS_RANGE },
{ "mur", PROP_REAL, { 1, PROP_NO_STR }, PROP_RNGII (1, 100) },
{ "rho", PROP_REAL, { 0.022e-6, PROP_NO_STR }, PROP_POS_RANGE },
{ "Model", PROP_STR, { PROP_NO_VAL, "FREESPACE" },
PROP_RNG_STR3 ("FREESPACE", "MIRROR", "DESCHARLES") },
{ "Subst", PROP_STR, { PROP_NO_VAL, "Subst1" }, PROP_NO_RANGE },
PROP_NO_PROP };
PROP_OPT [] = {
{ "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
PROP_NO_PROP };
struct define_t bondwire::cirdef =
{ "BOND", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };