1 /* XNECVIEW - a program for visualizing NEC2 input and output data 2 * 3 * Copyright (C) 1998-2011, Pieter-Tjerk de Boer -- pa3fwm@amsat.org 4 * 5 * Distributed on the conditions of version 2 of the GPL: see the files 6 * README and COPYING, which accompany this source file. 7 */ 8 9 /* ------------------------------------------------------------------------ */ 10 11 12 #include "config.h" /* file defining things like default colours etc. */ 13 14 15 #define VERSION "1.36" 16 17 18 typedef struct { /* structure to describe a point in 3D space */ 19 float x,y,z; 20 } Point; 21 22 typedef struct { /* structure to describe a straight wire (segment) */ 23 Point p0,p1; /* begin and end point */ 24 double rad; /* radius */ 25 int itg; /* tag number */ 26 int ns; /* number of segments for multi-segment wire; -segmentnumber for single-segment wire that's part of a larger wire (GA and GH cards) */ 27 int abs; /* absolute segment number of the first segment of this wire */ 28 int dispnr; /* flag: true (nonzero) on any multi-segment wire, and on (a) middle segment for a wire that was split into multiple single-segment wires (GA and GH) */ 29 } Wire; 30 31 typedef struct { /* structure to describe a surface patch */ 32 int type; /* see below */ 33 Point p0,p1,p2,p3; /* corners */ 34 Point pc; /* center */ 35 Point pa; /* tip of outward normal arrow */ 36 } Surface; 37 #define SU_rect 1 /* rectangular shape (p2,p3 ignored) */ 38 #define SU_arb 2 /* "arbitrary" shape, shown as a set of 8 crossing lines (p2,p3 ignored) */ 39 #define SU_tri 3 /* triangle (p3 ignored) */ 40 #define SU_quad 4 /* quadrilateral shape */ 41 42 typedef struct { /* structure to describe an excitation (only voltage sources, EX card) */ 43 Wire *wire; /* pointer to Wire data */ 44 int seg; /* segment number within wire */ 45 } Exci; 46 47 typedef struct { /* structure to describe a load */ 48 Wire *wire; /* pointer to Wire data */ 49 int firstseg; /* number of first loaded segment within wire */ 50 int lastseg; /* number of last loaded segment within wire */ 51 } Load; /* note: if an LD card specifies a loading which extends over several wires, it is represented here by one Load struct per wire */ 52 53 typedef struct { /* structure to describe a "network" in the antenna structure; a transmission line is a special case of this */ 54 Wire *wire1; /* pointer to Wire data of one end of the network / transmission line */ 55 int seg1; /* segment number within wire */ 56 Wire *wire2; /* same for the other end of the network / transmission line */ 57 int seg2; 58 int type; /* type: 0 = generic network; 1 = transmission line without phase reversal; -1 = transmission line with phase reversal */ 59 } Netw; 60 61 62 extern double extr_str; /* size of the biggest dimension of the structure data to be shown; used for (initial) scaling */ 63 extern double extr; /* size of the biggest dimension of all data to be shown; used for (initial) scaling */ 64 65 extern int quick; /* flag to indicate that drawing should be rough but quick */ 66 extern int redraw; /* flag which signifies need for redrawing */ 67 extern int dragging; /* flag to indicate that user is dragging the structure */ 68 69 /* these define the projection: */ 70 extern double phi,theta; /* angles defining direction of eye */ 71 extern double zoom; /* zoom factor */ 72 extern double trx,try; /* 2D-translation, as a fraction of winsize */ 73 extern int winsizex,winsizey; /* size of window in pixels */ 74 extern int winsize; /* min(winsizex,winsizey) */ 75 76 extern int gainscale; /* type of scaling of gain: */ 77 enum { GSlinpower,GSlinvolt,GSarrl,GSlog,numGS }; 78 extern char *GSnames[]; /* array with names of gainscales */ 79 extern char GSnumbers[][32]; /* array with descriptions of levels of scale lines in plot */ 80 81 extern int gainplot; /* type of radiation plot: */ 82 enum { GPnone,GPslice,GPframe,GPopaque,GPnearfield,numGP }; 83 84 extern int structplot; /* type of structure plot: */ 85 enum { SPnone,SPstruct,SPtags,SPcurrents,SPanim,numSP }; 86 87 extern int scaleplot; /* flag: plot gain scale? */ 88 89 extern int polarization; /* polarization for gain and currents displays */ 90 enum { POLnone,POLhor,POLvert,POLlhcp,POLrhcp,POLcolour }; /* note: if this order changes, find_fb() may also need to be changed */ 91 92 extern int phasedirlock; /* flag: is the direction used for calculation phases locked? */ 93 extern double phasephi,phasetheta; /* if so, this is that direction; otherwise, it is identical to phi and theta */ 94 95 extern double phaseoffset; /* phase offset for currents display */ 96 extern int distcor; /* flag: correct phase for distance to observer? */ 97 extern int maxthickness; /* line thickness used for maximum current in currents display */ 98 99 extern double animphase; /* phase (in rad) of the "animation" of currents and E and H fields */ 100 extern double animfreq; /* frequency of the animation: number of displayed cycles per second */ 101 extern double anim_update_interval; /* time (in milliseconds) between updates of the animation display */ 102 103 extern double escale; /* scale factor for the E field */ 104 extern double hscale; /* scale factor for the H field */ 105 extern int show_p; /* flag: display Poynting vector? */ 106 extern double qscale; /* scale factor for the currents */ 107 extern double iscale; /* scale factor for the charges */ 108 109 110 extern int win2sizex,win2sizey; /* size of freqplot window in pixels */ 111 extern int plot2_swr, plot2_z, plot2_z2, plot2_maxgain, plot2_dir, plot2_vgain; /* flags for the each of the frequency plots in window 2 */ 112 113 extern int numwires; 114 extern int maxwires; 115 extern Wire *wires; 116 extern int numsurfaces; 117 extern int maxsurfaces; 118 extern Surface *surfaces; 119 extern int numexcis; 120 extern int maxexcis; 121 extern Exci *excis; 122 extern int numloads; 123 extern int maxloads; 124 extern Load *loads; 125 extern int numnetws; 126 extern int maxnetws; 127 extern Netw *netws; 128 129 130 typedef struct { /* structure to contain, for one direction, the radiated power and polarization information */ 131 float total; /* total radiated power, dBi */ 132 float axial; /* axial ratio, with sign indicating the polarity: + left-hand circular, - right-hand */ 133 float tilt; /* tilt angle of major axis, radians; defined as in NEC output: 0 = vertical, >0 topleft/bottomright */ 134 } Gain; 135 136 typedef struct RAdpattern { /* structure to contain (far field) radiation pattern for one frequency */ 137 double *gtheta; /* pointer to array of theta values */ 138 double *gphi; /* pointer to array of phi values */ 139 Gain **gain; /* pointer to an array of pointers (one for every phi) to an array of Gain structs (one for every theta at that phi) */ 140 Point **gpo; /* pointer to an array of pointers (one for every phi) to an array of Points (one for every theta at that phi) */ 141 int numtheta; /* number of theta values */ 142 int numphi; /* number of phi values */ 143 struct RAdpattern *next; /* pointer to the next such structure, used if more than one set of radiation pattern data is available for one frequency */ 144 double *sin_gtheta; /* pointer to an array containing the sines of the theta values */ 145 double *sin_gphi; /* ... etc. for phi */ 146 double *cos_gtheta; /* ... and cosines */ 147 double *cos_gphi; 148 } Radpattern; 149 150 151 typedef struct { /* structure to contain the current (phase, magnitude, location, direction) information of one segment */ 152 /* note: part of the below information is in principle also available in the 153 arrays describing the antenna's structure as read from the NEC input file; 154 however, it seems more consistent to read this structure information now from the 155 NEC output file, so we're sure we have the right data even if the input and output 156 files are (accidentally) from different models. 157 */ 158 /* note2: the current in surface patches is also represented by the below structure; 159 basically, a surface patch current is transformed into two equivalent segments, 160 although in many practical cases one of them carries almost no current and can 161 therefore be omitted. 162 */ 163 /* note3: for the animations, it is more convenient to have real and imaginary 164 vectors. For segment currents, these obviously point in the same (or opposite) 165 directions, namely along the segment. For surface currents, they are non- 166 trivial; however, we don't need a second segment here (in contrast to the 167 other representation), so only the first 'numanimseg' (see below, Currents 168 structure) segments contain valid data in re[] and im[]. 169 */ 170 /* note4: although the name suggests otherwise, this structure can also contain 171 charge information. 172 */ 173 Point p0,p1; /* coordinates of segment endpoints */ 174 Point c; /* coordinate of segment center point */ 175 float a; /* amplitude of the current */ 176 float phase; /* phase of the current (degrees) */ 177 float dist; /* distance of center of segment from the plane through the origin, perpendicular to the viewing direction; positive if in front of this plane, negative otherwise */ 178 float area; /* area of a surface patch */ 179 float re[3],im[3]; /* real and imaginary vector */ 180 float q0[3],q1[3]; /* two unity vectors, orthogonal to each other and to the direction of the segment; used for drawing charges */ 181 float qre,qim; /* real and imaginary value of the charge */ 182 } Segcur; 183 184 typedef struct { /* structure to contain the current distribution for all segments at one frequency */ 185 Segcur *s; 186 int maxseg; /* current size of s[] */ 187 int numseg; /* number of valid entries in s[] */ 188 int numanimseg; /* number of those that are needed for the animations; i.e., excluding the extra segments caused by the decomposition of the surface patch currents */ 189 int numrealseg; /* number of those that are actually segments; so s[numrealseg...numseg-1] are surface patches */ 190 double maxI; /* highest segment current */ 191 double maxQ; /* highest segment charge */ 192 } Currents; 193 194 195 typedef struct NF { /* structure to contain the electric and magnetic field at some point (near the antenna) */ 196 Point p; /* location of the point */ 197 int evalid,hvalid; /* flags to indicate presence of E and H data */ 198 float ere[3]; /* real component of E vector */ 199 float eim[3]; /* imaginary component of E vector */ 200 float hre[3]; /* real component of H vector */ 201 float him[3]; /* imaginary component of H vector */ 202 float poy[3]; /* time-averaged Poynting vector */ 203 struct NF *next; /* pointer to next datapoint */ 204 } Nearfield; 205 206 207 208 /* indices in the element 'd' of the NECoutput structure defined below: */ 209 enum { 210 neco_zr, neco_zi, /* index of real and imaginary part of impedance */ 211 neco_zphi, neco_zabs, /* phi and absolute value of impedance */ 212 neco_swr, /* index of SWR */ 213 neco_maxgain, neco_fb, /* index of maximum gain and corresponding front/back ratio */ 214 neco_phi, neco_theta, /* index direction of maximum gain */ 215 neco_vgain, neco_vfb, /* index of gain in viewing direction and corresponding f/b ratio */ 216 neco_vgain2, neco_vfb2, /* same, but taking polarization into account; fb/fb2 as fb1/fb2 below */ 217 neco_maxgain_hor, neco_fb_hor1, neco_fb_hor2, neco_phi_hor, neco_theta_hor, 218 neco_maxgain_vert, neco_fb_vert1, neco_fb_vert2, neco_phi_vert, neco_theta_vert, 219 neco_maxgain_lhcp, neco_fb_lhcp1, neco_fb_lhcp2, neco_phi_lhcp, neco_theta_lhcp, 220 neco_maxgain_rhcp, neco_fb_rhcp1, neco_fb_rhcp2, neco_phi_rhcp, neco_theta_rhcp, 221 neco_numdat /* last element of the enum: number of elements in the array */ 222 }; 223 /* since (maximum) gain and corresponding quantities are not available in all NECoutput records, 224 the following macro is needed to tell whether a quantity is available always, or only if 225 radiation pattern data is available in the record: */ 226 #define ONLY_IF_RP(i) ((i)>=neco_maxgain) 227 /* a constant for more systematic access to the polarization-specific fields: */ 228 #define Neco_gsize 5 /* group size */ 229 #define Neco_polgain (neco_maxgain_hor-Neco_gsize) 230 #define Neco_polfb1 (neco_fb_hor1-Neco_gsize) 231 #define Neco_polfb2 (neco_fb_hor2-Neco_gsize) 232 #define Neco_polphi (neco_phi_hor-Neco_gsize) 233 #define Neco_poltheta (neco_theta_hor-Neco_gsize) 234 /* now, we can write say neco_phi_lhcp as Neco_gsize*POLlhcp+Neco_polphi */ 235 /* note: fb...1 is f/b ratio for this polarization; fb...2 is same but for back total power is used */ 236 237 typedef struct { /* structure to contain all output data that NEC produces for one frequency */ 238 double f; /* frequency in MHz */ 239 Radpattern *rp; /* pointer to radiation pattern data, if available; NULL otherwise */ 240 double d[neco_numdat]; 241 int rpgpovalid; /* flag: !=0 if the gpo field of *rp already contains valid data for the present settings */ 242 Currents *cu; /* pointer to currents data, if available; NULL otherwise */ 243 Nearfield *nf; /* pointer to nearfield data, if available; NULL otherwise */ 244 double maxe,maxh; /* largest values of E and H in nearfield data */ 245 } NECoutput; 246 247 extern NECoutput *neco; 248 extern int numneco; 249 extern int maxfreqs; 250 251 extern double globalmaxdb; /* maximum gain, global over all frequencies and all output data files */ 252 253 extern int rp_index; /* index of the entry in neco[] whose radiation pattern is being shown in the 3D plot */ 254 255 extern double r0; /* reference impedance for SWR calculations */ 256 257 extern int window1open; 258 extern int window2open; 259 260 261 extern char *inputfilename; 262 263 extern int fontheight; 264 265 #ifndef GdkColor 266 #include <gdk/gdk.h> 267 #endif 268 #define c_bg col[0] 269 #define c_axis col[1] 270 #define c_wire col[2] 271 #define c_surf col[3] 272 #define c_back col[4] 273 #define c_gain col[5] 274 #define c_scale col[6] 275 #define c_exci col[7] 276 #define c_load col[8] 277 #define c_netw col[9] 278 #define c_inactive col[10] 279 #define c_efield col[11] 280 #define c_hfield col[12] 281 #define c_poynting col[13] 282 #define c_qpos col[14] 283 #define c_qneg col[15] 284 #define c_gain_lin col[16] 285 #define c_gain_lhcp col[17] 286 #define c_gain_rhcp col[18] 287 #define c_currents (col+19) 288 #define NC NC_phase+19 289 extern GdkColor col[NC]; 290 291 292 293 typedef struct { 294 void (*SetLineAttributes)(unsigned int,int,int,int); 295 void (*DrawLine)(double,double,double,double); 296 void (*SetForeground)(GdkColor *); 297 void (*ClearWindow)(); 298 void (*DrawString)(double,double,char*,double,double); 299 void (*Complete)(); 300 void (*SetClipRectangle)(double,double,double,double); 301 void (*ClearRectangle)(double,double,double,double); 302 } Outdev; 303 304 extern Outdev *out; /* pointer to Outdev struct, determines destination of drawing commands issued through the below macros: */ 305 306 #define SetLineAttributes(a,b,c,d) out->SetLineAttributes((a),(b),(c),(d)) 307 #define DrawLine(a,b,c,d) out->DrawLine((a),(b),(c),(d)) 308 #define SetForeground(a) out->SetForeground(a) 309 #define ClearWindow() out->ClearWindow() 310 #define DrawStringLL(a,b,c) DrawString(a,b,c,0,0) /* draw text specifying lower left corner */ 311 #define DrawStringUL(a,b,c) DrawString(a,b,c,0,1) /* draw text specifying upper left corner */ 312 #define DrawString(a,b,c,d,e) out->DrawString(a,b,c,d,e) /* draw text specifying a corner defined by d and e: 313 d = 0...1 for left...right; e = 0...1 for lower...upper */ 314 #define SetClipRectangle(a,b,c,d) out->SetClipRectangle(a,b,c,d) /* set clip rectangle to (a,b)..(c,d) */ 315 #define ClearRectangle(a,b,c,d) out->ClearRectangle(a,b,c,d) /* clear part of window */ 316 317 318 void removecommas(char *p); /* change commas in string into spaces */ 319 320 void updateextremes(Point *p); /* update the value of extr_str with information about this Point */ 321 322 void read_nec_input(FILE *f); /* read the input file, and update the arrays of wires and surfaces accordingly */ 323 324 int read_nec_output(FILE *f); /* tries to read NEC output data from f, updates gain distribution arrays; returns 1 if not succesful */ 325 326 void process_nec_output(NECoutput *ne); /* transform the gain data array into an array of points in 3D space */ 327 328 void calc_vgain(void); /* update the vgain records in accordance with the viewing direction */ 329 330 void mark_gpo_invalid(void); /* mark gpo fields as invalid; must be called after every change of gain scale */ 331 332 void calcswr(NECoutput *ne); /* calculate the SWR from zr and zi */ 333 334 void calcphiabs(NECoutput *ne); /* calculate phi and abs of impedance from zr and zi */ 335 336 void initX(int *argcp,char **argv); /* initialize the X-window stuff */ 337 338 void mainX(int really); /* main loop (wait for event, process event, redisplay) */ 339 340 int Pending(void); /* test whether events are pending; returns !=0 if present (drawing) action should be interrupted */ 341 342 void reread(void); /* reread the input file(s) */ 343 344 void process_optionstring(char *s); /* process a set of options, contained in the string s */ 345 346 void draw_all(int ie); /* draw antenna structure and/or gain pattern; ie=interupt_enable */ 347 348 void calcproj(void); /* calculate the projection matrix etc. */ 349 350 int write_png(int which,const char *filename); /* write window 1 or 2 to an PNG file; return !=0 in case of error */ 351 352 int write_postscript(const char *filename,void (*drawfn)(int),int xsize, int ysize); 353 /* write postscript to file; return !=0 in case of error */ 354 355 void draw_all2(int dummy); /* draw plot(s) vs. frequency */ 356 357 double xfreq(int x); /* return frequency corresponding to X coordinate in frequency plot */ 358 int freqx(double f); /* return X coordinate corresponding to frequency */ 359 int freqindex(double f); /* return index in neco[] of data closest to frequency f */ 360 361 void *mymalloc(size_t n); /* like malloc(), but exits with error message if memory not available; implementation in parse_output.c */ 362 void *myrealloc(void *,size_t n); /* like realloc(), but exits with error message if memory not available; implementation in parse_output.c */ 363 364 void draw_opaque(Radpattern *); /* draw radiation pattern as an opaque surface */ 365 366 void setpolcolour(double axial); /* set the colour corresponding to this axial ratio */ 367 368 char *opaque_impossible(Radpattern *rp); /* returns NULL if opaque drawing of this Radpattern is possible; otherwise, pointer to string with explanation */ 369 370 371 /* a macro for conveniently expanding array sizes: */ 372 #define EXPAND_IF_NECESSARY(num,max,pointer) \ 373 if (num>=max) { \ 374 while (max<num+1) max=max*2; \ 375 pointer=myrealloc(pointer,max*(sizeof(*pointer))); \ 376 } 377 378 /* if your system doesn't have the function drem() available, uncomment 379 the following line and recompile (after deleting *.o) 380 */ 381 /* #define drem(x,y) ( (x) - (y)*rint((x)/(y)) ) */ 382 383