Skip to content

Latest commit

 

History

History
823 lines (577 loc) · 42.3 KB

README.md

File metadata and controls

823 lines (577 loc) · 42.3 KB

nPort: A Microwave Circuit Analysis Program

nP is a JavaScript library for analyzing microwave circuits. It helps you learn about, analyze and visualize the operation of various RF multiport circuits.

nPort creates one JavaScript global variable, nP.

API Reference


How to Download

  • Create a new folder named "nPort"
  • Download nPort by clicking here", then Save as... "nP.js" and put it in the "nPort" folder.
  • Create the file below and name it "index.html" and put it in the "nPort" folder.
  • Run "index.html". I recommend Chrome. You should see Hello, nPort! After that, you are ready to go.

Here below is an html page for "Hello, nPort!"

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>Hello, nPort!</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>
		
nP.log('Hello, nPort!');

		</script>
	</body>
</html>

nP-global

As nPort analyses in the frequency domain, it requires at least one frequency point to do anything. nPort has a default frequency of 2e9 or 2GHz. Therefore, you must specify either a single frequency or a list of frequencies to give nPort the domain it needs. The frequency or frequencies must be in an array. The units must by in Hz. Suppose you require a frequency list with 1001. There is a function, fGen(), that will create long arrays for you.

nP.global <>

The nPort Object that contains the Frequency, Zo, and Temperature values. There is also a member function that generates frequencies, always in Hz, in the form of fStart, fStop, and the number of points.

nP.fGen( fStart, fStop, points ) <>

Returns an array of frequencies from fStart to fStop. The number of points is limited by memory or execution time. Popular number of points are odd numbers because the center frequency is always produced. So the number of points like 11, 51, 101, 1001, and so on, are good.

Here below is an example on how to create a list with 21 points.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>Frequency List</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>
		
var g = nP.global;
g.fList = g.fGen(.1e9,10e9,21); // 21 points from 100 MHz to 10 GHz

nP.log('g.fList is an array, [f1, f2, ... flast].');
nP.log('nP.log lists arrays downwards since they can be long');
nP.log(g.fList);

		</script>
	</body>
</html>

nP-nPort

nPort <> Any RF device input/output or RF system inputs/outputs is an nPort. An nPort may have up to and including 9 ports maximum. However, most of nPorts will have 1, 2, 3, or 4 ports. For example, an RF short is a 1 port device. A simple 2 way power divider is a 3 port device. An ideal RF transformer could have either 2 or 4 ports. At the other extreme, a switched filter bank with 1 input and 8 outputs is a 9 port device.

nPort Methods

nPort methods operate on nPort Objects. All nPort Objects have these methods. nPort.cas() returns a new nPort Object enabling method chaining.

nPort.setglobal ( global )<> sets the global variables of an nPort: fList, Ro, and Temp mentioned above

nPort.getglobal <> gets the global variables of an nPort

nPort1.cas ( nPort2 )<> cascades two 2-ports and creates a new nPort. Method chaining enabled.

nPort.out ( 'sij|mag|dB|ang|Re|Im', ' ... ' )<> Creates an output data set that can be plotted with nP.lineChart() or can be seen in a table with nP.lineTable(). Arguments must be in quotes and separated by commas. For example for a filter 2-port named, filt1, to specify an out(), the syntax would be, filt1.out('s11mag','s11dB','s22ang').

  • mag the magnitude of a complex number, such as an s-parameter
  • ang the angle
  • dB the magnitude in dB
  • Re the real part
  • Im the imaginary part

Here is an example of nP.out() below

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>nP.out()</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>
		
var g = nP.global;
g.fList = [2e9, 4e9]; // 1 frequency set to 2GHz

var r1 = nP.seR(75);
var s11 = r1.out('s11mag');

nP.log('The s-parameter, s11, of a 75 ohm resistor in series');
nP.log(s11);

nP.log('Same thing using nP.lineTable')
nP.lineTable({inputTable: [s11]});

		</script>
	</body>
</html>

nPort Functions

nPort functions are not members of nPort, but they operate on nPort objects. Two general purpose functions are cascade and nodal.

