Related
I am used to make my discrete time control systems simulations in Matlab and now I'm trying python and numpy.
So, my code bellow is working, but I would like to iterate over the numpy vector instead appending values into a list. Is it possible?
In other words, instead of using
xl.append(xt)
ul.append(uc)
I would like to use some Matlab equivalent like x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*uc, but it's not working on my code. If I do that, instead of obtaining a two line column vector that is the expected, I got a 2x2 matrix and an error.
Another question: Why it's neccessary to use plt.plot(tk, u[:, 0], label='u') instead plt.plot(tk, u, label='u') ?
from control.matlab import *
import math
import numpy as np
import matplotlib.pyplot as plt
Ts = 0.1
N = 50
#x = np.zeros((2, N+1))
tk = np.zeros(N)
u = np.zeros(N)
v = np.random.randn(N)/86.6 #% measurement noise
wn = 1.12
wn2 = pow(wn, 2)
A = [[0, 1], [-1.5, -1.4]]
B = [[0], [1.5]]
C = [[1, 0]]
D = 0
# Control gains
K = np.array([2.64, 3.41071429])
# Now build a feedback with control law u = -K*x
Ad = np.eye(2) + np.multiply(A, Ts)
Bd = np.multiply(B, Ts)
Cd = C
xt = [[1.0], [0.12]] # initial states
xl = []
ul = []
for k in range(0, N):
tk[k] = k*Ts
uc = -K.dot(xt)
xt = np.dot(Ad, xt) + Bd*uc
xt[1, 0] += v[k]
xl.append(xt)
ul.append(uc)
x = np.array(xl)
u = np.array(ul)
#x = np.delete(x, N, 1) # delete the last position of x
#s = TransferFunction.s
#Gs = wn2/(s**2 + 0*s + wn2) # This is the KF solution
#yout, T = step(Gs)
plt.rcParams["figure.figsize"] = (10, 7)
plt.figure()
#plt.plot(T, yout, label='Open loop')
plt.plot(tk, x[:, 0], label='x_0')
plt.plot(tk, x[:, 1], label='x_1')
plt.plot(tk, u[:, 0], label='u')
plt.legend()
plt.title('Pendulum ex. 7.14 Franklin book')
plt.xlabel('Time')
plt.ylabel('amp.')
plt.show()
what I want is the code like this:
from control.matlab import *
import math
import numpy as np
import matplotlib.pyplot as plt
Ts = 0.1
N = 50
x = np.zeros((2, N+1))
tk = np.zeros(N)
u = np.zeros(N)
v = np.random.randn(N)/86.6 #% measurement noise
wn = 1.12
wn2 = pow(wn, 2)
A = [[0, 1], [-1.5, -1.4]]
B = [[0], [1.5]]
C = [[1, 0]]
D = 0
# Control gains
K = np.array([2.64, 3.41071429])
# Now build a feedback with control law u = -K*x
Ad = np.eye(2) + np.multiply(A, Ts)
Bd = np.multiply(B, Ts)
Cd = C
for k in range(0, N):
tk[k] = k*Ts
u[k] = -K.dot(x[:, k])
x[1, k] += v[k]
x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*u[k]
x = np.delete(x, N, 1) # delete the last position of x
#s = TransferFunction.s
#Gs = wn2/(s**2 + 0*s + wn2) # This is the KF solution
#yout, T = step(Gs)
plt.rcParams["figure.figsize"] = (10, 7)
plt.figure()
#plt.plot(T, yout, label='Open loop')
plt.plot(tk, x[:, 0], label='x_0')
plt.plot(tk, x[:, 1], label='x_1')
plt.plot(tk, u[:, 0], label='u')
plt.legend()
plt.title('Pendulum ex. 7.14 Franklin book')
plt.xlabel('Time')
plt.ylabel('amp.')
plt.show()
But it results in a following error:
Traceback (most recent call last):
File "C:\Users\ ... \np_matrices_v1.py", line 46, in <module>
x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*u[k]
ValueError: could not broadcast input array from shape (2,2) into shape (2,)
I don't know why, but if you try:
A = np.array([[1, 2], [2, 3]])
x = np.array([[0.5], [2.0]])
y = A.dot(x)
print(y)
xa = np.zeros((2, 10))
xa[:, 2] = A.dot(x)
You'll get:
Traceback (most recent call last):
File "C:\Users\eletr\.spyder-py3\temp.py", line 19, in <module>
xa[:, 2] = A.dot(x)
ValueError: could not broadcast input array from shape (2,1) into shape (2,)
But if you do:
import numpy as np
A = np.array([[1, 2], [2, 3]])
x = np.array([[0.5], [2.0]])
y = A.dot(x)
print(y)
xa = np.zeros((2, 10))
# xa[:, 2] = A.dot(x)
xa[:, [2]] = A.dot(x)
print(xa)
You'll get the correct answer:
[[4.5]
[7. ]]
[[0. 0. 4.5 0. 0. 0. 0. 0. 0. 0. ]
[0. 0. 7. 0. 0. 0. 0. 0. 0. 0. ]]
Can anyone explain it?
In [248]: A = np.array([[1, 2], [2, 3]])
...: x = np.array([[0.5], [2.0]])
In [249]: A.shape, x.shape
Out[249]: ((2, 2), (2, 1))
In [250]: y = A.dot(x)
In [251]: y.shape
Out[251]: (2, 1)
Note the shapes. x is (2,1), and as a result y is too. y can be assigned to a (2,1) slot, but not a (2,) shape.
In [252]: xa = np.zeros((2,5),int)
In [253]: xa
Out[253]:
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
In [254]: xa[:,2]
Out[254]: array([0, 0]) # (2,) shape
In [255]: xa[:,[2]]
Out[255]:
array([[0], # (2,1) shape
[0]])
In contrast to MATLAB numpy arrays can be 1d, e.g. (2,). Also leading dimensions are the outermost, as opposed to trailing. MATLAB readily reduces a (2,3,1) shape to (2,3), but a (2,1,1) only becomes (2,1).
broadcasting the way numpy uses arrays that can differ in shape. The two basic rules are that
- leading size 1 dimensions can added automatically to match
- size 1 dimensions can be adjusted to match
Thus a (2,) can become a (1,2).
If you remove the inner [] from x, you get a 1d array:
In [256]: x = np.array([0.5, 2.0])
In [257]: x.shape
Out[257]: (2,)
In [258]: A.dot(x)
Out[258]: array([4.5, 7. ]) # (2,) shape
This can then be assigned to a row of xa: xa[:,2] = A.dot(x)
reshape and ravel can be used to remove dimensions. Also indexing A.dot(x)[:,0]
I have an image and a mask. Both are numpy array. I get the mask through GraphSegmentation (cv2.ximgproc.segmentation), so the area isn't rectangle, but not divided. I'd like to get a rectangle just the size of masked area, but I don't know the efficient way.
In other words, unmasked pixels are value of 0 and masked pixels are value over 0, so I want to get a rectangle where...
top = the smallest index of axis 0 whose value > 0
bottom = the largest index of axis 0 whose value > 0
left = the smallest index axis 1 whose value > 0
right = the largest index axis 1 whose value > 0
image = src[top : bottom, left : right]
My code is below
segmentation = cv2.ximgproc.segmentation.createGraphSegmentation()
src = cv2.imread('image_file')
segment = segmentation.processImage(src)
for i in range(np.max(segment)):
dst = np.array(src)
dst[segment != i] = 0
cv2.imwrite('output_file', dst)
If you prefer pure Numpy, you can achieve this using np.where and np.meshgrid:
i, j = np.where(mask)
indices = np.meshgrid(np.arange(min(i), max(i) + 1),
np.arange(min(j), max(j) + 1),
indexing='ij')
sub_image = image[indices]
np.where returns a tuple of arrays specifying, pairwise, the indices in each axis for each non-zero element of mask. We then create arrays of all the row and column indices we will want using np.arange, and use np.meshgrid to generate two grid-shaped arrays that index the part of the image we're interested in. Note that we specify matrix-style indexing using index='ij' to avoid having to transpose the result (the default is Cartesian-style indexing).
Essentially, meshgrid constructs indices so that:
image[indices][a, b] == image[indices[0][a, b], indices[1][a, b]]
Example
Start with the following:
>>> image = np.arange(12).reshape((4, 3))
>>> image
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
Let's say we want to extract the [[3,4],[6,7]] sub-matrix, which is the bounding rectangle for the the following mask:
>>> mask = np.array([[0,0,0],[0,1,0],[1,0,0],[0,0,0]])
>>> mask
array([[0, 0, 0],
[0, 1, 0],
[1, 0, 0],
[0, 0, 0]])
Then, applying the above method:
>>> i, j = np.where(mask)
>>> indices = np.meshgrid(np.arange(min(i), max(i) + 1), np.arange(min(j), max(j) + 1), indexing='ij')
>>> image[indices]
array([[3, 4],
[6, 7]])
Here, indices[0] is a matrix of row indices, while indices[1] is the corresponding matrix of column indices:
>>> indices[0]
array([[1, 1],
[2, 2]])
>>> indices[1]
array([[0, 1],
[0, 1]])
I think using np.amax and np.amin and cropping the image is much faster.
i, j = np.where(mask)
indices = np.meshgrid(np.arange(min(i), max(i) + 1),
np.arange(min(j), max(j) + 1),
indexing='ij')
sub_image = image[indices]
Time taken: 50 msec
where = np.array(np.where(mask))
x1, y1 = np.amin(where, axis=1)
x2, y2 = np.amax(where, axis=1)
sub_image = image[x1:(x2+1), y1:(y2+1)]
Time taken: 5.6 msec
I don't get Hans's results when running the two methods (using NumPy 1.18.5). In any case, there is a much more efficient method, where you take the arg-max along each dimension
i, j = np.where(mask)
y, x = np.meshgrid(
np.arange(min(i), max(i) + 1),
np.arange(min(j), max(j) + 1),
indexing="ij",
)
Took 38 ms
where = np.array(np.where(mask))
y1, x1 = np.amin(where, axis=1)
y2, x2 = np.amax(where, axis=1) + 1
sub_image = image[y1:y2, x1:x2]
Took 35 ms
maskx = np.any(mask, axis=0)
masky = np.any(mask, axis=1)
x1 = np.argmax(maskx)
y1 = np.argmax(masky)
x2 = len(maskx) - np.argmax(maskx[::-1])
y2 = len(masky) - np.argmax(masky[::-1])
sub_image = image[y1:y2, x1:x2]
Took 2 ms
Timings script
I am a noobie to python and numpy (and programming in general). I am trying to speed up my code as much as possible. The math involves several summations over multiple axes of a few arrays. I've attained one level of vectorization, but I can't seem to get any deeper than that and have to resort to for loops (I believe there's three levels of recursion, M, N, and I, one of which I've eliminated, I). Here's my code for the relevant section (this code works, but I'd like to speed it up):
def B1(n, i):
return np.pi * n * dmaxi * (-1)**(n+1) * np.sin(qi[i]*dmaxi) * ((np.pi*n)**2 - (qi[i]*dmaxi)**2)**(-1)
for n in N:
B[n, :] = B1(n, I)
for m in M:
for n in N:
C[m, n] = np.dot((1/np.square(qi*Iq[0, :, 2]))*B[m, :], B[n, :])
Y[m] = np.dot((1/np.square(qi*Iq[0, :, 2]))*U[0, :, 1], B[m, :])
A = np.linalg.solve(C[1:, 1:], (0.25)*Y[1:])
dmaxi is just a float and m, n and i are integers. The arrays have the following shapes:
>>> qi.shape
(551,)
>>> N.shape
(18,)
>>> M.shape
(18,)
>>> I.shape
(551,)
>>> Iq.shape
(1, 551, 3)
>>> U.shape
(1, 551, 3)
As you can see I've vectorized the calculation of the 2nd axis of B, but I can't seem to do it for the 1st axis, C, and Y, which still require the for loops. It seems that when I try to do the same form of vectorization that I did for the 1st axis of B (define a function, then give the array as the argument), I get a broadcasting error since it appears to be trying to calculate both axes simultaneously, rather than the 1st, then the 2nd, which is why I had to force it into a for loop instead. The same problem occurs for both C and Y which is why they're both in for loops also. In case that's confusing, essentially what I tried was:
>>> B[:, :] = B1(N, I)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "sasrec_v6.py", line 155, in B1
return np.pi * n * dmaxi * (-1)**(n+1) * np.sin(qi[i]*dmaxi) * ((np.pi*n)**2 - (qi[i]*dmaxi)**2)**(-1)
ValueError: operands could not be broadcast together with shapes (18) (551)
Vectorizing the 2nd axis of B made a substantial improvement to the speed of my code, so I'm assuming that the same will apply for further vectorization (I hope I'm using that term correctly by the way).
You can use broadcasting to make 2d arrays from your 1d index vectors. I haven't tested these yet, but they should work:
If you reshape the N to be a column vector, then B1 will return a 2d array:
B[N] = B1(N[:, None], I)
For Y and C, I'd use np.einsum to have better control over which axes are mulitplied (probably this could be done with np.dot as well but I'm not sure how.
C[M[:, None], N] = np.einsum('ij,kj->ik',
B[M]/np.square(qi*Iq[0, :, 2]),
B[N])
Y[M] = np.einsum('i, ki->k',
U[0, :, 1]/np.square(qi*Iq[0, :, 2]),
B[M])
To see what that indexing trick does:
In [1]: a = np.arange(3)
In [2]: a
Out[2]: array([0, 1, 2])
In [3]: a[:, None]
Out[3]:
array([[0],
[1],
[2]])
In [4]: b = np.arange(4,1,-1)
In [5]: b
Out[5]: array([4, 3, 2])
In [6]: a[:, None] * b
Out[6]:
array([[0, 0, 0],
[4, 3, 2],
[8, 6, 4]])
It saves two orders of magnitude in time:
In [92]: %%timeit
....: B = np.zeros((18, 551))
....: C = np.zeros((18, 18))
....: Y = np.zeros((18))
....: for n in N:
....: B[n, :] = B1(n, I)
....: for m in M:
....: for n in N:
....: C[m, n] = np.dot((1/np.square(qi*Iq[0, :, 2]))*B[m, :], B[n, :])
....: Y[m] = np.dot((1/np.square(qi*Iq[0, :, 2]))*U[0, :, 1], B[m, :])
....:
100 loops, best of 3: 15.8 ms per loop
In [93]: %%timeit
....: Bv = np.zeros((18, 551))
....: Cv = np.zeros((18, 18))
....: Yv = np.zeros((18))
....: Bv[N] = B1(N[:, None], I)
....: Cv[M[:, None], N] = np.einsum('ij,kj->ik', B[M]/np.square(qi*Iq[0, :, 2]), B[N])
....: Yv[M] = np.einsum('i, ki->k', U[0, :, 1]/np.square(qi*Iq[0, :, 2]), B[M])
....:
1000 loops, best of 3: 1.34 ms per loop
Here's my test:
import numpy as np
# make fake data:
np.random.seed(5)
qi = np.random.rand(551)
N = np.random.randint(0,18,18)#np.arange(18)
M = np.random.randint(0,18,18)#np.arange(18)
I = np.arange(551)
Iq = np.random.rand(1, 551, 3)
U = np.random.rand(1, 551, 3)
B = np.zeros((18, 551))
C = np.zeros((18, 18))
Y = np.zeros((18))
Bv = np.zeros((18, 551))
Cv = np.zeros((18, 18))
Yv = np.zeros((18))
dmaxi = 1.
def B1(n, i):
return np.pi * n * dmaxi * (-1)**(n+1) * np.sin(qi[i]*dmaxi) * ((np.pi*n)**2 - (qi[i]*dmaxi)**2)**(-1)
for n in N:
B[n, :] = B1(n, I)
for m in M:
for n in N:
C[m, n] = np.dot((1/np.square(qi*Iq[0, :, 2]))*B[m, :], B[n, :])
Y[m] = np.dot((1/np.square(qi*Iq[0, :, 2]))*U[0, :, 1], B[m, :])
Bv[N] = B1(N[:, None], I)
print "B correct?", np.allclose(Bv, B)
# np.einsum test case:
n, m = 2, 3
a = np.arange(n*m).reshape(n,m)*8 + 2
b = np.arange(n*m)[::-1].reshape(n,m)
c = np.empty((n,n))
for i in range(n):
for j in range(n):
c[i,j] = np.dot(a[i],b[j])
cv = np.einsum('ij,kj->ik', a, b)
print "einsum test successful?", np.allclose(c,cv)
Cv[M[:, None], N] = np.einsum('ij,kj->ik',
B[M]/np.square(qi*Iq[0, :, 2]),
B[N])
print "C correct?", np.allclose(Cv, C)
Yv[M] = np.einsum('i, ki->k',
U[0, :, 1]/np.square(qi*Iq[0, :, 2]),
B[M])
print "Y correct?", np.allclose(Yv, Y)
output :D
B correct? True
einsum test successful? True
C correct? True
Y correct? True
I have the following function defined:
def eigval(matrix):
a = matrix[0, 0]
b = matrix[0, 1]
c = matrix[1, 0]
d = matrix[1, 1]
c1 = (a + d) + sqrt((4 * b * c) + ((a - d)**2))
c2 = (a + d) - sqrt((4 * b * c) + ((a - d)**2))
return c1 / 2, c2 / 2
It is created to find the eigenvalues of a 2 X 2 matrix. I am using it to iteratively run the Jacobi algorithm on a matrix. The matrix passed in is a dictionary that uses tuples as keys to represent the position and floats as values. This function will work fine for about 6 iterations, but then I will get a:
TypeError: __getitem__() takes exactly 2 arguments (2 given)
on the first line of the block (the one with the a).
I am completely confused by this because like I said, it works fine for about 6 runs and then stops.
EDIT: Here's a function that creates the kind of matrix I would pass in:
(Given that the matrix will be different for each iteration)
def create():
matrix = {}
matrix[0, 0] = 2
matrix[0, 1] = 1
matrix[1, 0] = 1
matrix[1, 1] = 2
return matrix
Any help is greatly appreciated! (P.S. first post here)
Your matrix is a dict using tuples as keys, this is probably not what you want to do.
Try using nested lists:
from math import sqrt
def create():
matrix = [[1, 2], [1, 2]]
return matrix
def eigval(matrix):
a = matrix[0][0]
b = matrix[1][0]
c = matrix[0][1]
d = matrix[1][1]
c1 = (a + d) + sqrt((4 * b * c) + ((a - d)**2))
c2 = (a + d) - sqrt((4 * b * c) + ((a - d)**2))
return [c1 / 2, c2 / 2]
>>> m = create()
>>> eigval(m)
[3.0, 0.0]
Or alternatively use numpy:
import numpy
def eigval(matrix):
a = matrix[0, 0]
b = matrix[1, 0]
c = matrix[0, 1]
d = matrix[1, 1]
c1 = (a + d) + sqrt((4 * b * c) + ((a - d)**2))
c2 = (a + d) - sqrt((4 * b * c) + ((a - d)**2))
return numpy.array([c1 / 2, c2 / 2])
>>> m = numpy.array([[1, 2], [1, 2]])
>>> m
array([[1, 2],
[1, 2]])
>>> eigvalues, eigvectors = numpy.linalg.eig(m)
>>> eigvalues
array([ 0., 3.])
>>> eigval(m)
array([ 3., 0.])
I need the Python / Numpy equivalent of Matlab (Octave) discrete Laplacian operator (function) del2(). I tried couple Python solutions, none of which seem to match the output of del2. On Octave I have
image = [3 4 6 7; 8 9 10 11; 12 13 14 15;16 17 18 19]
del2(image)
this gives the result
0.25000 -0.25000 -0.25000 -0.75000
-0.25000 -0.25000 0.00000 0.00000
0.00000 0.00000 0.00000 0.00000
0.25000 0.25000 0.00000 0.00000
On Python I tried
import numpy as np
from scipy import ndimage
import scipy.ndimage.filters
image = np.array([[3, 4, 6, 7],[8, 9, 10, 11],[12, 13, 14, 15],[16, 17, 18, 19]])
stencil = np.array([[0, 1, 0],[1, -4, 1], [0, 1, 0]])
print ndimage.convolve(image, stencil, mode='wrap')
which gives the result
[[ 23 19 15 11]
[ 3 -1 0 -4]
[ 4 0 0 -4]
[-13 -17 -16 -20]]
I also tried
scipy.ndimage.filters.laplace(image)
That gives the result
[[ 6 6 3 3]
[ 0 -1 0 -1]
[ 1 0 0 -1]
[-3 -4 -4 -5]]
So none of the outputs seem to match eachother. Octave code del2.m suggests that it is a Laplacian operator. Am I missing something?
Maybe you are looking for scipy.ndimage.filters.laplace().
You can use convolve to calculate the laplacian by convolving the array with the appropriate stencil:
from scipy.ndimage import convolve
stencil= (1.0/(12.0*dL*dL))*np.array(
[[0,0,-1,0,0],
[0,0,16,0,0],
[-1,16,-60,16,-1],
[0,0,16,0,0],
[0,0,-1,0,0]])
convolve(e2, stencil, mode='wrap')
Based on the code here
http://cns.bu.edu/~tanc/pub/matlab_octave_compliance/datafun/del2.m
I attempted to write a Python equivalent. It seems to work, any feedback will be appreciated.
import numpy as np
def del2(M):
dx = 1
dy = 1
rows, cols = M.shape
dx = dx * np.ones ((1, cols - 1))
dy = dy * np.ones ((rows-1, 1))
mr, mc = M.shape
D = np.zeros ((mr, mc))
if (mr >= 3):
## x direction
## left and right boundary
D[:, 0] = (M[:, 0] - 2 * M[:, 1] + M[:, 2]) / (dx[:,0] * dx[:,1])
D[:, mc-1] = (M[:, mc - 3] - 2 * M[:, mc - 2] + M[:, mc-1]) \
/ (dx[:,mc - 3] * dx[:,mc - 2])
## interior points
tmp1 = D[:, 1:mc - 1]
tmp2 = (M[:, 2:mc] - 2 * M[:, 1:mc - 1] + M[:, 0:mc - 2])
tmp3 = np.kron (dx[:,0:mc -2] * dx[:,1:mc - 1], np.ones ((mr, 1)))
D[:, 1:mc - 1] = tmp1 + tmp2 / tmp3
if (mr >= 3):
## y direction
## top and bottom boundary
D[0, :] = D[0,:] + \
(M[0, :] - 2 * M[1, :] + M[2, :] ) / (dy[0,:] * dy[1,:])
D[mr-1, :] = D[mr-1, :] \
+ (M[mr-3,:] - 2 * M[mr-2, :] + M[mr-1, :]) \
/ (dy[mr-3,:] * dx[:,mr-2])
## interior points
tmp1 = D[1:mr-1, :]
tmp2 = (M[2:mr, :] - 2 * M[1:mr - 1, :] + M[0:mr-2, :])
tmp3 = np.kron (dy[0:mr-2,:] * dy[1:mr-1,:], np.ones ((1, mc)))
D[1:mr-1, :] = tmp1 + tmp2 / tmp3
return D / 4
# Laplacian operator (2nd order cetral-finite differences)
# dx, dy: sampling, w: 2D numpy array
def laplacian(dx, dy, w):
""" Calculate the laplacian of the array w=[] """
laplacian_xy = np.zeros(w.shape)
for y in range(w.shape[1]-1):
laplacian_xy[:, y] = (1/dy)**2 * ( w[:, y+1] - 2*w[:, y] + w[:, y-1] )
for x in range(w.shape[0]-1):
laplacian_xy[x, :] = laplacian_xy[x, :] + (1/dx)**2 * ( w[x+1,:] - 2*w[x,:] + w[x-1,:] )
return laplacian_xy