I am studying Fourier series and want to plot some of the results in Python. One common function to analyze using Fourier series is the hat function:

The code below shows two different ways that I’ve coded the hat function. One uses numpy, the other uses a custom function hat(x,a,L) that I wrote. The parameter a represents the width of the hat, while L is the overall domain of the function from (-L,L).
I think that the function I wrote is more readable, but I doubt it’s as fast as the numpy piecewise function. But I think the numpy function is pretty ugly.
Is there a better way to write the hat function that is both more readable and fast?
import matplotlib.pyplot as plt
import numpy as np
# defining the hat function parameters, domain
L=-5
a=1
x=np.linspace(-L,L,100)
# using my hat function
y=hat(x,a,L)
plt.plot(x,y,'r')
plt.show()
# numpy hat function - piecewise
y=np.piecewise(x,
[x<-a,(-a<x)&(x<0),x==0,(0<x)&(x<a),a<x],
[0,lambda x:1+x,1,lambda x:1-x,0])
plt.plot(x,y,'r')
plt.show()
# hat function
def hat(x,a,L):
y=x.copy()
y[x<-a]=0
y[(x>-a)&(x<0)]=1+x[(x>-a)&(x<0)]
y[x==0]=1
y[(x>0)&(x<a)]=1-x[(x>0)&(x<a)]
y[x>a]=0
return y
>Solution :
Here’s another solution
def hat(x,a,L):
y=x.copy()
y[(x<-a) | (x>a)]=0
y[(x>-a)&(x<0)]+=1
y[x==a]=1
y[(x>0)&(x<a)]*=-1
y[(x>0)&(x<a)]+=1
return y
in your hat function, you have y[x==a]=1 but in the numpy version you have ,x==0, = ,1,, which are not the same.
_______
Something like this with symmetry
import matplotlib.pyplot as plt
import numpy as np
# defining the hat function parameters, domain
L=5
a=1
x=np.linspace(0,L,51)
# hat function
def hat(x,a,L):
y=x.copy()
y[x==0]=1
y[(x > 0) & (x < a)] *= -1
y[(x > 0) & (x < a)] += 1
y[(x>=a)]=0
y = np.hstack((y[-1:0:-1], y))
return y
# using my hat function
y2=hat(x,a,L)
x=np.linspace(-L,L,101)
# numpy hat function - piecewise
y=np.piecewise(x,
[x<-a,(-a<x)&(x<0),x==0,(0<x)&(x<a),a<x],
[0,lambda x:1+x,1,lambda x:1-x,0])
plt.plot(x,y,'b')
plt.plot(x,y2,'r')
plt.show()
____
you could also use math to compute the y signal and then put some zeros
x=np.linspace(-L,L,101)
y3 = np.zeros(x.shape)
y3[(x>-a)&(x<a)] = -np.abs(x[(x>-a)&(x<a)]) + 1
but it really depend on your case