The documentation you like to says:
In other words, irfft(rfft(a), len(a)) == a to within numerical accuracy.
This is not the case if you do irfft(pk, 8)
! The problem is due the odd samples and the symmetry of the Fourier transform in addition to your padding. Note that there are no problems at all all if len(p)
is odd.
For a better understanding consider this:
>>> p = np.array([1.,2.2,4.,1.])
>>> np.fft.fft(p)
array([ 8.2+0.j , -3.0-1.2j, 1.8+0.j , -3.0+1.2j])
>>> np.fft.fftfreq(len(p))
array([ 0. , 0.25, -0.5 , -0.25]) # 0.5 only occurs once negative
>>> np.fft.rfft(p)
array([ 8.2+0.j , -3.0-1.2j, 1.8+0.j ])
>>> np.fft.rfftfreq(len(p)) # (not available in numpy 1.6.)
array([ 0. , 0.25, 0.5 ]) # 0.5 occurs, here positive, it does not matter
# also consider the odd length FFT
>>> np.fft.fftfreq(len(p)+1)
array([ 0. , 0.2, 0.4, -0.4, -0.2]) # 0.4 is in there twice.
# And consider that this gives the result you expect:
>>> symmetric_p = np.fft.rfft(p)
>>> symmetric_p[-1] /= 2
>>> np.fft.irfft(symmetric_p, 8)[::2]*(8./4.)
array([ 1. , 2.2, 4. , 1. ])
Which means if you look closely. The FFT frequencies calculated are not symmetric if the input samples are even, instead there is an extra negative frequency (which actually could just as well be a positive frequency, since it always has no phase shift).
Because you are padding (for no real reason?) to a different frequency, the RFFT suddenly has extra "room" for this frequency. So if you look at it from the FFT point of view, you add this normally only once occuring negative frequency also as a positive frequency (which basically means it goes in double). If you look above the symmetric_p
halving this frequency gives the expected result with padding (it will not give the expected result without padding).