Skip to content

commited changes that I originally submitted for scipy.signal.cspline… #6553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 7, 2016

Conversation

anielsen001
Copy link
Contributor

…1d_eval cannot return complex results (Trac #1260) #1787. The bspline interpolator can produce complex results, but will only work correctly if the output uses complex values.

I originally made the trac ticket mentioned above. I have the changes implemented in this pull request.

The basic issue is that the bspline interpolator can produce correct complex results, but must use complex coefficients. In order for this to work, the zeros_like function has to be changed because in the case of a complex interpolator the bspline interpolation coefficients are complex while input x-values that are interpolated to may be real. (The zeros_like function operators on the x-values that are interpolated to.)

@@ -322,7 +322,7 @@ def cspline1d_eval(cj, newx, dx=1.0, x0=0):

"""
newx = (asarray(newx) - x0) / float(dx)
res = zeros_like(newx)
res = zeros(newx.shape,dtype=cj.dtype)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to have a space between the arguments here and below

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also zeros_like takes a dtype argument, so that could be

res = zeros_like(newx, dtype=cj.dtype)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are both good suggestions. It appears that zeros_like is a better choice since zeros here because it will attempt to keep the same memory layout as the original which could be more efficient. I made both changes on my fork.

@larsoner
Copy link
Member

larsoner commented Sep 8, 2016

You'll also need to add a test that fails on master but passes on this PR. It can be very simple.

@larsoner larsoner added scipy.signal needs-work Items that are pending response from the author labels Sep 8, 2016
@anielsen001
Copy link
Contributor Author

I added an example of the error and the result with my changes at this gist:
https://gist.github.com/anielsen001/7b1f7686bd3cb9697eedb3b2824d2807

It's clunky test requiring commenting and uncommenting lines. However, the crucial fact can be seen. Without there is a warning about losing the imaginary part and the resulting interpolated values have zero imaging part. After my suggested change the interpolated values retain their imaginary part and reflect the original data.

@larsoner
Copy link
Member

larsoner commented Sep 9, 2016

Can you add a simple test to this PR? Some trivial case is fine as long as it shows the bug properly

@anielsen001
Copy link
Contributor Author

anielsen001 commented Sep 10, 2016

This code block raises a ValueError on the scipy master and does not with my suggested patch. There is also a ComplexWarning issued that the imaginary part has been discarded on the scipy master. I was not sure what format is required for the test (will it become some part of an automatic system?) so if there is a template I should follow please point me toward that.

#!/usr/bin/env python

from scipy.signal import cspline1d
from scipy.signal import cspline1d_eval
#from bspline_change import cspline1d_eval

from numpy import *

from matplotlib.pylab import *

# create some smoothly varying complex signal to try and interpolate
x=arange(100)
y=zeros(x.shape,dtype=complex64)
T=10.0
f=1.0/T
y=sin(2.0*pi*f*x)+1.0J*cos(2.0*pi*f*x)

# get the cspline transform
cy=cspline1d(y)

# determine some xvalues to interpolate
xnew=arange(1.0,10.0,0.001)
ynew=cspline1d_eval(cy,xnew)

if (ynew.imag==0).all():
    raise ValueError,'scipy.signal.cspline1d_eval does not support complex numbers'

@person142
Copy link
Member

@anielsen001 the test would go in

https://github.com/scipy/scipy/blob/master/scipy/signal/tests/test_signaltools.py#L641

That way the test will run as part of the CI build. You can also run all the signal tests locally with python runtests.py -s signal from the top-level scipy directory. I might rewrite the test a bit to be something like:

def test_complex():
    x = np.arange(100)
    T=10.0
    f=1.0/T
    y = np.exp(2.0*np.pi*f*x)
    cy = signal.cspline1d(y)

    xnew = np.arange(1.0, 10.0, 0.001)
    ynew = signal.cspline1d_eval(cy, xnew)

    assert_(np.any(ynew.imag != 0))

Warning: didn't test this code.

@anielsen001
Copy link
Contributor Author

Thank you for the instructions and example. I created a test_complex() function and tested it locally; runs as I expect so I pushed the changes to my fork.

@person142
Copy link
Member

BTW you can check the pep8 stuff locally by installing pep8 (pip install pep8) and running pep8 scipy from the top-level directory. (Apologies if you already knew that.)

y = np.zeros(x.shape, dtype=np.complex64)
T = 10.0
f = 1.0 / T
y = np.sin(2.0 * np.pi * f * x) + \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing y = np.exp(2j*np.pi*f*x) should achieve the same thing. (Mathematically it's off by a factor of -i and a complex conjugation.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're correct. When I originally wrote the test I was trying to verify what was going on with pure real or complex terms so I wrote it up to easily add/remove the imaginary terms.

For the test purposes it does not matter what the input data is, as long as it comes across as complex before the interpolation.

The test code also computes many more values than are necessary to perform the test. I could cut down the test to save computation if that is seen as important.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for using complex exponential instead of cos + sin

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, yes please cut down on the number of points. For a big library like this, cutting test time is important.

@anielsen001
Copy link
Contributor Author

anielsen001 commented Sep 10, 2016

Thank you, I didn't know about using pep8 myself. I installed and ran my own checks.

@larsoner
Copy link
Member

@anielsen001 looks good to me except for my last couple of comments. After making those changes, can you squash your commits? Then we should be good to merge.

when the input data is complex.

Added test_complex() method to test if complex values are properly
returned.
@anielsen001
Copy link
Contributor Author

Thank you for all the comments. I switched to the complex exponential form and the test now uses just a single point which is all that's needed to test for complex value generation.

I learned to squash which was very handy to know.

@larsoner larsoner removed the needs-work Items that are pending response from the author label Sep 13, 2016
@larsoner
Copy link
Member

Thanks @anielsen001. Anybody else want to have a look? If not, I'll go ahead and merge in a few days. @anielsen001 feel free to ping me if I forget.

@anielsen001
Copy link
Contributor Author

@Eric89GXL and @person142 Thank you for your comments and assistance. I'll be glad to provide anything else if needed.

@ev-br ev-br merged commit 1a3f5b0 into scipy:master Oct 7, 2016
@ev-br
Copy link
Member

ev-br commented Oct 7, 2016

thanks @anielsen001 @Eric89GXL @person142

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants