Communications Radio

From Albatross

Jump to: navigation, search

Introduction

FIXME

http://www.zytrax.com/tech/wireless/calc.htm - Range Calculator Verdict: we should have an operating margin of better than 20dB at 10 km line of sight range, and 10dB (which should still work) at 35 km line of sight range.

Here is the code:

<script language="JavaScript" type="text/javascript">
<!--
// Copyright ZYTRAX, Inc. 2001 - 2003
// You are welcome to copy or use this script for non-commercial purposes
// We prefer you leave in this Copyright statement but don't insist on it	
// if you make improvements send us a copy or make the code available on your
// own web site.
// NO WARRANTY OR FITNESS FOR PURPOSE UNDERTAKEN - USE AT YOUR OWN RISK
// global variables
	var 	mw;	// milliwatts
	var	w;	// watts
	var	dbm;	// dBm
	var	dbw;	// dBW
	var	num;	// intermediate results
	var f;			// frequency
	var d;			// distance
	var ktm = .621;		// km to miles
	var mtk = 1.609;	// miles to klics
	var ftm = 3.28;		// meters to feet
	var mtf = .3048		// feet to meters
	var db;				// work variable
function round(number,places) {
	// rounding numbers
	places = (!places ? 2 : places);
	return Math.round(number*Math.pow(10,places))/Math.pow(10,places);
} 

function log10(x) {
	// Logging10
	return(Math.log(x) / Math.log(10));
}

function from_dbm(u_dbm) {
	// convert dbm to watts and milliwatts
	dbm = parseFloat(u_dbm);
	
	// validate dbm range
	if ((isNaN(dbm)) || (dbm < -110) || (dbm > 100)) 
	{
  	window.alert("dBm range from -110 to 100");
    return("Error");
  }
	
	mw = Math.pow(10,dbm / 10);
	
	return(round(mw,2));
}

function to_dbm(u_mw) {
	w = parseFloat(u_mw);
	
	// validate milliwatts range
	if ((isNaN(w)) || (w < 0) || (w > 20000)) 
	{
        window.alert("millWatts range = 0 to 20,000");

    	return("Error");
    }
	w = log10(w) / log10(10);
	dbm = round((10 * w),2);
	return(dbm);
}

function free_space(u_freq, u_km, u_miles) {
	
	f = parseFloat(u_freq);
	if ((d = check_m(u_km,u_miles,"Distance")) == "Error")
	{
		return("Error");
	}
	// validate frequency
	if ((isNaN(f)) || (f < 100) || (f > 60000))
	{
  	window.alert("Frequency (in MHz) range  = 20 to 60,000");
    return("Error");
    }
	
	f = log10(f) / log10(10);
	d = log10(d) / log10(10);
	
	return(round((20 * f) + (20 * d) + 36.56,2));
	
}
function check_dbm(u_dbm, u_mw)
{
	// normalise power to dbm
	if(u_dbm == "")
	{
		dbm = to_dbm(u_mw);
	}
	else
	{
		dbm = parseFloat(u_dbm);
	}
	//validate dbm range
	if ((isNaN(dbm)) || (dbm < -110) || (dbm > 100)) 
	{
  	window.alert("dBm range from -110 to 100");
    return("Error");
  }
	return(dbm);
}

function check_km(k,m,e) // returns KM
{
	if(k == ""){ 
		if(m == ""){ // must have a mile measure
			
			alert(e+" not supplied");// error
			return -1;
		}
		else{
			
			if(isNaN(m) || m < 0.1 || m > 100){
			alert(e+" (Miles) not numeric or not in range .1 to 100");
			return -1;
		}
			tm = parseFloat(m);
			return (tm * mtk);
		}
	}
	else{
		if(isNaN(k) || k < 0.1 || k > 100){
			alert(e+" (Km) not numeric or not in range .1 to 160");
			return -1;
		}
		return parseFloat(k);
	}
}
function check_m(u_km, u_miles, err) // returns MILES
{
	if(u_km == "")
	{
		// must be miles
		d = parseFloat(u_miles);
		if(isNaN(d) || d < 0.1 || d > 100)
		{
			window.alert(err+" range is .1 to 100 MILES");
    	return("Error");
		}
	}
	else
	{
		d = parseFloat(u_km);
		if(isNaN(d) || d < 0.1 || d > 160)
		{
			window.alert("Distance range is .1 to 160 KM");
    	return("Error");
		}
		d = d * ktm;
	}
	return(d);
}

