# Usage

**ec** [*options*] [*scripts* …]

`-i, --interactive`Open an interactive session.

`-s``<file>`, --startup`<file>`Run commands from file to initialize calculator before any script or interactive session is run, stack is cleared after it is run.

`-c, --nocolor`Do not use colors in the output.

`-v, --verbose`Narrate the execution of any scripts.

`-V, --version`Print the ec version information.

`-h, --help`Print the usage and exit.

# Description

**ec** is a stack-based (RPN) engineering calculator with a text-based user
interface that is intended to be used interactively.

If run with no arguments, an interactive session is started. If arguments are present, they are tested to see if they are filenames, and if so, the files are opened and the contents are executed as a script. If they are not file names, then the arguments themselves are treated as scripts and executed directly. The scripts are run in the order they are specified. In this case an interactive session would not normally be started, but if the interactive option is specified, it would be started after all scripts have been run.

The contents of *~/.ecrc*, *./.ecrc*, and the startup file will be run upon
startup if they exist, and then the stack is cleared.

# Stack

As you enter numbers they are pushed onto a stack. The most recent member
of the stack is referred to as the *x* register and the second most recent
is the *y* register. All other members of the stack are unnamed. Operators
consume numbers off the stack to use as operands and then they push the
results back on the stack. The operations are performed immediately and
there is no use of parentheses to group calculations. Any intermediate
results are stored on the stack until needed. For example,

46+

In this case 4 gets pushed on to the stack first to become *x*. Then 6 gets
pushed on to the stack to become *x*, which makes 4 *y*. Finally, + pulls
both off the stack, sums them, and then pushes the result of 10 back onto
the stack. The stack is left with only one number on it, 10.

After each line **ec** responds by printing the value of the *x* register.
Thus the above example would actually look like this:

0: 44: 66: +10:

The benefit of the stack is that it allows you to easily store temporary results while you perform your calculation. For example, to evaluate (34 - 61)*(23 - 56) you would use:

0: 3434: 6161: --27: 2323: 5656: --33: *891:

Notice that you entered the numbers as you saw them in the formula you were evaluating, and there was no need to enter parentheses, however the operators were rearranged in order to express the precedence of the operations.

It is not necessary to type enter after each number or operator. You can combine them onto one line and just type enter when you would like to see the result:

0: 34 61 - 23 56 - *891:

Furthermore, it is not necessary to type a space between a number and most operators. For example, the above could be entered as:

0: 34 61- 23 56- *891:

You can print the entire stack using *stack*, and clear it using *clstack*.
For example,

0: 1 2 3 stack3y: 2x: 13: clstack0: stack0:

# Real Numbers

Numbers can be entered using normal integer, floating point, and scientific notations. For example,

423.1415925,439,749.972.998e813.80651e-24

In addition, you can also use the normal SI scale factors to represent either large or small numbers without using scientific notation.

Y

1e24 (yotta)

Z

1e21 (zetta)

E

1e18 (exa)

P

1e15 (peta)

T

1e12 (terra)

G

1e9 (giga)

M

1e6 (mega)

k, K

1e3 (kilo)

_

unity (1)

m

1e-3 (milli)

u

1e-6 (micro)

n

1e-9 (nano)

p

1e-12 (pico)

f

1e-15 (fempto)

a

1e-18 (atto)

z

1e-21 (zepto)

y

1e-24 (yocto)

For example, 10M represents 1e7 and 8.8p represents 8.8e-12.

Optionally, numbers can be combined with simple units. For example,

10KHz3.16pF2.5_V4.7e-10F

Both units and scale factors are optional, which causes a natural ambiguity as to whether the first letter of a suffix is a scale factor or not. If the first letter is a valid scale factor, then it is assume to be a scale factor. In this way, ‘300K is treated as 300e3 rather than 300 Kelvin. If you intend the units without a scale factor, add the unit scale factor: ‘_’. Thus, use 300_K to enter 300 Kelvin.

In this case the units must be simple identifiers (must not contain special
characters). For complex units, such as “rads/s”, or for numbers that do not
have scale factors, it is possible to attach units to a number in the *x*
register by entering a quoted string.

0: 6.626e-34662.6e-36: “J-s”662.6e-36 J-s: 50k “V/V”50 KV/V:

The dollar sign ($) is a special unit that is given before the number.

$100K

Numbers my also contain commas as digit separators, which are ignored.

$200,000.00

