[net.ham-radio] Minimuf 3.5 From Dec QST

caf (12/09/82)

This is a C version of the MUF predicting program appearing in DEC 82
QST.  It should run on v7 or usg or compatible systems.  Testing so far
has consisted of comparing output with the example in the article.
with a -f flag, minimuf accepts 1 or more 10mHz readings from WWV
which are smoothed and converted to sunspot number according to the
graph in the article.  Enjoy.

	Chuck Forsberg, WA7KGX
	Chief Engr, Computer Development Inc.
	6700 S. W. 105th, Beaverton OR 97005   (503) 646-1599
	...!teklabs!ogcvax!metheus!cdi!caf

/*% cc -O % -lm -o minimuf
*/
/*
 * Minimuf 3.5 From Dec 1982 QST pp. 36-38.
 *  By Dr Paul Levine, J N Martin, D B Sailors, Robert B Rose
 *	Single F layer prediction Useful for 2 to 50 mHz, 250 to 6000 miles
 *	rms error reported to be +- 3.8 mHz.
 *  C version translated by Chuck Forsberg WA7KGX
 */
#include <stdio.h>
#include <math.h>

double sign();

#define PI 3.141593

double Txlat, Txlon;		/* transmitter latitude, longitude */
double Rxlat, Rxlon;		/* receiver latitude, longitude */
double Month;		/* month, 1 to 12 */
double Day;		/* day, 1 to 31 */
double Hr;		/* time in UTC 0 to 24 */
double Muf;		/* output MUF in mHz */
double Isn;		/* sunspot number */
double Flux;		/* 10mHz flux */

double r0,p1,r1,p0,k7,g1,k6,k5;
double k1,kstep,kend,a,b,p,q,c,w0,d,l0,k9,c0,t9,g7;
double t1,y2,k8,g0,m9;
double t,t4,g9,g8,u,g2,t6,u1;

char Months[] = "   JanFebMarAprMayJunJulAugSepOctNovDec";
int m[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};

main(argc,argv)
char *argv[];
{
    int ret;
    static getflux=0;

    if (--argc > 0)
	if (strcmp(*++argv, "-f")==0)
	    ++getflux;
    r0 = PI/180.;
    p1 = 2.*PI;
    r1 = 180./PI;
    p0 = PI/2.;

    do {
	fprintf(stderr, "Transmitter Latitude Longtitude\n");
	ret=scanf("%lf%lf", &Txlat, &Txlon);
	if (ret==EOF)
	    exit(0);
    }
	while (ret!=2 || Txlat>90. || Txlat<-90. || Txlon>360. || Txlon<-360.);

    do {
	fprintf(stderr, "Receiver Latutide Longtitude\n");
	ret=scanf("%lf%lf", &Rxlat, &Rxlon);
	if (ret==EOF)
	    exit(0);
    }
	while (ret!=2 || Rxlat>90. || Rxlat<-90. || Rxlon>360. || Rxlon<-360.);

    do {
	fprintf(stderr, "Day Month : ");
	ret = scanf("%lf%lf", &Day, &Month);
	if (ret==EOF)
	    exit(0);
    }
	while (ret != 2 || Month<1 || Month>12 || Day<1 || Day>m[(int)Month]);

    if (!getflux) {
	do {
	    fprintf(stderr, "Sunspot number : ");
	    ret=scanf("%lf", &Isn);
	    if (ret==EOF)
		exit(0);
	}
	    while (ret != 1 || Isn <= 0);
    }
    else
    {
	fprintf(stderr,
	  "Daily Flux reading[s], oldest first, terminate with 0\n");
	ret=scanf("%lf", &Flux);
	for (;;) {
	    ret=scanf("%lf", &Isn);
	    if (ret != 1 || Isn==0)
		break;
	    Flux = 0.8*Flux + 0.2*Isn;
	}
	if (Flux>130.)
	    Isn = (Flux-65.)*1.34;
	else
	    Isn = Flux - 35.;
    }

    printf("\n\nMinimuf 3.5 Maximum Usable Frequency Prediction\n\n");
    printf("Date %3.3s %2d\n", &Months[3*(int)Month], (int) Day);
    printf("Transmitter Latitide %lg Longtitude %lg\n", Txlat, Txlon);
    printf("Receiver    Latitide %lg Longtitude %lg\n", Rxlat, Rxlon);
    printf("Sunspot Number %lg\n\n", Isn);
    printf("	Hour	MUF(mHz)\n\n");

    Txlat *= r0; Txlon *= r0; Rxlat *= r0; Rxlon *= r0;

    for (Hr =0; Hr <= 23; Hr += 1.) {
	minimuf();
	printf("	%02d	%4.1lf\n", (int)Hr, Muf);
    }
    exit(0);
}

