From decc6013c22434feb9b31cbe38ff9234c23950c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Sat, 27 Jan 2024 23:39:30 +0100 Subject: [PATCH] re-work spectrogram method, so that RAM can be re-used --- code/numpy/fft/fft.c | 14 +-- code/numpy/fft/fft_tools.c | 47 +++------ code/numpy/fft/fft_tools.h | 5 +- code/ulab.c | 2 +- code/utils/utils.c | 192 ++++++++++++++++++++++++++++++++++--- docs/ulab-convert.ipynb | 49 ++++++++-- docs/ulab-intro.ipynb | 15 +-- 7 files changed, 249 insertions(+), 75 deletions(-) diff --git a/code/numpy/fft/fft.c b/code/numpy/fft/fft.c index 42621f52..81684d58 100644 --- a/code/numpy/fft/fft.c +++ b/code/numpy/fft/fft.c @@ -5,7 +5,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019-2021 Zoltán Vörös + * Copyright (c) 2019-2024 Zoltán Vörös * 2020 Scott Shawcroft for Adafruit Industries * 2020 Taku Fukada */ @@ -43,16 +43,16 @@ //| #if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE static mp_obj_t fft_fft(mp_obj_t arg) { - return fft_fft_ifft_spectrogram(arg, FFT_FFT); + return fft_fft_ifft(arg, FFT_FFT); } MP_DEFINE_CONST_FUN_OBJ_1(fft_fft_obj, fft_fft); #else static mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) { if(n_args == 2) { - return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_FFT); + return fft_fft_ifft(n_args, args[0], args[1], FFT_FFT); } else { - return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_FFT); + return fft_fft_ifft(n_args, args[0], mp_const_none, FFT_FFT); } } @@ -71,7 +71,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft); #if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE static mp_obj_t fft_ifft(mp_obj_t arg) { - return fft_fft_ifft_spectrogram(arg, FFT_IFFT); + return fft_fft_ifft(arg, FFT_IFFT); } MP_DEFINE_CONST_FUN_OBJ_1(fft_ifft_obj, fft_ifft); @@ -79,9 +79,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(fft_ifft_obj, fft_ifft); static mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) { NOT_IMPLEMENTED_FOR_COMPLEX() if(n_args == 2) { - return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_IFFT); + return fft_fft_ifft(n_args, args[0], args[1], FFT_IFFT); } else { - return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_IFFT); + return fft_fft_ifft(n_args, args[0], mp_const_none, FFT_IFFT); } } diff --git a/code/numpy/fft/fft_tools.c b/code/numpy/fft/fft_tools.c index 04c0b2f7..bc98b3d3 100644 --- a/code/numpy/fft/fft_tools.c +++ b/code/numpy/fft/fft_tools.c @@ -5,7 +5,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019-2021 Zoltán Vörös + * Copyright (c) 2019-2024 Zoltán Vörös */ #include @@ -45,7 +45,7 @@ imag[i] = data[2i+1] */ -void fft_kernel_complex(mp_float_t *data, size_t n, int isign) { +void fft_kernel(mp_float_t *data, size_t n, int isign) { size_t j, m, mmax, istep; mp_float_t tempr, tempi; mp_float_t wtemp, wr, wpr, wpi, wi, theta; @@ -94,9 +94,9 @@ void fft_kernel_complex(mp_float_t *data, size_t n, int isign) { /* * The following function is a helper interface to the python side. * It has been factored out from fft.c, so that the same argument parsing - * routine can be called from scipy.signal.spectrogram. + * routine can be called from utils.spectrogram. */ -mp_obj_t fft_fft_ifft_spectrogram(mp_obj_t data_in, uint8_t type) { +mp_obj_t fft_fft_ifft(mp_obj_t data_in, uint8_t type) { if(!mp_obj_is_type(data_in, &ulab_ndarray_type)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("FFT is defined for ndarrays only")); } @@ -134,20 +134,10 @@ mp_obj_t fft_fft_ifft_spectrogram(mp_obj_t data_in, uint8_t type) { } data -= 2 * len; - if((type == FFT_FFT) || (type == FFT_SPECTROGRAM)) { - fft_kernel_complex(data, len, 1); - if(type == FFT_SPECTROGRAM) { - ndarray_obj_t *spectrum = ndarray_new_linear_array(len, NDARRAY_FLOAT); - mp_float_t *sarray = (mp_float_t *)spectrum->array; - for(size_t i = 0; i < len; i++) { - *sarray++ = MICROPY_FLOAT_C_FUN(sqrt)(data[0] * data[0] + data[1] * data[1]); - data += 2; - } - m_del(mp_float_t, data, 2 * len); - return MP_OBJ_FROM_PTR(spectrum); - } + if(type == FFT_FFT) { + fft_kernel(data, len, 1); } else { // inverse transform - fft_kernel_complex(data, len, -1); + fft_kernel(data, len, -1); // TODO: numpy accepts the norm keyword argument for(size_t i = 0; i < 2 * len; i++) { *data++ /= len; @@ -202,7 +192,7 @@ void fft_kernel(mp_float_t *real, mp_float_t *imag, size_t n, int isign) { } } -mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) { +mp_obj_t fft_fft_ifft(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) { if(!mp_obj_is_type(arg_re, &ulab_ndarray_type)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("FFT is defined for ndarrays only")); } @@ -258,15 +248,8 @@ mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_i data_im -= len; } - if((type == FFT_FFT) || (type == FFT_SPECTROGRAM)) { + if(type == FFT_FFT) { fft_kernel(data_re, data_im, len, 1); - if(type == FFT_SPECTROGRAM) { - for(size_t i=0; i < len; i++) { - *data_re = MICROPY_FLOAT_C_FUN(sqrt)(*data_re * *data_re + *data_im * *data_im); - data_re++; - data_im++; - } - } } else { // inverse transform fft_kernel(data_re, data_im, len, -1); // TODO: numpy accepts the norm keyword argument @@ -275,13 +258,9 @@ mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_i *data_im++ /= len; } } - if(type == FFT_SPECTROGRAM) { - return MP_OBJ_FROM_PTR(out_re); - } else { - mp_obj_t tuple[2]; - tuple[0] = MP_OBJ_FROM_PTR(out_re); - tuple[1] = MP_OBJ_FROM_PTR(out_im); - return mp_obj_new_tuple(2, tuple); - } + mp_obj_t tuple[2]; + tuple[0] = MP_OBJ_FROM_PTR(out_re); + tuple[1] = MP_OBJ_FROM_PTR(out_im); + return mp_obj_new_tuple(2, tuple); } #endif /* ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE */ diff --git a/code/numpy/fft/fft_tools.h b/code/numpy/fft/fft_tools.h index 9444232f..aa598201 100644 --- a/code/numpy/fft/fft_tools.h +++ b/code/numpy/fft/fft_tools.h @@ -14,15 +14,14 @@ enum FFT_TYPE { FFT_FFT, FFT_IFFT, - FFT_SPECTROGRAM, }; #if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE void fft_kernel(mp_float_t *, size_t , int ); -mp_obj_t fft_fft_ifft_spectrogram(mp_obj_t , uint8_t ); +mp_obj_t fft_fft_ifft(mp_obj_t , uint8_t ); #else void fft_kernel(mp_float_t *, mp_float_t *, size_t , int ); -mp_obj_t fft_fft_ifft_spectrogram(size_t , mp_obj_t , mp_obj_t , uint8_t ); +mp_obj_t fft_fft_ifft(size_t , mp_obj_t , mp_obj_t , uint8_t ); #endif /* ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE */ #endif /* _FFT_TOOLS_ */ diff --git a/code/ulab.c b/code/ulab.c index f55768bc..df73f7bb 100644 --- a/code/ulab.c +++ b/code/ulab.c @@ -33,7 +33,7 @@ #include "user/user.h" #include "utils/utils.h" -#define ULAB_VERSION 6.5.0 +#define ULAB_VERSION 6.5.1 #define xstr(s) str(s) #define str(s) #s diff --git a/code/utils/utils.c b/code/utils/utils.c index 1d282d86..062aa0c6 100644 --- a/code/utils/utils.c +++ b/code/utils/utils.c @@ -5,7 +5,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2020-2021 Zoltán Vörös + * Copyright (c) 2020-2024 Zoltán Vörös */ #include @@ -16,6 +16,7 @@ #include "py/misc.h" #include "utils.h" +#include "../ulab_tools.h" #include "../numpy/fft/fft_tools.h" #if ULAB_HAS_UTILS_MODULE @@ -203,23 +204,188 @@ MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_uint32_buffer_obj, 1, utils_from_uint32_bu //| ... //| -mp_obj_t utils_spectrogram(size_t n_args, const mp_obj_t *args) { - #if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE - return fft_fft_ifft_spectrogram(args[0], FFT_SPECTROGRAM); +mp_obj_t utils_spectrogram(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } } , + #if !ULAB_FFT_IS_NUMPY_COMPATIBLE + { MP_QSTR_, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } }, + #else + { MP_QSTR_scratchpad, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } }, + { MP_QSTR_out, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } }, + { MP_QSTR_log, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_FALSE } }, + #endif + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("spectrogram is defined for ndarrays only")); + } + ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj); + + #if ULAB_MAX_DIMS > 1 + if(in->ndim != 1) { + mp_raise_TypeError(MP_ERROR_TEXT("spectrogram is implemented for 1D arrays only")); + } + #endif + + size_t len = in->len; + // Check if input is of length of power of 2 + if((len & (len-1)) != 0) { + mp_raise_ValueError(MP_ERROR_TEXT("input array length must be power of 2")); + } + + ndarray_obj_t *out = NULL; + + #if ULAB_FFT_IS_NUMPY_COMPATIBLE + mp_obj_t scratchpad_object = args[1].u_obj; + mp_obj_t out_object = args[2].u_obj; + mp_obj_t log_object = args[3].u_obj; #else - if(n_args == 2) { - return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_SPECTROGRAM); + mp_obj_t scratchpad_object = args[2].u_obj; + mp_obj_t out_object = args[3].u_obj; + mp_obj_t log_object = args[4].u_obj; + #endif + + if(out_object != mp_const_none) { + if(!mp_obj_is_type(out_object, &ulab_ndarray_type)) { + mp_raise_TypeError(MP_ERROR_TEXT("out must be an ndarray")); + } + out = MP_OBJ_TO_PTR(out_object); + if((out->dtype != NDARRAY_FLOAT) || (out->ndim != 1)){ + mp_raise_TypeError(MP_ERROR_TEXT("out must be a 1D array of float type")); + } + if(len != out->len) { + mp_raise_ValueError(MP_ERROR_TEXT("input and out arrays are not compatible")); + } } else { - return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_SPECTROGRAM); + out = ndarray_new_linear_array(len, NDARRAY_FLOAT); } - #endif + + ndarray_obj_t *scratchpad = NULL; + mp_float_t *tmp = NULL; + + if(scratchpad_object != mp_const_none) { + if(!mp_obj_is_type(scratchpad_object, &ulab_ndarray_type)) { + mp_raise_TypeError(MP_ERROR_TEXT("scratchpad must be an ndarray")); + } + + scratchpad = MP_OBJ_TO_PTR(scratchpad_object); + if(!ndarray_is_dense(scratchpad) || (scratchpad->ndim != 1)) { + mp_raise_ValueError(MP_ERROR_TEXT("scratchpad must be a 1D dense array")); + } + + #if ULAB_SUPPORTS_COMPLEX + if((scratchpad->dtype != NDARRAY_COMPLEX) && (scratchpad->dtype != NDARRAY_FLOAT)) { + mp_raise_ValueError(MP_ERROR_TEXT("scratchpad must be of complex or float type")); + } + if(((scratchpad->dtype == NDARRAY_COMPLEX) && (len != scratchpad->len)) || + ((scratchpad->dtype == NDARRAY_FLOAT) && (2 * len != scratchpad->len))) { + mp_raise_ValueError(MP_ERROR_TEXT("in and scratchpad arrays are not compatible")); + } + #else + if((scratchpad->dtype != NDARRAY_FLOAT)){ + mp_raise_TypeError(MP_ERROR_TEXT("scratchpad must be of float type")); + } + if(2 * len != scratchpad->len) { + mp_raise_ValueError(MP_ERROR_TEXT("input and scratchpad arrays are not compatible")); + } + #endif + + tmp = (mp_float_t *)scratchpad->array; + } else { + tmp = m_new0(mp_float_t, 2 * len); + } + + uint8_t *array = (uint8_t *)in->array; + + #if ULAB_FFT_IS_NUMPY_COMPATIBLE // ULAB_SUPPORTS_COMPLEX is automatically true + if(in->dtype == NDARRAY_COMPLEX) { + uint8_t sz = 2 * sizeof(mp_float_t); + for(size_t i = 0; i < len; i++) { + memcpy(tmp, array, sz); + tmp += 2; + array += in->strides[ULAB_MAX_DIMS - 1]; + } + } else { + mp_float_t (*func)(void *) = ndarray_get_float_function(in->dtype); + for(size_t i = 0; i < len; i++) { + *tmp++ = func(array); // real part + *tmp++ = 0; // imaginary part, clear + array += in->strides[ULAB_MAX_DIMS - 1]; + } + } + + tmp -= 2 * len; + fft_kernel(tmp, len, 1); + #else // we might have two real input vectors + + ndarray_obj_t *in2 = NULL; + + if(n_args == 2) { + if(!mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("spectrogram is defined for ndarrays only")); + } + in2 = MP_OBJ_TO_PTR(args[1].u_obj); + + #if ULAB_MAX_DIMS > 1 + if(in2->ndim != 1) { + mp_raise_TypeError(MP_ERROR_TEXT("spectrogram is implemented for 1D arrays only")); + } + #endif + if(len != in2->len) { + mp_raise_TypeError(MP_ERROR_TEXT("input arrays are not compatible")); + } + } + + mp_float_t (*func)(void *) = ndarray_get_float_function(in->dtype); + + for(size_t i = 0; i < len; i++) { + // real part; the imaginary part is 0, no need to assign + *tmp++ = func(array); + array += in->strides[ULAB_MAX_DIMS - 1]; + } + + if(n_args == 2) { + mp_float_t (*func2)(void *) = ndarray_get_float_function(in2->dtype); + array = (uint8_t *)in2->array; + for(size_t i = 0; i < len; i++) { + *tmp++ = func2(array); + array += in2->strides[ULAB_MAX_DIMS - 1]; + } + tmp -= len; + } + tmp -= len; + + fft_kernel(tmp, tmp + len, len, 1); + #endif /* ULAB_FFT_IS_NUMPY_COMPATIBLE */ + + mp_float_t *spectrum = (mp_float_t *)out->array; + uint8_t spectrum_sz = out->strides[ULAB_MAX_DIMS - 1] / sizeof(mp_float_t); + + for(size_t i = 0; i < len; i++) { + #if ULAB_FFT_IS_NUMPY_COMPATIBLE + *spectrum = MICROPY_FLOAT_C_FUN(sqrt)(*tmp * *tmp + *(tmp + 1) * *(tmp + 1)); + tmp += 2; + #else + *spectrum = MICROPY_FLOAT_C_FUN(sqrt)(*tmp * *tmp + *(tmp + len) * *(tmp + len)); + tmp++; + #endif + if(log_object == mp_const_true) { + *spectrum = MICROPY_FLOAT_C_FUN(log)(*spectrum); + } + spectrum += spectrum_sz; + } + + // FIXME: + // if(scratchpad_object == mp_const_none) { + // m_del(mp_float_t, tmp, 2 * len); + // } + return MP_OBJ_FROM_PTR(out); } -#if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(utils_spectrogram_obj, 1, 1, utils_spectrogram); -#else -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(utils_spectrogram_obj, 1, 2, utils_spectrogram); -#endif +MP_DEFINE_CONST_FUN_OBJ_KW(utils_spectrogram_obj, 1, utils_spectrogram); #endif /* ULAB_UTILS_HAS_SPECTROGRAM */ diff --git a/docs/ulab-convert.ipynb b/docs/ulab-convert.ipynb index bd587912..72fe5743 100644 --- a/docs/ulab-convert.ipynb +++ b/docs/ulab-convert.ipynb @@ -57,11 +57,11 @@ "# -- Project information -----------------------------------------------------\n", "\n", "project = 'The ulab book'\n", - "copyright = '2019-2022, Zoltán Vörös and contributors'\n", + "copyright = '2019-2024, Zoltán Vörös and contributors'\n", "author = 'Zoltán Vörös'\n", "\n", "# The full version, including alpha/beta/rc tags\n", - "release = '5.1.0'\n", + "release = '6.5.0'\n", "\n", "\n", "# -- General configuration ---------------------------------------------------\n", @@ -190,6 +190,7 @@ " numpy-universal\n", " numpy-fft\n", " numpy-linalg\n", + " numpy-random\n", " scipy-linalg\n", " scipy-optimize\n", " scipy-signal\n", @@ -215,7 +216,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2022-02-09T06:27:21.647179Z", @@ -256,14 +257,49 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2022-02-09T06:27:42.024028Z", "start_time": "2022-02-09T06:27:36.109093Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n", + "/home/v923z/anaconda3/lib/python3.9/site-packages/nbconvert/exporters/exporter.py:305: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n", + " nbformat.validate(nbc, relax_add_props=True)\n" + ] + } + ], "source": [ "files = ['ulab-intro',\n", " 'ulab-ndarray',\n", @@ -271,6 +307,7 @@ " 'numpy-universal',\n", " 'numpy-fft',\n", " 'numpy-linalg',\n", + " 'numpy-random',\n", " 'scipy-linalg',\n", " 'scipy-optimize',\n", " 'scipy-signal',\n", @@ -449,7 +486,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.13" }, "toc": { "base_numbering": 1, diff --git a/docs/ulab-intro.ipynb b/docs/ulab-intro.ipynb index 67d6b608..30266418 100644 --- a/docs/ulab-intro.ipynb +++ b/docs/ulab-intro.ipynb @@ -10,13 +10,6 @@ } }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Matplotlib is building the font cache; this may take a moment.\n" - ] - }, { "name": "stdout", "output_type": "stream", @@ -38,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2022-01-07T18:13:14.590799Z", @@ -239,7 +232,7 @@ "source": [ "## Enter ulab\n", "\n", - "`ulab` is a `numpy`-like module for `micropython` and its derivatives, meant to simplify and speed up common mathematical operations on arrays. `ulab` implements a small subset of `numpy` and `scipy`. The functions were chosen such that they might be useful in the context of a microcontroller. However, the project is a living one, and suggestions for new features are always welcome. \n", + "`ulab` is a `numpy`-like module for `micropython` and its derivatives, meant to simplify and speed up common mathematical operations on arrays. `ulab` implements a small subset of `numpy` and `scipy`, as well as a number of functions manipulating byte arrays. The functions were chosen such that they might be useful in the context of a microcontroller. However, the project is a living one, and suggestions for new features are always welcome. \n", "\n", "This document discusses how you can use the library, starting from building your own firmware, through questions like what affects the firmware size, what are the trade-offs, and what are the most important differences to `numpy` and `scipy`, respectively. The document is organised as follows:\n", "\n", @@ -404,7 +397,7 @@ "np.polyval(p, x)\n", "```\n", "\n", - "There are a couple of exceptions to this rule, namely `fft`, and `linalg`, which are sub-modules even in `numpy`, thus you have to write them out as \n", + "There are a couple of exceptions to this rule, namely `fft`, `linalg`, and `random`, which are sub-modules even in `numpy`, thus you have to write them out as \n", "\n", "```python\n", "from ulab import numpy as np\n", @@ -842,7 +835,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.13" }, "toc": { "base_numbering": 1,