// W3C DOM'ish
function check_int(num, lo, hi, def, err)
{
	if(num == "" && def != "")
	{
		return def;	// just return default 
	}
	
	tn = parseInt(num);
	if(isNaN(tn) || tn < lo || tn > hi)
	{
		alert(err+" must be in range "+lo+" to "+hi);
    return("Error");
	}
	return tn;
}
function fres_zone()
{
// note: uses explicit names in form which must be unique on page
	if((tl = check_km(document.getElementById("fltk").value,document.getElementById("fltm").value,"Total Link distance")) == -1)
	{
		return;
	}
	// tl valid numeric in Km check for obstacle
	if((d1 = check_km(document.getElementById("flok").value, document.getElementById("flom").value, "Obstacle Distance")) == -1)
	{
		return;
	}
	d2 = tl - d1;
	// check frequency present and numeric
	flf = document.getElementById("flf").value;
	if(flf == "")
	{
		alert("Frequency not specified");
		return;
	}
	if(isNaN(flf ))
	{
		alert("Frequency not numeric");
		return;
	}
	freq = parseFloat(flf);
	
	freq = freq /1000;	// in GHz
	// fresnel and obstacle free zone
	flrm = Math.round(17.3 * Math.sqrt((d1 * d2)/(freq * tl)));
	document.getElementById("flzm").value = flrm;
	document.getElementById("flzf").value = Math.round(flrm * ftm);
	document.getElementById("fld1k").value = round(d1,2);
	document.getElementById("fld1m").value = round(d1 * ktm,2);
	//  0.6 fresnel
	flr6m = Math.round(17.3 * Math.sqrt((0.6 * d1 * d2)/(freq * tl)));
	document.getElementById("flofm").value = flr6m;
	document.getElementById("floff").value = Math.round((flr6m * ftm));
	// earth's height at mid point
	ehm = (Math.pow(tl,2)/(8*6378)) * 1000;
	document.getElementById("flehm").value = round(ehm,2);
	document.getElementById("flehf").value = round(ehm * ftm,2);
}

function power_budget()
{
	if((dbm = check_dbm(document.getElementById("bdbm").value, document.getElementById("bmw").value)) == "Error")
	{
		return ("Error");
	}
	// antenna
	if((db = check_int(document.getElementById("bag").value,1,100, "", "Antenna Gain")) == "Error"){
		return "Error";
	}
	// result for gains
	radan_tot = dbm + db;
	document.getElementById("brr").value = round(dbm + db,2);
		
	if(document.getElementById("blf").value != "" || document.getElementById("blm").value != "")
	{
		// handle cable loss
		// we have a cable parameter normalise to meters
		if(document.getElementById("bcf").value != "")
		{
			// user supplied feet
			cable_loss = parseFloat(document.getElementById("bcf").value);
			if(isNaN(cable_loss))
			{
				window.alert("Cable loss not numeric");
    		return("Error");
			}
			cable_loss = cable_loss * ftm;
		}
		else
		{
			cable_loss = parseFloat(document.getElementById("bcm").value);
			if(isNaN(cable_loss))
			{
				window.alert("Cable loss not numeric");
    		return("Error");
			}
		}
		if(document.getElementById("blf").value != "")
		{
			// user supplied feet
			cable_length = parseFloat(document.getElementById("blf").value);
			if(isNaN(cable_length))
			{
				window.alert("Cable length not numeric");
    		return("Error");
			}
			cable_length = cable_length * mtf;
		}
		else
		{
			cable_length = parseFloat(document.getElementById("blm").value);
			if(isNaN(cable_length))
			{
				window.alert("Cable length not numeric");
    		return("Error");
			}
		}
		// normalise cable loss
		cable_tot = round((cable_loss /100) * cable_length,2);
		document.getElementById("bcr").value = cable_tot;
	}
	else
	{
		cable_tot = 0;
		document.getElementById("bcr").value = "0";
	}
	
	// handle connectors
	if(document.getElementById("bconno").value != "")
	{
		// handle connector loss
		f = parseFloat(document.getElementById("bconf").value);
		if ((isNaN(f)) || (f < 100) || (f > 25000))
		{
			window.alert("Frequency range 100 to 25,000 MHz");
    	return("Error");
		}
		f = f /1000; //frequency in GHz
		num_con = parseInt(document.getElementById("bconno").value);
		if (isNaN(num_con))
		{
			window.alert("Number of connectors not numeric");
    	return("Error");
		}
		// max. loss = 0.10 * sqrt(freq)
		con_tot = round(num_con * (0.1 * Math.sqrt(f)),2);
		document.getElementById("bconr").value = con_tot;
	}
	else
	{
		con_tot = 0;
		document.getElementById("bconr").value = "0";
	}
	document.getElementById("btr").value = round(radan_tot - con_tot - cable_tot,2);
}

function op_margin()
{
	//calculate various operating margins or antenna gains or distance
	want_dis = 0;
	want_tan = 0;
	want_ran = 0;
	if((sad = check_int(document.getElementById("spomsad").value, 1, 100, 30, "SAD factor")) == "Error"){
		return "Error";
	}
	sad = sad/100;
	if(document.getElementById("spk").value == "" && document.getElementById("spm").value == ""){
		want_dis = 1; // no distance - solve for distance only
	}
	else 
	{
		if((d = check_m(document.getElementById("spk").value, document.getElementById("spm").value, "Distance")) == "Error")
		{
			return("Error");
		}
	}
	// must always have valid frequency
	f = parseFloat(document.getElementById("spf").value);
	if(isNaN(f) || f < 20 || f > 60000)
	{
		window.alert("Frequency range is 20 to 60,000 MHz");
    return("Error");
	}
	if(!want_dis)
	{
		f = log10(f) / log10(10);
		d = log10(d) / log10(10);
		fs_loss = round((20 * f) + (20 * d) + 36.56,2);
	}
	// calculate tx power 
	// confirm TX antenna gain
	if (document.getElementById("sptxa").value == "" && want_dis)
	{
		window.alert("Cannot solve for distance and TX antenna gain");
    return("Error");
	}
	else 
	{
		if (document.getElementById("sptxa").value == "")
		{
			want_tan = 1;		// solve for tx gain
			tx_an = 0;			// temp
		}
		else
		{
			tx_an = parseFloat(document.getElementById("sptxa").value);
		}
	}
	if(isNaN(tx_an) || tx_an < 0 || tx_an > 100)
	{
		alert("Antenna gain range 0 to 100");
    return("Error");
	}
	// check radio power
	if((tx_dbm = check_dbm(document.getElementById("sptxdbm").value, document.getElementById("sptxmw").value)) == "Error")
	{
		return("Error");
	}
	// if cable loss invalid substitute 0
	tx_cable = parseFloat(document.getElementById("sptxc").value);
	if (isNaN(tx_cable))
	{
		tx_cable = 0;
		document.getElementById("sptxc").value = 0;
	}
	tx_budget = tx_an + tx_dbm - tx_cable;
	// calculate rx power 
	// confirm RX antenna gain
	if (document.getElementById("sprxa").value == "" && want_dis)
	{
		window.alert("Cannot solve for distance and RX antenna gain");
    return("Error");
	}
	else
	{
		if (document.getElementById("sprxa").value == "")
		{
			want_ran = 1;		// solve for rx gain
			rx_an = 0;
		}
		else
		{
			rx_an = parseFloat(document.getElementById("sprxa").value);
		}
	}
	if(isNaN(rx_an) || rx_an < 0 || rx_an > 100)
	{
		window.alert("Antenna gain range 0 to 100");
    return("Error");
	}
	// check radio power
	if((rx_dbm = check_dbm(document.getElementById("sprxdbm").value, "")) == "Error")
	{
		return("Error");
	}
	// if cable loss invalid substitute 0
	rx_cable = parseFloat(document.getElementById("sprxc").value);
	if (isNaN(rx_cable))
	{
		rx_cable = 0;
		document.getElementById("sprxc").value = 0;
	}
	rx_budget = rx_an - rx_dbm - rx_cable;
	
	// got everything we might need - figure out what to do
	if(!want_dis && !want_tan && !want_ran)
	{
		// straight calculation of margins
		document.getElementById("sprxr").value = round(rx_budget,2);
		document.getElementById("sptxr").value = round(tx_budget,2);
		document.getElementById("spfr").value = fs_loss;
		margin = tx_budget - fs_loss + rx_budget;
		document.getElementById("spomr").value = round(margin,2);
		document.getElementById("spomrx").value = round(margin + rx_dbm,2);
		document.getElementById("spomsad").value = round(((margin/tx_budget) * 100),2);
	}
	else 
	{
		if (want_dis)
		{
			// solve for distance
			document.getElementById("sprxr").value = round(rx_budget,2);
			document.getElementById("sptxr").value = round(tx_budget,2);
			// reduce tx_budget by SAD
			tx_budget = tx_budget - (tx_budget * sad);
			fs_loss = tx_budget + rx_budget;
			// now solve fs equation for distance
			alert("Solve for distance not currently operational - sorry");
    	return("Error");
		}
		else
		{
			document.getElementById("spfr").value = fs_loss;
			temp_budget = tx_budget - (tx_budget * sad);
			gain = Math.ceil(fs_loss - (temp_budget + rx_budget));
			if(gain < 0)
			{
				gain = 0;
			}
			// round gain up
			if(want_tan && want_ran)
			{
				// solve for two antenna (symetric)
				gain = Math.ceil(gain /2);
				document.getElementById("sptxa").value = gain;
				document.getElementById("sprxa").value = gain;
				tx_budget = tx_dbm - tx_cable + gain;
				rx_budget = gain - rx_dbm - rx_cable;
			}
			else
			{
				// solve for one antenna
				if(want_tan)
				{
					document.getElementById("sptxa").value = gain;
					tx_budget = tx_dbm - tx_cable + gain;
				}
				else
				{
					document.getElementById("sprxa").value = gain;
					rx_budget = gain - rx_dbm - rx_cable;
				}
			}
			document.getElementById("sprxr").value = round(rx_budget,2);
			document.getElementById("sptxr").value = round(tx_budget,2);
			document.getElementById("spfr").value = fs_loss;
			margin = tx_budget - fs_loss + rx_budget;
			document.getElementById("spomr").value = round(margin,2);
			document.getElementById("spomrx").value = round(margin + rx_dbm,2);
			if(document.getElementById("spomsad").value == "")
			{
				document.getElementById("spomsad").value = Math.ceil(sad * 100);
			}
		}
	}
}

//-->
</script>
Personal tools