-
Notifications
You must be signed in to change notification settings - Fork 9
Ranges
Often you will want to generate a "list" of numbers. You can do this JISA
by using the static methods within the Range
class. These will reach return a Range<...>
object that you can then iterate over. The available methods (thus types of range are):
// Equally-spaced range with a specified number of elements
Range<Double> a = Range.linear(double start, double stop, int numSteps);
// Range of whole numbers from start to stop inclusive represented as floating-point numbers
Range<Double> b = Range.linear(int start, int stop);
// Equally-spaced range with a specified step-size
Range<Double> c = Range.step(double start, double stop, double stepSize);
// Range of whole numbers from start to stop inclusive, represented as integers
Range<Integer> d = Range.count(int start, int stop);
// Geometric sequence from start to stop in specified number of steps
Range<Double> e = Range.exponential(double start, double stop, int numSteps);
// Geometric sequence from start until stop with specified geometric/multiplicative factor
Range<Double> f = Range.geometric(double start, double stop, double factor);
// The same number, a given number of times
Range<Double> g = Range.repeat(double value, int numTimes);
All ranges generated this way are done so by using Java's BigDecimal
arithmetic which is designed to avoid rounding errors.
When generating a range, you will be given a Range
object. There a slightly different types of these, for instance Range<Integer>
objects are ranges containing integer values whereas Range<Double>
objects contains floating-point values. For example, if you make a count
range then you will get an integer range but if you make a linear
range then they will be double values:
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
Range<Integer> count = Range.count(1, 10);
// [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 ]
Range<Double> linear = Range.linear(1, 10);
These objects are iterable meaning you can stick them straight into a for-loop:
Java
for (double v : Range.linear(1, 5)) {
System.out.println(v);
}
Kotlin
for (v in Range.linear(1, 5)) {
println(v)
}
Python
for v in Range.linear(1, 5):
print(v)
which will result in the output:
1.0
2.0
3.0
4.0
5.0
You can create sequences of equally-spaced numbers where
by use of linear(...)
or step(...)
depending on whether you want to define the range by the number of elements within it or by the step size, .
To create a linear range of numbers you have a few options. The one you'll likely use most often is linear(...)
:
Range.linear(double start, double stop, int numSteps);
This allows you to create a range starting a value and ending at another with a specified number of steps. For instance, if we wanted to go from 10 to 20 in 11 steps:
Range.linear(10, 20, 11);
The result of this would be a step-size of 1.0
. In this case then we are actually creating the range of integer values from 10 to 20 inclusive. For ranges such as these we can just specify the start and end values (so-long as they are integers):
Range.linear(int start, int stop);
In our case we could write:
Range.linear(10, 20);
// is the same as
Range.linear(10, 20, 11);
Despite all of the values in such a range being integers mathematically, they are not represented as integers in code. They are still double
values (ie with a decimal point). For instance, 10
is actually 10.0
. This is useful as things like SMU
objects require double
values to be supplied for setting voltage/current values even if they are to supply an integer amount of volts/amps.
However, if you need a range of integers (ie a Range<Integer>
object) then you can use count(...)
instead:
Range<Integer> range = Range.count(int start, int stop);
// as opposed to
Range<Double> range = Range.linear(int start, int stop);
Ranges don't have to always "count up" they can also "count down". For example to start at 20
and go down to 10
in integer steps:
Range.linear(20, 10, 11);
Range.linear(20, 10);
Range.count(20, 10);
Instead of defining a range based on the number of steps and letting JISA
calculate the required step-size, you can specify the step-size yourself. This is done by using step(...)
instead of linear(...)
:
Range.step(double start, double stop, double stepSize);
For instance, to go from 10.0
to 20.0
in steps of 0.5
:
Range.step(10, 20, 0.5);
Like with linear(...)
you can go down in value insted of up. You do not need to negate the step-size although doing so will have no effect:
Range.step(20, 10, 0.5);
// produces the same range as
Range.step(20, 10, -0.5);
Ranges where the mapping from one element to the next is by a multiplicative factor, ie:
can be achieved by use of the exponential(...)
and geometric(...)
methods depending on whether you want to specify the number of elements or the multiplicative factor,
To produce a geometric series with a defined number of elements:
Range.exponential(double start, double stop, int numSteps);
For instance:
Range.exponential(1, 100, 3);
will produce [1.0, 10.0, 100.0]
.
To instead define the range by the value of the multiplicative factor, use geometric(...)
like so:
Range.geometric(double start, double stop, double factor);
For instance:
Range.geometric(1, 32, 2);
will give us: [1.0, 2.0, 4.0, 8.0, 16.0, 32.0]
After creating a range, you can:
- Reverse the order of values
- Append the reverse of the range onto the end
- Make the range repeat itself
n
times - Cyclically shift elements in the range by
n
spaces (right: +ve, left: -ve) - Randomly shuffle the order of elements in the range
These are achieved by use of the following, respective, methods:
Range<T> reversed = range.reverse();
Range<T> mirrored = range.mirror();
Range<T> repeated = range.repeat(int n);
Range<T> shifted = range.shift(int n);
Range<T> shuffled = range.shuffle();
These are inteded to be called in a chained-fashion (most likely within a for
loop), for example (in Kotlin):
for (x in Range.linear(1, 3).mirror()) {
println(x)
}
will output:
1.0
2.0
3.0
3.0
2.0
1.0
An example of an application would be sweeping the voltage on an SMU
both ways:
for (voltage in Range.linear(0, 60).mirror()) {
smu.setVoltage(voltage)
// Measure something...
}
You can convert a Range
object into a RealMatrix
by use of reshape(...)
, column()
and row()
like so:
RealMatrix matrix = range.reshape(int rows, int cols);
RealMatrix colMatrix = range.column();
RealMatrix rowMatrix = range.row();
For instance, writing the following:
RealMatrix matrix = Range.linear(1, 9).reshape(3, 3);
will produce the following matrix:
whereas
RealMatrix matrix = Range.linear(1, 9).row();
gives:
and
RealMatrix matrix = Range.linear(1, 9).column();
gives:
- Getting Started
- Object Orientation
- Choosing a Language
- Using JISA in Java
- Using JISA in Python
- Using JISA in Kotlin
- Exceptions
- Functions as Objects
- Instrument Basics
- SMUs
- Thermometers (and old TCs)
- PID and Temperature Controllers
- Lock-Ins
- Power Supplies
- Pre-Amplifiers
- Writing New Drivers