nP.cascade ( ... nPorts )<> cascades a list of comma separated nPorts and returns a new nPort Object. nPort.cascade accepts 2-ports only and creates a new 2-port that is the cascade of all the individual 2-ports.

nP.nodal ([nPort1, node1, node2, ...],[nPort2, node2, node3], ... ['out', node1, node3])<> Enables complex interconnections of nPorts. The argument of nodal is a list of arrays separated by commas. Each array has the name of an nPort followed the node numbers separated by commas. The last array is output, it must have the syntax ['out', nodes]. nP.nodal creates a new nPort Object. The example below shows the html, schematic, and output plot of a 6GHz Wilkinson Power Divider. Follow the details in the schematic to set up nP.node(). Note the notation of ports and nodes between the html listing and the schematic. Check the listing, ...,[tee,9,7,5],... and in the schematic. Node 9 is connected to the node 1 of the tee. Node 7 is connected to node 2 of the tee. Node 5 is connected to node 3 of the tee. The final result is a 3-port named, wilkinson. Node 1 of the input is node 1 of wilkinson, Node, 7 of the input is node 2 of wilkinson. Node 3 of wilkinson is node 6 of the input.

An nPort Functions example, a wilkinson power divider

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>Wilkinson</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>
// set up the frequencies
var g = nP.global;
g.fList = g.fGen(0e9,12e9,101);

// define the components of the power divider
var tee = nP.Tee();
var t70 = nP.tlin(70.7, 0.49 * 0.0254);
var r100 = nP.seR(100);

// hook up the components with nodal, it creates a output 3-port named "wilkinson"
var wilkinson = nP.nodal([tee, 1,2,3],[t70,3,5],[t70,2,4],[tee,9,7,5],[tee,8,4,6],[r100,8,9],['out',1,7,6]);

// create a data set of s-parameters to plot
var plot = wilkinson.out('s21dB','s23dB');

// plot the frequency response
nP.lineChart({inputTable: [plot], yRange: [-60, 5], chartTitle: 'Wilkinson Power Divider'});

		</script>
	</body>
</html>

Here is the schematic and output plot for a wilkinson power divider.

An nPort Functions example, a lowpass filter solved 4 ways

The example below shows three ways of doing the same thing, as filt1 = filt2 = filt3 = filt4.
filt1 is defined by the cas method

filt2 is defined by the cascade function

filt3 is defined by the nodal function

filt4 is defined by the lpfGen function

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>Low Pass solved 4 ways</title>
	</head>
	<body>
		<svg id="chart1" width="400" height="300"></svg>
		<svg id="chart2" width="400" height="300"></svg>
		<svg id="chart3" width="400" height="300"></svg>
		<svg id="chart4" width="400" height="300"></svg>

		<script src="./nP.js"></script>
		<script>

var g = nP.global;	
g.fList = g.fGen(50e6, 3e9, 50);

// create 9 2-ports. Each 2-port is part of a lowpass LC filter
var c1 = nP.paC(3.1716836788279897e-12);
var l1 = nP.seL(9.566513256241392e-9);
var c2 = nP.paC(5.6621309381827996e-12);
var l2 = nP.seL(1.0721164178932893e-8);
var c3 = nP.paC(5.8499784682761105e-12);
var l3 = nP.seL(1.0721164178932898e-8);
var c4 = nP.paC(5.662130938182797e-12);
var l4 = nP.seL(9.566513256241397e-9);
var c5 = nP.paC(3.171683678827988e-12);

// using 'cas' to define filter1
var filter1 = c1.cas(l1).cas(c2).cas(l2).cas(c3).cas(l3).cas(c4).cas(l4).cas(c5);
nP.lineChart({inputTable: [filter1.out('s11dB','s21dB')], chartID: 'chart1', chartTitle:'Solved by nP.cas()'});

// using 'cascade' to define filter2
var filter2 = nP.cascade (c1,l1,c2,l2,c3,l3,c4,l4,c5);
nP.lineChart({inputTable: [filter2.out('s11dB','s21dB')], chartID: 'chart2', chartTitle:'Solved by nP.cascade()'});

