00001 // rfmatch.cc 00002 00003 // This program performs a modest analysis of an SIS receiver using 00004 // purely linear circuit analysis in the same way as earlier tools 00005 // like pcircuit. It simulates superconducting microstrip RF 00006 // circuitry and evaluates its matching characteristics into a fixed 00007 // load representing the SIS junction: 00008 00009 // Create the RF circuit for 1/2 of a twinslot, quasioptical SIS 00010 // mixer. Analyze its frequency response for matching into an SIS 00011 // junction with specified physical characteristics. 00012 // 00013 // The circuit will be modelled as follows: 00014 // 00015 // RF --- --- --- --- branch --- --- short 00016 // IN o--| |---| |---| |---| |-----+-----| |---| |---+ to 00017 // --- --- --- --- | --- --- | ground 00018 // antenna rf_1 rf_2 tune_2 o sis_cap tune_1 V 00019 // OUT 00020 // (into SIS Rn) 00021 // 00022 // Below each element is the name of the object representing it in the 00023 // program code below. The SIS junction is represented in a purely linear 00024 // fashion as a parallel RC combination. The power coupled into the R of 00025 // the RC is what we determine in this program. 00026 00027 #include "supermix.h" 00028 00029 // ========================================================================== 00030 // THE PHYSICAL SPECIFICATIONS OF THE RF CIRCUIT: 00031 00032 // THE CHARACTERISTICS OF THE SUPERCONDUCTING FILMS 00033 // Here we just create a new class to hold the relevant physical 00034 // parameters needed. We immediately declare two objects of the 00035 // class, holding the relevant numbers for Noibium and NbTiN. 00036 // 00037 // The member variables of the class are of type parameter, so 00038 // they could be controlled by the optimizer, if desired. See 00039 // lna/lna_opt.cc for details. 00040 // 00041 // Notice how we can initialize the member variables in simple 00042 // classes like this one. 00043 struct sc_material { parameter Vgap, Tc, rho_normal; } 00044 nb = { 2.9*mVolt, 9.20*Kelvin, 5.0*Micro*Ohm*Centi*Meter }, 00045 nbtin = { 5.0*mVolt, 15.75*Kelvin, 30.0*Micro*Ohm*Centi*Meter }; 00046 00047 // THE WIDTHS AND LENGTHS OF THE MICROSTRIPS 00048 // Another newly-created class, this time to hold the dimensions 00049 // of the individual microstrip circuit elements. 00050 struct wl { parameter width, length; } 00051 RF1 = { 5.8*Micron, 11.2*Micron }, // transformer section 1 (nearest antenna) 00052 RF2 = { 3.3*Micron, 15.0*Micron }, // transformer section 2 00053 L1 = { 5.0*Micron, 6.9*Micron/2 }, // tuning inductor from SIS to virtual ground 00054 L2 = { 5.0*Micron, 2.5*Micron }; // tuning inductor between transformer and SIS 00055 00056 // We don't need new classes to hold the remaining info; we'll 00057 // just use parameters. 00058 00059 // THE LAYER THICKNESSES 00060 parameter 00061 GP_THICKNESS = 3000.*Angstrom, // ground plane superconductor thickness 00062 TOP_THICKNESS = 3000.*Angstrom, // top strip superconductor thickness 00063 SIO_THICKNESS = 4500.*Angstrom, // SiO layer generally 00064 TUNE_THICKNESS = 2500.*Angstrom; // SiO in tuning inductor 00065 00066 // SIS JUNCTION PARAMETERS 00067 parameter 00068 RNA = 21.8*Ohm*Micron*Micron, // normal resistance - area product 00069 SCAP = 82.0*fFarad/Micron/Micron, // specific capacitance (per area) 00070 AREA = 1.2*1.2*Micron*Micron; // effective junction area 00071 00072 // THE FILE NAME FOR THE ANTENNA IMPEDANCE INFORMATION 00073 const char * const ANT_FILE = "Zslot.750"; 00074 00075 00076 // ========================================================================== 00077 // CLASSES WHICH ACTUALLY CALCULATE THE SIS RN AND CAPACITANCE: 00078 00079 // The SIS junction objects in supermix want to know the actual normal 00080 // resistance and capacitance of a junction. Since the SIS objects hold 00081 // this information in parameters, they can be set to shadow other 00082 // parameter-like variables (objects of type abstract_real_parameter). 00083 // See parameter/real_parameter.h and parameter/abstract_real_parameter.h 00084 // for further details. Here we create two objects each with their own 00085 // unique class. Each one will act just like a double in equations, with 00086 // the additional feature of being shadowable by other parameters. 00087 // 00088 // To qualify as an abstract_real_parameter, an object must define the get() 00089 // member function, which returns its value. 00090 // 00091 // Note that we use "struct" instead of "class" in the type definitions. This 00092 // just ensures that all members of a class object are public (accessible). 00093 00094 // Rn, THE NORMAL RESISTANCE: 00095 struct calc_Rn : public abstract_real_parameter { 00096 double get() const { return RNA/AREA; } 00097 } Rn; 00098 00099 // Cap, THE JUNCTION CAPACITANCE: 00100 struct calc_Cap : public abstract_real_parameter { 00101 double get() const { return SCAP*AREA; } 00102 } Cap; 00103 00104 00105 // ========================================================================== 00106 // With the global definitions out of the way, we start the main routine: 00107 int main() 00108 { 00109 // SET THE GLOBAL TEMPERATURE AND NORMALIZATION IMPEDANCE 00110 // See how we use our newly created type calc_Rn. device::Z0 is of type 00111 // parameter, so it can "shadow" another parameter-like variable if 00112 // assigned its address (the purpose of the '&'). When device::Z0 is 00113 // asked for its value, it in turn asks Rn's value by calling Rn.get(). 00114 // Rn then asks RNA and AREA for their values before calculating their 00115 // ratio. Consequently, if the program changes either RNA or AREA, 00116 // subsequent accesses of device::Z0 will return a different result. 00117 // Since device::Z0 determines the normalizing impedance for S matrix 00118 // calculations, changes to RNA or AREA will have wide-ranging effects. 00119 device::T = 4.2*Kelvin; 00120 device::Z0 = & Rn; // we use the SIS Rn as our normalizing impedance 00121 00122 00123 // CREATE THE SUPERCONDUCTING FILMS AND THE DIELECTRIC MATERIALS 00124 // See surfaceZ.h for a description of super_film, which is derived from 00125 // type surfimp. super_film will calculate its surface impedance by 00126 // first building an interpolation table, greatly speeding up repeated 00127 // accesses. The interpolation table is dynamically extended in range 00128 // as required, so its use is transparent to the user. 00129 // 00130 // Dielectrics are defined in trlines.h. We use type const_diel, which 00131 // uses two parameters to hold its characteristics: a dielectric constant 00132 // and a loss tangent. 00133 00134 // The top film is Niobium. 00135 super_film top; 00136 top.Vgap = & nb.Vgap; 00137 top.Tc = & nb.Tc; 00138 top.rho_normal = & nb.rho_normal; 00139 top.Thick = & TOP_THICKNESS; 00140 00141 // The groundplane is NbTiN. 00142 super_film gp; 00143 gp.Vgap = & nbtin.Vgap; 00144 gp.Tc = & nbtin.Tc; 00145 gp.rho_normal = & nbtin.rho_normal; 00146 gp.Thick = & GP_THICKNESS; 00147 00148 // Air is the dielectric above the microstrips; we just treat it as vacuum. 00149 const_diel air; 00150 air.eps = 1.0; 00151 air.tand = 0.0; 00152 00153 // SiO is the dielectric between the strip and the groundplane. 00154 const_diel sio; 00155 sio.eps = 5.6; 00156 sio.tand = 0.0; 00157 00158 00159 // CREATE THE MICROSTRIPS USING THE ABOVE MATERIALS 00160 // class microstrip is defined in trlines.h. It requires materials, 00161 // dimensions, and the dielectric layer thickness. 00162 00163 // For convenience, we first create a generic microstrip using our materials. 00164 microstrip ms; 00165 ms.ground_plane(gp); 00166 ms.substrate(sio); 00167 ms.top_strip(top); 00168 ms.superstrate(air); 00169 00170 // Now the ones we actually use, copying the generic one. We must assign 00171 // dimensions as well. 00172 00173 // rf_1 and rf_2 make up the matching transformer between the antenna and 00174 // the SIS junction. rf_1 will be connected to the antenna. 00175 microstrip rf_1(ms); 00176 rf_1.width = & RF1.width; 00177 rf_1.length = & RF1.length; 00178 rf_1.sub_thick = & SIO_THICKNESS; 00179 microstrip rf_2(ms); 00180 rf_2.width = & RF2.width; 00181 rf_2.length = & RF2.length; 00182 rf_2.sub_thick = & SIO_THICKNESS; 00183 00184 // tune_1 is the inductance which tunes out the SIS junction capacitance. 00185 // Since there is a virtual ground midway between the two halves of the 00186 // twinslot receiver, we use only 1/2 of the total tuning length. tune_2 00187 // is the bit between the SIS and the RF matching transformer. 00188 microstrip tune_1(ms); 00189 tune_1.width = & L1.width; 00190 tune_1.length = & L1.length; 00191 tune_1.sub_thick = & TUNE_THICKNESS; 00192 microstrip tune_2(ms); 00193 tune_2.width = & L2.width; 00194 tune_2.length = & L2.length; 00195 tune_2.sub_thick = & TUNE_THICKNESS; 00196 00197 00198 // CREATE THE ANTENNA 00199 // The antenna will be modelled as a transformer, transforming the 00200 // normalizing impedance device::Z0 to the antenna embedding impedance 00201 // given by the file named in ANT_FILE. We use an interpolation of the 00202 // file's complex impedance vs. frequency data, employing a variable of 00203 // type complex_interp (defined in complex_interp.h). The interpolation 00204 // will return the complex impedance at the current frequency stored in 00205 // the global frequency variable device::f. We also must supply the 00206 // units used in the file (GHz and Ohm). 00207 // 00208 // The definition of a transformer is in transformer.h. We set the 00209 // impedance of port 2 (Z2) to shadow the interpolation of the 00210 // antenna impedance. The other port's impedance will shadow device::Z0 00211 // by default. This shadowing works because the transformer's impedances 00212 // are held in variables of type complex_parameter 00213 // (parameter/complex_parameter.h) and a complex_interp is derived from 00214 // abstract_complex_parameter. Shadowing works the same way as for the 00215 // real_parameter types. 00216 complex_interp Z_ant(device::f, ANT_FILE, GHz, Ohm); 00217 transformer antenna; 00218 antenna.Z2 = & Z_ant; 00219 00220 00221 // A CAPACITOR TO MODEL THE SIS JUNCTION 00222 // The SIS junction's capacitance is modelled here using a lumped-element 00223 // capacitor (see elements.h) with a value calculated using the special 00224 // calc_Cap class we defined previously. 00225 capacitor sis_cap; 00226 sis_cap.parallel(); 00227 sis_cap.C = & Cap; // shadows our junction capacitance calculator 00228 00229 00230 // BUILD THE COMPLETE RF CIRCUIT MODEL 00231 // We'll create the branch and short that we need as well (see elements.h). 00232 // Refer to the comments in filter/filter.annotated.cc for a description of 00233 // code similar to that below. 00234 00235 branch tee; 00236 short_term ground; 00237 00238 circuit rf; 00239 rf.connect( antenna, 2, rf_1, 1 ); 00240 rf.connect( rf_1, 2, rf_2, 1 ); 00241 rf.connect( rf_2, 2, tune_2, 1 ); 00242 rf.connect( tune_2, 2, tee, 1 ); 00243 rf.connect( tee, 2, sis_cap, 1 ); 00244 rf.connect( sis_cap, 2, tune_1, 1 ); 00245 rf.connect( tune_1, 2, ground, 1 ); 00246 00247 int input = rf.add_port( antenna, 1 ); // RF power input to antenna 00248 int output = rf.add_port( tee, 3 ); // power output into SIS resistance 00249 00250 00251 // ========================================================================== 00252 // PERFORM THE CALCULATION AND OUTPUT THE RESULTS 00253 00254 // Again refer to the comments in filter/filter.annotated.cc for a description. 00255 00256 cout << fixed << setprecision(3); 00257 cout << "# 750 GHz Twinslot RF Match, antenna -> SIS" << endl; 00258 cout << "# SIS Rn (Ohm): " << Rn/Ohm << " ; SIS Cap (fF): " << Cap/fFarad << endl; 00259 cout << "#" << endl; 00260 cout << "# F(THz)" << "\t" << "S21" << "\t" << "Phase" << endl; 00261 00262 complex::out_degree(); 00263 complex::out_separator("\t"); 00264 00265 for(double f = 300.0; f <= 1500.0; f += 1.0) { 00266 device::f = f*GHz; 00267 sdata response = rf.get_data(); 00268 complex S21 = response.S[output][input]; 00269 cout << " " << device::f/(1000*GHz)<< "\t" << S21 << endl; 00270 } 00271 00272 }
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7