The dollar sign ($) is a special unit that is given before the number.

**ec** takes a conservative approach to units. You can enter them and it
remembers them, but they do not survive any operation where the resulting
units would be in doubt. In this way it displays units when it can, but
should never display incorrect or misleading units. For example:

0: 100MHz100 MHz: 2pi*628.32M:

You can display real numbers using one of four available formats, *fix*,
*sci*, *eng*, or *si*. These display numbers using fixed point notation (a
fixed number of digits to the right of the decimal point), scientific
notation (a mantissa and an exponent), engineering notation (a mantissa and
an exponent, but the exponent is constrained to be a multiple of 3), and SI
notation (a mantissa and a SI scale factor). You can optionally give an
integer immediately after the display mode to indicate the desired
precision. For example,

0: 10,00010K: fix210,000.00: sci31.000e+04: eng210.0e+03: si410K: 2pi*62.832K:

Notice that scientific and engineering notations always displays the specified number of digits whereas SI notation suppresses zeros at the end of the number.

When displaying numbers using SI notation, **ec** does not use the
full range of available scale factors under the assumption that the largest
and smallest would be unfamiliar to most people. For this reason, **ec**
only uses the most common scale factors when outputting numbers (T, G, M, K,
m, u, n, p, f, a).

# Integers

You can enter integers in either hexadecimal (base 16), decimal (base 10), octal (base 8), or binary (base 2). You can use either programmers notation (leading 0) or Verilog notation (leading ‘) as shown in the examples below:

0xFF

hexadecimal

99

decimal

0o77

octal

0b1101

binary

‘hFF

Verilog hexadecimal

‘d99

Verilog decimal

‘o77

Verilog octal

‘b1101

Verilog binary

Internally, **ec** represents all numbers as double-precision real numbers.
To display them as decimal integers, use *fix0*. However, you can display
the numbers in either base 16 (hexadecimal), base 10 (decimal), base 8
(octal) or base 2 (binary) by setting the display mode. Use either *hex*,
*fix0*, *oct*, *bin*, *vhex*, *vdec*, *voct*, or *vbin*. In each of
these cases the number is rounded to the closest integer before it is
displayed. Add an integer after the display mode to control the number of
digits. For example:

0: 10001K: hex0x3b8: hex80x000003b8: hex00x3b8: voct‘o1750:

# Complex Numbers

**ec** provides limited support for complex numbers. Two imaginary constants
are available that can be used to construct complex numbers, *j* and
*j2pi*. In addition, two functions are available for converting complex
numbers to real, *mag* returns the magnitude and *ph* returns the phase.
They are unusual in that they do not replace the value in the *x* register
with the result, instead they simply push either the magnitude of phase into
the *x* register, which pushes the original complex number into the *y*
register. For example,

0: 1 j +1 + j: mag1.4142: pop1 + j: ph45 degs: stacky: 1 + jx: 45 degs45 degs:

You can also add the imaginary unit to real number constants. For example,

0: j10Mj10M: -j1u *10:

Only a small number of functions actually support complex numbers; currently
only *exp* and *sqrt*. However, most of the basic arithmetic operators
support complex numbers.

# Constants

**ec** provides several useful mathematical and physical constants that are
accessed by specifying them by name. Several of the constants have both MKS
and CGS forms (ec uses ESU-CGS). You can set which version you want by
setting the desired unit system as follows:

0: mks0: h662.61e-36 J-s: k13.806e-24 J/K: cgs13.806e-24 J/K: h6.6261e-27 erg-s: k138.06 aerg/K:

Notice that the unit-system is sticky, meaning that it remains in force until explicitly changed. ‘mks’ is the default unit system.

The physical constants are given in base units (meters, grams, seconds). For example, the mass of an electron is given in grams rather than kilograms as would be expected for MKS units. Similarly, the speed of light is given in meters per second rather than centimeters per second as would be expected of CGS units. This is necessary so that numbers are not displayed with two scale factors (ex. 1 mkg). Thus, it may be necessary for you to explicitly convert to kg (MKS) or cm (CGS) before using values in formulas that are tailored for one specific unit system.

The 2014 NIST values are used. The available constants include:

pi

the ratio of a circle’s circumference to its diameter

2pi

the ratio of a circle’s circumference to its radius

rt2

square root of two

0C

0 Celsius in Kelvin

j

imaginary unit (square root of −1)

j2pi

j2π

k