// using 'nodal' to define filter3
var filter3 = nP.nodal([c1,1,2],[l1,2,3],[c2,3,4],[l2,4,5],[c3,5,6],[l3,6,7],[c4,7,8],[l4,8,9],[c5,9,10],['out',1,10]);
nP.lineChart({inputTable: [filter3.out('s11dB','s21dB')], chartID: 'chart3', chartTitle:'Solved by nP.nodal()'});

// using 'lpfGen' to define filter4
var filter4 = nP.lpfGen([50,
		3.1716836788279897e-12,
		9.566513256241392e-9,
		5.6621309381827996e-12,
		1.0721164178932893e-8,
		5.8499784682761105e-12,
		1.0721164178932898e-8,
		5.662130938182797e-12,
		9.566513256241397e-9,
		3.171683678827988e-12,
		50]);
nP.lineChart({inputTable: [filter4.out('s11dB','s21dB')], chartID: 'chart4',chartTitle:'Solved by nP.lpfGen()'});

		</script>
	</body>
</html>

Here is the schematic and output plots for the lowpass filter.


nP-RLC

These are 2 ports containing resistors, capacitors, inductors, and transformers.

// seR reads, "series resistor"
// paR reads, "parallel resistor"

nP.seR( R = 75 ) <> Series resistor. Creates and returns a new nPort Object. If no argument, the default value is 75 Ohms.

nP.paR( R = 75 ) <> Parallel resistor. Creates and returns a new nPort Object. If no argument, the default value is 75 Ohms.

nP.seL( L = 5e-9 ) <> Series Inductor. Creates and returns a new nPort Object. If no argument, the default value is 5e-9 Henries.

nP.paL( L = 5e-9 ) <> Parallel Inductor. Creates and returns a new nPort Object. If no argument, the default value is 5e-9 Henries.

nP.seC( C = 1e-12 ) <> Series Capacitor. Creates and returns a new nPort Object. If no argument, the default value is 1e-12 Farads.

nP.paC( C = 1e-12 ) <> Parallel capacitor. Creates and returns a new nPort Object. If no argument, the default value is 1e-12 Farads.

RLC's with more than one component

The names may sound cryptic, but here is how to interpret them. The first two letters indicate that the 2-port is either a series or parallel 2-port. The third and forth letters indicate that the components are either in series or in parallel. The remaining letters are reference designators: RL, RC, LC, RLC.

// seSeRL reads, "series, resistor inductor in series "
// paSeRL reads, "parallel, resistor inductor in series"

nP.seSeRL( R = 75, L = 5e-9 ) <> A series, series resistor-inductor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 5e-9 Henries.

nP.paSeRL( R = 75, L = 5e-9 ) <> A parallel, series resistor-inductor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 5e-9 Henries.

nP.seSeRC( R = 75, C = 1e-12 ) <> A series, series resistor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 1e-12 Farads.

nP.paSeRC( R = 75, C = 1e-12 ) <> A parallel, series resistor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 1e-12 Farads.

nP.seSeLC( L = 5e-9, C = 1e-12 ) <> A series, series inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 5e-9 Henries and 1e-12 Farads.

nP.paSeLC( L = 5e-9, C = 1e-12 ) <> A parallel, inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 5e-9 Henries and 1e-12 Farads.

nP.seSeRLC( R = 75, L = 5e-9, C = 1e-12 ) <> A series, series resistor-inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 ohms, 5e-9 Henries and 1e-12 Farads.

nP.paSeRLC( R = 75, L = 5e-9, C = 1e-12 ) <> A parallel, series resistor-inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms, 5e-9 Henries and 1e-12 Farads.

nP.paPaRL( R = 75, L = 5e-9 ) <> A parallel, parallel resistor-inductor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 5e-9 Henries.

nP.sePaRL( R = 75, L = 5e-9 ) <> A series, parallel resistor-inductor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 5e-9 Henries.

nP.paPaRC( R = 75, C = 1e-12 ) <> A parallel, parallel resistor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 1e-12 Farads.

