X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fdesign_coupler.c;fp=src%2Fdesign_coupler.c;h=4cb7469ddaee47fc2bd04fddf39c2b0811f6b22b;hb=6b66971c81ba66fc706c04decfa5a69a19e57c4d;hp=0000000000000000000000000000000000000000;hpb=a51f9bc3e458756855df5ab51a7e7ec015a9aebd;p=debian%2Fatlc diff --git a/src/design_coupler.c b/src/design_coupler.c new file mode 100644 index 0000000..4cb7469 --- /dev/null +++ b/src/design_coupler.c @@ -0,0 +1,349 @@ +/* atlc - arbitrary transmission line calculator, for the analysis of +transmission lines are directional couplers. + +Copyright (C) 2002. Dr. David Kirkby, PhD (G8WRB). + +This program 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 package_version 2 +of the License, or (at your option) any later package_version. + +This program 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 program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +USA. + +Dr. David Kirkby, e-mail drkirkby at gmail.com + +*/ + +#include "config.h" + +#include "definitions.h" +#include "exit_codes.h" + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef SYS_TYPES_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_TIME_H +#include +#endif + +#ifdef HAVE_MATH_H +#include +#endif + + +extern int errno; +int verbose=2; + +/* desgin_coupler does two very different things in the one program +1) Given a frequency range, the required coupling factor, it calcuates +the odd and even mode impedances needed for a coupler. It does this +assuming the length of the coupler is lambda/4, although you can vary +that on the command line with the -l option. + +2) Once the optimal values for the even and odd mode impedances are +found, it itteratively looks up the odd and even mode impedances for two +think lines of various widths (w) and spacings (s), looking for the +combination that gives the best rms error between the required +impedances and those that will result with the coupler design as +presented. + +It is assumed by default that the height of the box is of one unit (1 +mm, 1" etc, but this may be changed on the command line. This will scale +the parameters w and s by the same multiple. + +*/ + +int main(int argc, char **argv) /* Read parameters from command line */ +{ + int q, Hflag=FALSE; + int calculate_physical_dimensions=FALSE; + int calculate_physical_dimensions_to_high_accuracy=FALSE; + double er; + double Zo=-1, length=-1, fmin, fmax, fmean, fstep=-1, cf, Zodd, Zeven; + double f, vcf, vcf_for_quarter_wave_line, w, s, error, error_max=1e30; + double wanted_coupling_factor_in_dB, step=0.02, fq; + double Zeven_x=-1, Zodd_x=-1, best_s=-1, best_w=-1; + double height_of_box=1.0; + double best_Zodd=-1, best_Zeven=-1, best_Zo=-1; + + /* SGI's MipsPro compiler is very fussy. The following line, along + with one right at the end, forces Zo_x to be set and used, + alhtough it serves no other userful purpose but to keep the + compiler happy */ + double Zo_x=1; + while((q=get_options(argc,argv,"DeQqdCL:s:Z:H:")) != -1) + switch (q) + { + case 'd': + calculate_physical_dimensions=TRUE; + break; + case 'D': + calculate_physical_dimensions=TRUE; + calculate_physical_dimensions_to_high_accuracy=TRUE; + break; + case 'e': + give_examples_of_using_design_coupler(); + break; + case 'C': + print_copyright((char *) "2002"); + Hflag=TRUE; + exit_with_msg_and_exit_code("",OKAY); + break; + case 'L': + length=atof(my_optarg); /* Sets the length of coupler */ + break; + case 'H': + height_of_box=atof(my_optarg); /* Set height of coupler's enclosure */ + Hflag=TRUE; + break; + case 's': /* Set frequncy steps in which coupling is computed */ + fstep=atof(my_optarg); + break; + case 'Z': /* Set the characteristic impedance - default is 50 Ohms */ + Zo=atof(my_optarg); + break; + case 'q': /* Run in quite mode, giving less output */ + verbose--; + break; + case '?': + usage_design_coupler(); + break; + } /* End of the switch statement */ + + if(argc-my_optind != 3) /* This should be so hopefully !! */ + { + usage_design_coupler(); + exit_with_msg_and_exit_code("",PROGRAM_CALLED_WITH_WRONG_NUMBER_OF_ARGUMENTS); + } + wanted_coupling_factor_in_dB=atof(argv[my_optind]); + fmin=atof(argv[my_optind+1]); + fmax=atof(argv[my_optind+2]); + fmean=(fmin+fmax)/2.0; + if(fstep <0 ) + fstep=(fmax-fmin)/4.0; + + if (wanted_coupling_factor_in_dB <= 0.0 ) /* Only 0 can happen */ + { + /* I don't think this can happen unless the user enter 0 as the + first parameter, as a negative number entered will be taken as a + command line option */ + fprintf(stderr,"\nThe coupled power must be less than the input power."); + fprintf(stderr," But please enter a\n*positive* number in dB for the"); + fprintf(stderr," first command line parameter. If you want a \ncoupler"); + fprintf(stderr," with a coupled port that is 12 dB down on the input"); + fprintf(stderr," power, covering\n144-146 MHz, enter this as:\n\n"); + fprintf(stderr,"design_coupler 12 144 146\n\n"); + fprintf(stderr,"If you want the physical dimensions of the coupler"); + fprintf(stderr," designed for you, add the\n-d option on the command"); + fprintf(stderr," line, like this:\n\ndesign_coupler -q -12 144 146\n\n"); + fprintf(stderr,"If you run design_coupler with no command line"); + fprintf(stderr," arguments, like this:\n\ndesign_coupler\n\n"); + fprintf(stderr,"then design_coupler will print some information,"); + fprintf(stderr," showing *all* the options. \nIf you run design_coupler"); + fprintf(stderr," with the -e option like this:\n\n"); + fprintf(stderr,"design_coupler -e\n\n"); + fprintf(stderr,"lots of examples will be shown of the correct usage.\n"); + exit_with_msg_and_exit_code("",IMPOSSIBLE_COUPLING_COEFFICIENT); + } + if (fmax <= fmin) + { + fprintf(stderr,"The second command line argumentent you gave, which"); + fprintf(stderr," is for the *minimum*\noperating frequenncy in MHz,"); + fprintf(stderr," is less than the third argument, which is the\n"); + fprintf(stderr,"*maximum* operating frequency in MHz.\n\n"); + fprintf(stderr,"If you want a coupler"); + fprintf(stderr," with a coupled port that is 12 dB down on the input\n"); + fprintf(stderr,"power, covering 144-146 MHz, enter this as:\n\n"); + fprintf(stderr,"design_coupler 12 144 146\n\n"); + fprintf(stderr,"If you want the physical dimensions of the coupler"); + fprintf(stderr," designed for you, add the\n-d option on the command"); + fprintf(stderr," line, like this:\n\ndesign_coupler -d 12 144 146\n\n"); + fprintf(stderr,"If you run design_coupler with no command line arguments,"); + fprintf(stderr," then design_coupler\nwill print some information,"); + fprintf(stderr," showing *all* the options. If you run\ndesign_coupler"); + fprintf(stderr," with the -e option like this:\n\n"); + fprintf(stderr,"design_coupler -e\n\n"); + fprintf(stderr,"lots of examples will be shown of the correct usage.\n"); + fprintf(stderr,"Exiting ...\n"); + exit_with_msg_and_exit_code("",FMAX_NOT_ABOVE_FMIN); + } + if (Zo < 0.0) + Zo=50.0; + if(length<0.0) + length=75.0/fmean; /* By default, make it a quarter wave long */ + /* The following sent in an email by Paul AA1L, sums the theory up + You make Zo=50=sqrt(Zoo*Zoe) and + c=(Zoe-Zoo)/(Zoe+Zoo), c being the voltage coupling coefficient. + I.e., for a 20dB coupler c=0.1 is the midband + coupling. + Coupling varies as sin^2(f/fq), fq being frequency where the coupled + length is a quarter wave. + + HOWEVER, the above is not quite the full story, as that says coupling + peaks at sin(1), when in fact its sin(Pi/2) + */ + + /* vfc stands for 'voltage coupling factor' */ + + /* I need to find values for Zodd and Zeven to use, but first convert + the coupling factor on the command line into the voltage coupling + factor c */ + + /* vfc stands for 'voltage coupling factor' */ + + /* When the line is a quarter wave, one can get any amount of coupling + you want, including a vfc of 1, in which case all the power transfers + to the coupled port. Normally, the vcf will be less than 1.0. for a 20 + dB couplier is it 0.1 */ + + vcf_for_quarter_wave_line=1.0/pow(10.0,wanted_coupling_factor_in_dB/20.0); + + fq=75/length; /* frequency at which line is a quarter wave long */ + + /* If the line is less than a quarter wave long, then less power is + coupled, so to compensate we need to increase the voltage coupling + factor 'vcf above that of the value for a quarter wave line. + Since the 'vcf' varies as sin(0.5 *PI * f/fq)^2, where + fq is the frequency at which the line is a quarter-wave long, we must + divide the vcf_for_quarter_wave_line by sin(0.5 *PI*f/fq)^2 to get + the required vcf. */ + vcf=vcf_for_quarter_wave_line*(1.0/sin(0.5*M_PI*fmean/fq)); + /* Check that the voltage coupling factor does not exceed one */ + if ( vcf > 1.0 ) + { + fprintf(stderr,"\n*****ERROR****\n"); + 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); + fprintf(stderr,"Either couple off a smaller fraction of the main power to the coupled port,\n"); + fprintf(stderr,"or make the line closer to an odd multiple of a quarter wave.\n"); + 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); + exit_with_msg_and_exit_code("",IMPOSSIBLE_TO_MAKE_COUPLER_THAT_LENGTH); + } + + /* After mucking around with Mathematica a bit, I found it was + possible to invert the equations */ + + Zodd = sqrt(1-vcf)*Zo/sqrt(1+vcf); + Zeven=Zo*Zo/Zodd; + + printf("\nFor a %.3f dB %.3f Ohm coupler with a length of %.4f m,\n",wanted_coupling_factor_in_dB, Zo, length); + printf("you need to have an odd-mode impedance Zodd of %.3f Ohms and\n",Zodd); + printf("an even mode impedance Zeven of %.3f Ohms\n\n",Zeven); + if(verbose >=1) /* Only print if user does not specifiy and -qq options */ + { + printf("%.3f dB down <-- ************************** ---> %3.3f Ohm termination\n\n",wanted_coupling_factor_in_dB,Zo); + printf("Drive this port --> ************************** ---> %3.3f Ohm termination\n",Zo); + printf(" <------- %8.4f m ----->\n",length); + printf("\nDrive Port 1, coupler out of port 2 and terminate the other ports in Zo\n"); + printf("Such a coupler will have the response indicated below.\n\n"); + /*printf("length =%.4f mean=%.3f vcf=%.3f vcf_for_quarter_wave_line=%.3f \n",length, fmean, vcf, vcf_for_quarter_wave_line);*/ + } + for(f=fmin; f<=fmax; f+=fstep) + { + cf=20*log10(vcf*sin(0.5*M_PI*f/fq)); /* This is what is now needed for some given length (and so fq) */ + if(verbose == 2) + printf("f = %7.3f MHz coupling is %.3f dB down on the main arm\n",f,cf); + } + 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); + if(calculate_physical_dimensions==FALSE) + { + printf("You may try to find a coupler with these dimensions using the -d option\n\n"); + printf("Currently the -d option is not that fast, as it uses a brain-dead algorithm\n"); + printf("Hopefully one day the algorithm will be speeded up.\n"); + } + if(calculate_physical_dimensions==TRUE) + { + er=1.0; + printf("Please be patient - this will take a few minutes or so\n"); + for(s = 0.02; s<=100; s+=step) + { + for(w = 0.02; w<= 11.0; w += step) + { + /* Results are calculated assuming the box is one unit (mm, inch + etc) high and later scaled */ + + calculate_Zodd_and_Zeven(&Zodd_x, &Zeven_x, &Zo_x, w, 1.0, s, er); + error=pow(Zodd-Zodd_x,2.0) + pow(Zeven-Zeven_x,2.0); + if( error < error_max ) + { + best_s=s; + best_w=w; + best_Zo=sqrt(best_Zo * best_Zeven); + best_Zodd=Zodd; + best_Zeven=Zeven; + error_max=error; + } + } + } + printf("w = %.4f s = %.4f which gives Zo = %.4f Zodd = %.4f Zeven = %.4f\n",best_w, best_s, best_Zo, best_Zodd, best_Zeven); + /* Now try to get closer, if -D option given */ + if (calculate_physical_dimensions_to_high_accuracy == TRUE) + { + for(s = best_s-step; s<=best_s+step; s+=step/1000) + { + for(w = best_w-step; w<= best_w+step; w += step/1000) + { + calculate_Zodd_and_Zeven(&Zodd_x, &Zeven_x, &Zo_x, w, 1.0, s, er); + error=fabs(Zodd-Zodd_x) + fabs(Zeven-Zeven_x); + if( error < error_max ) + { + best_s=s; + best_w=w; + best_Zodd=Zodd; + best_Zeven=Zeven; + error_max=error; + } + } + } + } + best_Zo=sqrt(best_Zodd * best_Zeven); + if(verbose <= 0) + { + printf("|-----------^------------------------------------------------------------------|\n"); + printf("| | |\n"); + printf("| | <---w---><-----s----><---w--> |\n"); + printf("| H --------- -------- |\n"); + printf("| | |\n"); + printf("| | Er=1.0 (air) |\n"); + printf("------------v------------------------------------------------------------------\n"); + printf("<-----------------------------------------W----------------------------------->\n"); + } + printf("H =%.4f w = %.4f s = %.4f\n",height_of_box, height_of_box*best_w, height_of_box*best_s); + 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); + printf("These dimensions give Zo = %.4f Zodd = %.4f Zeven = %.4f Ohms\n", best_Zo, best_Zodd, best_Zeven); + if(Hflag==FALSE) + { + printf("****NOTE ****\n"); + printf("Although H is shown as 1.0, it can be 1 mm, 1 cm or even 1 m. It is important\n"); + 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); + printf("If you know the height H of your enclosure, use the -H option to indicate\n"); + printf("its value. This will ensure all the dimensions are scaled automatically for you.\n"); + } + printf("****NOTE 2****\n"); + printf("The length *must* be %.4f m if you use these dimensions for W, H, w and s.\n",length); + 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); + printf("See: http://atlc.sourceforge.net\n"); + printf("See: http://atlc.sourceforge.net/couplers.html\n"); + } + return(OKAY); +}