/*ARGSUSED*/ int MUTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) { MUTmodel *model = (MUTmodel*)inModel; MUTinstance *here; int ktype; NG_IGNORE(states); /* loop through all the inductor models */ for( ; model != NULL; model = model->MUTnextModel ) { /* loop through all the instances of the model */ for (here = model->MUTinstances; here != NULL ; here=here->MUTnextInstance) { ktype = CKTtypelook("Inductor"); if(ktype <= 0) { SPfrontEnd->IFerror (ERR_PANIC, "mutual inductor, but inductors not available!", NULL); return(E_INTERN); } if (!here->MUTind1) here->MUTind1 = (INDinstance *) CKTfndDev(ckt, here->MUTindName1); if (!here->MUTind1) { IFuid namarray[2]; namarray[0]=here->MUTname; namarray[1]=here->MUTindName1; SPfrontEnd->IFerror (ERR_WARNING, "%s: coupling to non-existant inductor %s.", namarray); } if (!here->MUTind2) here->MUTind2 = (INDinstance *) CKTfndDev(ckt, here->MUTindName2); if (!here->MUTind2) { IFuid namarray[2]; namarray[0]=here->MUTname; namarray[1]=here->MUTindName2; SPfrontEnd->IFerror (ERR_WARNING, "%s: coupling to non-existant inductor %s.", namarray); } /* macro to make elements with built in test for out of memory */ #define TSTALLOC(ptr,first,second) \ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ return(E_NOMEM);\ } } while(0) TSTALLOC(MUTbr1br2,MUTind1->INDbrEq,MUTind2->INDbrEq); TSTALLOC(MUTbr2br1,MUTind2->INDbrEq,MUTind1->INDbrEq); } } return(OK); }
/* ARGSUSED */ int TFanal(CKTcircuit *ckt, int restart) /* forced restart flag */ { int size; int insrc = 0, outsrc = 0; double outputs[3]; IFvalue outdata; /* structure for output data vector, will point to * outputs vector above */ IFvalue refval; /* structure for 'reference' value (not used here) */ int error; int converged; int i; void *plotptr = NULL; /* pointer to out plot */ GENinstance *ptr = NULL; IFuid uids[3]; int Itype; int Vtype; char *name; #define tfuid (uids[0]) /* unique id for the transfer function output */ #define inuid (uids[1]) /* unique id for the transfer function input imp. */ #define outuid (uids[2]) /* unique id for the transfer function out. imp. */ /* first, find the operating point */ converged = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, ckt->CKTdcMaxIter); Itype = CKTtypelook("Isource"); Vtype = CKTtypelook("Vsource"); if(Itype != -1) { error = CKTfndDev(ckt,&Itype,&ptr, ((TFan*)ckt->CKTcurJob)->TFinSrc, (GENmodel *)NULL, (IFuid)NULL); if(error ==0) { ((TFan*)ckt->CKTcurJob)->TFinIsI = 1; ((TFan*)ckt->CKTcurJob)->TFinIsV = 0; } else { ptr = NULL; } } if( (Vtype != -1) && (ptr==NULL) ) { error = CKTfndDev(ckt,&Vtype,&ptr, ((TFan*)ckt->CKTcurJob)->TFinSrc, (GENmodel *)NULL, (IFuid)NULL); ((TFan*)ckt->CKTcurJob)->TFinIsV = 1; ((TFan*)ckt->CKTcurJob)->TFinIsI = 0; if(error !=0) { (*(SPfrontEnd->IFerror))(ERR_WARNING, "Transfer function source %s not in circuit", &(((TFan*)ckt->CKTcurJob)->TFinSrc)); ((TFan*)ckt->CKTcurJob)->TFinIsV = 0; return(E_NOTFOUND); } } size = SMPmatSize(ckt->CKTmatrix); for(i=0;i<=size;i++) { ckt->CKTrhs[i] = 0; } if(((TFan*)ckt->CKTcurJob)->TFinIsI) { ckt->CKTrhs[ptr->GENnode1] -= 1; ckt->CKTrhs[ptr->GENnode2] += 1; } else { insrc = CKTfndBranch(ckt,((TFan*)ckt->CKTcurJob)->TFinSrc); ckt->CKTrhs[insrc] += 1; } SMPsolve(ckt->CKTmatrix,ckt->CKTrhs,ckt->CKTrhsSpare); ckt->CKTrhs[0]=0; /* make a UID for the transfer function output */ (*(SPfrontEnd->IFnewUid))(ckt,&tfuid,(IFuid)NULL,"Transfer_function", UID_OTHER, NULL); /* make a UID for the input impedance */ (*(SPfrontEnd->IFnewUid))(ckt,&inuid,((TFan*)ckt->CKTcurJob)->TFinSrc, "Input_impedance", UID_OTHER, NULL); /* make a UID for the output impedance */ if(((TFan*)ckt->CKTcurJob)->TFoutIsI) { (*(SPfrontEnd->IFnewUid))(ckt,&outuid,((TFan*)ckt->CKTcurJob)->TFoutSrc ,"Output_impedance", UID_OTHER, NULL); } else { name = (char *) MALLOC(sizeof(char)*(strlen(((TFan*)ckt->CKTcurJob)->TFoutName)+22)); (void)sprintf(name,"output_impedance_at_%s", ((TFan*)ckt->CKTcurJob)->TFoutName); (*(SPfrontEnd->IFnewUid))(ckt,&outuid,(IFuid)NULL, name, UID_OTHER, NULL); } error = (*(SPfrontEnd->OUTpBeginPlot))(ckt,(void *)(ckt->CKTcurJob), ((TFan*)(ckt->CKTcurJob))->JOBname,(IFuid)NULL,(int)0,3, uids,IF_REAL,&plotptr); if(error) return(error); /*find transfer function */ if(((TFan*)ckt->CKTcurJob)->TFoutIsV) { outputs[0] = ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutPos->number] - ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutNeg->number] ; } else { outsrc = CKTfndBranch(ckt,((TFan*)ckt->CKTcurJob)->TFoutSrc); outputs[0] = ckt->CKTrhs[outsrc]; } /* now for input resistance */ if(((TFan*)ckt->CKTcurJob)->TFinIsI) { outputs[1] = ckt->CKTrhs[ptr->GENnode2] - ckt->CKTrhs[ptr->GENnode1]; } else { if(fabs(ckt->CKTrhs[insrc])<1e-20) { outputs[1]=1e20; } else { outputs[1] = -1/ckt->CKTrhs[insrc]; } } if(((TFan*)ckt->CKTcurJob)->TFoutIsI && (((TFan*)ckt->CKTcurJob)->TFoutSrc == ((TFan*)ckt->CKTcurJob)->TFinSrc)) { outputs[2]=outputs[1]; goto done; /* no need to compute output resistance when it is the same as the input */ } /* now for output resistance */ for(i=0;i<=size;i++) { ckt->CKTrhs[i] = 0; } if(((TFan*)ckt->CKTcurJob)->TFoutIsV) { ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutPos->number] -= 1; ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutNeg->number] += 1; } else { ckt->CKTrhs[outsrc] += 1; } SMPsolve(ckt->CKTmatrix,ckt->CKTrhs,ckt->CKTrhsSpare); ckt->CKTrhs[0]=0; if(((TFan*)ckt->CKTcurJob)->TFoutIsV) { outputs[2]= ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutNeg->number] - ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutPos->number]; } else { outputs[2] = 1/MAX(1e-20,ckt->CKTrhs[outsrc]); } done: outdata.v.numValue=3; outdata.v.vec.rVec=outputs; refval.rValue = 0; (*(SPfrontEnd->OUTpData))(plotptr,&refval,&outdata); (*(SPfrontEnd->OUTendPlot))(plotptr); return(OK); }
int NOISEan (CKTcircuit *ckt, int restart) { static Ndata *data; /* va, must be static, for continuation of * interrupted(Ctrl-C), longer lasting noise * analysis */ double realVal; double imagVal; int error; int posOutNode; int negOutNode; int step; IFuid freqUid; double freqTol; /* tolerence parameter for finding final frequency; hack */ int i, src_type; NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; GENinstance *inst = CKTfndDev(ckt, job->input); posOutNode = (job->output) -> number; negOutNode = (job->outputRef) -> number; /* see if the source specified is AC */ { //bool ac_given = FALSE; int ac_given = FALSE; if (!inst || inst->GENmodPtr->GENmodType < 0) { SPfrontEnd->IFerrorf (ERR_WARNING, "Noise input source %s not in circuit", job->input); return E_NOTFOUND; } if (inst->GENmodPtr->GENmodType == CKTtypelook("Vsource")) { ac_given = ((VSRCinstance *)inst) -> VSRCacGiven; src_type = SV_VOLTAGE; } else if(inst->GENmodPtr->GENmodType == CKTtypelook("Isource")) { ac_given = ((ISRCinstance *)inst) -> ISRCacGiven; src_type = SV_CURRENT; } else { SPfrontEnd->IFerrorf (ERR_WARNING, "Noise input source %s is not of proper type", job->input); return E_NOTFOUND; } if (!ac_given) { SPfrontEnd->IFerrorf (ERR_WARNING, "Noise input source %s has no AC value", job->input); return E_NOACINPUT; } } if ( (job->NsavFstp == 0.0) || restart) { /* va, NsavFstp is double */ switch (job->NstpType) { case DECADE: job->NfreqDelta = exp(log(10.0)/ job->NnumSteps); break; case OCTAVE: job->NfreqDelta = exp(log(2.0)/ job->NnumSteps); break; case LINEAR: job->NfreqDelta = (job->NstopFreq - job->NstartFreq)/ (job->NnumSteps - 1); break; default: return(E_BADPARM); } /* error = DCop(ckt); */ error = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, ckt->CKTdcMaxIter); if (error) return(error); /* Patch to noisean.c by Richard D. McRoberts. */ ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; error = CKTload(ckt); if(error) return(error); data = TMALLOC(Ndata, 1); step = 0; data->freq = job->NstartFreq; data->outNoiz = 0.0; data->inNoise = 0.0; data->squared = cp_getvar("sqrnoise", CP_BOOL, NULL) ? 1 : 0; /* the current front-end needs the namelist to be fully declared before an OUTpBeginplot */ SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL); data->numPlots = 0; /* we don't have any plots yet */ error = CKTnoise(ckt,N_DENS,N_OPEN,data); if (error) return(error); /* * all names in the namelist have been declared. now start the * plot */ if (src_type == SV_VOLTAGE) fixme_inoise_type = data->squared ? SV_SQR_VOLTAGE_DENSITY : SV_VOLTAGE_DENSITY; else fixme_inoise_type = data->squared ? SV_SQR_CURRENT_DENSITY : SV_CURRENT_DENSITY; fixme_onoise_type = data->squared ? SV_SQR_VOLTAGE_DENSITY : SV_VOLTAGE_DENSITY; if (!data->squared) for (i = 0; i < data->numPlots; i++) data->squared_value[i] = ciprefix("inoise", data->namelist[i]) || ciprefix("onoise", data->namelist[i]); error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, data->squared ? "Noise Spectral Density Curves - (V^2 or A^2)/Hz" : "Noise Spectral Density Curves", freqUid, IF_REAL, data->numPlots, data->namelist, IF_REAL, &(data->NplotPtr)); if (error) return(error); if (job->NstpType != LINEAR) { SPfrontEnd->OUTattributes (data->NplotPtr, NULL, OUT_SCALE_LOG, NULL); } } else { /* we must have paused before. pick up where we left off */ step = (int)(job->NsavFstp); switch (job->NstpType) { case DECADE: case OCTAVE: data->freq = job->NstartFreq * exp (step * log (job->NfreqDelta)); break; case LINEAR: data->freq = job->NstartFreq + step * job->NfreqDelta; break; default: return(E_BADPARM); } job->NsavFstp = 0; data->outNoiz = job->NsavOnoise; data->inNoise = job->NsavInoise; /* saj resume rawfile fix*/ error = SPfrontEnd->OUTpBeginPlot (NULL, NULL, NULL, NULL, 0, 666, NULL, 666, &(data->NplotPtr)); /*saj*/ } switch (job->NstpType) { case DECADE: case OCTAVE: freqTol = job->NfreqDelta * job->NstopFreq * ckt->CKTreltol; break; case LINEAR: freqTol = job->NfreqDelta * ckt->CKTreltol; break; default: return(E_BADPARM); } data->lstFreq = data->freq; /* do the noise analysis over all frequencies */ while (data->freq <= job->NstopFreq + freqTol) { if(SPfrontEnd->IFpauseTest()) { job->NsavFstp = step; /* save our results */ job->NsavOnoise = data->outNoiz; /* up until now */ job->NsavInoise = data->inNoise; return (E_PAUSE); } ckt->CKTomega = 2.0 * M_PI * data->freq; ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEAC | MODEACNOISE; ckt->noise_input = inst; /* * solve the original AC system to get the transfer * function between the input and output */ NIacIter(ckt); realVal = ckt->CKTrhsOld [posOutNode] - ckt->CKTrhsOld [negOutNode]; imagVal = ckt->CKTirhsOld [posOutNode] - ckt->CKTirhsOld [negOutNode]; data->GainSqInv = 1.0 / MAX(((realVal*realVal) + (imagVal*imagVal)),N_MINGAIN); data->lnGainInv = log(data->GainSqInv); /* set up a block of "common" data so we don't have to * recalculate it for every device */ data->delFreq = data->freq - data->lstFreq; data->lnFreq = log(MAX(data->freq,N_MINLOG)); data->lnLastFreq = log(MAX(data->lstFreq,N_MINLOG)); data->delLnFreq = data->lnFreq - data->lnLastFreq; if ((job->NStpsSm != 0) && ((step % (job->NStpsSm)) == 0)) { data->prtSummary = TRUE; } else { data->prtSummary = FALSE; } /* data->outNumber = 1; */ data->outNumber = 0; /* the frequency will NOT be stored in array[0] as before; instead, * it will be given in refVal.rValue (see later) */ NInzIter(ckt,posOutNode,negOutNode); /* solve the adjoint system */ /* now we use the adjoint system to calculate the noise * contributions of each generator in the circuit */ error = CKTnoise(ckt,N_DENS,N_CALC,data); if (error) return(error); data->lstFreq = data->freq; /* update the frequency */ switch (job->NstpType) { case DECADE: case OCTAVE: data->freq *= job->NfreqDelta; break; case LINEAR: data->freq += job->NfreqDelta; break; default: return(E_INTERN); } step++; } error = CKTnoise(ckt,N_DENS,N_CLOSE,data); if (error) return(error); data->numPlots = 0; data->outNumber = 0; if (job->NstartFreq != job->NstopFreq) { error = CKTnoise(ckt,INT_NOIZ,N_OPEN,data); if (error) return(error); if (src_type == SV_VOLTAGE) fixme_inoise_type = data->squared ? SV_SQR_VOLTAGE : SV_VOLTAGE; else fixme_inoise_type = data->squared ? SV_SQR_CURRENT : SV_CURRENT; fixme_onoise_type = data->squared ? SV_SQR_VOLTAGE : SV_VOLTAGE; if (!data->squared) for (i = 0; i < data->numPlots; i++) data->squared_value[i] = ciprefix("inoise", data->namelist[i]) || ciprefix("onoise", data->namelist[i]); SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, data->squared ? "Integrated Noise - V^2 or A^2" : "Integrated Noise", NULL, 0, data->numPlots, data->namelist, IF_REAL, &(data->NplotPtr)); error = CKTnoise(ckt,INT_NOIZ,N_CALC,data); if (error) return(error); error = CKTnoise(ckt,INT_NOIZ,N_CLOSE,data); if (error) return(error); } FREE(data); return(OK); }