nP.sePaRC( R = 75, C = 1e-12 ) <> A series, parallel resistor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms and 1e-12 Farads.

nP.paPaLC( L = 5e-9, C = 1e-12 ) <> A parallel, parallel inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 5e-9 Henries and 1e-12 Farads.

nP.sePaLC( L = 5e-9, C = 1e-12 ) <> A series, parallel inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 5e-9 Henries and 1e-12 Farads.

nP.paPaRLC( R = 75, L = 5e-9, C = 1e-12 ) <> A parallel, parallel resistor-inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms, 5e-9 Henries and 1e-12 Farads.

nP.sePaRLC( R = 75, L = 5e-9, C = 1e-12 ) <> A series, parallel resistor-inductor-capacitor. Creates and returns a new nPort Object. If no arguments, the default values are 75 Ohms, 5e-9 Henries and 1e-12 Farads.


nP-Transformers

nP.trf( N = 0.5 ) <> Parallel capacitor. Creates and returns a new nPort Object. If no argument, the default value is turns ratio of N = 0.5 . N is also equal to N = sqrt(Zp/Zs), where Zp is primary impedance and Zs is the secondary impedance.

nP.trf4Port( N = 0.5 ) <> Parallel capacitor. Creates and returns a new nPort Object. If no argument, the default value is turns ratio of N = 0.5 . This is a 4 Port element. The primary ports are 1 and 3 and the secondary ports are 2 and 4. N is also equal to N = sqrt(Zp/Zs), where Zp is primary impedance and Zs is the secondary impedance.


nP-Lowpass

This section has chebychev low pass filter synthesis functions

nP.chebyLPNsec( passFreq = .2, rejFreq = 1.5, ripple = 0.1, rejection = 30 ) <> A function that computes and returns the number of sections in a Chebychev Low Pass filter prototype given the pass frequency, the rejection frequency, ripple, and rejection level. The default values are shown in the function argument.

nP.chebyLPgk( n = 3, ripple = 0.1 ) <> A function that computes and returns an array of the gk values in a Chebychev Low Pass filter prototype given the number of sections and ripple. The default values are shown in the function argument.

nP.chebyLPLCs( cheby = [1, 1.0315851425078764, 1.1474003299537219, 1.0315851425078761, 1], maxPassFrequency = 0.2e9, zo = 50) ) <> A function that computes and returns an array of the C-L-C ... values in a Chebychev Low Pass filter prototype given an array of the gk values. The default values are shown in the function argument.

nP.lpfGen( filt = [50, 1.641818746502858e-11, 4.565360855435164e-8, 1.6418187465028578e-11, 50] ) <> Creates and returns a new nPort Object. The argument is an array of scaled low pass filter parameters generated by an nPort function such as chebyLPLCs. If no argument, the default value is [50, 1.641818746502858e-11, 4.565360855435164e-8, 1.6418187465028578e-11, 50].


nP-Open-Short-Load

These are ideal one-ports

nP.Open( ) <> Creates and returns a new nPort Object of a one port Open. No argument required.

nP.Short( ) <> Creates and returns a new nPort Object of a one port Short. No argument required.

nP.Load( ) <> Creates and returns a new nPort Object of a one port Load. No argument required.


nP-Connections

Connections are 3-Port and n-Port "dummy" components. Using these connections enables 2-Port components to be connected together to form more complex circuits such as power dividers.

nP.Tee( ) <> Creates and returns a new nPort Object of 3-port interconnect, a 3 input junction. Valid only with nP.nodal(). See the wilkinson example. No argument required, must use nP.nodal().

nP.Tee4( ) <> Creates and returns a new nPort Object of 4-port interconnect, a 4 input junction. Valid only with nP.nodal(). No argument required, must use nP.nodal().

nP.Tee5( ) <> Creates and returns a new nPort Object of 5-port interconnect, a 5 input junction. Valid only with nP.nodal(). No argument required, must use nP.nodal().

nP.SeriesTee( ) <> Creates and returns a new nPort Object of 3-port interconnect. Ports 1 and 2 are input and outputs. Port 3 is the series port. Valid only with nP.nodal(). No argument required, must use nP.nodal().

