Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scale the real part of complex numpy array

I have a vector of complex numbers (the result of a FFT) and I would like to scale only the real part of the complex numbers by factors in another vector.

Example

cplxarr= np.array([1+2j, 3+1j, 7-2j])
factarr= np.array([.5, .6, .2])
# desired result of cplxarr * factarr :
# np.array([.5+2j 1.8+1j 1.4-2j])

(Yes, it's about human-hearing frequency response in a very specific setting.)
Obviously the multiplication with the vectors as above scales the imaginary parts too.

How do I set up factarr and what operation do I have to do in order to achieve the desired result? If it's possible at all, that is, without separating the real and imaginary parts, scaling the real parts and reassembling as a new complex vector.

like image 259
tzot Avatar asked Feb 18 '23 08:02

tzot


1 Answers

This'll do it:

>>> factarr*cplxarr.real + (1j)*cplxarr.imag
array([ 0.5+2.j,  1.8+1.j,  1.4-2.j])

Not sure if it's the best way though.


It turns out that for me at least (OS-X 10.5.8, python 2.7.3, numpy 1.6.2) This version is about twice as fast as the other version which uses np.vectorize:

>>> from timeit import timeit
>>> timeit('factarr*cplxarr.real+(1j)*cplxarr.imag',setup='from __main__ import factarr,cplxarr')
21.008132934570312
>>> timeit('f(cplxarr.real * factarr, cplxarr.imag)',setup='from __main__ import factarr,cplxarr; import numpy as np; f=np.vectorize(np.complex)')
46.52931499481201

It doesn't seem to make much of a difference between using np.complex and complex provided by python:

>>> timeit('f(cplxarr.real * factarr, cplxarr.imag)',setup='from __main__ import  factarr,cplxarr; import numpy as np; f=np.vectorize(complex)')
44.87726283073425

THE CURRENT LEADER IN THE TIMINGS STANDINGS (proposed by eryksun in the comments below)

>>> timeit.timeit('a = cplxarr.copy(); a.real *= factarr ',setup='from __main__ import factarr,cplxarr')
8.336654901504517

And proof that it works:

>>> a = cplxarr.copy()
>>> a.real *= factarr 
>>> a
array([ 0.5+2.j,  1.8+1.j,  1.4-2.j])

This obviously would be even faster if you wanted to do the operation in place (and could therefore leave the copy off).

like image 199
mgilson Avatar answered Feb 21 '23 00:02

mgilson