1 #ifdef HAVE_STDLIB_H
2 #include <stdlib.h>
3 #endif
4 #include <stdio.h>
5 #include <memory.h>
6 #include <errno.h>
7 #include "yagi.h"
8 #include <errno.h>
9 
10 #define MAX_NON_ITERATIVE 100000
11 
solve_equations(double frequency,int driven,int parasitic,double ** driven_data,double ** parasitic_data,double * v,double ** z,double * pin,struct FCOMPLEX * voltage,struct FCOMPLEX * current,struct FCOMPLEX * input_impedance,struct element_data * coordinates,double ** A,double * b,int * indx)12 void solve_equations(double frequency, int driven, int parasitic, double **driven_data, double **parasitic_data, double *v, double **z, double *pin, struct FCOMPLEX *voltage, struct FCOMPLEX *current, struct FCOMPLEX *input_impedance, struct element_data *coordinates, double **A, double *b, int *indx)
13 {
14 	int elements, element_number, i, j;
15 	double d, **A_pre_LUdcmp, *b_copy, t1, t2;
16 	elements=driven+parasitic;
17 	fill_z_matrix(frequency,driven,parasitic,driven_data,parasitic_data, z);
18 	/* Now we must fill the V vector, which gives the voltage at the centre of
19 	each driven element. Since we know the magnitude of the voltage and phase,
20 	we can calculate the real and imaginary components of voltage. NB */
21 	fill_v_vector(driven, parasitic, driven_data, v);
22 
23 	/* We now have the voltage vector V, and the impedance matrix Z. All
24 	we need to do now is solve a set of NxN equations, where N is the
25 	number of elements, to get N values of current, which we can put in
26 	the I matrix.
27 	Unfortunately, this is not trivual, by any standards!!!  It is
28 	complicated by the fact the the N equations are all complex.
29 	The method used us a brute-force approach mentioned by Press
30 	in their 2nd Edition of the Numerical Recipes in C book. Here we
31 	put the data in the form:
32 
33 	|Zr -Zi|   |Ir|   = |Vr|   which we will call A.x=b
34 	|Zi  Zr|   |Ii|     |Vi|
35 
36 	so the Z data goes now in a 2Nx2N matrix. This is a bit wasteful of space
37 	and time, but it will do here. */
38 	/* Copy impedance data from 'z' to matrix A */
39 	copy_complex_data_to_real_matrix(elements,z,A);
40 	/* The following function prints to stantard output the z matrix of the
41 	antenna. It is really only used during debugging, so it can be commented
42 	out normally. */
43 	/* print_z_matrix(frequency,elements,z);  */
44 	/* read voltage data from v into b */
45 	for(i=1;i<=elements;++i)
46 	{
47 		b[i]= v[2*i-1];           /* real data */
48 		b[i+elements]=v[2*i];    /* imaginary data */
49 		voltage[i].r=v[2*i-1];
50 		voltage[i].i=v[2*i];
51 	}
52 	/* If there are a lot of elements, its possible that rounding errors
53 	will destroy the accuracy of the results. If there are more than
54 	MAX_NON_ITERATIVE elements, we do the usual LU decompositioon and
55 	back-substitution, then do an iterative improvement of the
56 	solution */
57 	if(elements > MAX_NON_ITERATIVE)
58 	{
59 		A_pre_LUdcmp=dmatrix(1L, 2L*(long)elements, 1L, 2L*(long) elements);
60 		b_copy=dvector(1L, 2L*(long)elements);
61 		/* I had troubled using memcpy to copy matrices - probably becuase
62 		they are offset by  1 */
63 		copy_matrix(2*elements, 2*elements, A_pre_LUdcmp, A);
64 		/* copy vector b */
65 		for(j=1;j<=2*elements;++j)
66 			b_copy[j]=b[j];
67 	}
68 	/* Perform a LU decompositon of A */
69 	ludcmp(A, elements*2, indx, &d);
70 	/* We now have the voltages in b. After lubksb is run, we get the
71 	currents in b . A contains an LU decomposed version of the original A*/
72 	lubksb(A, 2*elements, indx, b); /* current's in b after lubksb has run*/
73 	if(elements>MAX_NON_ITERATIVE)
74 	{
75 		t1=b[1];
76 		mprove(A_pre_LUdcmp, A, 2*elements, indx, b_copy, v);
77 		free_dmatrix(A_pre_LUdcmp,1L, 2L*(long)elements, 1L, 2L*(long) elements);
78 		/* free_dvector(bcopy,1L,2L*elements); */
79 	   t2=b[1];
80 		if(t1!=t2)
81 		{
82 			printf("b[1]'s differ before and after mprove: before = %.16f after =%.16f\n", t1, t2);
83 			exit(1);
84 		}
85 	}
86 	/* Put currents an FCOMPLEX matrix current[element]
87 	currents are stored in b as r,r,r,r ..... i,i,i,i */
88 	for(element_number=1;element_number<=elements;element_number++)
89 	{
90 		current[element_number].r=b[element_number];
91 		current[element_number].i=b[element_number+elements];
92 	}
93 	z_input(voltage[1], current[1], input_impedance);
94 	*pin=calculate_power_input(input_impedance->r,current[1]); /* in Watts */
95 	/* Sometimes the input power goes < 0. I'm not sure why this occurs, but
96 	the implication is that the antenna is a source of energy, which is silly.
97 	The gain is negative then (not in dB), so taking the log to put in dB
98 	would cause a numerical error. When this occurs, we print a message to
99 	stderr, then write the data in a file "problem". The user may then
100 	investigate what went wrong. */
101 	if(*pin <= 0.0)
102 	{
103 		/* fprintf(stderr,"Input power less than 0! Undesirable, but non-fatal error.\n"); */
104 		*pin=1e20; /* Force it to a large value */
105    /* do_since_better(0,"problem","problem",*input_impedance, \
106 	rubbish,flag, "This causes Pin < 0.0 - findout why!",frequency, frequency, \
107 	frequency,frequency/10.0, elements, driven, parasitic, \
108 	180.0, driven_data, parasitic_data, 1.0, 0.0); */
109 	}
110 	for(i=1;i<=driven;++i)
111 	{
112 		coordinates[i].x=driven_data[i][X];
113 		coordinates[i].y=driven_data[i][Y];
114 		coordinates[i].length=driven_data[i][LENGTH];
115 	}
116 	for(i=driven+1;i<=elements;++i)
117 	{
118 		coordinates[i].x=parasitic_data[i-driven][X];
119 		coordinates[i].y=parasitic_data[i-driven][Y];
120 		coordinates[i].length=parasitic_data[i-driven][LENGTH];
121 	}
122 
123 #ifdef DEBUG
124 	if(errno)
125 	{
126 	fprintf(stderr,"Errno =%d in solve.c\n", errno);
127 	exit(1);
128 	}
129 #endif
130 }
131