Boltzmann constant

h

Planck constant

q

elementary charge (the charge of an electron)

c

speed of light in a vacuum

eps0

permittivity of free space

mu0

permeability of free space

Z0

Characteristic impedance of free space

hbar

Reduced Planck constant

me

rest mass of an electron

mp

mass of a proton

mn

mass of a neutron

mh

mass of a hydrogen atom

amu

unified atomic mass unit

G

universal gravitational constant

g

earth gravity

Rinf

Rydberg constant

sigma

Stefan-Boltzmann constant

alpha

Fine structure constant

R

molar gas constant

NA

Avogadro Number

rand

random number between 0 and 1

As an example of using the predefined constants, consider computing the thermal voltage, kT/q.

0: k 27 0C + * q/ “V”25.865 mV:

# Variables

You can store the contents of the *x* register to a variable by using an
equal sign followed immediately by the name of the variable:

```
=«name»
```

where «name» represents the desired name of the variable. It must be a simple identifer and must be immediately adjacent to the =.

To recall it, simply use the name:

```
«name»
```

For example,

0: 100MHz =freq100 MHz: 2pi* “rads/s” =omega628.32 Mrads/s: 1pF =cin1 pF: 1 omega cin* /1.5915K:

You can display all known variables using *vars*. If you did so immediately
after entering the lines above, you would see:

1.5915K: varsRref: 50 Ohmscin: 1 pFfreq: 100 MHzomega: 628.32 Mrads/s

Choosing a variable name that is the same as a one of a built-in command or constant causes the built-in name to be overridden. Be careful when doing this as once a built-in name is overridden it can no longer be accessed.

Notice that a variable *Rref* exists that you did not create. This is a
predefined variable that is used in dBm calculations. You are free to change
its value if you like.

# User-Defined Functions

You can define functions in the following way:

```
( ... )«name»
```

Here ‘(’ starts the function definition and ‘)«name»’ ends it. «name» represents the desired name of the function. It must be a simple identifer and must be immediately adjacent to the ). The ‘…’ represents a sequence of calculator actions.

For example:

0: (2pi * “rads/s”)to_omega0: (2pi / “Hz”)to_freq0: 100MHz100 MHz: to_omega628.32 Mrads/s: to_freq100 MHz:

The actions entered while defining the function are not evaluated until the function itself is evaluated.

Once defined, you can review your function with the *vars* command. It shows
both the variable and the function definitions:

Rref: 50 Ohmsto_freq: (2pi / “Hz”)to_omega: (2pi * “rads/s”)

The value of the functions are delimited with parentheses.

# Unit Conversions

You can perform unit conversions using:

>«units»

where «units» are the desired units. «units» must be a simple identifier
though the first character is allowed to be one of a small number of special
characters that typically begin units. Specifically, $, °, Å, Ƀ, or ș``.
«units» must be immediately adjacent to the >. If the value in the *x*
register has units, the value will be converted to the new units. If the
value does not have units, its units will be set to «units».

For example, to convert grams to pounds and back:

0: 100kg100 kg: >lbs220.46 lbs: >g100 kg:

The following example is a little contrived to show two things. First, a value with no units gets assigned the specified units when subject to a conversion. Second, several names are known for the same units and the name assigned to the result is the name specified on the convert command.

0: 100100: >kg100 kg: >lb220.46 lb:

Converters are provides for the following units:

Temperature:

K: |
K, F °F, R °R |

C °C: |
K, C °C, F °F, R °R |

Distance:

m: |
km, m, cm, mm, um μm micron, nm, Å angstrom, mi mile miles, in inch inches |

Mass/Weight:

g: |
oz, lb lbs |

Time:

s: |
sec second seconds, min minute minutes, hour hours hr, day days |

Bits/Bytes:

b: |
B |

Bitcoin:

BTC btc Ƀ: |
USD usd $, sats sat ș |

sats sat ș: |
USD usd $, BTC btc Ƀ |

The conversions can occur between a pair of units, one from the first column
and one from the second. They do not occur when both units are only in the
second column. So for example, it is possible to convert between *g* and
*lbs*, but not between *oz* and *lb*. However, if you notice, the units in
the second column are grouped using commas. A set of units within commas
are considered equivalent, meaning that there are multiple names for the
same underlying unit. For example, *in*, *inch*, and *inches* are all
considered equivalent. You can convert between equivalent units even though
both are found in the second column.