Compare attenuator analysis results with and without nP.seriesTee()

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>seriesTee</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>

var g = nP.global;	
g.fList = [2e9]; // 2GHz

// define the resistors for the attenuator
var r1 = nP.paR(292.4);
var r2 = nP.seR(17.6);
var r3 = nP.paR(292.4);

// using cas to combine the 2-ports
var attn1 = r1.cas(r2).cas(r3);
var attn1Out = attn1.out('s21dB','s11dB');
nP.lineTable({inputTable: [attn1Out], tableTitle:'Solved by nP.cas()'});

// define the seriesTee and open
var tee = nP.seriesTee();
var open = nP.Open();
var r4 = nP.paR(17.6); // note, the 17.6 ohm resistor must be a parallel 2-port!

// use nodal to combine the 2-ports
var attn2 = nP.nodal([r1,1,2], [tee,2,3,4], [r4,4,5], [open,5], [r3,3,6], ['out',1,6]);
var attn2Out = attn2.out('s21dB','s11dB');
nP.lineTable({inputTable: [attn2Out], tableTitle:'seriesTee realization solved with nP.nodal()'});

		</script>
	</body>
</html>


nP-Transmission-lines

nP.tlin( Z = 60, Length = 0.5 * 0.0254 ) <> An ideal two port transmission line. The tlin is lossless and the dielectric constant is 1.0 . Z is the characteristic impedance in Ohms, and Length is the physical length in meters. Creates and returns a new nPort Object. If no arguments, the default values are 60 Ohms, 0.5 * 0.0254 Meters.

nP.tclin( Zoe = 100, Zoo = 30, Length = 1.47 * 0.0254 ) <> An ideal four port coupled transmission line. The ports are numbered clockwise. Port 1 is the upper left, Port 2 is the upper right, Port 3 is the lower right, and Port 4 is the lower left. When the input is at Port 1, the through port is Port 2, the coupled port is Port 4, and the isolated port is Port 3. The tclin is lossless and the dielectric constant is 1.0 . Zoe is the even mode characteristic impedance in Ohms, Zoo is the odd mode characteristic impedance in Ohms, and Length is the physical length in meters. Creates and returns a new nPort Object. If no arguments, the default values are 100 Ohms, 30 Ohms, and 1.341 * 0.0254 Meters. Note: 1.341 * 0.0254 is the 1/4 wavelength at 2.2GHz.

Here below is a coupled bandpass filter example.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>Edge coupled filter</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>

// this is for a quarter wave at 6GHz
var g = nP.global;	
g.fList = g.fGen(4e9,8e9,21);

// set up the couplers
var tclin1 = nP.tclin(79.667,37.834,0.491 * 0.0254);
var tclin2 = nP.tclin(60.866,42.505,0.491 * 0.0254);
var tclin3 = nP.tclin(79.667,37.834,0.491 * 0.0254);

// set up the open
var open = nP.Open();

// set up the filter
var filt = nP.nodal([tclin1,1,2,3,4],[tclin2,3,5,6,7],[tclin3,6,8,9,10],[open,2],[open,4],[open,5],[open,7],[open,8],[open,10],['out',1,9]);
var filtOut = filt.out('s21dB','s11dB');

// set up the plot
var plot = {chartTitle:'Edge Coupled Filter', inputTable: [filtOut]};

// plot the data
nP.lineChart(plot);

// set up the table
var table = {tableTitle:'Edge Coupled Filter', inputTable: [filtOut]};

// tabulate the data
nP.lineTable(table);

		</script>
	</body>
</html>

Here is the schematic and output plots for the edge coupled filter.


nP-Microstrip

nP.mlin( Width = 0.98e-3, Height = 1.02e-3, Length = 0.5 * 0.025, Thickness = 0.0000125 * 0.054, er = 10, rho = 0, tand = 0.000 ) <> A microstrip two port transmission line. Width is the strip width in meters, Height is the substrate height in meters. Length is the length in meters. er is the relative dielectric constant. rho is the loss relative to copper. tand is the dielecric loss tangent. Dispersion is factored in, Skin effect is not.


