Skip to content

Commit d83ada7

Browse files
MAINT: Convert hysteresis_relay to C++.
1 parent 5cb7329 commit d83ada7

6 files changed

+134
-205
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1703,7 +1703,7 @@ It generates the following plot:
17031703

17041704
#### `backlash`
17051705

1706-
`backlash(x, deadband, initial)`, a gufunc with signature `(i),(),()->(i)`,
1706+
`backlash(x, deadband, initial)`, a gufunc with signature `(n),(),()->(n)`,
17071707
computes the "backlash" response of a signal; see the Wikipedia article
17081708
[Backlash (engineering)](https://en.wikipedia.org/wiki/Backlash_(engineering)).
17091709
The function emulates the
@@ -1733,7 +1733,7 @@ the plot
17331733
#### `hysteresis_relay`
17341734

17351735
`hysteresis_relay(x, low_threshold, high_threshold, low_value, high_value, init)`,
1736-
a gufunc with signature `(i),(),(),(),(),()->(i)`, passes `x` through a relay with
1736+
a gufunc with signature `(n),(),(),(),(),()->(n)`, passes `x` through a relay with
17371737
hysteresis (like a [Schmitt trigger](https://en.wikipedia.org/wiki/Schmitt_trigger)).
17381738
The function is similar to the
17391739
[relay block](https://www.mathworks.com/help/simulink/slref/relay.html)

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ requires = [
88

99
[project]
1010
name = 'ufunclab'
11-
version = '0.0.8.dev11'
11+
version = '0.0.8.dev12'
1212
description = 'NumPy ufuncs and utilities.'
1313
readme = 'README.md'
1414
requires-python = '>=3.9'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
3+
from ufunc_config_types import UFuncExtMod, UFunc, UFuncSource
4+
5+
6+
HYSTERESIS_RELAY_DOCSTRING = """\
7+
hysteresis_relay(x, low_threshold, high_threshold, low_value, high_value, init, /, ...)
8+
9+
Pass x through a 'relay' with hysteresis.
10+
11+
Parameters
12+
----------
13+
x : array_like
14+
Input signal
15+
low_threshold : scalar
16+
Low end of hysteresis interval.
17+
high_threshold : scalar
18+
High end of the hysteresis interval.
19+
low_value : scalar
20+
Output value for x < low_threshold.
21+
high_value : scalar
22+
Outout value for x > high_threshold.
23+
init : scalar
24+
Initial output value if the initial value of x is
25+
between low_threshold and high_threshold. Normally
26+
this would be either low_value or high_value, but
27+
the function does not require it.
28+
29+
Returns
30+
-------
31+
out : ndarray
32+
Output of the relay.
33+
34+
Notes
35+
-----
36+
The function expects ``low_threshold <= high_threshold``.
37+
It does not check that this condition is satisfied.
38+
39+
Examples
40+
--------
41+
>>> import numpy as np
42+
>>> from ufunclab import hysteresis_relay
43+
>>> x = np.array([-0.2, -0.6, -2, 0.2, 1.2, 2, 0.5, -0.7, -0.2, 0.7])
44+
45+
`x` is the input signal. The lower and upper thresholds
46+
are -0.5 and 0.5, respectively. The low and high output
47+
values are -1 and 1 (except for the initial output, which
48+
is 0, as determined by the last argument of `hysteresis_relay`).
49+
50+
>>> hysteresis_relay(x, -0.5, 0.5, -1, 1, 0)
51+
array([ 0., -1., -1., -1., 1., 1., 1., -1., -1., 1.])
52+
"""
53+
54+
55+
hysteresis_relay_core_source = UFuncSource(
56+
funcname='hysteresis_relay_core',
57+
typesignatures=['ffffff->f', 'dddddd->d', 'gggggg->g'],
58+
)
59+
60+
hysteresis_relay_gufunc = UFunc(
61+
name='hysteresis_relay',
62+
docstring=HYSTERESIS_RELAY_DOCSTRING,
63+
header='hysteresis_relay_gufunc.h',
64+
signature='(n),(),(),(),(),() -> (n)',
65+
sources=[hysteresis_relay_core_source],
66+
)
67+
68+
69+
MODULE_DOCSTRING = """\
70+
This module defines the hysteresis_relay function.
71+
"""
72+
73+
extmod = UFuncExtMod(
74+
module='_hysteresis_relay',
75+
docstring=MODULE_DOCSTRING,
76+
ufuncs=[hysteresis_relay_gufunc],
77+
)

src/hysteresis_relay/hysteresis_relay_gufunc.c.src

-201
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#ifndef HYSTERESIS_RELAY_GUFUNC_H
2+
#define HYSTERESIS_RELAY_GUFUNC_H
3+
4+
#define PY_SSIZE_T_CLEAN
5+
#include "Python.h"
6+
7+
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
8+
#include "numpy/ndarraytypes.h"
9+
10+
#include "../src/util/strided.hpp"
11+
12+
13+
template<typename T>
14+
static void
15+
hysteresis_relay_core(
16+
npy_intp n, // core dimension n
17+
T *p_x, // pointer to first element of x, a strided 1-d array with shape (n,)
18+
const npy_intp x_stride, // stride (in bytes) of x
19+
T *p_low_threshold,
20+
T *p_high_threshold,
21+
T *p_low_value,
22+
T *p_high_value,
23+
T *p_init,
24+
T *p_out, // pointer to out, a strided 1-d array with shape (n,)
25+
const npy_intp out_stride // stride (in bytes) of out
26+
)
27+
{
28+
T low_threshold = *p_low_threshold;
29+
T high_threshold = *p_high_threshold;
30+
T low_value = *p_low_value;
31+
T high_value = *p_high_value;
32+
T init = *p_init;
33+
34+
for (npy_intp k = 0; k < n; ++k) {
35+
T x = get(p_x, x_stride, k);
36+
if (x < low_threshold) {
37+
set(p_out, out_stride, k, low_value);
38+
}
39+
else if (x > high_threshold) {
40+
set(p_out, out_stride, k, high_value);
41+
}
42+
else {
43+
if (k == 0) {
44+
set(p_out, out_stride, k, init);
45+
}
46+
else {
47+
set(p_out, out_stride, k, get(p_out, out_stride, k - 1));
48+
}
49+
}
50+
}
51+
}
52+
53+
#endif

ufunclab/meson.build

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ gufunc_cxx_src_dirs = [
4949
'all_same',
5050
'backlash',
5151
'corr',
52+
'hysteresis_relay',
5253
'mad',
5354
'meanvar',
5455
'minmax',
@@ -192,7 +193,6 @@ numpy_templated_c_gufunc_dirs = [
192193
'cross',
193194
'fillnan1d',
194195
'first',
195-
'hysteresis_relay',
196196
'linear_interp1d',
197197
'means',
198198
'peaktopeak',

0 commit comments

Comments
 (0)