Repository: scipy/scipy

Issue:
BUG: resample_poly does not preserve dtype
### Describe your issue.

When given an input of dtype `np.float32`, the output of resamply_poly has dtype `float64`.


This was previously raised as #9104, but I think incompletely addressed in #9105. I think the fix (and corresponding test) only apply when the window is explicitly constructed by the user as is done in the test here:
https://github.com/scipy/scipy/blob/ce782b6a805b4d98e40ccb444203ddfff4eb74ac/scipy/signal/tests/test_signaltools.py#L1253-L1259

If the window is not explicitly constructed by the user, it is constructed automatically, and apparently always with dtype=float64.  This would result in (unintended) dtype promotion.

Probably the easiest fix here is to match the window dtype to the input signal if it is constructed automatically.

### Reproducing Code Example

```python
import scipy
import numpy as np

x = np.random.randn(22050).astype(np.float32)
y = scipy.signal.resample_poly(x, 2, 1)
```


### Error message

```shell
No error message, but `y.dtype = np.float64`, when I would expect it to match the input (float32).
```


### SciPy/NumPy/Python version information

1.7.1 1.20.3 sys.version_info(major=3, minor=9, micro=7, releaselevel='final', serial=0)
BUG: resample_poly does not preserve dtype
### Describe your issue.

When given an input of dtype `np.float32`, the output of resamply_poly has dtype `float64`.


This was previously raised as #9104, but I think incompletely addressed in #9105. I think the fix (and corresponding test) only apply when the window is explicitly constructed by the user as is done in the test here:
https://github.com/scipy/scipy/blob/ce782b6a805b4d98e40ccb444203ddfff4eb74ac/scipy/signal/tests/test_signaltools.py#L1253-L1259

If the window is not explicitly constructed by the user, it is constructed automatically, and apparently always with dtype=float64.  This would result in (unintended) dtype promotion.

Probably the easiest fix here is to match the window dtype to the input signal if it is constructed automatically.

### Reproducing Code Example

```python
import scipy
import numpy as np

x = np.random.randn(22050).astype(np.float32)
y = scipy.signal.resample_poly(x, 2, 1)
```


### Error message

```shell
No error message, but `y.dtype = np.float64`, when I would expect it to match the input (float32).
```


### SciPy/NumPy/Python version information

1.7.1 1.20.3 sys.version_info(major=3, minor=9, micro=7, releaselevel='final', serial=0)


Discussion:
Thanks @bmcfee. I would not call it a bug, since we don't guarantee anything. But it's a good point. Would you like to make a PR?
> I would not call it a bug, since we don't guarantee anything.

Fair enough, bug looked like the most relevant issue template. :grin: 

Yeah, I can put up a PR for this.

Thanks @bmcfee. I would not call it a bug, since we don't guarantee anything. But it's a good point. Would you like to make a PR?
> I would not call it a bug, since we don't guarantee anything.

Fair enough, bug looked like the most relevant issue template. :grin: 

Yeah, I can put up a PR for this.


Resolving patch:
diff --git a/scipy/signal/signaltools.py b/scipy/signal/signaltools.py
--- a/scipy/signal/signaltools.py
+++ b/scipy/signal/signaltools.py
@@ -3278,7 +3278,8 @@ def resample_poly(x, up, down, axis=0, window=('kaiser', 5.0),
         max_rate = max(up, down)
         f_c = 1. / max_rate  # cutoff of FIR filter (rel. to Nyquist)
         half_len = 10 * max_rate  # reasonable cutoff for sinc-like function
-        h = firwin(2 * half_len + 1, f_c, window=window)
+        h = firwin(2 * half_len + 1, f_c,
+                   window=window).astype(x.dtype)  # match dtype of x
     h *= up
 
     # Zero-pad our filter to put the output samples at the center


Test patch:
diff --git a/scipy/signal/tests/test_signaltools.py b/scipy/signal/tests/test_signaltools.py
--- a/scipy/signal/tests/test_signaltools.py
+++ b/scipy/signal/tests/test_signaltools.py
@@ -1258,6 +1258,14 @@ def test_output_float32(self, padtype):
         y = signal.resample_poly(x, 1, 2, window=h, padtype=padtype)
         assert(y.dtype == np.float32)
 
+    @pytest.mark.parametrize('padtype', padtype_options)
+    @pytest.mark.parametrize('dtype', [np.float32, np.float64])
+    def test_output_match_dtype(self, padtype, dtype):
+        # Test that the dtype of x is preserved per issue #14733
+        x = np.arange(10, dtype=dtype)
+        y = signal.resample_poly(x, 1, 2, padtype=padtype)
+        assert(y.dtype == x.dtype)
+
     @pytest.mark.parametrize(
         "method, ext, padtype",
         [("fft", False, None)]