nP-math

nP.complex

The following complex number library is not needed to use nPort. However, nPort provides a basic complex number class object.

nP.complex(x, y) <> Initializes and returns a Complex object containing the property names x and jy. Here is a script you could use.

c.getR( ) <> Method that gets the real part of a complex number.

c.getI( ) <> Method that gets the imaginary part of a complex number.

c.setR( real ) <> Method that sets the real part of a complex number.

c.setI( imaginary ) <> Method that sets the imaginary part of a complex number.

c.add( c2 ) <> Method that adds two complex numbers, c1 and c2, and returns a Complex object. c1 is implied by the 'dot' that calls the method. Method chaining capable.

c1.sub( c2 ) <> Method that subtracts two complex numbers, c1 and c2, and returns a Complex object. c1 is implied by the 'dot' that calls the method. Method chaining capable.

c1.mul( c2 ) <> Method that multiplies two complex numbers, c1 and c2, and returns a Complex object. c1 is implied by the 'dot' that calls the method. Method chaining capable.

c1.div( c2 ) <> Method that divides two complex numbers, c1 and c2, and returns a Complex object. c1 is implied by the 'dot' that calls the method. Method chaining capable.

c.inv( ) <> Method that inverts a complex number and returns a Complex object. Method chaining capable.

c.neg( ) <> Method that changes the sign of x and iy in a complex number and returns a Complex object. Method chaining capable.

c.mag( ) <> Method that returns the magnitude of a complex number. No method chaining.

c.ang( ) <> Method that returns the angle, in degrees, of a complex number. No method chaining.

c.mag10dB( ) <> Method that returns the 10dB magnitude of a complex number . No method chaining.

c.mag20dB( ) <> Method that returns the 20dB magnitude of a complex number . No method chaining

c.sinhCplx( ) <> Method that returns the complex hyperbolic sine of a complex number and returns a Complex object. This method is key for transmission line equations. Method Chaining capable.

nP.coshCplx( ) <> Method that returns the complex hyperbolic cosine of a complex number and returns a Complex object. Method chaining capable.

Here are some examples of complex number arithmetic

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>Complex</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>

// define some complex numbers
var c1 = nP.complex(1,2);
var c2 = nP.complex(2,3);
var c3 = nP.complex(5,-7);

// use nP.log to show c3
nP.log('show c3 = nP.complex(5,-7)');
nP.log(c3); 

nP.log('--------');

// get and show the real part of c2
nP.log('show the real part of c2');
var realPartOfc2 = c2.getR();
nP.log(realPartOfc2);

nP.log('--------');

// in one step, set and show a new imaginary part of c1
nP.log('change the imaginary part of c1 to 42 in one step');
nP.log( c1.setI(42).getI() );

nP.log('--------');

// perform multiple operations with method chaining
nP.log('demo method chaining in one step');
nP.log( c1.add(c1).sub(c2).mul(c3) ); 

nP.log('--------')

// hyperbolic complex sin and cos functions used for transmission lines
var C = nP.complex(1,2);
var gamma = nP.complex(3,4);
var B = nP.complex(5,6);
Ds = C.mul(gamma.coshCplx()).add(B.mul(gamma.sinhCplx()));
nP.log('an example to show that coshCplx and sinhCplx work together');
nP.log(Ds); // 21.557232562315377 -j98.12775767092192}

		</script>
	</body>
</html>

nP.matrix

The following matrix library is not needed to use nPort. However, nPort provides a basic matrix arithmetic class object. This class performs matrix addition, subtraction and inversion with real numbers or with complex numbers. Lastly, there are Gaussian elimination methods for matrices with real or complex numbers.

nP.matrix( [ [array row 1], [array row 2], ... [array row n] ] ) <> A Constructor that is passed a table and returns a matrix object.

nP.dimension( rows, cols, initial ) <> A Function that creates a matrix object with rows and cols with an initial value such a 0, or 1, or "text", or a complex number nP.complex(1,). Note, dim does not create a matrix object, but it can be the argument that is passed to the matrix constructor.

