Skip to content

Commit 7b6ee2e

Browse files
authored
Merge pull request #235 from Sparks29032/nsinterp
Add function for Nyquist-Shannon grid interpolation
2 parents d919fef + b1213b1 commit 7b6ee2e

File tree

4 files changed

+92
-2
lines changed

4 files changed

+92
-2
lines changed

doc/source/examples/resampleexample.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ given enough datapoints.
5858
nickel_resample = wsinterp(grid, nickel_grid, nickel_func)
5959
target_resample = wsinterp(grid, target_grid, target_func)
6060

61-
We can now plot the difference to see that these two functions are quite similar.:
61+
We can now plot the difference to see that these two functions are quite similar.::
6262

6363
plt.plot(grid, target_resample)
6464
plt.plot(grid, nickel_resample)
@@ -78,3 +78,10 @@ given enough datapoints.
7878
In the case of our dataset, our band-limit is ``qmax=25.0`` and our function spans :math:`r \in (0.0, 60.0)`.
7979
Thus, our original grid requires :math:`25.0 * 60.0 / \pi < 478`. Since our grid has :math:`601` datapoints, our
8080
reconstruction was perfect as shown from the comparison between ``Nickel.gr`` and ``NiTarget.gr``.
81+
82+
This computation is implemented in the function ``nsinterp``.::
83+
84+
from diffpy.utils.resampler import nsinterp
85+
qmin = 0
86+
qmax = 25
87+
nickel_resample = (nickel_grid, nickel_func, qmin, qmax)

news/nsinterp.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* Function nsinterp for automatic interpolation onto the Nyquist-Shannon grid.
4+
5+
**Changed:**
6+
7+
* <news item>
8+
9+
**Deprecated:**
10+
11+
* <news item>
12+
13+
**Removed:**
14+
15+
* <news item>
16+
17+
**Fixed:**
18+
19+
* <news item>
20+
21+
**Security:**
22+
23+
* <news item>

src/diffpy/utils/resampler.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,46 @@ def wsinterp(x, xp, fp, left=None, right=None):
7979
return fp_at_x
8080

8181

82+
def nsinterp(xp, fp, qmin=0, qmax=25, left=None, right=None):
83+
"""One-dimensional Whittaker-Shannon interpolation onto the Nyquist-Shannon grid.
84+
85+
Takes a band-limited function fp and original grid xp and resamples fp on the NS grid.
86+
Uses the minimum number of points N required by the Nyquist sampling theorem.
87+
N = (qmax-qmin)(rmax-rmin)/pi, where rmin and rmax are the ends of the real-space ranges.
88+
fp must be finite, and the user inputs qmin and qmax of the frequency-domain.
89+
90+
Parameters
91+
----------
92+
xp: ndarray
93+
The array of known x values.
94+
fp: ndarray
95+
The array of y values associated with xp.
96+
qmin: float
97+
The lower band limit in the frequency domain.
98+
qmax: float
99+
The upper band limit in the frequency domain.
100+
101+
Returns
102+
-------
103+
x: ndarray
104+
The Nyquist-Shannon grid computed for the given qmin and qmax.
105+
fp_at_x: ndarray
106+
The interpolated values at points x. Returns a single float if x is a scalar,
107+
otherwise returns a numpy.ndarray.
108+
"""
109+
# Ensure numpy array
110+
xp = np.array(xp)
111+
rmin = np.min(xp)
112+
rmax = np.max(xp)
113+
114+
nspoints = int(np.round((qmax - qmin) * (rmax - rmin) / np.pi))
115+
116+
x = np.linspace(rmin, rmax, nspoints)
117+
fp_at_x = wsinterp(x, xp, fp)
118+
119+
return x, fp_at_x
120+
121+
82122
def resample(r, s, dr):
83123
"""Resample a PDF on a new grid.
84124

tests/test_resample.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import numpy as np
44
import pytest
55

6-
from diffpy.utils.resampler import wsinterp
6+
from diffpy.utils.resampler import nsinterp, wsinterp
77

88

99
def test_wsinterp():
@@ -30,3 +30,23 @@ def test_wsinterp():
3030
assert np.allclose(fp_at_x[1:-1], fp)
3131
for i in range(len(x)):
3232
assert fp_at_x[i] == pytest.approx(wsinterp(x[i], xp, fp))
33+
34+
35+
def test_nsinterp():
36+
# Create a cosine function cos(2x) for x \in [0, 3pi]
37+
xp = np.linspace(0, 3 * np.pi, 100)
38+
fp = np.cos(2 * xp)
39+
40+
# Want to resample onto the grid {0, pi, 2pi, 3pi}
41+
x = np.array([0, np.pi, 2 * np.pi, 3 * np.pi])
42+
43+
# Get wsinterp result
44+
ws_f = wsinterp(x, xp, fp)
45+
46+
# Use nsinterp with qmin-qmax=4/3
47+
qmin = np.random.uniform()
48+
qmax = qmin + 4 / 3
49+
ns_x, ns_f = nsinterp(xp, fp, qmin, qmax)
50+
51+
assert np.allclose(x, ns_x)
52+
assert np.allclose(ws_f, ns_f)

0 commit comments

Comments
 (0)