{"id":196291,"date":"2025-02-26T09:39:49","date_gmt":"2025-02-26T09:39:49","guid":{"rendered":"https:\/\/innovationspace.ansys.com\/knowledge\/?post_type=topic&#038;p=196291"},"modified":"2025-05-22T13:17:51","modified_gmt":"2025-05-22T13:17:51","slug":"jupyter-notebook-programming-with-the-scade-python-wrapper","status":"publish","type":"topic","link":"https:\/\/innovationspace.ansys.com\/knowledge\/forums\/topic\/jupyter-notebook-programming-with-the-scade-python-wrapper\/","title":{"rendered":"Jupyter notebook programming with the SCADE Python Wrapper"},"content":{"rendered":"<h3  id=\"INTRODUCTION\">Introduction<\/h3>\n<p>In the rapidly evolving landscape of safety-critical software development, integrating modern tools can significantly enhance productivity and flexibility. Ansys SCADE, renowned for its robust support in developing certified software, can be further empowered by leveraging <a href=\"https:\/\/jupyter.org\/\">Jupyter Notebooks<\/a>.<\/p>\n<p>This article explores how Jupyter Notebooks can extend SCADE&#8217;s capabilities, enabling developers to streamline workflows, automate tasks, and enhance data visualization. Discover how this synergy can revolutionize your development process.<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-banner-scaled.jpg\" style=\"max-height: 700px !important\" \/><br \/>\n    <em>Photo credit: Pixabay @ <a href=\"https:\/\/www.pexels.com\/photo\/lighted-dj-board-164745\/\">Pexels<\/a><\/em>\n<\/p>\n<h3  id=\"A-FIRST-ORDER-LOW-PASS-FILTER-EXAMPLE\">A first-order low-pass filter example<\/h3>\n<p>In this article, we&#8217;ll demonstrate how to extend SCADE&#8217;s capabilities using a simple yet effective example: a first-order <a href=\"https:\/\/en.m.wikipedia.org\/wiki\/Low-pass_filter\">low-pass filter<\/a>.<\/p>\n<p>We will use the following recursive equation to represent our RC Filter:<\/p>\n<p>$$y[i]= y[i-1] + a(x[i] &#8211; y[i-1])$$<\/p>\n<p>Where:<\/p>\n<p>$$\\alpha = \\frac{\\Delta t}{\\frac{1}{2 \\pi \\omega_{c}}+ \\Delta t}$$<\/p>\n<p>$\\Delta t$ is the interval between each sampling <\/p>\n<p>$\\omega_{c}$ is the cutoff frequency<\/p>\n<h3  id=\"DESIGNING-OUR-FILTER-IN-SCADE\">Designing our filter in SCADE<\/h3>\n<p>Implementing a first order low pass filter in SCADE is quite simple and would give the following diagram:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-lowpassrc.jpg\" style=\"max-height: 300px !important\" \/><br \/>\n    <em>Low Pass filter in SCADE<\/em>\n<\/p>\n<p>Note the use of the <code>FBY<\/code> operator, which allows us to reference the value of <code>y<\/code> from previous cycles ($y[i-1]$ in our equation above).<\/p>\n<h3  id=\"PLANNING-OUR-TESTS\">Planning our tests<\/h3>\n<p>Testing a low-pass filter involves verifying its performance against expected behavior, such as attenuation of high-frequency components and preservation of low-frequency components. We will perform two kinds of tests to validate our filter.<\/p>\n<h4  id=\"TIME-DOMAIN-TESTING\">Time-domain testing<\/h4>\n<p>Test with step inputs to measure settling time, overshoot, and response characteristics.<\/p>\n<h4  id=\"FREQUENCY-RESPONSE-TESTING\">Frequency response testing<\/h4>\n<p>Verify the filter&#8217;s behavior across a range of frequencies:<\/p>\n<ul>\n<li>Test the filter with low and high-frequency sine waves to observe attenuation, or frequency sweeps (sinusoids of varying frequencies).<\/li>\n<li>Compare output magnitudes against the theoretical response (e.g., -3 dB at cutoff frequency for a first-order filter).<\/li>\n<li>Visualize the frequency response using a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Fast_Fourier_transform\">Fast Fourier Transform<\/a> or a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bode_plot\">Bode plot<\/a>:\n<ul>\n<li>Cutoff frequency: verify that the filter attenuates signals beyond the designed cutoff frequency.<\/li>\n<li>Phase shift: check the phase delay introduced by the filter, especially for critical applications.<\/li>\n<li>Attenuation rate: measure how quickly the filter reduces unwanted frequencies.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3  id=\"TESTING-OUR-FILTER-IN-SCADE\">Testing our filter in SCADE<\/h3>\n<h4  id=\"TIME-DOMAIN-TESTING\">Time-domain testing<\/h4>\n<p>We design a test harness in SCADE to generate the step signal:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-harness-step-1.jpg\" style=\"max-height: 600px !important\" \/><br \/>\n    <em>Step harness<\/em>\n<\/p>\n<p>Note that we could also use a test scenario that leverages files of pre-calculated input values and expected output values.<\/p>\n<p>This test harness is executed in the SCADE simulator. We can observe the response values on simple graphs:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-step-response-1.png\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Step response in SCADE<\/em>\n<\/p>\n<h4  id=\"FREQUENCY-RESPONSE-TESTING\">Frequency response testing<\/h4>\n<p>We create a new test harness to generate a sine wave signal:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-harness-sin-1.jpg\" style=\"max-height: 600px !important\" \/><br \/>\n    <em>Sine wave signal harness<\/em>\n<\/p>\n<p>Using the simulator, we can plot the input and output signals:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-sin-response-1.png\" style=\"max-height: 500px !important\" \/><br \/>\n    <em>Sine wave signal and filtered signal<\/em>\n<\/p>\n<p>This gives us a first view of our filter&#8217;s output. However, SCADE is a software development tool and is not suited for more detailed signal analysis. We need a different set of tools to verify the frequency response of our filter.<\/p>\n<p>To go further, we will rely on a tool called the SCADE Python Wrapper: it provides a Python proxy to the generated C code from a SCADE Suite application. This allows us to run our SCADE application directly from Python code, set inputs, observe local variables, outputs, and probes.<\/p>\n<p>This opens the entire Python ecosystem to a SCADE application<a href=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-a-whole-new-world.gif\">.<\/a><\/p>\n<h3  id=\"TESTING-OUR-FILTER-WITH-A-JUPYTER-NOTEBOOK\">Testing our filter with a Jupyter notebook<\/h3>\n<p>To test our filter further, we will use a Jupyter notebook in which we will exercise our SCADE model.<\/p>\n<h4  id=\"INSTALLING-THE-SCADE-PYTHON-WRAPPER\">Installing the SCADE Python Wrapper<\/h4>\n<p>First, let&#8217;s install the <a href=\"https:\/\/python-wrapper.scade.docs.pyansys.com\/\">SCADE Python Wrapper<\/a>. It is available as a public Python package which can be installed from the Ansys SCADE Extension Manager (in SCADE 2024R2+), or from a simple command line in the included Python installation:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>pip<span style=\"color: #bbbbbb\"> <\/span>install<span style=\"color: #bbbbbb\"> <\/span>ansys-scade-python-wrapper\r\n<\/pre>\n<\/div>\n<h4  id=\"GENERATING-A-PYTHON-MODULE-FOR-OUR-SCADE-MODEL\">Generating a Python module for our SCADE model<\/h4>\n<p>Once the Python wrapper is installed for our instance of SCADE, we see new screens and options in our SCADE code generation settings.<\/p>\n<p>We start by creating a new code generation configuration under <em>Project &gt; Configurations<\/em>:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-add-configuration-1.jpg\" style=\"max-height: 285px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>Then, in <em>Project &gt; Code Generator &gt; Settings &gt; Code Integration<\/em>, we select <em>Proxy for Python<\/em> as a <em>Target<\/em>:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-configuration-integration-1.jpg\" style=\"max-height: 350px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>We select, in tab <em>Compiler<\/em>, the proper options for our target environment:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-configuration-compiler-1.jpg\" style=\"max-height: 350px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>In tab <em>General<\/em>, we check that the proper root operator is selected:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-configuration-general-1.jpg\" style=\"max-height: 350px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>Finally, in tab <em>Python<\/em>, we choose a module name:<\/p>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-configuration-python-1.jpg\" style=\"max-height: 350px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>We now generate and build the module, which ends up in the target directory (as previously defined in code generator options). Two important files are generated: <code>MyPythonModule.py<\/code> and <code>MyPythonModule.dll<\/code>.<\/p>\n<p><code>MyPythonModule.py<\/code> uses <code>ctypes<\/code> to wrap our operator in a class that exposes its inputs (<code>x<\/code> and <code>alpha<\/code>), its output (<code>y<\/code>), and functions to run it:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"color: #999988;font-style: italic\"># generated by SCADE Python Proxy Extension 1.8.2<\/span>\r\n\r\n<span style=\"font-weight: bold\">from<\/span> <span style=\"color: #555555\">pathlib<\/span> <span style=\"font-weight: bold\">import<\/span> Path\r\n<span style=\"font-weight: bold\">import<\/span> <span style=\"color: #555555\">ctypes<\/span>\r\n\r\n<span style=\"color: #999988;font-style: italic\"># load the SCADE executable code<\/span>\r\n_lib <span style=\"font-weight: bold\">=<\/span> ctypes<span style=\"font-weight: bold\">.<\/span>cdll<span style=\"font-weight: bold\">.<\/span>LoadLibrary(<span style=\"color: #999999\">str<\/span>(Path(<span style=\"color: #008080\">__file__<\/span>)<span style=\"font-weight: bold\">.<\/span>with_suffix(<span style=\"color: #bb8844\">&#039;&#039;<\/span>)))\r\n\r\n<span style=\"color: #999988;font-style: italic\"># C structures<\/span>\r\n<span style=\"font-weight: bold\">class<\/span> <span style=\"color: #445588;font-weight: bold\">_CinC_LowPassRC<\/span>(ctypes<span style=\"font-weight: bold\">.<\/span>Structure):\r\n\u00a0 \u00a0 _fields_ <span style=\"font-weight: bold\">=<\/span> [(<span style=\"color: #bb8844\">&#039;x&#039;<\/span>, ctypes<span style=\"font-weight: bold\">.<\/span>c_float),\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 (<span style=\"color: #bb8844\">&#039;alpha&#039;<\/span>, ctypes<span style=\"font-weight: bold\">.<\/span>c_float)]\r\n\r\n<span style=\"font-weight: bold\">class<\/span> <span style=\"color: #445588;font-weight: bold\">LowPassRC<\/span>:\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">__init__<\/span>(<span style=\"color: #999999\">self<\/span>, cosim: <span style=\"color: #999999\">bool<\/span> <span style=\"font-weight: bold\">=<\/span> <span style=\"font-weight: bold\">True<\/span>):\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_in_c <span style=\"font-weight: bold\">=<\/span> _CinC_LowPassRC()\r\n\u00a0 \u00a0 \u00a0 \u00a0 alloc_fct <span style=\"font-weight: bold\">=<\/span> _lib<span style=\"font-weight: bold\">.<\/span>py_alloc_LowPassRC\r\n\u00a0 \u00a0 \u00a0 \u00a0 alloc_fct<span style=\"font-weight: bold\">.<\/span>argtypes <span style=\"font-weight: bold\">=<\/span> []\r\n\u00a0 \u00a0 \u00a0 \u00a0 alloc_fct<span style=\"font-weight: bold\">.<\/span>restype <span style=\"font-weight: bold\">=<\/span> ctypes<span style=\"font-weight: bold\">.<\/span>c_void_p\r\n\u00a0 \u00a0 \u00a0 \u00a0 context <span style=\"font-weight: bold\">=<\/span> alloc_fct()\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_out_c <span style=\"font-weight: bold\">=<\/span> ctypes<span style=\"font-weight: bold\">.<\/span>c_void_p<span style=\"font-weight: bold\">.<\/span>from_address(context)\r\n\u00a0 \u00a0 \u00a0 \u00a0 offsets <span style=\"font-weight: bold\">=<\/span> (ctypes<span style=\"font-weight: bold\">.<\/span>c_int64 <span style=\"font-weight: bold\">*<\/span> <span style=\"color: #009999\">1<\/span>)<span style=\"font-weight: bold\">.<\/span>in_dll(_lib, <span style=\"color: #bb8844\">&quot;py_offsets_LowPassRC&quot;<\/span>)\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>reset_fct <span style=\"font-weight: bold\">=<\/span> _lib<span style=\"font-weight: bold\">.<\/span>LowPassRC_reset\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>reset_fct<span style=\"font-weight: bold\">.<\/span>restype <span style=\"font-weight: bold\">=<\/span> ctypes<span style=\"font-weight: bold\">.<\/span>c_void_p\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>cycle_fct <span style=\"font-weight: bold\">=<\/span> _lib<span style=\"font-weight: bold\">.<\/span>LowPassRC\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>cycle_fct<span style=\"font-weight: bold\">.<\/span>argtypes <span style=\"font-weight: bold\">=<\/span> [\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ctypes<span style=\"font-weight: bold\">.<\/span>POINTER(_CinC_LowPassRC),\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ctypes<span style=\"font-weight: bold\">.<\/span>POINTER(ctypes<span style=\"font-weight: bold\">.<\/span>c_void_p),\r\n\u00a0 \u00a0 \u00a0 \u00a0 ]\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>cycle_fct<span style=\"font-weight: bold\">.<\/span>restype <span style=\"font-weight: bold\">=<\/span> ctypes<span style=\"font-weight: bold\">.<\/span>c_void_p\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_y <span style=\"font-weight: bold\">=<\/span> ctypes<span style=\"font-weight: bold\">.<\/span>c_float<span style=\"font-weight: bold\">.<\/span>from_address(context <span style=\"font-weight: bold\">+<\/span> offsets[<span style=\"color: #009999\">0<\/span>])\r\n\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">__del__<\/span>(<span style=\"color: #999999\">self<\/span>):\r\n\u00a0 \u00a0 \u00a0 \u00a0 free_fct <span style=\"font-weight: bold\">=<\/span> _lib<span style=\"font-weight: bold\">.<\/span>py_free_LowPassRC\r\n\u00a0 \u00a0 \u00a0 \u00a0 free_fct<span style=\"font-weight: bold\">.<\/span>argtypes <span style=\"font-weight: bold\">=<\/span> [ctypes<span style=\"font-weight: bold\">.<\/span>c_void_p]\r\n\u00a0 \u00a0 \u00a0 \u00a0 free_fct<span style=\"font-weight: bold\">.<\/span>restype <span style=\"font-weight: bold\">=<\/span> <span style=\"font-weight: bold\">None<\/span>\r\n\u00a0 \u00a0 \u00a0 \u00a0 free_fct(ctypes<span style=\"font-weight: bold\">.<\/span>byref(<span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_out_c))\r\n\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">call_reset<\/span>(<span style=\"color: #999999\">self<\/span>) <span style=\"font-weight: bold\">-&gt;<\/span> <span style=\"font-weight: bold\">None<\/span>:\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>reset_fct(ctypes<span style=\"font-weight: bold\">.<\/span>byref(<span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_out_c))\r\n\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">call_cycle<\/span>(<span style=\"color: #999999\">self<\/span>, cycles: <span style=\"color: #999999\">int<\/span> <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">1<\/span>, refresh: <span style=\"color: #999999\">bool<\/span> <span style=\"font-weight: bold\">=<\/span> <span style=\"font-weight: bold\">True<\/span>, debug: <span style=\"color: #999999\">bool<\/span> <span style=\"font-weight: bold\">=<\/span> <span style=\"font-weight: bold\">False<\/span>) <span style=\"font-weight: bold\">-&gt;<\/span> <span style=\"font-weight: bold\">None<\/span>:\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"font-weight: bold\">for<\/span> i <span style=\"font-weight: bold\">in<\/span> <span style=\"color: #999999\">range<\/span>(cycles):\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>cycle_fct(\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_in_c,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_out_c,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 )\r\n\r\n\u00a0 \u00a0 @property\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">x<\/span>(<span style=\"color: #999999\">self<\/span>) <span style=\"font-weight: bold\">-&gt;<\/span> <span style=\"color: #999999\">float<\/span>:\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"font-weight: bold\">return<\/span> <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_in_c<span style=\"font-weight: bold\">.<\/span>x\r\n\r\n\u00a0 \u00a0 @x<span style=\"font-weight: bold\">.<\/span>setter\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">x<\/span>(<span style=\"color: #999999\">self<\/span>, value: <span style=\"color: #999999\">float<\/span>) <span style=\"font-weight: bold\">-&gt;<\/span> <span style=\"font-weight: bold\">None<\/span>:\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_in_c<span style=\"font-weight: bold\">.<\/span>x <span style=\"font-weight: bold\">=<\/span> value\r\n\r\n\u00a0 \u00a0 @property\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">alpha<\/span>(<span style=\"color: #999999\">self<\/span>) <span style=\"font-weight: bold\">-&gt;<\/span> <span style=\"color: #999999\">float<\/span>:\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"font-weight: bold\">return<\/span> <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_in_c<span style=\"font-weight: bold\">.<\/span>alpha\r\n\r\n\u00a0 \u00a0 @alpha<span style=\"font-weight: bold\">.<\/span>setter\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">alpha<\/span>(<span style=\"color: #999999\">self<\/span>, value: <span style=\"color: #999999\">float<\/span>) <span style=\"font-weight: bold\">-&gt;<\/span> <span style=\"font-weight: bold\">None<\/span>:\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_in_c<span style=\"font-weight: bold\">.<\/span>alpha <span style=\"font-weight: bold\">=<\/span> value\r\n\r\n\u00a0 \u00a0 @property\r\n\u00a0 \u00a0 <span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">y<\/span>(<span style=\"color: #999999\">self<\/span>) <span style=\"font-weight: bold\">-&gt;<\/span> <span style=\"color: #999999\">float<\/span>:\r\n\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"font-weight: bold\">return<\/span> <span style=\"color: #999999\">self<\/span><span style=\"font-weight: bold\">.<\/span>_y<span style=\"font-weight: bold\">.<\/span>value\r\n\r\n<span style=\"color: #999988;font-style: italic\"># end of file<\/span>\r\n<\/pre>\n<\/div>\n<h4  id=\"SETTING-UP-OUR-JUPYTER-NOTEBOOK\">Setting up our Jupyter notebook<\/h4>\n<p>Jupyter notebooks are a great tool for interactive programming. They allow a developer to write code and documentation in successive blocks that can then be re-run at will. The notebook presented in this article is available for download at the end. For now, let&#8217;s walk through it section by section.<\/p>\n<p>First, we initiate the notebook by adding the generated Python Proxy module to our path and importing it. The most straightforward way to do this would be to append it to <code>sys.path<\/code>:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"font-weight: bold\">import<\/span> <span style=\"color: #555555\">sys<\/span><span style=\"font-weight: bold\">,<\/span> <span style=\"color: #555555\">os<\/span>\r\n\r\nharness_dir <span style=\"font-weight: bold\">=<\/span> os<span style=\"font-weight: bold\">.<\/span>path<span style=\"font-weight: bold\">.<\/span>join(os<span style=\"font-weight: bold\">.<\/span>path<span style=\"font-weight: bold\">.<\/span>abspath(<span style=\"color: #bb8844\">&#039;&#039;<\/span>), <span style=\"color: #bb8844\">&#039;LowPassRCSuite&#039;<\/span>, <span style=\"color: #bb8844\">&#039;PythonProxy&#039;<\/span>)\r\nsys<span style=\"font-weight: bold\">.<\/span>path<span style=\"font-weight: bold\">.<\/span>append(harness_dir)\r\n<span style=\"font-weight: bold\">from<\/span> <span style=\"color: #555555\">MyPythonModule<\/span> <span style=\"font-weight: bold\">import<\/span> LowPassRC\r\n<\/pre>\n<\/div>\n<p>Then, we import modules that will be useful later on:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"font-weight: bold\">%<\/span>matplotlib ipympl\r\n<span style=\"font-weight: bold\">import<\/span> <span style=\"color: #555555\">matplotlib.pyplot<\/span> <span style=\"font-weight: bold\">as<\/span> <span style=\"color: #555555\">plt<\/span>\r\n<span style=\"font-weight: bold\">import<\/span> <span style=\"color: #555555\">numpy<\/span> <span style=\"font-weight: bold\">as<\/span> <span style=\"color: #555555\">np<\/span>\r\n<span style=\"font-weight: bold\">import<\/span> <span style=\"color: #555555\">scipy<\/span>\r\n<span style=\"font-weight: bold\">import<\/span> <span style=\"color: #555555\">math<\/span>\r\n<\/pre>\n<\/div>\n<p>Now, we can instantiate our SCADE operator as an object (meaning we can have different instances of an operator, each with independent states).<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>lowpassfilter <span style=\"font-weight: bold\">=<\/span> LowPassRC()\r\n<\/pre>\n<\/div>\n<p>From there, we can use pretty much everything accessible from the Python ecosystem.<\/p>\n<h4  id=\"TIME-DOMAIN-TESTING\">Time-domain testing<\/h4>\n<p>Since we want to feed discrete signals to our filter, we write:<\/p>\n<ul>\n<li>A wrapping function that takes the signal and parameters as input and returns the filtered signal.<\/li>\n<li>A function to compute alpha from the sampling period and the cutoff frequency:<\/li>\n<\/ul>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span><span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">run_lowpass<\/span>(alpha:<span style=\"color: #999999\">float<\/span>,x:<span style=\"color: #999999\">list<\/span>):\r\n    lowpassfilter<span style=\"font-weight: bold\">.<\/span>call_reset()\r\n    lowpassfilter<span style=\"font-weight: bold\">.<\/span>alpha<span style=\"font-weight: bold\">=<\/span> alpha\r\n    out_list <span style=\"font-weight: bold\">=<\/span> []\r\n    <span style=\"font-weight: bold\">for<\/span> i <span style=\"font-weight: bold\">in<\/span> <span style=\"color: #999999\">range<\/span>(<span style=\"color: #009999\">0<\/span>, <span style=\"color: #999999\">len<\/span>(x)):\r\n        lowpassfilter<span style=\"font-weight: bold\">.<\/span>x <span style=\"font-weight: bold\">=<\/span> x[i]\r\n        lowpassfilter<span style=\"font-weight: bold\">.<\/span>call_cycle()\r\n        out_list<span style=\"font-weight: bold\">.<\/span>append(lowpassfilter<span style=\"font-weight: bold\">.<\/span>y)\r\n    <span style=\"font-weight: bold\">return<\/span> out_list\r\n\r\n<span style=\"font-weight: bold\">def<\/span> <span style=\"color: #990000;font-weight: bold\">get_alpha<\/span>(wc:<span style=\"color: #999999\">float<\/span>,dt:<span style=\"color: #999999\">float<\/span>):\r\n    RC <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">1<\/span><span style=\"font-weight: bold\">\/<\/span>(wc<span style=\"font-weight: bold\">*<\/span><span style=\"color: #009999\">2<\/span><span style=\"font-weight: bold\">*<\/span>math<span style=\"font-weight: bold\">.<\/span>pi)\r\n    <span style=\"font-weight: bold\">return<\/span> dt<span style=\"font-weight: bold\">\/<\/span>(RC<span style=\"font-weight: bold\">+<\/span>dt)\r\n<\/pre>\n<\/div>\n<p>Now, let&#8217;s run our filter using a simple step signal:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>fs <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">100<\/span> <span style=\"color: #999988;font-style: italic\"># Sampling time of 10ms<\/span>\r\ndt <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">1<\/span><span style=\"font-weight: bold\">\/<\/span>fs <span style=\"color: #999988;font-style: italic\"># Sampling time of 10ms<\/span>\r\nwc <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">10<\/span> <span style=\"color: #999988;font-style: italic\"># cutoff frequency of 10 Hz<\/span>\r\nt <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">1<\/span> <span style=\"color: #999988;font-style: italic\"># Signal duration<\/span>\r\nimpulse <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>concatenate((np<span style=\"font-weight: bold\">.<\/span>zeros(<span style=\"color: #009999\">50<\/span>),np<span style=\"font-weight: bold\">.<\/span>ones(<span style=\"color: #009999\">50<\/span>))) <span style=\"color: #999988;font-style: italic\"># Let&#039;s make 100 samples, the step is at the 51st sampling.<\/span>\r\n\r\ntime <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>linspace(<span style=\"color: #009999\">0<\/span>,t,t<span style=\"font-weight: bold\">*<\/span>fs)\r\n\r\na <span style=\"font-weight: bold\">=<\/span> get_alpha(wc,dt) <span style=\"color: #999988;font-style: italic\"># Compute the alpha value for our filter<\/span>\r\nfiltered_impulse <span style=\"font-weight: bold\">=<\/span> run_lowpass(a,impulse) <span style=\"color: #999988;font-style: italic\"># Run the signal through the filter, get the output<\/span>\r\n<\/pre>\n<\/div>\n<p>And plot the results:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>plt<span style=\"font-weight: bold\">.<\/span>style<span style=\"font-weight: bold\">.<\/span>use(<span style=\"color: #bb8844\">&#039;default&#039;<\/span>)\r\nfig1 <span style=\"font-weight: bold\">=<\/span> plt<span style=\"font-weight: bold\">.<\/span>figure()\r\nax1 <span style=\"font-weight: bold\">=<\/span> fig1<span style=\"font-weight: bold\">.<\/span>add_subplot(<span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>)\r\nax1<span style=\"font-weight: bold\">.<\/span>plot(time, impulse, label<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;Step&#039;<\/span>)\r\nax1<span style=\"font-weight: bold\">.<\/span>plot(time, filtered_impulse, label<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;Filtered Step&#039;<\/span>)\r\n<\/pre>\n<\/div>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-step-signal-1.svg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>Now, let&#8217;s try a sinusoid signal:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>fs <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">500<\/span> <span style=\"color: #999988;font-style: italic\"># Sampling time of 10ms<\/span>\r\ndt <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">1<\/span><span style=\"font-weight: bold\">\/<\/span>fs <span style=\"color: #999988;font-style: italic\"># Sampling time of 10ms<\/span>\r\nwc <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">10<\/span> <span style=\"color: #999988;font-style: italic\"># cutoff frequency of 10 Hz<\/span>\r\nt <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">1<\/span> <span style=\"color: #999988;font-style: italic\"># Signal duration<\/span>\r\nsin_freq <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">8<\/span>\r\ntime <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>linspace(<span style=\"color: #009999\">0<\/span>,t,t<span style=\"font-weight: bold\">*<\/span>fs)\r\nsin <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>sin(time<span style=\"font-weight: bold\">*<\/span><span style=\"color: #009999\">2<\/span><span style=\"font-weight: bold\">*<\/span>math<span style=\"font-weight: bold\">.<\/span>pi<span style=\"font-weight: bold\">*<\/span>sin_freq)\r\na <span style=\"font-weight: bold\">=<\/span> get_alpha(wc,dt)\r\nfiltered_sin <span style=\"font-weight: bold\">=<\/span> run_lowpass(a,sin)\r\n<\/pre>\n<\/div>\n<p>And plot the results:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>fig2 <span style=\"font-weight: bold\">=<\/span> plt<span style=\"font-weight: bold\">.<\/span>figure()\r\nax2 <span style=\"font-weight: bold\">=<\/span> fig2<span style=\"font-weight: bold\">.<\/span>add_subplot(<span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>)\r\nax2<span style=\"font-weight: bold\">.<\/span>plot(time, sin, label<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;Sin&#039;<\/span>)\r\nax2<span style=\"font-weight: bold\">.<\/span>plot(time, filtered_sin, label<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;Filtered Sin&#039;<\/span>)\r\n<\/pre>\n<\/div>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-sinusoid-1.svg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>And with this, we have replicated our time-domain testing in a Jupyter notebook.<\/p>\n<h4  id=\"FREQUENCY-RESPONSE-IN-JUPYTER\">Frequency response in Jupyter<\/h4>\n<p>This is where we got stuck last time. As a reminder, we want to check the frequency response of our filter.<\/p>\n<p>First, we generate a sweep signal:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>duration <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">5<\/span> <span style=\"color: #999988;font-style: italic\"># 5 second signal<\/span>\r\nsampling_freq <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">200000<\/span> <span style=\"color: #999988;font-style: italic\"># 20kHz sampling freq<\/span>\r\nmin_freq <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">0.2<\/span> <span style=\"color: #999988;font-style: italic\"># Generate a signal that start at 0.2hz<\/span>\r\nmax_freq <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">10000<\/span> <span style=\"color: #999988;font-style: italic\"># And ends up at 10kHz<\/span>\r\n\r\nt1 <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>linspace(<span style=\"color: #009999\">0<\/span>,duration,sampling_freq <span style=\"font-weight: bold\">*<\/span> duration)\r\nsweep_frequency <span style=\"font-weight: bold\">=<\/span> [(min_freq<span style=\"font-weight: bold\">*<\/span>(max_freq<span style=\"font-weight: bold\">\/<\/span>min_freq)<span style=\"font-weight: bold\">**<\/span>(t<span style=\"font-weight: bold\">\/<\/span>duration)) <span style=\"font-weight: bold\">for<\/span> t <span style=\"font-weight: bold\">in<\/span> t1]\r\nsweep_signal <span style=\"font-weight: bold\">=<\/span> scipy<span style=\"font-weight: bold\">.<\/span>signal<span style=\"font-weight: bold\">.<\/span>chirp(t<span style=\"font-weight: bold\">=<\/span>t1,f0<span style=\"font-weight: bold\">=<\/span>min_freq,t1<span style=\"font-weight: bold\">=<\/span>duration,f1<span style=\"font-weight: bold\">=<\/span>max_freq,method<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;log&#039;<\/span>) <span style=\"color: #999988;font-style: italic\"># Generate a swept sine signal<\/span>\r\n\r\n<span style=\"color: #999988;font-style: italic\"># Plot it<\/span>\r\nfig3 <span style=\"font-weight: bold\">=<\/span> plt<span style=\"font-weight: bold\">.<\/span>figure()\r\nax3 <span style=\"font-weight: bold\">=<\/span> fig3<span style=\"font-weight: bold\">.<\/span>add_subplot(<span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>)\r\nax3<span style=\"font-weight: bold\">.<\/span>plot(sweep_frequency, sweep_signal, label<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;Swept Signal&#039;<\/span>)\r\nax3<span style=\"font-weight: bold\">.<\/span>set_xscale(<span style=\"color: #bb8844\">&#039;log&#039;<\/span>)\r\n<\/pre>\n<\/div>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-sweep-signal-1.svg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>We feed this signal to our filter and gather outputs:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>wc <span style=\"font-weight: bold\">=<\/span> \u00a0max_freq<span style=\"font-weight: bold\">*<\/span><span style=\"color: #009999\">0.1<\/span> <span style=\"color: #999988;font-style: italic\"># 1000 Hz cutoff frequency<\/span>\r\ndt <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">1<\/span><span style=\"font-weight: bold\">\/<\/span>sampling_freq\r\nalpha <span style=\"font-weight: bold\">=<\/span> get_alpha(wc,dt)\r\n\r\noutput_signal <span style=\"font-weight: bold\">=<\/span> run_lowpass(alpha<span style=\"font-weight: bold\">=<\/span>alpha,x<span style=\"font-weight: bold\">=<\/span>sweep_signal)\r\n\r\n<span style=\"color: #999988;font-style: italic\"># Plot the result<\/span>\r\nfig4 <span style=\"font-weight: bold\">=<\/span> plt<span style=\"font-weight: bold\">.<\/span>figure()\r\nax4 <span style=\"font-weight: bold\">=<\/span> fig4<span style=\"font-weight: bold\">.<\/span>add_subplot(<span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">1<\/span>)\r\nax4<span style=\"font-weight: bold\">.<\/span>plot(sweep_frequency, sweep_signal, label<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;Sweep Signal&#039;<\/span>)\r\nax4<span style=\"font-weight: bold\">.<\/span>plot(sweep_frequency, output_signal, label<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;Output Signal&#039;<\/span>)\r\nax4<span style=\"font-weight: bold\">.<\/span>set_xscale(<span style=\"color: #bb8844\">&#039;log&#039;<\/span>)\r\n<\/pre>\n<\/div>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-sweep-and-output-signals-1.svg\" style=\"max-height: 500px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>We can see the attenuation from 1kHz, corresponding to the cutoff frequency of our low-pass filter.<\/p>\n<p>We can now leverage <code>numpy<\/code> to perform a Fast Fourier Transform on the signal and get the frequency response:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff;overflow:auto;width:auto;background:none;border:none;padding:.2em .6em\">\n<pre style=\"margin: 0;line-height: 125%\"><span><\/span>f <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>fft<span style=\"font-weight: bold\">.<\/span>rfftfreq(sampling_freq<span style=\"font-weight: bold\">*<\/span>duration, <span style=\"color: #009999\">1<\/span> <span style=\"font-weight: bold\">\/<\/span> sampling_freq)\r\nX_in <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>fft<span style=\"font-weight: bold\">.<\/span>rfft(sweep_signal)\r\nX_out <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>fft<span style=\"font-weight: bold\">.<\/span>rfft(output_signal)\r\n\r\n<span style=\"color: #999988;font-style: italic\"># Compute frequency response and phase Shift<\/span>\r\nH <span style=\"font-weight: bold\">=<\/span> X_out <span style=\"font-weight: bold\">\/<\/span> X_in\r\nmagnitude_response <span style=\"font-weight: bold\">=<\/span> <span style=\"color: #009999\">20<\/span> <span style=\"font-weight: bold\">*<\/span> np<span style=\"font-weight: bold\">.<\/span>log10(np<span style=\"font-weight: bold\">.<\/span>abs(H)) <span style=\"color: #999988;font-style: italic\"># Convert to dB<\/span>\r\nphase_response <span style=\"font-weight: bold\">=<\/span> np<span style=\"font-weight: bold\">.<\/span>unwrap(np<span style=\"font-weight: bold\">.<\/span>angle(H, deg<span style=\"font-weight: bold\">=True<\/span>))\r\n\r\n<span style=\"color: #999988;font-style: italic\"># Plot frequency response and phase shift<\/span>\r\nfig <span style=\"font-weight: bold\">=<\/span> plt<span style=\"font-weight: bold\">.<\/span>figure()\r\nax1 <span style=\"font-weight: bold\">=<\/span> fig<span style=\"font-weight: bold\">.<\/span>add_subplot(<span style=\"color: #009999\">2<\/span>,<span style=\"color: #009999\">1<\/span>,<span style=\"color: #009999\">1<\/span>)\r\nax2 <span style=\"font-weight: bold\">=<\/span> fig<span style=\"font-weight: bold\">.<\/span>add_subplot(<span style=\"color: #009999\">2<\/span>,<span style=\"color: #009999\">1<\/span>, <span style=\"color: #009999\">2<\/span>,sharex<span style=\"font-weight: bold\">=<\/span>ax1)\r\nax1<span style=\"font-weight: bold\">.<\/span>set_xscale(<span style=\"color: #bb8844\">&#039;log&#039;<\/span>)\r\nax1<span style=\"font-weight: bold\">.<\/span>axvline(wc,color<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;#ffb71b&#039;<\/span>)\r\nax1<span style=\"font-weight: bold\">.<\/span>axline((<span style=\"color: #009999\">0.0<\/span>,<span style=\"font-weight: bold\">-<\/span><span style=\"color: #009999\">3.0<\/span>),(wc,<span style=\"font-weight: bold\">-<\/span><span style=\"color: #009999\">3.0<\/span>),color<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;#ffb71b&#039;<\/span>) <span style=\"color: #999988;font-style: italic\"># We expect attenuation at wc to be -3dB<\/span>\r\nax1<span style=\"font-weight: bold\">.<\/span>set_ylabel(<span style=\"color: #bb8844\">&#039;Magnitude (dB)&#039;<\/span>)\r\nax2<span style=\"font-weight: bold\">.<\/span>set_xlabel(<span style=\"color: #bb8844\">&#039;Frequency (Hz)&#039;<\/span>)\r\nax2<span style=\"font-weight: bold\">.<\/span>axvline(wc,color<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;#ffb71b&#039;<\/span>)\r\nax2<span style=\"font-weight: bold\">.<\/span>axline((<span style=\"color: #009999\">0.0<\/span>,<span style=\"font-weight: bold\">-<\/span><span style=\"color: #009999\">45.0<\/span>),(wc,<span style=\"font-weight: bold\">-<\/span><span style=\"color: #009999\">45.0<\/span>),color<span style=\"font-weight: bold\">=<\/span><span style=\"color: #bb8844\">&#039;#ffb71b&#039;<\/span>) <span style=\"color: #999988;font-style: italic\"># And phase shift at wc to be at -45 deg<\/span>\r\nax1<span style=\"font-weight: bold\">.<\/span>set_xlim(<span style=\"color: #009999\">1<\/span>,max_freq)\r\nax2<span style=\"font-weight: bold\">.<\/span>set_ylabel(<span style=\"color: #bb8844\">&#039;Phase (deg)&#039;<\/span>)\r\nax1<span style=\"font-weight: bold\">.<\/span>plot(f, magnitude_response)\r\nax2<span style=\"font-weight: bold\">.<\/span>plot(f, phase_response)\r\n<\/pre>\n<\/div>\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-freq-response-1.svg\" style=\"max-height: 700px !important\" \/><br \/>\n    <em><\/em>\n<\/p>\n<p>Because we are using a Jupyter notebook, we can quickly repeat these analyses with different parameter values for the filter, and rapidly find out which ones provide the expected performances.<\/p>\n<h3  id=\"CONCLUSION\">Conclusion<\/h3>\n<p>In this article, we saw how to bridge SCADE&#8217;s model-based development environment with the Jupyter interactive computing platform. This opens the Python ecosystem to SCADE engineers, unlocking boundless possibilities: custom analysis, simulation scripting, seamless integration with external tools, and many more.<\/p>\n<p>Through the example of a first-order low-pass filter, we demonstrated how Jupyter Notebooks can enhance SCADE&#8217;s capabilities by enabling parameter tuning, automating simulations, and visualizing results in an interactive and user-friendly environment.<\/p>\n<h3  id=\"WANT-TO-LEARN-MORE\">Want to learn more?<\/h3>\n<p>You may download the example model and notebook from this blog <a href=\"https:\/\/github.com\/ansys\/scade-examples\/releases\/latest\/download\/2025-02-26-python-wrapper.zip\">here<\/a> (or <a href=\"https:\/\/github.com\/ansys\/scade-examples\/tree\/main\/models\/2025-02-26-python-wrapper\/\">browse its sources<\/a>).<\/p>\n<p>You may also start a 30-day free trial of SCADE Suite using this <a href=\"https:\/\/www.ansys.com\/products\/embedded-software\/ansys-scade-suite\/scade-trial\">link<\/a>. If you&#8217;d like to know more about how Ansys SCADE can improve your software development workflow, you may contact us from the <a href=\"https:\/\/www.ansys.com\/products\/embedded-software\">Ansys Embedded Software page<\/a>.<\/p>\n<h3  id=\"ABOUT-THE-AUTHOR\">About the author<\/h3>\n<table style=\"max-width: 1000px;border: none !important\">\n<tr>\n<td style=\"padding: 0px 10px;border: none !important\">\n<p style=\"text-align: center\">\n    <img decoding=\"async\" src=\"https:\/\/innovationspace.ansys.com\/knowledge\/wp-content\/uploads\/sites\/4\/2025\/02\/scade-035-author-1.png\" style=\"max-height: 150px !important\" \/><br \/>\n                <em><\/em>\n<\/p>\n<\/td>\n<td style=\"padding: 0px 10px;border: none !important\">\n<p><strong>Romain Andrieux<\/strong> (<a href=\"https:\/\/www.linkedin.com\/in\/romain-andrieux-922a36103\">LinkedIn<\/a>) is a Product Specialist Engineer at Ansys. He has been working on SCADE Ecosystem and the SCADE Support team development for 2 years.<\/p>\n<\/td>\n<\/tr>\n<\/table>\n","protected":false},"template":"","class_list":["post-196291","topic","type-topic","status-publish","hentry","topic-tag-jupyter","topic-tag-matplotlib","topic-tag-notebook","topic-tag-numpy","topic-tag-python","topic-tag-scade","topic-tag-scipy"],"aioseo_notices":[],"acf":[],"custom_fields":[{"0":{"_edit_lock":["1747919756:1769"],"_edit_last":["1769"],"_aioseo_title":[null],"_aioseo_description":[null],"_aioseo_keywords":["a:0:{}"],"_aioseo_og_title":[null],"_aioseo_og_description":[null],"_aioseo_og_article_section":[""],"_aioseo_og_article_tags":["a:0:{}"],"_aioseo_twitter_title":[null],"_aioseo_twitter_description":[null],"filter_by_optics_product":["Lumerical"],"_filter_by_optics_product":["field_64fb192ba3121"],"application_name":[""],"_application_name":["field_64a80903c8e15"],"family":[""],"_family":["field_64a809229a857"],"siebel_km_number":[""],"_siebel_km_number":["field_63ecbffce60db"],"salesforce_km_number":[""],"_salesforce_km_number":["field_63ecc018e60dc"],"km_published_date":[""],"_km_published_date":["field_64c77704499dd"],"product_version":[""],"_product_version":["field_64c776cb4fd2e"],"_bbp_forum_id":["27825"],"_bbp_topic_id":["196673"],"_bbp_author_ip":["194.98.52.82"],"_bbp_last_reply_id":["0"],"_bbp_last_active_id":["196292"],"_bbp_last_active_time":["2025-02-26 09:39:50"],"_bbp_reply_count":["0"],"_bbp_reply_count_hidden":["0"],"_bbp_voice_count":["0"],"_btv_view_count":["1802"],"_bbp_likes_count":["7"]},"test":"solution"}],"_links":{"self":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics\/196291","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics"}],"about":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/types\/topic"}],"version-history":[{"count":11,"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics\/196291\/revisions"}],"predecessor-version":[{"id":196673,"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/topics\/196291\/revisions\/196673"}],"wp:attachment":[{"href":"https:\/\/innovationspace.ansys.com\/knowledge\/wp-json\/wp\/v2\/media?parent=196291"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}