v923z / micropython-ulab

a numpy-like fast vector module for micropython, circuitpython, and their derivatives
https://micropython-ulab.readthedocs.io/en/latest
MIT License
432 stars 117 forks source link

[BUG]: fft.ifft gives incorrect results with complex support #551

Closed A622266 closed 2 years ago

A622266 commented 2 years ago

When printing a complex array, an exception is thrown and the program terminates. The following code runs correctly in CPython. It also appears to run correctly in ulab on my esp32 if the print(z) statement is omitted. If print(z) is replaced by print(t), the array is output as expected, and matches the CPython output for the array t. The output when print(z) is run is included below, showing ulab version and error message.

try:
    import ulab
    from ulab import numpy as np
    from ulab import scipy as spy
    print('version string: ', ulab.__version__)
    print('you are running ulab')

except ImportError:
    import numpy as np
    import scipy as spy
    import matplotlib.pyplot as plt
    print('you are runnning CPython')

def analytic_signal(x):
     N = len(x)
     X = np.fft.fft(x)
     h = np.zeros(N)
     h[0] = 1
     h[1:N//2] = 2*np.ones(N//2-1)
     h[N//2] = 1
     Z = X*h
     z = np.fft.ifft(Z)
     return z

# from analytic_signal import analytic_signal

t = np.linspace(0.0, 0.01, num=2**7)
x = np.sin(2*np.pi*700*t)
z = analytic_signal(x)
print(z)

try:
    plt.subplot(2,1,2)
    plt.plot(t,z.real,'k',label='Real(z[n])')
    plt.plot(t,z.imag,'r',label='Imag(z[n])')
    plt.title('Components of Analytic signal')
    plt.xlabel('n')
    plt.ylabel('z_r[n] and z_i[n]')
    plt.legend()
    plt.show()

except NameError:
    pass

Here is the output: <> version string: 6.0.0-4D-c you are running ulab Guru Meditation Error: Core 0 panic'ed (InstrFetchProhibited). Exception was unhandled. Core 0 register dump: PC : 0xffffffff PS : 0x00060e30 A0 : 0x8013e779 A1 : 0x3ffcde80
A2 : 0x3ffcdeac A3 : 0x3ffe7590 A4 : 0x00000000 A5 : 0x00000000
A6 : 0x3f41a138 A7 : 0x3ffcdea0 A8 : 0x80115a70 A9 : 0x3ffcde60
A10 : 0x3ffcdeac A11 : 0x3ffe7590 A12 : 0x00000000 A13 : 0x3ffcdee0
A14 : 0x00000001 A15 : 0x3ffcdfec SAR : 0x00000002 EXCCAUSE: 0x00000014
EXCVADDR: 0xfffffffc LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0x00000000

ELF file SHA256: ca4ae591a65e13df

Backtrace: 0x7ffffffc:0x3ffcde80 |<-CORRUPTED

Rebooting... ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 load:0x3fff0018,len:4 load:0x3fff001c,len:4252 load:0x40078000,len:11920 load:0x40080400,len:3344 entry 0x4008060c you are runnning CPython you are running ulab MicroPython v1.19.1-528-gb8982ec5f on 2022-10-07; ESP32 module with ESP32 Type "help()" for more information. <>

I also tried to type help() as suggested in the prompt, but there was no further output (I needed to terminate the terminal session).

v923z commented 2 years ago

Thanks for reporting the issue. Here are a couple of comments.

From this it is not clear, whether the issue is with the ifft function, or the complex printout. Could you, please, provide a minimal example that fails? Only ulab, a single statement, no matplotlib, no clutter.

It would also be interesting to know, whether this is tied to 4D, or is a more general problem. Almost all tests are written for the 2D case, and those pass, at least, on the unix port.

Which brings me to the last point: is this something that you experience only on the ESP32, or the unix port also falters?

If the root of an issue is already identified in the bug report, that definitely speeds up the implementation of a fix. Thanks!

A622266 commented 2 years ago
import ulab
from ulab import numpy as np

z = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
X = np.fft.fft(z)
print(X)
z = np.fft.ifft(X)
print(z)

The issue seems to be related to ifft, since X prints okay in the script above, but print(z) exhibits the issue. I'll try re-flashing the ESP32 for 2D. On the unix port, do you mean to build the unix port and flash to ESP32?

A622266 commented 2 years ago

Above also fails in the same way with this version running on ESP32: version string: 6.0.0-2D-c

A622266 commented 2 years ago

print(z) executes from the above script when using the REPL via mpremote. I am using pyboard.py to execute the script when the error occurs

v923z commented 2 years ago

print(z) executes from the above script when using the REPL via mpremote. I am using pyboard.py to execute the script when the error occurs

So, if you print via mpremote, do you get reasonable values from the ifft method?

v923z commented 2 years ago

the ESP32 for 2D. On the unix port, do you mean to build the unix port and flash to ESP32?

No, that definitely won't work. But if you compile the unix port, then you should have a micropython executable under ulab/micropython/ports/unix, which you can then run on your computer, and use ulab as you would on the ESP32. This is also what we use in the gitlab workflow to test the ulab code.

I'm on a windows machine in the next two days, but I could look into this on Friday. I've checked the code, and I don't see anything obvious at the moment.

A622266 commented 2 years ago

So, if you print via mpremote, do you get reasonable values from the ifft method?

No, on closer inspection, the values produced using mpremote REPL don't make sense. The output is all zeros except first value. In CPython, the final values for z are the original values, except in complex form -- which is expected.

I will try the unix port next.

v923z commented 2 years ago

OK, so this is an issue in the ifft function. Thanks for sorting this out. I'll implement a fix in the next couple of days.

A622266 commented 2 years ago

Hi, do you still anticipate a near term fix for this issue?

v923z commented 2 years ago

Yes, I'll try to patch this up. But PRs are always welcome:-)

v923z commented 2 years ago

@A622266 I think https://github.com/v923z/micropython-ulab/pull/557 should fix the issue. My tests passed. Could you, please, report back, if it still doesn't work?

A622266 commented 2 years ago

I tried in my use case, and it works as expected. Thanks! I will continue to use it in my application and will let you know about any issue.

v923z commented 2 years ago

Fixed by https://github.com/v923z/micropython-ulab/pull/557