-1

I am trying to define a function in Python in order to use it later, and there is a problem in using if statement inside of the function. The goal is define the following function for every real argument and, as for special points (where the value is defned by a limit), define it from the condition. So the code is

import numpy as np;

#%% Impulse response of a band pass filter (BPF)

t_0_BPF = 10;
A_fc = 1;
def impulse_responce_BPF(t_var): 
    if t_var == t_0_BPF:
        return 2*A_fc/np.pi
    else:
        return 2*A_fc/np.pi * np.sin (2*np.pi*20/2*(t_var-t_0_BPF) )/(t_var-t_0_BPF) *np.cos(2*np.pi*45*(t_var-t_0_BPF))

I have to add an "if" condition in order to avoid to have "nan" values when t_var = t_0_BPF (sinc funciton).

So when I am trying to use the function when the input is an array, there is a problem.

t = np.zeros(10)
impulse_responce_BPF(t)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[1], line 14
     11         return 2*A_fc/np.pi * np.sin (2*np.pi*20/2*(t_var-t_0_BPF) )/(t_var-t_0_BPF) *np.cos(2*np.pi*45*(t_var-t_0_BPF))
     13 t = np.arange(10);
---> 14 impulse_responce_BPF(t)

Cell In[1], line 8, in impulse_responce_BPF(t_var)
      6 def impulse_responce_BPF(t_var): 
      7     # it is proportional to sin(2 pi deltaF_BW/2 * t) / t *cos(2 pi * F_center)
----> 8     if t_var == t_0_BPF:
      9         return 2*A_fc/np.pi
     10     else:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

I understand that there is a problem in interpreting the logic condition "t_var == t_0_BPF:" which is an array. Anyway, I am interested in using the function in this vectorized way. Is there a way to not having this error? Or to define the function differently.

  • You cannot pass an array to any arbitrary function and then expect Numpy to apply the function element-wise to the array. The function doesn't know anything about Numpy, and it has assumed control of the logic. `if` statements will not work properly with the array. This is an extremely common problem, although the canonicals we have for it are a bit roundabout right now. – Karl Knechtel May 08 '23 at 15:26
  • Ok, thank you, I see. I use it in this way because of MATLAB background and it works normally this way. – Pierre Polovodov May 09 '23 at 08:04

2 Answers2

0

This can be done using np.where() without any if statements.

def impulse_responce_BPF(t_var): 
    return(np.where(t_0_BPF == t_var,
    2*A_fc/np.pi,
    2*A_fc/np.pi * np.sin (2*np.pi*20/2*(t_var-t_0_BPF) )/(t_var-t_0_BPF) *np.cos(2*np.pi*45*(t_var-t_0_BPF))))

np.where(conditional, x, y) returns x where conditional evaluates to True, and y where it evaluates to False.

Original answer, misinterpreting the question:

Changing if t_var == t_0_BPF: to if np.any(t_0_BPF == t_var) accomplishes what you want.

This checks if any of the values in the t_0_BPF array are equal to t_var.

bc1155
  • 263
  • 7
  • Shouldn't it be `np.all` for equality of all elements of the arrays? Or I'm missing something. – B Remmelzwaal May 08 '23 at 12:08
  • The problem if I do so, and say that t = np.arange(11); impulse_responce_BPF(t); It basically finds that there is a value equal to t_0_BPF and assignes one value. The function returns single value 0.64, I would like to have a vector corresponding to t vector – Pierre Polovodov May 08 '23 at 12:10
  • Apologies I misinterpreted the question to start with. Updated the answer with a more suitable solution. – bc1155 May 08 '23 at 12:32
  • Thanks, @bc1155 , it seems to work for me. There is warning that is shown : "RuntimeWarning: invalid value encountered in divide 2*A_fc/np.pi * np.sin (2*np.pi*20/2*(t_var-t_0_BPF) )/(t_var-t_0_BPF) *np.cos(2*np.pi*45*(t_var-t_0_BPF))))" – Pierre Polovodov May 08 '23 at 14:41
  • But it works anyway – Pierre Polovodov May 08 '23 at 14:41
0

Can't you simplify the variable names and the formula definitions , read that was big headache.

I assumed that you need to return an array whose values should be handled in an if else condition base on the input array values. This could have been solved by a simple for loop traversing all the elements and calculating on each element ,then finally return the output array.

so here is the complete code import numpy as np;

#%% Impulse response of a band pass filter (BPF)

t_0_BPF = 10;
A_fc = 1;
def impulse_responce_BPF(t):
    y=t.copy() #create a array to store output values
    for i in range(0,t.shape[0]):#loop for traversing
        t_var=t[i] # define t_var as individual elements
        if t_var == t_0_BPF:
            y[i]= 2*A_fc/np.pi
        else:
            y[i]=(2*A_fc/np.pi
                    * np.sin (2*np.pi*20/2*(t_var-t_0_BPF) )
                    /(t_var-t_0_BPF)
                    *np.cos(2*np.pi*45*(t_var-t_0_BPF)))
    return y

t = np.zeros(10)

def impulse_responce_BPF_v2(t_var): # a pure numpy version without if esle
    lst1=np.where(t_var!=float(t_0_BPF))
    lst2=np.where(t_var==float(t_0_BPF))
    y=t.copy()
    y[lst1]=(2*A_fc/np.pi
       * np.sin (2*np.pi*20/2*(t_var[lst1]-t_0_BPF) )
       /(t_var[lst1]-t_0_BPF)
       *np.cos(2*np.pi*45*(t_var[lst1]-t_0_BPF)))
    y[lst2]=2*A_fc/np.pi
    return y
print(impulse_responce_BPF_v2(t))
Vishnu Balaji
  • 175
  • 1
  • 11
  • Is the loop method slower then vectorization? I mean, afterwards I should calculate a lot and if this method is used, there will be double loops. I basically will convolve this function with other vector. And when I do that it is much slower then if the vectorization is used . – Pierre Polovodov May 08 '23 at 14:21
  • yes it slower because you need to loop through to actually check the if else conditions, if you want speed you can use index slicing from where and slice calculate the array. the key point here is index slicing of numpy works in a similar fashion but using C lang for faster but non flexible data manipulation . the solution also has been updated as a different function – Vishnu Balaji May 08 '23 at 15:23