I am working to convert this MATLAB code that generates a waveform to Python. For context this is a simulation of band excitation response from an atomic force microscope (not relevant to code error). Here is the MATLAB code
%simulate BE response over a line scan
% define experimental parameters
IO_rate = 4E6; %[samples/sec]
N_pixels = 128; % number of pixels along a line scan
N_points_per_pixel = 2^13; % number of data points per pixel
w1 = 200E3; % lower edge of band
w2 = 400E3; % upper edge of band
noise_level = .1; %add noise to the signal
w_vec = -IO_rate/2: IO_rate/N_points_per_pixel : IO_rate/2-IO_rate/N_points_per_pixel; %frequency vector over a pixel
% vary A, wo, Q, and phase over pixels
p_vec = (0:N_pixels-1)/N_pixels;
A_vec = sin(2*pi*3*p_vec)+2; %amplitude
wo_vec = 250E3 + 100E3*p_vec; %resonance
Q_vec = 100 - 50*p_vec; % Q-factor
phi_vec = sign(p_vec-.5); % phase
% build drive signal, define in the Fourier domain
D_vec = zeros(size(w_vec));
D_vec( ((abs(w_vec)<w2) + (abs(w_vec)>w1)) == 2 ) = 1; % drive bins located within upper and lower band edges
band_ind = find( (((w_vec)<w2) + ((w_vec)>w1)) == 2 );
d_vec = fftshift(ifft(ifftshift(D_vec))); % find drive signal in the time domain
% build response at each pixel
R_mat = zeros(N_pixels,N_points_per_pixel);
r_mat = zeros(N_pixels,N_points_per_pixel);
for k1 = 1 : N_pixels
H_vec = (A_vec(k1).*wo_vec(k1).^2).*exp(1i*phi_vec(k1))./(w_vec.^2 + 1i*wo_vec(k1)*w_vec/Q_vec(k1) - wo_vec(k1).^2); %cantilever transfer function
R_mat(k1,:) = (H_vec.*D_vec); %response of the cantilever in the Fourier domain
%determine response in the time domain (this is a little hokey, but it should work for simulation)
r_mat(k1,:) = fliplr((real((ifft(fftshift(R_mat(k1,:)))))));
end
% build full response in the time domain;
r_vec = reshape(r_mat.',[ 1 N_pixels*N_points_per_pixel]);
% add noise
r_vec = r_vec + noise_level*2*(rand(size(r_vec))-.5);
Here is what I have so far for converting this to python code
#simulate BE response over a line scan
# define experimental parameters
IO_rate = 4E6; #[samples/sec]
N_pixels = 128; # number of pixels along a line scan
N_points_per_pixel = 8192; # number of data points per pixel
w1 = 200E3; # lower edge of band
w2 = 400E3; # upper edge of band
noise_level = .1; #add noise to the signal
w_vec = np.arange(-IO_rate/2, IO_rate/2-IO_rate/N_points_per_pixel + 1, IO_rate/N_points_per_pixel)
# vary A, wo, Q, and phase over pixels
p_vec = np.arange(0, N_pixels-1)/N_pixels
A_vec = np.sin(2*np.pi*3*p_vec)+2 #amplitude
wo_vec = 250E3 + 100E3*p_vec #resonance
Q_vec = 100 - 50*p_vec # Q-factor
phi_vec = np.sign(p_vec-.5) # phase
D_vec = np.zeros(np.size(w_vec))
ind = (abs(w_vec)<w2) & (abs(w_vec)>w1);
D_vec[ind] = 1; #assign those indices to 1.
band_ind = np.nonzero(((w_vec)<w2) & ((w_vec)>w1));
d_vec = np.fft.fftshift(np.fft.ifft(np.fft.ifftshift(D_vec))) #find drive signal in the time domain
R_mat = np.zeros((N_pixels,N_points_per_pixel))
r_mat = np.zeros((N_pixels,N_points_per_pixel))
for k1 in range(1,N_pixels-1):
H_vec = ((A_vec[k1]*wo_vec[k1]**2)*np.exp(1j*phi_vec[k1])/(w_vec**2 + 1j*wo_vec[k1]*w_vec/Q_vec[k1] - wo_vec[k1]**2)); #cantilever transfer function
R_mat[k1,:] = (H_vec*D_vec); #response of the cantilever in the Fourier domain
r_mat[k1,:] = np.fliplr((np.real((np.fft.ifft(np.fft.fftshift(R_mat[k1,:]))))));
After executing the for loop, I get the error
ValueError Traceback (most recent call last)
<ipython-input-63-fd7d23539df1> in <module>()
2 H_vec = ((A_vec[k1]*wo_vec[k1]**2)*np.exp(1j*phi_vec[k1])/(w_vec**2 + 1j*wo_vec[k1]*w_vec/Q_vec[k1] - wo_vec[k1]**2)); #cantilever transfer function
3 R_mat[k1,:] = (H_vec*D_vec); #response of the cantilever in the Fourier domain
----> 4 r_mat[k1,:] = np.fliplr((np.real((np.fft.ifft(np.fft.fftshift(R_mat[k1,:]))))));
<__array_function__ internals> in fliplr(*args, **kwargs)
/usr/local/lib/python3.6/dist-packages/numpy/lib/twodim_base.py in fliplr(m)
93 m = asanyarray(m)
94 if m.ndim < 2:
---> 95 raise ValueError("Input must be >= 2-d.")
96 return m[:, ::-1]
97
ValueError: Input must be >= 2-d.
It was my understanding that numpy.fliplr
was equivalent to fliplr
in MATLAB, is there an alternative I can use to flip the array left to right or some fix for this?
The function np.fliplr
requires a 2-dimensional array. The result of your call to np.fft.ifft
here is a 1-dimensional array whose shape is (8192,)
. Since the argument here is already a single row, try using np.flip()
.
As a bonus for your future consideration, np.flip
works on any specified axis, whereas np.fliplr
works only on rows.