ixfx
Version:
Bundle of ixfx libraries
1,584 lines (1,583 loc) • 70.5 kB
TypeScript
import { A as MovingWindowOptions } from "./index-CJB9BrLB.js";
//#region ../packages/numbers/src/apply-to-values.d.ts
/**
* Apples `fn` to every key of `obj` which is numeric.
* ```js
* const o = {
* name: 'john',
* x: 10,
* y: 20
* };
* const o2 = applyToValues(o, (v) => v * 2);
*
* // Yields: { name: 'john', x: 20, y: 40 }
* ```
* @param object
* @param apply
* @returns
*/
declare const applyToValues: <T extends Record<string, any>>(object: T, apply: (v: number) => number) => T;
//#endregion
//#region ../packages/numbers/src/average.d.ts
/**
* Calculate median value of an array of numbers
* @param data
* @returns
*/
declare const median: (data: number[] | readonly number[]) => number;
/**
* Calculate the mean of `array`.
* @param array
* @returns
*/
declare const mean: (array: number[] | readonly number[]) => number;
/**
* Computes an average of an array with a set of weights applied.
*
* Weights can be provided as an array, expected to be on 0..1 scale, with indexes
* matched up to input data. Ie. data at index 2 will be weighed by index 2 in the weightings array.
*
* ```js
* // All items weighted evenly
* averageWeighted([1,2,3], [1,1,1]); // 2
*
* // First item has full weight, second half, third quarter
* averageWeighted([1,2,3], [1, 0.5, 0.25]); // 1.57
*
* // With reversed weighting of [0.25,0.5,1] value is 2.42
* ```
*
* A function can alternatively be provided to compute the weighting based on array index, via {@link weight}.
*
* ```js
* averageWeighted[1,2,3], Random.gaussian()); // 2.0
* ```
*
* This is the same as:
*
* ```js
* const data = [ 1, 2, 3 ];
* const w = weight(data, Random.gaussian());
* const avg = averageWeighted(data, w); // 2.0
* ```
* @param data Data to average
* @param weightings Array of weightings that match up to data array, or an easing function
* @see {@link average} Compute averages without weighting.
*/
declare const averageWeighted: (data: number[] | readonly number[], weightings: number[] | readonly number[] | ((arrayIndex: number) => number)) => number;
/**
* Returns a function that computes a weighted average of an array
*
* ```js
* const w = averageWeigher(v => Math.random() * v);
*
* // Give each array index a random
* w([1,2,3,4]);
* ```
* @param weigher
* @returns
*/
declare const averageWeigher: (weigher: (arrayIndex: number) => number) => (data: number[]) => number;
//#endregion
//#region ../packages/numbers/src/clamp.d.ts
/**
* Clamps a value between min and max (both inclusive)
* Defaults to a 0-1 range, useful for percentages.
*
* @example Usage
* ```js
* // 0.5 - just fine, within default of 0 to 1
* clamp(0.5);
* // 1 - above default max of 1
* clamp(1.5);
* // 0 - below range
* clamp(-50, 0, 100);
* // 50 - within range
* clamp(50, 0, 50);
* ```
*
* For clamping integer ranges, consider {@link clampIndex }
* For clamping `{ x, y }` points, consider {@link https://api.ixfx.fun/_ixfx/geometry/Points/clamp/ @ixfx/geometry/Points.clamp}.
* For clamping bipolar values: {@link Bipolar.clamp}
* @param value Value to clamp
* @param min value (inclusive)
* @param max value (inclusive)
* @returns Clamped value
*/
declare function clamp$1(value: number, min?: number, max?: number): number;
/**
* Returns a function that clamps values.
*
* ```js
* const c = clamper(0,100);
* c(50); // 50
* c(101); // 100
* c(-5); // 0
* ```
* @param min Minimum value. Default: 0
* @param max Maximum value. Default: 1
*/
declare function clamper(min?: number, max?: number): (v: number) => number;
/**
* Clamps integer `v` between 0 (inclusive) and array length or length (exclusive).
* Returns value then will always be at least zero, and a valid array index.
*
* @example Usage
* ```js
* // Array of length 4
* const myArray = [`a`, `b`, `c`, `d`];
* clampIndex(0, myArray); // 0
* clampIndex(5, 3); // 2
* ```
*
* Throws an error if `v` is not an integer.
*
* For some data it makes sense that data might 'wrap around' if it exceeds the
* range. For example rotation angle. Consider using {@link wrap} for this.
*
* @param v Value to clamp (must be an interger)
* @param arrayOrLength Array, or length of bounds (must be an integer)
* @returns Clamped value, minimum will be 0, maximum will be one less than `length`.
*/
declare function clampIndex(v: number, arrayOrLength: number | readonly any[]): number;
declare function maxAbs(values: Iterable<number>): number;
declare function maxAbs(...values: number[]): number;
//#endregion
//#region ../packages/numbers/src/count.d.ts
/**
* Yields `amount` integers, counting by one from zero. If a negative amount is used,
* count decreases. If `offset` is provided, this is added to the return result.
* @example
* ```js
* const a = [...count(5)]; // Yields five numbers: [0,1,2,3,4]
* const b = [...count(-5)]; // Yields five numbers: [0,-1,-2,-3,-4]
* for (const v of count(5, 5)) {
* // Yields: 5, 6, 7, 8, 9
* }
* const c = [...count(5,1)]; // Yields [1,2,3,4,5]
* ```
*
* @example Used with forEach
* ```js
* // Prints `Hi` 5x
* forEach(count(5), () => // do something);
* ```
*
* If you want to accumulate return values, consider using Flow.repeat.
*
* @example Run some code every 100ms, 10 times:
* ```js
* import { interval } from '@ixfx/flow.js'
* import { count } from '@ixfx/numbers.js'
* const counter = count(10);
* for await (const v of interval(counter, { fixedIntervalMs: 100 })) {
* // Do something
* }
* ```
* @param amount Number of integers to yield
* @param offset Added to result
*/
declare function count(amount: number, offset?: number): Generator<number, void, void>;
//#endregion
//#region ../packages/numbers/src/difference.d.ts
type DifferenceKind = `numerical` | `relative` | `relativeSigned` | `absolute`;
/**
* Returns the difference from the `initial` value. Defaults to absolute difference.
* ```js
* const rel = differenceFromFixed(100);
* rel(100); // 0
* rel(150); // 50
* rel(50); // 50
* ```
*
* 'numerical' gives sign:
* ```js
* const rel = differenceFromFixed(100, `numerical`);
* rel(100); // 0
* rel(150); // 50
* rel(50); // -50
* ```
*
* 'relative' gives proportion to initial
* ```js
* const rel = differenceFromFixed(100, `relative`);
* rel(100); // 0
* rel(150); // 0.5
* rel(10); // 0.90
* ```
*
* Using 'relativeSigned', we get negative relative result
* when value is below the initial value.
*
* Use {@link differenceFromLast} to compare against the last value,
* rather than the same fixed value.
* @param {number} initial Value to compare against
* @returns Difference from initial value
*/
declare const differenceFromFixed: (initial: number, kind?: DifferenceKind) => (value: number) => number;
/**
* Returns a function which yields difference compared to last value.
*
* If no initial value is provided, the first difference will be returned as 0.
*
* Difference can be returned in various formats:
* * 'absolute': numerical difference, without sign
* * 'numerical': numerical difference, with sign, so you can see if difference is higher or lower
* * 'relative': difference divided by last value, giving a proportional difference. Unsigned.
* * 'relativeSigned': as above, but with sign
*
* Use {@link differenceFromFixed} to compare against a fixed value instead of the last value.
*
* ```js
* let d = differenceFromLast(`absolute`);
* d(10); // 0
* d(11); // 1
* d(10); // 1
* ```
*
* ```js
* let d = differenceFromLast(`numerical`);
* d(10); // 0
* d(11); // 1
* d(10); // -1
* ```
*
* ```js
* let d = differenceFromLast(`relative`);
* d(10); // 0
* d(11); // 0.1
* d(10); // 0.1
* ```
* ```js
* let d = differenceFromLast(`relativeSigned`);
* d(10); // 0
* d(11); // 0.1
* d(10); // -0.1
* ```
*
* An initial value can be provided, eg:
* ```js
* let d = differenceFromLast(`absolute`, 10);
* d(11); // 1
* ```
* @param kind Kind of output value
* @param initialValue Optional initial value
* @returns
*/
declare const differenceFromLast: (kind?: DifferenceKind, initialValue?: number) => (v: number) => number;
//#endregion
//#region ../packages/numbers/src/filter.d.ts
/**
* Filters an iterator of values, only yielding
* those that are valid numbers
*
* ```js
* const data = [true, 10, '5', { x: 5 }];
* for (const n of Numbers.filterIterable(data)) {
* // 10
* }
* ```
* @param it
*/
declare function filterIterable(it: Iterable<unknown>): Generator<unknown, void, unknown>;
/**
* Returns a function that yields _true_ if a value
* is at least `threshold`
* ```js
* const t = thresholdAtLeast(50);
* t(50); // true
* t(0); // false
* t(55); // true
* ```
* @param threshold
* @returns
*/
declare const thresholdAtLeast: (threshold: number) => (v: number) => boolean;
/**
* Returns a function that yields _true_
* if a number is at least _min_ and no greater than _max_
*
* ```js
* const t = rangeInclusive(50, 100);
* t(40); // false
* t(50); // true
* t(60); // true
* t(100); // true
* t(101); // false
* ```
* @param min
* @param max
* @returns
*/
declare const rangeInclusive: (min: number, max: number) => (v: number) => boolean;
//#endregion
//#region ../packages/numbers/src/flip.d.ts
/**
* Flips a percentage-scale number: `1 - v`.
*
* The utility of this function is that it sanity-checks
* that `v` is in 0..1 scale.
*
* ```js
* flip(1); // 0
* flip(0.5); // 0.5
* flip(0); // 1
* ```
* @param v
* @returns
*/
declare const flip: (v: number | (() => number)) => number;
//#endregion
//#region ../packages/numbers/src/generate.d.ts
/**
* Generates a range of numbers, starting from `start` and counting by `interval`.
* If `end` is provided, generator stops when reached
*
* Unlike {@link numericRange}, numbers might contain rounding errors
*
* ```js
* for (const c of numericRangeRaw(10, 100)) {
* // 100, 110, 120 ...
* }
* ```
*
* Get results as an array
* ```js
* const c = [...numericRangeRaw(1,0,5)]; // [0,1,2,3,4]
* ```
* @param interval Interval between numbers
* @param start Start
* @param end End (if undefined, range never ends). Inclusive.
*/
declare const numericRangeRaw: (interval: number, start?: number, end?: number, repeating?: boolean) => Generator<number, void, unknown>;
/**
* Generates a range of numbers, with a given interval.
*
* @example For-loop
* ```
* let loopForever = numericRange(0.1); // By default starts at 0 and counts upwards forever
* for (v of loopForever) {
* console.log(v);
* }
* ```
*
* @example If you want more control over when/where incrementing happens...
* ```js
* let percent = numericRange(0.1, 0, 1);
*
* let percentResult = percent.next().value;
* ```
*
* Note that computations are internally rounded to avoid floating point math issues. So if the `interval` is very small (eg thousandths), specify a higher rounding
* number.
*
* @param interval Interval between numbers
* @param start Start. Defaults to 0
* @param end End (if undefined, range never ends). Inclusive.
* @param repeating Range loops from start indefinately. Default _false_
* @param rounding A rounding that matches the interval avoids floating-point math hikinks. Eg if the interval is 0.1, use a rounding of 10
*/
declare const numericRange: (interval: number, start?: number, end?: number, repeating?: boolean, rounding?: number) => Generator<number, void, unknown>;
/**
* Yields numeric range between 0.0-1.0.
*
* ```
* // Yields: [0, 0.2, 0.4, 0.6, 0.8, 1]
* const a = [...numericPercent(0.2)];
*
* // Repeating flag set to true:
* for (const v of numericPercent(0.2, true)) {
* // Infinite loop. V loops back to 0 after hitting 1
* }
* ```
*
* If `repeating` is true, it loops back to 0 after reaching 1
* @param interval Interval (default: 0.01, ie. 1%)
* @param repeating Whether generator should loop (default: false)
* @param start Start (default: 0)
* @param end End (default: 1)
* @returns
*/
declare const numericPercent: (interval?: number, repeating?: boolean, start?: number, end?: number) => Generator<number, void, unknown>;
//#endregion
//#region ../packages/numbers/src/guard.d.ts
/**
* Returns true if `possibleNumber` is a number and not NaN
* @param possibleNumber
* @returns
*/
declare const isValid: (possibleNumber: unknown) => boolean;
//#endregion
//#region ../packages/numbers/src/is-approx.d.ts
/**
* Returns a function that checks if a value is within range of a base value
* ```js
* const tenPercent = isApprox(0.1);
* // Check if 101 is within 10% range of 100
* tenPercent(100, 101);
* ```
* @param rangePercent
*/
declare function isApprox(rangePercent: number): (baseValue: number, value: number) => boolean;
/**
* Returns a function to check if a value is within range of a base value
* ```js
* const close = isApprox(0.1, 100);
* // Check if 101 is within 10% range of 100
* close(101);
* ```
* @param rangePercent
* @param baseValue
*/
declare function isApprox(rangePercent: number, baseValue: number): (value: number) => boolean;
/**
* Returns _true/false_ if `value` is within `rangePercent` of `baseValue`.
*
* ```js
* // True
* isApprox(0.1, 100, 101);
* isApprox(0.1, 100, 99);
* isApprox(0.1, 100, 100);
*
* // False
* isApprox(0.1, 100, 98);
* isApprox(0.1, 100, 102);
* ```
* @param rangePercent
* @param baseValue
* @param value
*/
declare function isApprox(rangePercent: number, baseValue: number, value: number): boolean;
/**
* Yields a function that checks if a value is close to any target value
* ```js
* const c = isCloseToAny(1, 10, 20, 30, 40);
* c(11); // True - within 1 range of 10
* c(19); // True - within 1 range of 20
* c(0); // False
* ```
*
* Returned function accepts multiple values, returning
* _true_ if any of them are within range
* ```js
* c(0, 1, 11); // Would return true based on 11
* ```
* @param allowedRangeAbsolute
* @param targets
* @returns
*/
declare const isCloseToAny: (allowedRangeAbsolute: number, ...targets: number[]) => (...values: number[]) => boolean;
//#endregion
//#region ../packages/numbers/src/kalman.d.ts
type Kalman1dFilterOptions = {
/**
* Process noise
* @default 1
*/
r: number;
/**
* Measurement noise
* @default 1
*/
q: number;
/**
* State vector
* @default 1
*/
a: number;
/**
* Control vector
* @default 0
*/
b: number;
/**
* Measurement vector
* @default 1
*/
c: number;
};
/**
* KalmanFilter
*
* author: Wouter Bulten
* see {@link http://github.com/wouterbulten/kalmanjs}
* version Version: 1.0.0-beta
* copyright Copyright 2015-2018 Wouter Bulten
* license MIT License
*/
declare class Kalman1dFilter {
R: number;
Q: number;
A: number;
C: number;
B: number;
cov: number;
x: number;
/**
* Create 1-dimensional kalman filter
*/
constructor(options?: Partial<Kalman1dFilterOptions>);
/**
* Filter a new value
* @param {Number} z Measurement
* @param {Number} u Control
* @return {Number}
*/
filter(z: number, u?: number): number;
/**
* Predict next value
* @param {Number} [u] Control
* @return {Number}
*/
predict(u?: number): number;
/**
* Return uncertainty of filter
* @return {Number}
*/
uncertainty(): number;
/**
* Return the last filtered measurement
* @return {Number}
*/
lastMeasurement(): number;
/**
* Set measurement noise Q
* @param {Number} noise
*/
setMeasurementNoise(noise: number): void;
/**
* Set the process noise R
* @param {Number} noise
*/
setProcessNoise(noise: number): void;
}
/**
* Returns a function that performs 1D Kalman filtering.
*
* ```js
* const f = kalman1dFilter();
* f(10); // 10
* ```
*
* Under the hood creates a {@link Kalman1dFilter} instance and returns its `filter` method.
* @param options
* @returns
*/
declare const kalman1dFilter: (options?: Partial<Kalman1dFilterOptions>) => (z: number, u?: number) => number;
//#endregion
//#region ../packages/numbers/src/types.d.ts
type NumbersComputeResult = {
/**
* Tally of number of items
*/
readonly count: number;
/**
* Smallest value in array
*/
readonly min: number;
/**
* Total of all items
*/
readonly total: number;
/**
* Largest value in array
*/
readonly max: number;
/**
* Average value in array
*/
readonly avg: number;
};
type NumbersComputeOptions = Readonly<{
/**
* Start index, inclusive
*/
/**
* End index, exclusive
*/
nonNumbers?: `throw` | `ignore` | `nan`;
}>;
type NumberScaler = (v: number) => number;
type NumberScalerTwoWay = {
out: NumberScaler;
in: NumberScaler;
};
/**
* Wrapper around a bipolar value. Immutable.
*
* ```js
* let b = Bipolar.immutable();
* let b = Bipolar.immutable(0.5);
* b = b.add(0.1);
* ```
*/
type BipolarWrapper = {
/**
* Current value
*/
value: number;
/**
* Nudge toward zero by amount
* ```js
* let b = immutable(1);
* b = b.towardZero(0.1); // 0.9
* ```
* @param amount Amount to nudge by
* @returns Modified copy
*/
towardZero: (amount: number) => BipolarWrapper;
/**
* Add some amount to the bipolar value, clipping it
* to the -1...1 range
* ```js
* let b = immutable(0);
* b = b.add(0.5); // 0.5
* ```
* @param amount
* @returns
*/
add: (amount: number) => BipolarWrapper;
/**
* Multiple the value by `amount`, clipping result
* to the -1...1 range.
* ```js
* let b = immutable(1);
* b = b.multiply(0.1); // 0.9
* ````
* @param amount
* @returns
*/
multiply: (amount: number) => BipolarWrapper;
/**
* Inverse value
* ```js
* let b = immutable(1);
* b = b.inverse(); // -1
* ```
* @returns
*/
inverse: () => BipolarWrapper;
/**
* Convert to 0..1 scale
* ```js
* let b = immutable(-1);
* b.asScalar(); // 0
* ```
* @returns
*/
asScalar: () => number;
/**
* Interpolate toward `target` by `amount`
* @param amount
* @param target
* @returns
*/
interpolate: (amount: number, target: number) => BipolarWrapper;
[Symbol.toPrimitive]: (hint: string) => number | string | boolean;
};
type NumericRange = Readonly<{
min: number;
max: number;
}>;
type RangeStream = {
seen: (v: any) => NumericRange;
reset: () => NumericRange;
min: number;
max: number;
range: NumericRange;
};
declare namespace bipolar_d_exports {
export { clamp, fromScalar, immutable, scale$1 as scale, scaleUnclamped, toScalar, towardZero };
}
/**
* Wrapper for bipolar-based values. Immutable.
* All functions will clamp to keep it in legal range.
*
* ```js
* let v = immutable(); // Starts with 0 by default
* v = v.add(0.1); // v.value is 0.1
* v = v.inverse(); // v.value is -0.1
* v = v.multiply(0.2); // v.value is -0.02
*
* v = immutable(1);
* v = v.towardZero(0.1); // 0.9
* v = v.interpolate(0.1, 1);
* ```
*
* Wrapped values can be coerced into number:
* ```js
* const v = immutable(1);
* const x = +v+10;
* // x = 11
* ```
* @param startingValueOrBipolar Initial numeric value or BipolarWrapper instance
* @throws {TypeError} If start value is out of bipolar range or invalid
* @returns
*/
declare const immutable: (startingValueOrBipolar?: number | BipolarWrapper) => BipolarWrapper;
/**
* Converts bipolar value to a scalar. That is, converts from
* -1..1 range to 0..1.
*
* ```js
* Bipolar.toScalar(-1); // 0.0
* Bipolar.toScalar( 0); // 0.5
* Bipolar.toScalar( 1); // 1.0
* ```
*
* Range can be changed:
* ```js
* Bipolar.toScalar(0, 100); // Uses 0..100 scale, so output is 50
* Bipolar.toScalar(0, 100, 50); // Uses 50..1000 scale, so output is 75
* ```
*
* Throws an error if `bipolarValue` is not a number or NaN
* @param bipolarValue Value to convert to scalar
* @returns Scalar value on 0..1 range.
*/
declare const toScalar: (bipolarValue: number, max?: number, min?: number) => number;
/**
* Makes a scalar into a bipolar value.
*
* That is, input range is 0..1, output range is -1...1
*
* ```js
* Bipolar.fromScalar(1); // 1
* Bipolar.fromScalar(0); // -1
* Bipolar.fromScalar(0.5); // 0
* ```
*
* Throws an error if `scalarValue` is outside 0..1 scale.
* @param scalarValue Scalar value to convert
* @returns Bipolar value on -1..1 scale
*/
declare const fromScalar: (scalarValue: number) => number;
/**
* Scale & clamp value to bipolar range (-1..1).
* ```js
* // Scale 100 on 0..100 scale
* Bipolar.scale(100, 0, 100); // 1
* Bipolar.scale(50, 0, 100); // 0
* Bipolar.scale(0, 0, 100); // -1
* ```
*
* Return value is clamped.
* @param inputValue Value to scale
* @param inMin Minimum of scale
* @param inMax Maximum of scale
* @returns Bipolar value on -1..1 scale
*/
declare const scale$1: (inputValue: number, inMin: number, inMax: number) => number;
/**
* Scale a number to bipolar range (-1..1). Not clamped, so we might exceed range.
*
* ```js
* // Scale 100 on 0..100 scale
* Bipolar.scaleUnclamped(100, 0, 100); // 1
* Bipolar.scaleUnclamped(50, 0, 100); // 0
* Bipolar.scaleUnclamped(0, 0, 100); // -1
* ```
*
* @param inputValue Value to scale
* @param inMin Minimum of scale
* @param inMax Maximum of scale
* @returns Bipolar value on -1..1 scale
*/
declare const scaleUnclamped: (inputValue: number, inMin: number, inMax: number) => number;
/**
* Clamp a bipolar value
* ```js
* Bipolar.clamp(-1); // -1
* Bipolar.clamp(-1.1); // -1
* ```
*
* Throws an error if `bipolarValue` is not a number or NaN.
* @param bipolarValue Value to clamp
* @returns Clamped value on -1..1 scale
*/
declare const clamp: (bipolarValue: number) => number;
/**
* Pushes a bipolar value toward zero by `amount`.
* Return value is clamped on bipolar range of -1..1
*
* ```js
* Bipolar.towardZero(-1, 0.1); // -0.9
* Bipolar.towardZero( 1, 0.1); // 0.9
* Bipolar.towardZero( 0, 0.1); // 0.0
* Bipolar.towardZero( 1, 1.1); // 0.0
* ```
*
* If `amount` is greater than 1, 0 is returned.
* Throws an error if `bipolarValue` or `amount` are not numbers.
* Throws an error if `amount` is below zero.
* @param bipolarValue Bipolar value to nudge toward zero
* @param amount Amount to nudge by
* @returns Bipolar value -1...1
*/
declare const towardZero: (bipolarValue: number, amount: number) => number;
//#endregion
//#region ../packages/numbers/src/interpolate.d.ts
/**
* Interpolation options.
*
* Limit: What to do if interpolation amount exceeds 0..1 range
* * clamp: lock to A & B (inclusive) Default.
* * wrap: wrap from end to start again
* * ignore: allow return values outside of A..B range
*
* Transform: name of function to transform `amount` prior to interpolate. This is useful for creating non-linear interpolation results.
*
* For example:
* ```js
* // Divide interpolation amount in half
* const interpolatorInterval({ mins: 1 }, 10, 100, {
* transform: (amount) => amount * Math.random()
* });
* ```
* In the above example, the results would get more random over time.
* `interpolatorInterval` will still step through the interpolation range of 0..1 in an orderly fashion, but we're transforming that range using a custom function before producing the result.
*
*/
type BasicInterpolateOptions = {
limits: `clamp` | `wrap` | `ignore`;
transform: (v: number) => number;
};
/**
* Returns an interpolation function with a fixed interpolation amount. This
* function will need the A and B values to interpolate between (ie start and end)
*
* Interpolation amount is usually 0..1, where 0 will return the A value, 1 will return the B value, 0.5 will be halfway between the two etc.
*
* ```js
* // Create function
* const fn = interpolate(0.1);
*
* // Later, use to interpolate between a and b
* fn(50, 100); // 10% of 50..100 range
* ```
*
* This is useful if you have a fixed interpolation amount, but varying A and B values.
* @param amount Interpolation value (0..1 usually)
* @param options Options
*/
declare function interpolate(amount: number, options?: Partial<BasicInterpolateOptions>): (a: number, b: number) => number;
/**
* Interpolates between `a` and `b` by `amount`.
*
* Interpolation amount is usually 0..1, where 0 will return the A value, 1 will return the B value, 0.5 will be halfway between the two etc.
*
* ```js
* // Get the value at 10% of range between 50-100
* const fn = interpolate(0.1, 50, 100);
* ```
*
* This is useful if you have dynamic interpolation amount as well as A & B values.
* Consider using `interpolate(amount)` if you have a fixed interpolation amount.
* @param amount Interpolation value (0..1 usually)
* @param a Starting value (corresponding to an interpolation of 0)
* @param b End value (corresponding to an interpolation value of 1)
* @param options Options
*/
declare function interpolate(amount: number, a: number, b: number, options?: Partial<BasicInterpolateOptions>): number;
/**
* Returns an interpolation function with a fixed A and B values.
* The returned function requires an interpolation amount. This is usually 0..1, where 0 will return the A value, 1 will return the B value, 0.5 will be halfway between the two etc.
*
* ```js
* // Create function to interpolate between 50..100
* const fn = interpolate(50, 100);
*
* // Later, use to interpolate
* fn(0.1); // 10% of 50..100 range
* ```
* @param a Starting value (corresponding to an interpolation of 0)
* @param b End value (corresponding to an interpolation value of 1)
* @param options Options
*/
declare function interpolate(a: number, b: number, options?: Partial<BasicInterpolateOptions>): (amount: number) => number;
/**
* Returns a function that interpolates from A to B.
* It steps through the interpolation with each call to the returned function.
* This means that the `incrementAmount` will hinge on the rate
* at which the function is called. Alternatively, consider {@link https://api.ixfx.fun/_ixfx/modulation/interpolatorInterval/}
* which steps on the basis of clock time.
*
* ```js
* // Interpolate from 0..1 by 0.01
* const v = interpolatorStepped(0.01, 100, 200);
* v(); // Each call returns a value closer to target
* // Eg: 100, 110, 120, 130 ...
* ```
*
* Under the hood, it calls `interpolate` with an amount that
* increases by `incrementAmount` each time.
*
* When calling `v()` to step the interpolator, you can also pass
* in new B and A values. Note that the order is swapped: the B (target) is provided first, and
* then optionally A.
*
* ```js
* const v = interpolatorStepped(0.1, 100, 200); // Interpolate 100->200
* v(300, 200); // Retarget to 200->300 and return result
* v(150); // Retarget 200->150 and return result
* ```
*
* This allows you to maintain the current interpolation progress.
* @param incrementAmount Amount to increment by
* @param a Start value. Default: 0
* @param b End value. Default: 1
* @param startInterpolationAt Starting interpolation amount. Default: 0
* @param options Options for interpolation
* @returns
*/
declare const interpolatorStepped: (incrementAmount: number, a?: number, b?: number, startInterpolationAt?: number, options?: Partial<BasicInterpolateOptions>) => (retargetB?: number, retargetA?: number) => number;
/**
* Interpolate between angles `a` and `b` by `amount`. Angles are in radians.
*
* ```js
* interpolateAngle(0.5, Math.PI, Math.PI/2);
* ```
* @param amount
* @param aRadians Start angle (radian)
* @param bRadians End angle (radian)
* @returns
*/
declare const interpolateAngle: (amount: number, aRadians: number, bRadians: number, options?: Partial<BasicInterpolateOptions>) => number;
//#endregion
//#region ../packages/numbers/src/iqr.d.ts
/**
* Calculate interquartile range.
*
* If `n` is unspecified, `data.length` is used.
* @param data
* @param n
* @returns
*/
declare const interquartileRange: (data: number[], n?: number) => number;
/**
* Returns a function which itself returns _true_ if a value is an outlier.
*
* This can be used for example to get a copy of an array without outliers:
* ```js
* const p = computeIsOutlier(someData);
* const someDataWithoutOutliers = someData.filter(value => !p(value));
* ```
*
* Outliers are defined as: "a point which falls more than 1.5 times the interquartile range above the third quartile or below the first quartile." [Wolfram](https://mathworld.wolfram.com/Outlier.html)
*
* If array length is less than 4, no value will be considered an outlier.
* @param data Data to filter
* @param multiplier Multiplier of Q3 Q1. Default: 1.5
* @returns
*/
declare const computeIsOutlier: (data: number[], multiplier?: number) => (value: number) => boolean;
/**
* Gets the value at a specific quantile
* ```js
* getQuantile(data, 25); // 1st quartile
* getQuantile(data, 75); // 3rd quartile
* ```
* @param data
* @param quantile
* @param presorted Pass _true_ if `data` is already sorted
* @returns
*/
declare const getQuantile: (data: number[], quantile: number, presorted?: boolean) => number;
//#endregion
//#region ../packages/numbers/src/linear-space.d.ts
/**
* Generates a `step`-length series of values between `start` and `end` (inclusive).
* Each value will be equally spaced.
*
* ```js
* for (const v of linearSpace(1, 5, 6)) {
* // Yields: [ 1, 1.8, 2.6, 3.4, 4.2, 5 ]
* }
* ```
*
* Numbers can be produced from large to small as well
* ```js
* const values = [...linearSpace(10, 5, 3)];
* // Yields: [10, 7.5, 5]
* ```
* @param start Start number (inclusive)
* @param end End number (inclusive)
* @param steps How many steps to make from start -> end
* @param precision Number of decimal points to round to
*/
declare function linearSpace(start: number, end: number, steps: number, precision?: number): IterableIterator<number>;
//#endregion
//#region ../packages/numbers/src/moving-average.d.ts
/**
* A moving average calculator (exponential weighted moving average) which does not keep track of
* previous samples. Less accurate, but uses less system resources.
*
* The `scaling` parameter determines smoothing. A value of `1` means that
* the latest value is used as the average - that is, no smoothing. Higher numbers
* introduce progressively more smoothing by weighting the accumulated prior average more heavily.
*
* ```
* const ma = movingAverageLight(); // default scaling of 3
* ma(50); // 50
* ma(100); // 75
* ma(75); // 75
* ma(0); // 50
* ```
*
* Note that the final average of 50 is pretty far from the last value of 0. To make it more responsive,
* we could use a lower scaling factor: `movingAverageLight(2)`. This yields a final average of `37.5` instead.
*
* @param scaling Scaling factor. 1 is no smoothing. Default: 3
* @returns Function that adds to average.
*/
declare const movingAverageLight: (scaling?: number) => (value?: number) => number;
/**
* Creates a moving average for a set number of `samples`.
* It returns a function which in turn yields an average value.
*
* Moving average are useful for computing the average over a recent set of numbers.
* A lower number of samples produces a computed value that is lower-latency yet more jittery.
* A higher number of samples produces a smoother computed value which takes longer to respond to
* changes in data.
*
* Sample size is considered with respect to the level of latency/smoothness trade-off, and also
* the rate at which new data is added to the moving average.
*
*
* ```js
* const ma = movingAverage(10);
* ma(10); // 10
* ma(5); // 7.5
* ```
*
* A weighting function can be provided to shape how the average is
* calculated - eg privileging the most recent data over older data.
* It uses `Arrays.averageWeighted` under the hood.
*
* ```js
* import { movingAverage } from '@ixfx/numbers.js';
* import { gaussian } from '@ixfx/modulation.js';
*
* // Give more weight to data in middle of sampling window
* const ma = movingAverage(100, gaussian());
* ```
*
* Because it keeps track of `samples` previous data, there is a memory impact. A lighter version is {@link movingAverageLight} which does not keep a buffer of prior data, but can't be as easily fine-tuned.
* @param samplesOrOptions Number of samples to compute average from, or object of options
* @returns
*/
declare const movingAverage: (samplesOrOptions: number | MovingAverageOptions) => (value: number) => any;
declare const movingAverageWithContext: (samplesOrOptions: number | MovingAverageOptions) => {
seen: (value: number) => any;
readonly data: any[];
readonly average: number;
};
type MovingAverageNanOptions = `throw` | `ignore`;
type MovingAverageOptions = MovingWindowOptions<number> & Partial<{
/**
* If set, a weighted average will be
* calculated instead of a plain average.
* @param v
* @returns
*/
weighter: (v: number) => number;
nanPolicy: MovingAverageNanOptions;
}>;
/**
* Noise filtering
*
* Algorithm: https://gery.casiez.net/1euro/
*
* Based on [Jaan Tollander de Balsch's implementation](https://jaantollander.com/post/noise-filtering-using-one-euro-filter/)
* @param cutoffMin Default: 1
* @param speedCoefficient Default: 0
* @param cutoffDefault Default: 1
*/
declare const noiseFilter: (cutoffMin?: number, speedCoefficient?: number, cutoffDefault?: number) => (value: number, timestamp?: number) => number;
//#endregion
//#region ../packages/numbers/src/normalise-types.d.ts
/**
* Normalisation strategies
*
* In brief,
* * `minmax`: Produces values on 0..1 scale. Sensitive to outliers.
* * ``score`: Mean value will be normalised to 0, those on standard deviation 1. Less sensitive to outliers.
* * `robust`: Does the best job if outliers are expected
*
* Keep in mind you could also remove outliers from the dataset before using a
* basic min-max normalisation.
*
* For more details, see Wikipedia:
* * [Min-Max normalisation](https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization))
* * [Z-score normalisation](https://en.wikipedia.org/wiki/Feature_scaling#Standardization_(Z-score_Normalization))
* * [Robust scaling]](https://en.wikipedia.org/wiki/Feature_scaling#Robust_Scaling)
*/
type NormalisationStrategy = `minmax` | `zscore` | `robust`;
type NormalisationStreamStrategy = `minmax`;
type MinMaxStreamOptions = {
minDefault: number;
maxDefault: number;
};
/**
* Options for computing min-max normalisation
*/
type MinMaxArrayOptions = {
/**
* Minimum value of range
*/
minForced: number;
/**
* Maximum value of range
*/
maxForced: number;
/**
* Clamp input value to min/max
*/
clamp: boolean;
};
type ZScoreArrayOptions = {
meanForced: number;
standardDeviationForced: number;
};
type RobustArrayOptions = {
medianForced: number;
iqrForced: number;
};
type NormalisationStreamOptions = MinMaxStreamOptions;
type NormalisationArrayOptions = MinMaxArrayOptions | ZScoreArrayOptions | RobustArrayOptions;
/**
* Context for stream normalisation
*/
type NormaliseStreamContext = NumericRange & {
/**
* Passes a value to the normaliser, getting
* back the normalised result
* @param v Value to add
* @returns Normalised result
*/
seen: (v: number) => number;
/**
* Reset the normaliser, by default to
* extreme ranges so it will calibrate after the
* next value.
* @param minDefault Start min value (default: Number.MAX_SAFE_INTEGER)
* @param maxDefault Start max value (default: Number.MIN_SAFE_INTERGER)
* @returns
*/
reset: (minDefault?: number, maxDefault?: number) => void;
/**
* Get the current min value of range.
*
* If no values have been passed through the stream it will be
* the initial minDefault or Number.MAX_SAFE_INTEGER
*/
get min(): number;
/**
* Get the current max value of range.
*
* If no values have been passed through the stream it will be
* the initial maxDefault or Number.MIN_SAFE_INTEGER
*/
get max(): number;
/**
* Gets the absolute range (ie. max-min) of the normaliser.
*
* If normaliser hasn't received any values it will use its default min/max.
*/
get range(): number;
};
declare namespace normalise_minmax_d_exports {
export { array$3 as array, arrayWithContext$3 as arrayWithContext, compute$2 as compute, stream$1 as stream, streamWithContext$1 as streamWithContext };
}
/**
* Returns a function which can do min-max normalisation, baking-in the min and max values.
* ```js
* // Normalise with min value of 20, max of 100
* const fn = compute(20, 100);
*
* // Use function with input value of 40
* fn(40);
* ```
*
* @param min Minimum value of range
* @param max Maximum value of range
* @param clamp Whether to clamp input value to min/max range. Default: _false_
* @returns
*/
declare const compute$2: (min: number, max: number, clamp?: boolean) => (value: number) => number;
/**
* Normalises an array using the [min-max](https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization)) technique.
*
* This version returns additional context of the normalisation, alternatively use {@link array}
*
* ```js
* const c = arrayWithContext(someValues);
* c.values; // Array of normalised values
* c.original; // Original input array
* c.min / c.max / c.range
* ```
*
* By default, computes min and max values based on contents of `values`. Clamping is not required
* for this case, so it's _false_ by default.
*
* @param values Values
* @param options Optionally uses 'minForced' and 'maxForced' properties to scale values instead of actual min/max values of data.
*/
declare const arrayWithContext$3: (values: readonly number[], options?: Partial<MinMaxArrayOptions>) => {
values: number[];
original: any[];
min: number;
max: number;
range: number;
};
/**
* Normalises an array using the [min-max](https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization)) technique.
* By default uses the actual min/max of the array as the normalisation range.
*
* [ixfx Guide on Normalising](https://ixfx.fun/cleaning/normal/)
*
* Use {@link arrayWithContext} to get back the min/max/range and original values
*
* ```js
* // Yields: [0.5, 0.1, 0.0, 0.9, 1]
* Normalise.MinMax.array([5,1,0,9,10]);
* ```
*
* `minForced` and/or `maxForced` can
* be provided to use an arbitrary range.
*
* ```js
* // Forced range 0-100
* // Yields: [0.05, 0.01, 0.0, 0.09, 0.10]
* Normalise.MinMax.array([5,1,0,9,10], { minForced: 0, maxForced: 100 });
* ```
*
* Return values are clamped to always be 0-1, inclusive.
*
* @param values Values
* @param options Options to override or min/max values.
*/
declare const array$3: (values: readonly number[], options?: Partial<MinMaxArrayOptions>) => number[];
/**
* [Min-max scaling](https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization))
*
* A more advanced form of {@link stream}
*
* With this version
* @example
* ```js
* const s = Normalise.MinMax.streamWithContext();
* s.seen(2); // 1 (because 2 is highest seen)
* s.seen(1); // 0 (because 1 is the lowest so far)
* s.seen(1.5); // 0.5 (50% of range 1-2)
* s.seen(0.5); // 0 (because it's the new lowest)
* ```
*
* And the more advanced features
* ```js
* s.min / s.max / s.range
* s.reset();
* s.reset(10, 100);
* ```
* @returns
*/
declare const streamWithContext$1: (options?: Partial<MinMaxStreamOptions>) => NormaliseStreamContext;
/**
* Normalises numbers using the [min-max](https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization)) technique.
*
* Adjusts min/max as new values are processed. Return values will be in the range of 0-1 (inclusive).
*
* [ixfx Guide on Normalising](https://ixfx.fun/cleaning/normal/)
*
* Use {@link streamWithContext} if you want to be able to check the min/max or reset the normaliser.
*
* @example
* ```js
* const s = Normalise.MinMax.stream();
* s(2); // 1 (because 2 is highest seen)
* s(1); // 0 (because 1 is the lowest so far)
* s(1.5); // 0.5 (50% of range 1-2)
* s(0.5); // 0 (because it's the new lowest)
* ```
*
* Since normalisation is being adjusted as new min/max are encountered, it might
* be that value normalised to 1 at one time is different to what normalises to 1
* at a later time.
*
* If you already know what to expect of the number range, passing in `minDefault`
* and `maxDefault` primes the normalisation.
* ```js
* const s = Normalise.MinMax.stream();
* s(5); // 1, because it's the highest seen
*
* // With priming:
* const s = Normalise.MinMax.stream({ minDefault:0, maxDefault:10 });
* s(5); // 0.5, because we're expecting range 0-10
* ```
*
* If a value exceeds the default range, normalisation adjusts.
* Errors are thrown if min/max defaults are NaN or if one attempts to
* normalise NaN.
*
* @returns
*/
declare const stream$1: (options: MinMaxStreamOptions) => (value: number) => number;
declare namespace normalise_zscore_d_exports {
export { array$2 as array, arrayWithContext$2 as arrayWithContext, compute$1 as compute };
}
/**
* Returns a function that computes zscore-based normalisation.
*
* ```js
* // Calculate necessary components
* const m = mean(data);
* const s = standardDeviation(data);
*
* // Get the function
* const fn = compute(m, s);
*
* // Use it
* fn(10); // Yields the normalised value
* ```
*
* It can be used to normalise a whole array
* ```js
* const normalised = someData.map(fn);
* ```
*
* If you want to calculate for a whole array, use {@link array}.
* @param mean Mean of data
* @param standardDeviation Standard deviation of data
* @returns
*/
declare const compute$1: (mean: number, standardDeviation: number) => (value: number) => number;
/**
* Returns the an array of normalised values, along with the mean and standard deviation of `array`.
* If you just want the computed results, use {@link Normalise.ZScore.array}.
*
* By default it will compute mean and std.dev based on `array`. If you have these already, they
* can be passed as options.
* @param array
* @returns
*/
declare const arrayWithContext$2: (array: readonly number[] | number[], options?: Partial<ZScoreArrayOptions>) => {
mean: number;
standardDeviation: number;
values: number[];
original: readonly number[] | number[];
};
/**
* Returns an array of normalised values using the 'z score' algorithm.
*
* By default it will compute mean and std.dev based on `array`. If you have these already, they
* can be passed as options.
* @param values
* @param options
* @returns
*/
declare const array$2: (values: readonly number[] | number[], options?: Partial<ZScoreArrayOptions>) => number[];
declare namespace normalise_robust_d_exports {
export { array$1 as array, arrayWithContext$1 as arrayWithContext, compute };
}
/**
* Calculates 'robust scaling' of a single value, `x`, based on provided mean and standard deviation.
*
* ```js
* const m = median(someData);
* const i = interquartileRange(someData);
* const fn = compute(m, i);
*
* // Use normaliser function
* fn(10);
* ```
* If you want to calculate for a whole array, use {@link array}.
* @param median Median of data
* @param iqr Interquartile range of data
* @returns
*/
declare const compute: (median: number, iqr: number) => (value: number) => number;
/**
* Returns the an array of normalised values, along with the mean and standard deviation of `array`.
* If you just want the computed results, use {@link Normalise.Robust.array}.
*
* By default it will compute mean and std.dev based on `array`. If you have these already, they
* can be passed as options.
* @param array
* @returns
*/
declare const arrayWithContext$1: (array: readonly number[] | number[], options?: Partial<RobustArrayOptions>) => {
median: number;
iqr: number;
values: number[];
original: number[];
};
/**
* Returns an array of normalised values using the 'z score' algorithm.
*
* By default it will compute mean and std.dev based on `array`. If you have these already, they
* can be passed as options.
* @param values
* @param options
* @returns
*/
declare const array$1: (values: readonly number[] | number[], options?: Partial<RobustArrayOptions>) => number[];
declare namespace normalise_d_exports {
export { normalise_minmax_d_exports as MinMax, MinMaxArrayOptions, MinMaxStreamOptions, NormalisationArrayOptions, NormalisationStrategy, NormalisationStreamOptions, NormalisationStreamStrategy, NormaliseStreamContext, normalise_robust_d_exports as Robust, RobustArrayOptions, normalise_zscore_d_exports as ZScore, ZScoreArrayOptions, array, arrayWithContext, stream, streamWithContext };
}
/**
* Normalises numbers with additional context on the range.
*
* For more details, see:
* * {@link MinMax.streamWithContext}
*
* @param strategy
* @param options
* @returns
*/
declare const streamWithContext: (strategy: NormalisationStreamStrategy, options?: Partial<NormalisationStreamOptions>) => NormaliseStreamContext;
/**
* Normalises numbers. Return values will be in the range of 0-1 (inclusive).
*
* [ixfx Guide on Normalising](https://ixfx.fun/cleaning/normal/)
*
* Use {@link streamWithContext} if you want to be able to check the min/max or reset the normaliser.
*
* @example
* ```js
* const s = Normalise.stream(`minmax`);
* s(2); // 1 (because 2 is highest seen)
* s(1); // 0 (because 1 is the lowest so far)
* s(1.5); // 0.5 (50% of range 1-2)
* s(0.5); // 0 (because it's the new lowest)
* ```
*
* For more details, see:
* * {@link MinMax.stream}
* @returns
*/
declare const stream: (strategy?: NormalisationStreamStrategy, options?: Partial<NormalisationStreamOptions>) => (value: number) => number;
/**
* Normalise an array of values with added context, depending on strategy.
*
* Strategies are available: minmax, zscore & robust
*
* [ixfx Guide on Normalising](https://ixfx.fun/cleaning/normal/)
*
* Use {@link array} to get back the min/max/range and original values
*
* ```js
* const { values, min, max, range } = Normalise.arrayWithContext(`minmax`, [5,1,0,9,10]);
* // values will be normalised output
* ```
*
* For more details, see:
* * {@link MinMax.array}
* * {@link ZScore.array}
* * {@link Robust.array}
* @param strategy
* @param values
* @param options
* @returns
*/
declare const arrayWithContext: (strategy: NormalisationStrategy, values: readonly number[], options?: Partial<NormalisationArrayOptions>) => {
mean: number;
standardDeviation: number;
values: number[];
original: readonly number[] | number[];
} | {
values: number[];
original: any[];
min: number;
max: number;
range: number;
} | {
median: number;
iqr: number;
values: number[];
original: number[];
};
/**
* Normalise an array of values.
*
* Strategies are available: minmax, zscore & robust
*
* [ixfx Guide on Normalising](https://ixfx.fun/cleaning/normal/)
*
* Use {@link arrayWithContext} to get back the min/max/range and original values
*
* ```js
* // Yields: [0.5, 0.1, 0.0, 0.9, 1]
* Normalise.array(`minmax`, [5,1,0,9,10]);
* ```
*
* For more details, see:
* * {@link MinMax.array} [Wikipedia](https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization))
* * {@link ZScore.array} [Wikipedia](https://en.wikipedia.org/wiki/Feature_scaling#Standardization_(Z-score_Normalization))
* * {@link Robust.array} [Wikipedia](https://en.wikipedia.org/wiki/Feature_scaling#Robust_Scaling)
*
* @param strategy
* @param values
* @param options
* @returns
*/
declare const array: (strategy: NormalisationStrategy, values: readonly number[], options?: Partial<NormalisationArrayOptions>) => number[];
//#endregion
//#region ../packages/numbers/src/number-array-compute.d.ts
/**
* Calculate the min, max, total, average and count of input array `data`.
* ```js
* const { total, min, max, avg, count } = numberArrayCompute([ 1, 2, 3 ]);
* ```
* @param data
* @param opts
* @returns
*/
declare const numberArrayCompute: (data: (number | undefined)[] | readonly (number | undefined)[], opts?: NumbersComputeOptions) => NumbersComputeResult;
//#endregion
//#region ../packages/numbers/src/numeric-arrays.d.ts
/**
* Applies a function `fn` to the elements of an array, weighting them based on their relative position.
*
* ```js
* // Six items
* weight([1,1,1,1,1,1], Modulation.gaussian());
*
* // Yields:
* // [0.02, 0.244, 0.85, 0.85, 0.244, 0.02]
* ```
*
* `fn` is expected to map (0..1) => (0..1), such as an easing function. The input to the
* `fn` is the relative position of an element. Thus the first element will be 0, the middle 0.5 and so on.
* The output of `fn` is then multiplied by the original value.
*
* In the below example (which is also the default if `fn` is not specified), the relative position is
* how values are weighted:
*
* ```js
* weight([1,1,1,1,1,1], (relativePos) => relativePos);
* // Yields:
* // [0, 0.2, 0.4, 0.6, 0.8, 1]
* ```
*
* Throws TypeError if `data` is not an array or for any element not a number.
* @param data Array of numbers
* @param fn Returns a weighting based on the given relative position. If unspecified, `(x) => x` is used.
*/
declare const weight: (data: number[] | readonly number[], fn?: (relativePos: number) => number) => number[];
/**
* Returns an array of all valid numbers from `data`
*
* @param data
* @returns
*/
declare const validNumbers: (data: readonly number[]) => number[];
/**
* Returns the dot product of arbitrary-sized arrays. Assumed they are of the same length.
* @param values
* @param nonNumber What to do if array contains an invalid number. Error: throw an exception, 'treat-as-zero' use as 0 instead, 'ignore', let math run with invalid number
* @returns
*/
declare const dotProduct: (values: readonly (readonly number[])[], nonNumber?: `error` | `treat-as-zero` | `ignore`) => number;
/**
* Calculates the average of all numbers in an array.
* Array items which a