Bitcoin conversions are performed by accessing quotes from coingecko.com. You must have an internet connection for this feature to work.

For example:

0: 1BTC1 BTC: >$$46,485.00:

You can use user-defined functions to create functions that create units directly. For example, here are function definitions for converting bitcoin and temperatures that you can put in your ~/.ecrc file:

```
# bitcoin
(>Ƀ )tb # convert unitless number to bitcoin
(>Ƀ >$)btd # convert bitcoin to dollars
(>Ƀ >ș)bts # convert bitcoin to satoshis
(>ș )ts # convert unitless number to satoshis
(>ș >Ƀ)stb # convert satoshis to bitcoin
(>ș >Ƀ)stb # convert satoshis to bitcoin
(>ș >$)std # convert bitcoin to dollars
(>$ >Ƀ)dtb # convert dollars to bitcoin
(>$ >ș)dts # convert dollars to satoshis
# temperature
(>°C )tc # convert unitless number to Celsius
(>°C >K)ctk # convert Celsius to Kelvin
(>°C >°F)ctf # convert Celsius to Fahrenheit
(>°F )tf # convert unitless number to Fahrenheit
(>°F >K)ftk # convert Fahrenheit to Kelvin
(>°F >°C)ftc # convert Fahrenheit to Celsius
(>K >°C)ktc # convert Kelvin to Celsius
(>K >°F)ktf # convert Kelvin to Fahrenheit
```

With these function, you can convert a simple number (without units) directly to the desired units:

0: 1 btd$46,485.00:

# Help

You can use *help* to get a listing of the various features available in EC
along with a short summary of each feature. For more detailed information,
you can use ‘?’. If you use ‘?’ alone you will get a list of all available
help topics. If you use ‘?<*topic*>’ where *topic* us either a symbol or a
name, you will get a detailed description of that topic.

# Initialization

At start up **ec** reads and executes commands from files. It first tries
‘~/.ecrc’ and runs any commands it contains if it exists. It then tries
‘./.ecrc’ if it exists. Finally it runs the startup file specified on the
command line (with the **-s** or **–startup** option). It is common to put
your generic preferences in ‘~/.exrc’. For example, if your are an
astronomer with a desire for high precision results, you might use:

```
# initialization file for ec (engineering calculator)
eng6
6.626070e-27 "erg-s" =h # Planck's constant in CGS units
1.054571800e-27 "erg-s" =hbar # Reduced Planck's constant in CGS units
1.38064852e-16 "erg/K" =k # Boltzmann's constant in CGS units
```

This tells **ec** to use 6 digits of resolution and redefines *h* and *hbar*
so that they are given in CGS units. The redefining of the names *h*,
*hbar*, and *k* would normally cause **ec** to print a warning, but such
warnings are suppressed when reading initialization files and scripts.

After all of the startup files have been processed, the stack is cleared.

A typical initialization script (~/.ecrc) for a circuit designer might be:

```
# Initialize Engineering Calculator
27 "C" =T # ambient temperature
(k T 0C + * q/ "V")vt # thermal voltage
(2pi* "rads/s")tw # to omega - converts Hertz to rads/s
(2pi/ "Hz")tf # to freq - converts rads/s to Hertz
```

# Scripting

Command line arguments are evaluated as if they were typed into an interactive session with the exception of filename arguments. If an argument corresponds to an existing file, the file treated as a script, meaning it is is opened its contents are evaluated. Otherwise, the argument itself is evaluate (often it needs to be quoted to protect its contents from being interpreted by the shell). When arguments are given the calculator by default does not start an interactive session. For example: to compute an RC time constant you could use:

$ ec 22k 1pF*22n

Notice that the * in the above command is interpreted as glob character, which is generally not what you want, so it is often best to quote the script:

$ ec ‘22k 1pF*’22n

Only the calculator commands would be quoted in this manner. If you included
a file name on the command line to run a script, it would have to be given
alone. For example, assume that the file ‘bw’ exists and contains ‘* 2pi*
recip “Hz”’. This is a script that assumes that the value of R and C are
present in the *x* and *y* resisters, and then computes the 3dB bandwith of
the corresponding RC filter. You could run the script with:

$ ec ‘22k 1pF’ bw7.2343 MHz

Normally **ec** only prints the value of the *x* register and only as it
exits. It is possible to get more control of the output using back-quoted
strings. For example:

$ ec ‘`Hello world!`’Hello world!0