nP.copyMatrix() <> A Method that makes a copy of an existing matrix. Use this to duplicate matrices.

m1.add( m2 ) <> Method that adds two matrices, m1 and m2, and returns a matrix object. m1 is implied by the 'dot' that calls the method. Method chaining capable.

m1.addCplx( m2 ) <> Method that adds two complex matrices, m1 and m2, and returns a matrix object. m1 is implied by the 'dot' that calls the method. Method chaining capable.

m1.sub( m2 ) <> Method that adds two matrices, m1 and m2, and returns a matrix object. m1 is implied by the 'dot' that calls the method. Method chaining capable.

m1.subCplx( m2 ) <> Method that adds two complex matrices, m1 and m2, and returns a matrix object. m1 is implied by the 'dot' that calls the method. Method chaining capable.

m1.mul( m2 ) <> Method that adds two matrices, m1 and m2, and returns a matrix object. m1 is implied by the 'dot' that calls the method. Method chaining capable.

m1.mulCplx( m2 ) <> Method that adds two complex matrices, m1 and m2, and returns a matrix object. m1 is implied by the 'dot' that calls the method. Method chaining capable.

m.solveGuass( ) <> Method that uses Guassian Elimination and Forward Substitution to solve a matrix and returns a matrix object. Method chaining capable.

m.solveGuassCplx( ) <> Method that uses Guassian Elimination and Forward Substitution to solve a complex matrix and returns a matrix object. Method chaining capable.

m.invert( ) <> Method that inverts a matrix and returns a matrix object. Method chaining capable.

m.invertCplx( ) <> Method that inverts a complex matrix and returns a matrix object. Method chaining capable.

Here are some examples of Matrix arithmetic

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>Matrix</title>
	</head>
	<body>
		<script src="./nP.js"></script>
		<script>

// real numbers
nP.log('define and show the 3 by 3 matrix, a');
var a = nP.matrix([
	[3,5,2],
	[0,8,2],
	[6,2,8]
]);
nP.log(a);

nP.log('--------');

nP.log('perform matrix operations with method chaining for matrix, b');
var b = a.invert().mul(nP.matrix([[8],[-7],[26]]));
nP.log(b);

nP.log('--------');

nP.log('define matrix c, and d; show matrix d');
var c = nP.matrix([[1]]);
var d = c.add(c).add(c).add(c);
nP.log(d);

nP.log('--------');

// complex numbers
nP.log('define and show the 3 by 3 matrix with complex numbers, e');
var e = nP.matrix([
	[nP.complex(3,0), nP.complex(5,0), nP.complex(2,0)],
	[nP.complex(0,3), nP.complex(8,0), nP.complex(2,0)],
	[nP.complex(6,0), nP.complex(2,0), nP.complex(8,-1)]
]);
nP.log(e);

nP.log('--------');

nP.log('perform operations on matrices with complex numbers with method chaining');
var f = e.invertCplx().mulCplx(nP.matrix([[nP.complex(8,0)],[nP.complex(-7,0)],[nP.complex(26,0)]]));
nP.log(f);

		</script>
	</body>
</html>

nP-chart

nP.lineChart

nP.lineChart( lineChartInputObject = { } ) <> is a function that draws a chart in a html page. It is based on d3, Data-Driven Documents. If you don't provide your own svg element, linechart() will create it for you. If you provide svg elements, you must specify a unique ID, width, and height attributes for each svg you create, such as:

<svg id="myChart" width="400" height="300"></svg>```


lineChartInputObject = {
inputTable : [out1, out2 ... outn],
// an array of outs, default is an internal inputTable

chartID : 'chart',
// a string id, default is 'chart1'

metricPrefix : 'giga',
// a string of a metric prefix ,  default is 'giga'
// Note the prefixes for the ```metricPrefix
//'giga', 'mega', 'kilo', 'none', 'deci', 'centi', 'milli', 'micro', 'nano', and 'pico'

chartTitle : '',
// a string of the chart title; default is blank

xAxisTitle : 'Frequency',
// a string of the x axis title; default is 'Frequency'