minimuf()
{
    k7 = sin(Txlat)*sin(Rxlat)+cos(Txlat)*cos(Rxlat)*cos(Rxlon-Txlon);
    if (k7 > 1.)
	k7 = 1.;
    else if (k7 < -1.)
	k7 = -1.;
    g1 = acos(k7);
    k6 = 1.59 * g1;
    if (k6 < 1.)
	k6 = 1.;
    k5 = 1./k6;
    Muf = 100.;

    kstep = .9999-1./k6;
    kend = 1.-1./(2.*k6);
    for (k1=1./(2.*k6); kstep>0? k1 <= kend : k1 >= kend; k1 += kstep) {
	if (k5 != 1.0)
	    k5 = 0.5;
	p = sin(Rxlat);
	q = cos(Rxlat);
	a = (sin(Txlat)- p * cos(g1)) / (q * sin(g1));
	b = g1*k1;
	c = p * cos(b)+q*sin(b)*a;
	d = (cos(b) - c*p) / (q*sqrt(1-(c*c)));
	if (d > 1.)
	    d = 1.;
	else if (d < -1.)
	    d = -1.;
	d = acos(d);
	w0 = Rxlon+sign(sin(Txlon-Rxlon))*d;
	if (w0 < 0)
	    w0 += p1;
	if ( w0 > p1)
	    w0 -= p1;
	if ( c < -1.)
	    c = -1.;
	else if (c > 1.)
	    c = 1.;
	l0 = p0-acos(c);
	t1 = 0.0172*(10.+(Month-1.)*30.4+Day);
	y2 = 0.409*cos(t1);
	k8 = 3.82 * w0+12.+0.13*(sin(t1)+1.2*sin(2.*t1));
	k8 = k8-12.*(1.+sign(k8-24.))*sign(fabs(k8-24.));
	if (cos(l0+y2) <= -0.26) {
	    k9 = g0 = 0;
	    m9 = 2.5 * g1 * k5;
	    if (m9 > p0)
		m9 = p0;
	    m9 = sin(m9);
	    m9 = 1. + 2.5 * m9 * sqrt(m9);
	}
	else
	{
	    k9 = (-0.26+sin(y2)*sin(l0))/(cos(y2)*cos(l0)+0.001);
	    k9 = 12. - atan(k9/sqrt(fabs(1.-k9*k9)))*7.639437;
	    t = k8-k9/2.+Rxlat*(1.-sign(k8-k9/2.))*sign(fabs(k8-k9/2.));
	    t4 = k8+k9/2.-12.*(1.+sign(k8+k9/2.-24.))*sign(fabs(k8-k9/2.-24.));
	    c0 = fabs(cos(l0+y2));
	    t9 = 9.7*pow(c0,9.6);
	    if (t9 < 0.1)
		t9 = 0.1;
	    m9 = 2.5*g1*k5;
	    if (m9 > p0)
		m9 = p0;
	    m9 = sin(m9);
	    m9 = 1. + 2.5*m9*sqrt(m9);
	    if ((t4 < t && (Hr-t4)*(t-Hr) > 0)
	      || (t4 >= t && (Hr-t)*(t4-Hr) <= 0))
	    {
		t6 = Hr+12.*(1.+sign(t4-Hr))*sign(fabs(t4-Hr));
		g8 = PI*t9/k9;
		u = (t4-t6)/2.;
		u1 = -k9/t9;
		g0 = c0*(g8*(exp(u1)+1.))*exp(u)/(1.+g8*g8);
	    }
	    else
	    {
		t6 = Hr+12.*(1.+sign(t-Hr))*sign(fabs(t-Hr));
		g9 = PI * (t6-t)/k9;
		g8 = PI * t9/k9;
		u = (t-t6)/t9;
		g0 = c0*(sin(g9)+g8*(exp(u)-cos(g9)))/(1.+g8*g8);
		g7=c0*(g8*(exp(-k9/t9)+1.))*exp((k9-24.)/2.)/(1.+g8*g8);
		if (g0 < g7)
		    g0 = g7;
	    }
	}

	g2 =(1.+Isn/250.)*m9*sqrt(6.+58.*sqrt(g0));
	g2 = g2*(1.-0.1*exp((k9-24.)/3.));
	g2 = g2*(1.+(1.-sign(Txlat)*sign(Rxlat))*0.1);
	g2 = g2*(1.-0.1*(1.+sign(fabs(sin(l0))-cos(l0))));
	if (Muf > g2)
	    Muf = g2;
    }
    return;
}

double
sign(g)
double(g);
{
    if (g > 0.)
	return 1.;
    if (g < 0.)
	return -1.;
    return 0.0;
}