"grader = otter.Notebook(\"Projections and signal restoration.ipynb\")"
]
},
{
"cell_type": "markdown",
"id": "4133723e-952b-4b1c-bb3d-a7f78a957024",
"metadata": {},
"source": [
"# Matrix Analysis 2025 - EE312\n",
"\n",
"## Week 3 - Signal restoration using projections\n",
"[LTS2](https://lts2.epfl.ch)"
]
},
{
"cell_type": "markdown",
"id": "fb42154f-8832-4960-9fee-3372b473ef69",
"metadata": {},
"source": [
"Let us consider a signal with $N$ elements, i.e. a vector in $\\mathbb{R}^N$. \n",
"Under our observations conditions, we can only recover partially the signal's values, the other remain unknown, i.e. we know that:\n",
"\n",
"$x[k] = x_k$ for $k\\in E = \\{e_0, e_1, \\dots,e_{M-1}\\}$, with $E\\in\\mathbb{N}^M$ and $e_i\\neq e_j \\forall i\\neq j$ (i.e. each known index is unique).\n",
"\n",
"We also make the assumption that the signal is contained within **lower frequencies of the spectrum**. This can be expressed using the (normalized) Fourier matrix you have constructed last week $\\hat{W}$.\n",
"\n",
"In this notebook, we will try to reconstruct the signal by projecting its observation successively on the Fourier subspace defined above, then back to its original domain (with the constraint regarding its values), then on the Fourier domain, etc. This is a simplified version of a more general method called [\"Projection onto convex sets\" (POCS)](https://en.wikipedia.org/wiki/Projections_onto_convex_sets). The method is illustrated by the figure below (of course you do not project on lines but on spaces having larger dimension).\n",
"\n",
"\n",
"\n",
"### 1. Low-pass filter\n",
"Let us first create example signals to validate our implementation of the filtering operation."
"1. Implement a function that returns the normalized Fourier matrix of size N (use your implementation from week 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f886d8a6-4cb7-4187-ae4b-4615a06caa2d",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"def fourier_matrix(N):\n",
" ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e101a935",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"grader.check(\"q1\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "62fae5a8-f3c4-477b-a53f-a0106730b842",
"metadata": {},
"outputs": [],
"source": [
"W_hat = fourier_matrix(N)"
]
},
{
"cell_type": "markdown",
"id": "1e0a2337-446d-49d3-8521-55d07a1539bc",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"Let $X = \\hat{W}x$, $X$ is the *discrete Fourier transform* of the input signal $x$. The frequency condition can then be rewritten as \n",
"\n",
"$X[k] = 0$ for $w_c < k\\leq N-w_c$. \n",
"\n",
"2. Implement the function that returns a $N\\times N$ matrix $P$, s.t. $PX$ satisfies the above condition for a given $w_c$. Make sure the input values are valid, if not raise a `ValueError` exception."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aeed4067-1130-4e6c-9fbd-ab8d0a3a41c0",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"def lowpass_matrix(N, w_c):\n",
" \"\"\"\n",
" Computes the P matrix that will remove high-frequency coefficients in a DFT transformed signal\n",
"\n",
" Parameters\n",
" ----------\n",
" N : length of the input signal\n",
" w_c : cutoff frequency\n",
"\n",
" Returns\n",
" -------\n",
" The P matrix\n",
" \"\"\"\n",
" ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d1f7f40c",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"grader.check(\"q2\")"
]
},
{
"cell_type": "markdown",
"id": "fef68750-d97f-4625-bd5e-5f13e7894f7d",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"3. Now let us try the filtering on the test signals and make sure it behaves appropriately. Using the matrix $P$ defined above, choose the parameter $w_c$ approiately s.t. the filtered signals retain $w_1$ and $w_2$ but discard $w_3$."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bc1370d5-c7b2-4598-b573-d57bec56aa1b",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"w_c = ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "85787e70-1427-4860-8a7b-94d20432bd76",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"# Compute the DFT of x1 and x2\n",
"X1 = W_hat@x1\n",
"X2 = W_hat@x2\n",
"\n",
"# Get the lowpass filter matrix\n",
"P = lowpass_matrix(N, w_c)\n",
"\n",
"# Filter X1 and X2 and apply inverse DFT\n",
"x1_f = ...\n",
"x2_f = ..."
]
},
{
"cell_type": "markdown",
"id": "700eb2e2-3137-4916-a829-9e8e2ba8c6e5",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"NB: Make sure the filtered output is **real** (or its imaginary part should be smaller than $10^{-12}$)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e960728d-c2c0-4b9d-ab73-3db971f559a1",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"# Plot the filtered signals\n",
"# x1_f should still contain both frequencies, x2_f only one\n",
"plt.plot(x1_f)\n",
"plt.plot(x2_f, 'r')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dd892e03",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"grader.check(\"q3\")"
]
},
{
"cell_type": "markdown",
"id": "c34b8fc7-8a51-4fe5-a6ab-1cc27da2cd1e",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- BEGIN QUESTION -->\n",
"\n",
"4. Prove that $P$ is a projection."
]
},
{
"cell_type": "markdown",
"id": "610729bb",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"source": [
"_Type your answer here, replacing this text._"
]
},
{
"cell_type": "markdown",
"id": "7f17f3ae-6a39-4e86-a29c-879c96b4e5fb",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- END QUESTION -->\n",
"\n",
"### 2. Signal extension\n",
"\n",
"In order to express the condition on $x[k]$ as a pure matrix operation we need to make use of an extension of the input signal and design a slightly different Fourier transform matrix to use properly those extended signals. \n",
"\n",
"Let us denote by $x_E$ the vector from $\\mathbb{R}^M$ containing the known values of $x$, i.e. the $x_k$ for $k\\in E$.\n",
"\n",
"For each vector $y$ in $\\mathbb{R}^N$ we define its extension as $\\tilde{y} = \\begin{pmatrix}y \\\\ x_E\\end{pmatrix}$. \n",
"\n",
"**This notation will remain throughout the notebook**, i.e. a vector with a tilde denotes its extension made by adding the $x_E$ values at the end."
]
},
{
"cell_type": "markdown",
"id": "f9434f5f-ceb9-42bf-9b5e-bd7d7a94dae8",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"5. Let us define the matrix $B_E$ and $y=B_E x$, s.t. $y[k] = 0$ if $k\\in E$ and $y[k] = x[k]$ otherwise. Write a function that returns its extended version $\\tilde{B_E}$ s.t. $\\tilde{y}=\\tilde{B_E}\\tilde{x}$, for any $x\\in\\mathbb{R}^N$. \n",
"\n",
"- $\\tilde{B_E}$ is a square matrix of size $N+M$.\n",
"- Check the validity of parameters and raise a `ValueError` in case of invalid inputs."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dae1c4aa-c6ce-4f35-b309-aa6dd09e9abf",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"def Bt_E(N, E):\n",
" \"\"\"\n",
" Computes the $\\tilde{B}_E$ matrix \n",
"\n",
" Parameters\n",
" ----------\n",
" N : length of the input signal\n",
" E : list of suitable indices. e.g. for N=5 a valid E could be [1, 3]\n",
"\n",
" Returns\n",
" -------\n",
" The $\\tilde{B}_E$ matrix \n",
" \"\"\"\n",
" ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2dddfff8",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"grader.check(\"q5\")"
]
},
{
"cell_type": "markdown",
"id": "853c1a3b-9ed9-461c-86f9-12992e07337d",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"Let us know design $C_E$ as an operator from $\\mathbb{R}^{N+M} \\rightarrow \\mathbb{R}^{N+M}$ such that when applied to any extended vector $\\tilde{z}$ s.t. $\\tilde{z}[k] = 0, \\forall k\\in E$ as input (i.e. for instance the output of $\\tilde{B}_E$), it generates a vector $\\tilde{z}_R$ s.t.:\n",
"\n",
"$\\tilde{z}_R[k] = \\left\\{\\begin{matrix} x_k \\mbox{ if } k\\in E \\\\ \\tilde{z}[k] \\mbox{ otherwise} \\end{matrix}\\right.$\n",
"\n",
"6. Write a function that generates $C_E$. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "932ae153-f336-4b0f-b7c0-774c02ccaad1",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"def C_E(N, E):\n",
" \"\"\"\n",
" Computes the $C_E$ matrix \n",
"\n",
" Parameters\n",
" ----------\n",
" N : length of the input signal\n",
" E : list of suitable indices. e.g. for N=5 a valid E could be [1, 3]\n",
"\n",
" Returns\n",
" -------\n",
" The $C_E$ matrix \n",
" \"\"\"\n",
" ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "577b22ec",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"grader.check(\"q6\")"
]
},
{
"cell_type": "markdown",
"id": "0e57be3f-1c44-445a-86ad-07e20fbcd1d2",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- BEGIN QUESTION -->\n",
"\n",
"7. What is the effect of $D_E = C_E \\tilde{B}_E$ on an extended signal $\\tilde{x}$ ? "
]
},
{
"cell_type": "markdown",
"id": "273c0bc5",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"source": [
"_Type your answer here, replacing this text._"
]
},
{
"cell_type": "markdown",
"id": "3b2caf03-41cb-41f9-93eb-778047b9b944",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- END QUESTION -->\n",
"\n",
"<!-- BEGIN QUESTION -->\n",
"\n",
"8. Verify (numerically on an example) that $D_E$ is a projector. You can use the function `numpy.testing.assert_array_almost_equal` to check that arrays are almost equal (with a good precision)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94dbc7f8-c2fc-4337-9828-dd2e3311830d",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"# Set some parameters\n",
"N=5\n",
"E=[1,3]\n",
"# Compute D_E\n",
"D_E = ...\n",
"# Now check that D_E is a projector\n",
"..."
]
},
{
"cell_type": "markdown",
"id": "7fb30993-5350-4e9b-aa45-b657b450a3a1",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- END QUESTION -->\n",
"\n",
"### 3. Extended signals in the Fourier domain\n",
"Let us now define an operator that will work almost as the normalized Fourier transform, except that it will be applied to the extended signals and preserve the $x_E$ part. This can be easily done using the following block matrix:\n",
"Using this definition, multiplying an extended signal $\\tilde{x}$ by $\\tilde{W}$ will result in a vector containing the Fourier transform of $x$ followed by $x_E$, preserving the known initial values."
]
},
{
"cell_type": "markdown",
"id": "3157e22e-f7d7-44b8-a4fd-9ddec1d7aa8a",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- BEGIN QUESTION -->\n",
"\n",
"9. Prove that $\\tilde{W}$ is orthonormal. "
]
},
{
"cell_type": "markdown",
"id": "0fd7c9a7",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"source": [
"_Type your answer here, replacing this text._"
]
},
{
"cell_type": "markdown",
"id": "f140c720-eaed-4fd2-8b9f-6b99a1a5b0ff",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- END QUESTION -->\n",
"\n",
"10. Write a function that returns $\\tilde{W}$."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b744a698-40d5-41a6-9623-76a19f50bcd2",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"def Wt_E(N, E):\n",
" \"\"\"\n",
" Computes the $\\tilde{W}_E$ matrix \n",
"\n",
" Parameters\n",
" ----------\n",
" N : length of the input signal\n",
" E : list of suitable indices. e.g. for N=5 a valid E could be [1, 3]\n",
"\n",
" Returns\n",
" -------\n",
" The $\\tilde{W}_E$ matrix \n",
" \"\"\"\n",
" ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94532bbb",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"grader.check(\"q10\")"
]
},
{
"cell_type": "markdown",
"id": "1afee45d-78e6-498b-905b-cbc97eeaf2d5",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"11. Recalling the low-pass matrix $P$ defined previously, build $\\tilde{P}$ s.t. when applied to $\\tilde{W}\\tilde{x}$ it results in a vector containing the filtered values (still in the Fourier domain) followed by $x_E$."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4576bfbc-a249-4d89-919d-47763c8a60f9",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"def Pt_E(N, M, w_c):\n",
" ..."
]
},
{
"cell_type": "markdown",
"id": "781d7752-74ae-4ec2-8ea2-4279b54ee5e7",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- BEGIN QUESTION -->\n",
"\n",
"12. A signal $\\tilde{x}$ will be filtered by doing $\\tilde{W}^H \\tilde{P}\\tilde{W}\\tilde{x}$.\n",
"Prove that this is a projection."
]
},
{
"cell_type": "markdown",
"id": "53c720a8",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"source": [
"_Type your answer here, replacing this text._"
]
},
{
"cell_type": "markdown",
"id": "1c8c4469-7264-4968-b700-897be635a193",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- END QUESTION -->\n",
"\n",
"### 4. Signal restoration"
]
},
{
"cell_type": "markdown",
"id": "ac24806d-105d-4fbf-bc98-788dbcc7c0ba",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- BEGIN QUESTION -->\n",
"\n",
"13. We can now use all defined above to implement a function that performs an iteration, taking as input the extension of $x$ as defined above, that does the following:\n",
"- compute the filtered version of the signal using $\\tilde{W}^H \\tilde{P}\\tilde{W}$ (i.e. projecting on the space of \"smooth signals\")\n",
"- restore the known values in the signal by using $D_E = C_E\\tilde{B}_E$ (i.e project back on the space of signals having the known initial values we have set)\n",
"\n",
"Make sure to force the result to real values by using `np.real` before returning"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "155e3277-bcef-44ed-b53f-a1b2e5ad7363",
"metadata": {
"tags": [
"otter_answer_cell"
]
},
"outputs": [],
"source": [
"def restoration_iter(Wt, Pt, Dt, xt):\n",
" \"\"\"\n",
" Performs a full restoration iteration by\n",
" - projecting the signal into Fourier, performing low-pass filtering followed by inverse DFT\n",
" - restoring the known initial values into the filtered signal\n",
"\n",
" Parameters\n",
" ----------\n",
" Wt : \\tilde{W} matrix\n",
" Pt : \\tilde{P} matrix\n",
" Dt : \\tilde{D} matrix\n",
" xt : \\tilde{x} vector\n",
"\n",
" Returns\n",
" -------\n",
" The new $\\tilde{x} vector after the iteration\n",
" \"\"\"\n",
" ..."
]
},
{
"cell_type": "markdown",
"id": "758aa9ce-1ebc-49e1-b2f6-ca8e1035b31c",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- END QUESTION -->\n",
"\n",
"<!-- BEGIN QUESTION -->\n",
"\n",
"15. Finally we are ready to apply all this to an example."
"plt.plot(x, 'r+', alpha=0.7) # plot original for comparison"
]
},
{
"cell_type": "markdown",
"id": "bf876405-b60c-4f7c-9162-56d58cafd19f",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"Depending on $M$, you will find that the method can reconstruct perfectly the signal or not. "
]
},
{
"cell_type": "markdown",
"id": "94962762",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"<!-- END QUESTION -->\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "738294c5",
"metadata": {
"deletable": false,
"editable": false
},
"source": [
"## Submission\n",
"\n",
"Make sure you have run all cells in your notebook in order before running the cell below, so that all images/graphs appear in the output. The cell below will generate a zip file for you to submit. **Please save before exporting!**"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7d10d7ed",
"metadata": {
"deletable": false,
"editable": false
},
"outputs": [],
"source": [
"# Save your notebook first, then run this cell to export your submission.\n",
"grader.export(pdf=False, run_tests=True)"
]
},
{
"cell_type": "markdown",
"id": "159a45fb",
"metadata": {},
"source": [
" "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.10"
},
"otter": {
"OK_FORMAT": true,
"tests": {
"q1": {
"name": "q1",
"points": null,
"suites": [
{
"cases": [
{
"code": ">>> from scipy.linalg import dft\n>>> np.testing.assert_array_almost_equal(fourier_matrix(16), dft(16, scale='sqrtn'))\n",
"failure_message": "Check your implementation",
"hidden": false,
"locked": false,
"success_message": "Good, your implementation returns correct results"
},
{
"code": ">>> W = fourier_matrix(8)\n>>> np.testing.assert_array_almost_equal(np.conj(W.T) @ W, np.eye(8))\n",
"failure_message": "Check your implementation, resulting matrix should be orthogonal.",
"hidden": false,
"locked": false,
"success_message": "Good, your implementation returns an orthogonal matrix"
"success_message": "Good, your implementation returns correct results"
},
{
"code": ">>> with np.testing.assert_raises(ValueError):\n... lowpass_matrix(0, 0)\n>>> with np.testing.assert_raises(ValueError):\n... lowpass_matrix(16, -1)\n>>> with np.testing.assert_raises(ValueError):\n... lowpass_matrix(32, 17)\n",
"failure_message": "Did you forget to validate the input parameters before performing the computation ?",
"hidden": false,
"locked": false,
"success_message": "Good, you properly validated parameters before computing the result"
}
],
"scored": true,
"setup": "",
"teardown": "",
"type": "doctest"
}
]
},
"q3": {
"name": "q3",
"points": null,
"suites": [
{
"cases": [
{
"code": ">>> assert w_c > w2 and w_c < w3\n",
"failure_message": "Check your value of w_c",
"hidden": false,
"locked": false,
"success_message": "Your value of w_c looks correct"
Let us consider a signal with $N$ elements, i.e. a vector in $\mathbb{R}^N$.
Under our observations conditions, we can only recover partially the signal's values, the other remain unknown, i.e. we know that:
$x[k] = x_k$ for $k\in E = \{e_0, e_1, \dots,e_{M-1}\}$, with $E\in\mathbb{N}^M$ and $e_i\neq e_j \forall i\neq j$ (i.e. each known index is unique).
We also make the assumption that the signal is contained within **lower frequencies of the spectrum**. This can be expressed using the (normalized) Fourier matrix you have constructed last week $\hat{W}$.
In this notebook, we will try to reconstruct the signal by projecting its observation successively on the Fourier subspace defined above, then back to its original domain (with the constraint regarding its values), then on the Fourier domain, etc. This is a simplified version of a more general method called ["Projection onto convex sets" (POCS)](https://en.wikipedia.org/wiki/Projections_onto_convex_sets). The method is illustrated by the figure below (of course you do not project on lines but on spaces having larger dimension).

### 1. Low-pass filter
Let us first create example signals to validate our implementation of the filtering operation.
Let $X = \hat{W}x$, $X$ is the *discrete Fourier transform* of the input signal $x$. The frequency condition can then be rewritten as
$X[k] = 0$ for $w_c < k\leq N-w_c$.
2. Implement the function that returns a $N\times N$ matrix $P$, s.t. $PX$ satisfies the above condition for a given $w_c$. Make sure the input values are valid, if not raise a `ValueError` exception.
3. Now let us try the filtering on the test signals and make sure it behaves appropriately. Using the matrix $P$ defined above, choose the parameter $w_c$ approiately s.t. the filtered signals retain $w_1$ and $w_2$ but discard $w_3$.
In order to express the condition on $x[k]$ as a pure matrix operation we need to make use of an extension of the input signal and design a slightly different Fourier transform matrix to use properly those extended signals.
Let us denote by $x_E$ the vector from $\mathbb{R}^M$ containing the known values of $x$, i.e. the $x_k$ for $k\in E$.
For each vector $y$ in $\mathbb{R}^N$ we define its extension as $\tilde{y} = \begin{pmatrix}y \\ x_E\end{pmatrix}$.
**This notation will remain throughout the notebook**, i.e. a vector with a tilde denotes its extension made by adding the $x_E$ values at the end.
5. Let us define the matrix $B_E$ and $y=B_E x$, s.t. $y[k] = 0$ if $k\in E$ and $y[k] = x[k]$ otherwise. Write a function that returns its extended version $\tilde{B_E}$ s.t. $\tilde{y}=\tilde{B_E}\tilde{x}$, for any $x\in\mathbb{R}^N$.
- $\tilde{B_E}$ is a square matrix of size $N+M$.
- Check the validity of parameters and raise a `ValueError` in case of invalid inputs.
Let us know design $C_E$ as an operator from $\mathbb{R}^{N+M} \rightarrow \mathbb{R}^{N+M}$ such that when applied to any extended vector $\tilde{z}$ s.t. $\tilde{z}[k] = 0, \forall k\in E$ as input (i.e. for instance the output of $\tilde{B}_E$), it generates a vector $\tilde{z}_R$ s.t.:
$\tilde{z}_R[k] = \left\{\begin{matrix} x_k \mbox{ if } k\in E \\\tilde{z}[k] \mbox{ otherwise} \end{matrix}\right.$
8. Verify (numerically on an example) that $D_E$ is a projector. You can use the function `numpy.testing.assert_array_almost_equal` to check that arrays are almost equal (with a good precision)
Let us now define an operator that will work almost as the normalized Fourier transform, except that it will be applied to the extended signals and preserve the $x_E$ part. This can be easily done using the following block matrix:
Using this definition, multiplying an extended signal $\tilde{x}$ by $\tilde{W}$ will result in a vector containing the Fourier transform of $x$ followed by $x_E$, preserving the known initial values.
11. Recalling the low-pass matrix $P$ defined previously, build $\tilde{P}$ s.t. when applied to $\tilde{W}\tilde{x}$ it results in a vector containing the filtered values (still in the Fourier domain) followed by $x_E$.
13. We can now use all defined above to implement a function that performs an iteration, taking as input the extension of $x$ as defined above, that does the following:
- compute the filtered version of the signal using $\tilde{W}^H \tilde{P}\tilde{W}$ (i.e. projecting on the space of "smooth signals")
- restore the known values in the signal by using $D_E = C_E\tilde{B}_E$ (i.e project back on the space of signals having the known initial values we have set)
Make sure to force the result to real values by using `np.real` before returning
Depending on $M$, you will find that the method can reconstruct perfectly the signal or not.
%% Cell type:markdown id:94962762 tags:
<!-- END QUESTION -->
%% Cell type:markdown id:738294c5 tags:
## Submission
Make sure you have run all cells in your notebook in order before running the cell below, so that all images/graphs appear in the output. The cell below will generate a zip file for you to submit. **Please save before exporting!**
%% Cell type:code id:7d10d7ed tags:
``` python
# Save your notebook first, then run this cell to export your submission.