yAxisTitle : 'dB',
// a string of the y axis title; default is 'dB'

xRange : [min,max],
// an array of min, max such as [2e9, 12e9]; default is autorange based on data

yRange : [min,max],
// an array of min, max such as [0, -80]; default is autorange based on data

showPoints : 'show',
// a string with either 'show' or 'hide', if not specified, default is 'show'

showLables : 'show',
// a string with either 'show' or 'hide', if not specified, default is 'show'

traceColor: 'color',
// a string with either 'color' or 'gray', if not specified, default is 'color'
}

If you do not provide a lineChartInputObject argument, lineChart() will display its default plot that is good for setting up your html page so you can see how it looks.

Here is the default lineChart(), it generates an svg element that has 400px in width and 300px in height. When the cursor is moved over a data point, it turns black and the values are shown at the lower right corner of the chart. In this case, the values are 7.2GHz and -19.3dB. If you click on a point, it stays black and shows the values at the bottom. Click it again to make revert to the original color. Next, To convert it into a PNG for a "Save image as ..." to file, click on the square at the upper right corner of the chart, then move the cursor over any part of the image and perform a "Save image as..." to file.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>lineChart Default</title>
	</head>
	<body>
		<script src="./nP.js"></script>

		<script>

nP.lineChart();

		</script>
	</body>
</html>

Here is the default nP.lineChart output

nP.lineTable

nP.lineTable( lineTableInputObject = { } ) <> A function that produces a table of data. You can click and drag across the table to copy and paste to a spreadsheet. Also, you can create an png for table and perform a "Save image as ..." to file the way you can for lineChart. If you don't provide your own svg element, lineTable() will create it for you. If you provide svg elements, you must specify a unique ID, width, and height attributes for each svg you create, such as:

<svg id="myTable" width="400" height="300"></svg>

lineTableInputObject = {
inputTable : [out1, out2 ... outn],
// an array of outs, default is an internal inputTable

tableID : 'chart',
// a string id, default is 'chart1'

metricPrefix : 'giga',
// a string of a metric prefix ,  default is 'giga'
// Note the prefixes for the ```metricPrefix
//'giga', 'mega', 'kilo', 'none', 'deci', 'centi', 'milli', 'micro', 'nano', and 'pico'

tableTitle : '',
// a string of the chart title; default is blank

headColor : 'color',
// a string with either 'color' or 'gray', if not specified, default is 'color'

tableWH : 'no',
// a string with either 'no' or 'yes'. if set to 'yes', an alert box is shown that has the Width and the Height of the svg containing the table, if not specified, default is 'no'
}

If you do not provide a lineTableInputObject argument, lineTable() will display its default plot that is good for setting up your html page so you can see how it looks.

Here is the default lineTable(), it generates an svg element that has 350px in width and 503px in height. To convert it into a PNG for a "Save image as ..." to file, click on the square at the upper right corner of the chart, then move the cursor over any part of the image and perform a "Save image as..." to file.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width">
		<title>lineTable Default</title>
	</head>
	<body>
		<script src="./nP.js"></script>

		<script>

nP.lineTable();

		</script>
	</body>
</html>

Unlike lineChart, where you can set the size in advance, lineTable does not know its size until it is rendered. As columns and rows are created, the svg is sized appropriately. To find out what the final size is, use the key-value pair, tableWH: 'yes', of the inputTableInputObject.

Here is the default nP.lineTable output

nP.log

nP.log( input ) <> A function that proforms a console.log function that logs to your web page rather than in the console. It take one parameter called input. It can be helpful in troubleshooting such as easily examining the contents of arrays and matrices containing complex numbers. It can be any of the the following data types:

a 'string'
a number
a boolean
an array // logs arrays downward, not across
a Complex // from nP.complex()
a Matrix // from nP.matrix()
an out // from nP.out()

You can pass any function as an input that returns any of the above data types, for example these are all valid:

nP.log(Math.sqrt(2)) // 1.414
nP.log(nP.complex(1,2)) // 1.000 + j2.000
nP.log(4<2) // false