Whatever is found within back-quotes is printed to the output. Notice that
the value of the *x* register is also output, which may not be desired when
you are generating your own output. You can stop the value of the *x*
register from being printed by finishing with the *quit* command, which
tells **ec** to exit immediately:

$ ec ‘`Hello world!` quit’Hello world!

You can add the values of registers and variables to your print statements.
*$N* prints out the value of register *N*, where 0 is the *x* register,
1 is the *y* register, etc. *$name* will print the value of a variable
with the given name. Alternatively, you can use *${N*} and *${name*} to
disambiguate the name or number. To print a dollar sign, use *$$*. To
print a newline or a tab, use *\n* and *\t*. For example,

0: 100MHz =freq100 MHz: 2pi* “rads/s”628.32 Mrads/s: `$freq corresponds to $0.`100 MHz corresponds to 628.32 Mrads/s.628.32 Mrads/s:

To illustrate its use in a script, assume that a file named *lg* exists and
contains a calculation for the loop gain of a PLL:

```
# computes and displays loop gain of a frequency synthesizer
# x register is taken to be frequency
=freq
88.3u "V/per" =Kdet # gain of phase detector
9.07G "Hz/V" =Kvco # gain of voltage controlled oscillator
2 =M # divide ratio of divider at output of VCO
8 =N # divide ratio of main divider
2 =F # divide ratio of prescalar
freq 2pi* "rads/s" =omega
Kdet Kvco* omega/ M/ =a
N F* =f
a f* =T
\`Open loop gain = $a\\nFeedback factor = $f\\nLoop gain = $T\`
quit
```

When reading scripts from a file, the ‘#’ character introduces a comment. It and anything that follows is ignored until the end of the line.

Notice that the script starts by saving the value in the *x* register to the
variable *freq*. This script would be run as:

$ ec 1KHz lgOpen loop gain = 63.732Feedback factor = 16Loop gain = 1.0197K

The first argument does not correspond to a file, so it is executed as a script. It simply pushes 1KHz onto the stack. The second argument does correspond to a file, so its contents are executed. The script ends with a print command, so the results are printed to standard output as the script terminates.

One issue with command line scripting that you need to be careful of is that
if an argument is a number with a leading minus sign it will be mistaken to
be a command line option. To avoid this issue, specify the number without
the minus sign and follow it with *chs*. Alternatively, you can embed the
number in quotes but add a leading space. For example,

$ ec -30 dbmvec: -30 dbmv: unknown option.$ ec 30 chs dbmv10 mV$ ec ‘ -30’ dbmv10 mV

# Initialization Scripts

You can use scripts to preload in a set of useful constants and function
that can then be used in interactive calculations. To do so, use the **-i**
or *–interactive* command line option. For example, replace the earlier
‘lg’ script with the following:

88.3u “V/per” =Kdet9.07G “Hz/V” =Kvco2 =M8 =N2 =F(N F* recip)f(2pi * Kdet * Kvco* M*)a(a f*)Tclstack

Now run:

$ ec -i lg0: 1kHz T629.01M:

Doing so runs lg, which loads values into the various variables, and then they can be accessed in further calculations.

Notice that the script ends with *clstack* so that you start fresh in your
interactive session. It simply clears the stack so that the only effect of
the script is to initialize the variables. Using **-s** or **–startup**
does this for you automatically.

Alternatively, you can put the constants you wish to predeclare in
*./.ecrc*, in which case they are automatically loaded whenever you invoke
**ec** in the directory that contains the file. Similarly, placing
constants in *~/.ecrc* causes them to be declared for every invocation of
**ec**.

# Errors

If an error occurs on a line, an error message is printed and the stack is restored to the values it had before the line was entered. So it is almost as if you never typed the line in at all. The exception being that any variables or modes that are set on the line before the error occurred are retained. For example,

0: 1KOhms =r1 KOhms: 100MHz =freq 1pF = c=: unrecognized1 KOhms: stackx: 1 KOhms1 KOhms: varsRref: 50 Ohmsfreq: 100MHzr: 1 KOhms

The error occurred when trying to assign a value to *c* because a space was
accidentally left between the equal sign and the variable name. Notice that
100MHz was saved to the variable *freq*, but the stack was restored to the
state it had before the offending line was entered.

## Comments

Any text that follows a # is ignored. In this way you can add documentation to initialization files and scripts, as shown in the next few sections.