Kris Jensen
Kris Jensen

Reputation: 23

vectorize a function with multiple inputs to form a unique function

I have a function that takes this form:

def signal_prototype(t, A, f, p):
    return A*np.sin(2*np.pi*f*t+p)

I would like to vectorize this so that I can use the function as follows.

signal_A = SOME_VECTORIZE_FUNCTION(signal_prototype, t=t, A=1, f=10000, p=0)
signal_B = SOME_VECTORIZE_FUNCTION(signal_prototype, t=t, A=1, f=10000, p=np.pi/4)
signal_C = SOME_VECTORIZE_FUNCTION(signal_prototype, t=t, A=1, f=10000, p=np.pi/2)
signal_D = SOME_VECTORIZE_FUNCTION(signal_prototype, t=t, A=1, f=10000, p=3*np.pi/4)

t = np.linspace(0,1e-3,100000)
X1 = signal_A(t)
X2 = signal_B(t)
X3 = signal_C(t)
X4 = signal_D(t)

Thank you!

I tried using np.vectorize and reading the documentation. There does not appear to be any way to send in static arguments to vectorize.

However, vectorize might not be the best tool for this.

I have a complicated set of differential equations that these signals are an input for. So, I need the functions in the form f(t,x).

The new signal functions are created dynamically as conditions in the model change. So, creating a static version of each equation is not a good option.

Upvotes: 1

Views: 79

Answers (2)

Kris Jensen
Kris Jensen

Reputation: 23

The answers above really helped me figure out what I needed to do.

X1 = partial(signal_prototype, A=1e-3, f=1e3, p=0)
X2 = partial(signal_prototype, A=1e-3, f=1e3, p=np.pi/4)
X3 = partial(signal_prototype, A=1e-3, f=1e3, p=np.pi/2)
X4 = partial(signal_prototype, A=1e-3, f=1e3, p=3*np.pi/4)

now I have my functions that can be called like this.

X1(t)
X2(t)
etc...

Upvotes: 0

ti7
ti7

Reputation: 18930

np.sin() is already vectorized in that it will work on an array

>>> np.sin(np.array([1,2,3]))
array([0.84147098, 0.90929743, 0.14112001])

You can directly call your functions instead

def signal_prototype(t, A, f, p):
    return A*np.sin(2*np.pi*f*t+p)

t = np.linspace(0,1e-3,100000)

X1 = signal_prototype(t=t, A=1, f=10000, p=0)
X2 = signal_prototype(t=t, A=1, f=10000, p=np.pi/4)
X3 = signal_prototype(t=t, A=1, f=10000, p=np.pi/2)
X4 = signal_prototype(t=t, A=1, f=10000, p=3*np.pi/4)

If you want to create a single function for each, you could use lambda or functools.partial as suggested

signal_A = lambda t: signal_prototype(t=t, A=1, f=10000, p=0)
signal_B = lambda t: signal_prototype(t=t, A=1, f=10000, p=np.pi/4)
signal_C = lambda t: signal_prototype(t=t, A=1, f=10000, p=np.pi/2)
signal_D = lambda t: signal_prototype(t=t, A=1, f=10000, p=3*np.pi/4)

X1 = signal_A(t)
X2 = signal_B(t)
X3 = signal_C(t)
X4 = signal_D(t)

Or just return the partial function yourself (effectively the same as lambda)

def wrapper(func, **kwargs):
    def wrapped(t):
        return func(t, **kwargs)            
    return wrapped

signal_A = wrapper(signal_prototype, A=1, f=10000, p=0)
signal_B = wrapper(signal_prototype, A=1, f=10000, p=np.pi/4)
signal_C = wrapper(signal_prototype, A=1, f=10000, p=np.pi/2)
signal_D = wrapper(signal_prototype, A=1, f=10000, p=3*np.pi/4)

You can extend this if you want to pass a default t or make it optinonal, though I can't advise doing so and just have it to illustrate how powerful this is as it's never advisable to return things with different types (such as imo a function with a variable number of arguments)

do not do this

def wrapper(func, t=None, **kwargs):
    if t is not None:
        def wrapped(t=t):
            return func(t, **kwargs)
    else:
        def wrapped(t):
            return func(t, **kwargs)
    return wrapped
>>> wrapper(signal_prototype, A=1, f=10000, p=0)(t)
array([ 0.00000000e+00,  6.28324773e-04,  1.25664930e-03, ...,
       -1.25664930e-03, -6.28324773e-04, -2.44929360e-15])
>>> wrapper(signal_prototype, t=t, A=1, f=10000, p=0)()
array([ 0.00000000e+00,  6.28324773e-04,  1.25664930e-03, ...,
       -1.25664930e-03, -6.28324773e-04, -2.44929360e-15])

Upvotes: 0

Related Questions