1 /* atlc - arbitrary transmission line calculator, for the analysis of
2 transmission lines are directional couplers.
4 Copyright (C) 2002. Dr. David Kirkby, PhD (G8WRB).
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either package_version 2
9 of the License, or (at your option) any later package_version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 Dr. David Kirkby, e-mail drkirkby at gmail.com
27 #include "definitions.h"
28 #include "exit_codes.h"
35 #include <sys/types.h>
58 /* desgin_coupler does two very different things in the one program
59 1) Given a frequency range, the required coupling factor, it calcuates
60 the odd and even mode impedances needed for a coupler. It does this
61 assuming the length of the coupler is lambda/4, although you can vary
62 that on the command line with the -l option.
64 2) Once the optimal values for the even and odd mode impedances are
65 found, it itteratively looks up the odd and even mode impedances for two
66 think lines of various widths (w) and spacings (s), looking for the
67 combination that gives the best rms error between the required
68 impedances and those that will result with the coupler design as
71 It is assumed by default that the height of the box is of one unit (1
72 mm, 1" etc, but this may be changed on the command line. This will scale
73 the parameters w and s by the same multiple.
77 int main(int argc, char **argv) /* Read parameters from command line */
80 int calculate_physical_dimensions=FALSE;
81 int calculate_physical_dimensions_to_high_accuracy=FALSE;
83 double Zo=-1, length=-1, fmin, fmax, fmean, fstep=-1, cf, Zodd, Zeven;
84 double f, vcf, vcf_for_quarter_wave_line, w, s, error, error_max=1e30;
85 double wanted_coupling_factor_in_dB, step=0.02, fq;
86 double Zeven_x=-1, Zodd_x=-1, best_s=-1, best_w=-1;
87 double height_of_box=1.0;
88 double best_Zodd=-1, best_Zeven=-1, best_Zo=-1;
90 /* SGI's MipsPro compiler is very fussy. The following line, along
91 with one right at the end, forces Zo_x to be set and used,
92 alhtough it serves no other userful purpose but to keep the
95 while((q=get_options(argc,argv,"DeQqdCL:s:Z:H:")) != -1)
99 calculate_physical_dimensions=TRUE;
102 calculate_physical_dimensions=TRUE;
103 calculate_physical_dimensions_to_high_accuracy=TRUE;
106 give_examples_of_using_design_coupler();
109 print_copyright((char *) "2002");
111 exit_with_msg_and_exit_code("",OKAY);
114 length=atof(my_optarg); /* Sets the length of coupler */
117 height_of_box=atof(my_optarg); /* Set height of coupler's enclosure */
120 case 's': /* Set frequncy steps in which coupling is computed */
121 fstep=atof(my_optarg);
123 case 'Z': /* Set the characteristic impedance - default is 50 Ohms */
126 case 'q': /* Run in quite mode, giving less output */
130 usage_design_coupler();
132 } /* End of the switch statement */
134 if(argc-my_optind != 3) /* This should be so hopefully !! */
136 usage_design_coupler();
137 exit_with_msg_and_exit_code("",PROGRAM_CALLED_WITH_WRONG_NUMBER_OF_ARGUMENTS);
139 wanted_coupling_factor_in_dB=atof(argv[my_optind]);
140 fmin=atof(argv[my_optind+1]);
141 fmax=atof(argv[my_optind+2]);
142 fmean=(fmin+fmax)/2.0;
144 fstep=(fmax-fmin)/4.0;
146 if (wanted_coupling_factor_in_dB <= 0.0 ) /* Only 0 can happen */
148 /* I don't think this can happen unless the user enter 0 as the
149 first parameter, as a negative number entered will be taken as a
150 command line option */
151 fprintf(stderr,"\nThe coupled power must be less than the input power.");
152 fprintf(stderr," But please enter a\n*positive* number in dB for the");
153 fprintf(stderr," first command line parameter. If you want a \ncoupler");
154 fprintf(stderr," with a coupled port that is 12 dB down on the input");
155 fprintf(stderr," power, covering\n144-146 MHz, enter this as:\n\n");
156 fprintf(stderr,"design_coupler 12 144 146\n\n");
157 fprintf(stderr,"If you want the physical dimensions of the coupler");
158 fprintf(stderr," designed for you, add the\n-d option on the command");
159 fprintf(stderr," line, like this:\n\ndesign_coupler -q -12 144 146\n\n");
160 fprintf(stderr,"If you run design_coupler with no command line");
161 fprintf(stderr," arguments, like this:\n\ndesign_coupler\n\n");
162 fprintf(stderr,"then design_coupler will print some information,");
163 fprintf(stderr," showing *all* the options. \nIf you run design_coupler");
164 fprintf(stderr," with the -e option like this:\n\n");
165 fprintf(stderr,"design_coupler -e\n\n");
166 fprintf(stderr,"lots of examples will be shown of the correct usage.\n");
167 exit_with_msg_and_exit_code("",IMPOSSIBLE_COUPLING_COEFFICIENT);
171 fprintf(stderr,"The second command line argumentent you gave, which");
172 fprintf(stderr," is for the *minimum*\noperating frequenncy in MHz,");
173 fprintf(stderr," is less than the third argument, which is the\n");
174 fprintf(stderr,"*maximum* operating frequency in MHz.\n\n");
175 fprintf(stderr,"If you want a coupler");
176 fprintf(stderr," with a coupled port that is 12 dB down on the input\n");
177 fprintf(stderr,"power, covering 144-146 MHz, enter this as:\n\n");
178 fprintf(stderr,"design_coupler 12 144 146\n\n");
179 fprintf(stderr,"If you want the physical dimensions of the coupler");
180 fprintf(stderr," designed for you, add the\n-d option on the command");
181 fprintf(stderr," line, like this:\n\ndesign_coupler -d 12 144 146\n\n");
182 fprintf(stderr,"If you run design_coupler with no command line arguments,");
183 fprintf(stderr," then design_coupler\nwill print some information,");
184 fprintf(stderr," showing *all* the options. If you run\ndesign_coupler");
185 fprintf(stderr," with the -e option like this:\n\n");
186 fprintf(stderr,"design_coupler -e\n\n");
187 fprintf(stderr,"lots of examples will be shown of the correct usage.\n");
188 fprintf(stderr,"Exiting ...\n");
189 exit_with_msg_and_exit_code("",FMAX_NOT_ABOVE_FMIN);
194 length=75.0/fmean; /* By default, make it a quarter wave long */
195 /* The following sent in an email by Paul AA1L, sums the theory up
196 You make Zo=50=sqrt(Zoo*Zoe) and
197 c=(Zoe-Zoo)/(Zoe+Zoo), c being the voltage coupling coefficient.
198 I.e., for a 20dB coupler c=0.1 is the midband
200 Coupling varies as sin^2(f/fq), fq being frequency where the coupled
201 length is a quarter wave.
203 HOWEVER, the above is not quite the full story, as that says coupling
204 peaks at sin(1), when in fact its sin(Pi/2)
207 /* vfc stands for 'voltage coupling factor' */
209 /* I need to find values for Zodd and Zeven to use, but first convert
210 the coupling factor on the command line into the voltage coupling
213 /* vfc stands for 'voltage coupling factor' */
215 /* When the line is a quarter wave, one can get any amount of coupling
216 you want, including a vfc of 1, in which case all the power transfers
217 to the coupled port. Normally, the vcf will be less than 1.0. for a 20
218 dB couplier is it 0.1 */
220 vcf_for_quarter_wave_line=1.0/pow(10.0,wanted_coupling_factor_in_dB/20.0);
222 fq=75/length; /* frequency at which line is a quarter wave long */
224 /* If the line is less than a quarter wave long, then less power is
225 coupled, so to compensate we need to increase the voltage coupling
226 factor 'vcf above that of the value for a quarter wave line.
227 Since the 'vcf' varies as sin(0.5 *PI * f/fq)^2, where
228 fq is the frequency at which the line is a quarter-wave long, we must
229 divide the vcf_for_quarter_wave_line by sin(0.5 *PI*f/fq)^2 to get
231 vcf=vcf_for_quarter_wave_line*(1.0/sin(0.5*M_PI*fmean/fq));
232 /* Check that the voltage coupling factor does not exceed one */
235 fprintf(stderr,"\n*****ERROR****\n");
236 fprintf(stderr,"Sorry, you can't make a %6.3f dB coupler with a coupled line of %7.4f m long.\n",wanted_coupling_factor_in_dB, length);
237 fprintf(stderr,"Either couple off a smaller fraction of the main power to the coupled port,\n");
238 fprintf(stderr,"or make the line closer to an odd multiple of a quarter wave.\n");
239 fprintf(stderr,"Odd mulitples of a quarter wave are: %.4f, %.4f, %.4f, %.4f .. m\n", 75/fmean, 3*75/fmean, 5*75/fmean, 7*75/fmean);
240 exit_with_msg_and_exit_code("",IMPOSSIBLE_TO_MAKE_COUPLER_THAT_LENGTH);
243 /* After mucking around with Mathematica a bit, I found it was
244 possible to invert the equations */
246 Zodd = sqrt(1-vcf)*Zo/sqrt(1+vcf);
249 printf("\nFor a %.3f dB %.3f Ohm coupler with a length of %.4f m,\n",wanted_coupling_factor_in_dB, Zo, length);
250 printf("you need to have an odd-mode impedance Zodd of %.3f Ohms and\n",Zodd);
251 printf("an even mode impedance Zeven of %.3f Ohms\n\n",Zeven);
252 if(verbose >=1) /* Only print if user does not specifiy and -qq options */
254 printf("%.3f dB down <-- ************************** ---> %3.3f Ohm termination\n\n",wanted_coupling_factor_in_dB,Zo);
255 printf("Drive this port --> ************************** ---> %3.3f Ohm termination\n",Zo);
256 printf(" <------- %8.4f m ----->\n",length);
257 printf("\nDrive Port 1, coupler out of port 2 and terminate the other ports in Zo\n");
258 printf("Such a coupler will have the response indicated below.\n\n");
259 /*printf("length =%.4f mean=%.3f vcf=%.3f vcf_for_quarter_wave_line=%.3f \n",length, fmean, vcf, vcf_for_quarter_wave_line);*/
261 for(f=fmin; f<=fmax; f+=fstep)
263 cf=20*log10(vcf*sin(0.5*M_PI*f/fq)); /* This is what is now needed for some given length (and so fq) */
265 printf("f = %7.3f MHz coupling is %.3f dB down on the main arm\n",f,cf);
267 printf("\nYou may force the length to be any value you want using the -L option - it does\nnot have to be %.4f metres long\n",length);
268 if(calculate_physical_dimensions==FALSE)
270 printf("You may try to find a coupler with these dimensions using the -d option\n\n");
271 printf("Currently the -d option is not that fast, as it uses a brain-dead algorithm\n");
272 printf("Hopefully one day the algorithm will be speeded up.\n");
274 if(calculate_physical_dimensions==TRUE)
277 printf("Please be patient - this will take a few minutes or so\n");
278 for(s = 0.02; s<=100; s+=step)
280 for(w = 0.02; w<= 11.0; w += step)
282 /* Results are calculated assuming the box is one unit (mm, inch
283 etc) high and later scaled */
285 calculate_Zodd_and_Zeven(&Zodd_x, &Zeven_x, &Zo_x, w, 1.0, s, er);
286 error=pow(Zodd-Zodd_x,2.0) + pow(Zeven-Zeven_x,2.0);
287 if( error < error_max )
291 best_Zo=sqrt(best_Zo * best_Zeven);
298 printf("w = %.4f s = %.4f which gives Zo = %.4f Zodd = %.4f Zeven = %.4f\n",best_w, best_s, best_Zo, best_Zodd, best_Zeven);
299 /* Now try to get closer, if -D option given */
300 if (calculate_physical_dimensions_to_high_accuracy == TRUE)
302 for(s = best_s-step; s<=best_s+step; s+=step/1000)
304 for(w = best_w-step; w<= best_w+step; w += step/1000)
306 calculate_Zodd_and_Zeven(&Zodd_x, &Zeven_x, &Zo_x, w, 1.0, s, er);
307 error=fabs(Zodd-Zodd_x) + fabs(Zeven-Zeven_x);
308 if( error < error_max )
319 best_Zo=sqrt(best_Zodd * best_Zeven);
322 printf("|-----------^------------------------------------------------------------------|\n");
324 printf("| | <---w---><-----s----><---w--> |\n");
325 printf("| H --------- -------- |\n");
327 printf("| | Er=1.0 (air) |\n");
328 printf("------------v------------------------------------------------------------------\n");
329 printf("<-----------------------------------------W----------------------------------->\n");
331 printf("H =%.4f w = %.4f s = %.4f\n",height_of_box, height_of_box*best_w, height_of_box*best_s);
332 printf("W must be *at least* %.4f, but larger does not matter.\n",5*height_of_box+ 2*best_w*height_of_box + height_of_box*best_s);
333 printf("These dimensions give Zo = %.4f Zodd = %.4f Zeven = %.4f Ohms\n", best_Zo, best_Zodd, best_Zeven);
336 printf("****NOTE ****\n");
337 printf("Although H is shown as 1.0, it can be 1 mm, 1 cm or even 1 m. It is important\n");
338 printf("that w is %.4f times whatever H is, and that s is %.4f times whatever H is, but the absolute numbers are irrelavant.\n",best_w, best_s);
339 printf("If you know the height H of your enclosure, use the -H option to indicate\n");
340 printf("its value. This will ensure all the dimensions are scaled automatically for you.\n");
342 printf("****NOTE 2****\n");
343 printf("The length *must* be %.4f m if you use these dimensions for W, H, w and s.\n",length);
344 printf("If %.4f m is inconvenient, change it with the -L option and recalculate\n to get new values of W, H, w and s\n",length);
345 printf("See: http://atlc.sourceforge.net\n");
346 printf("See: http://atlc.sourceforge.net/couplers.html\n");