{"id":30983,"date":"2024-09-25T13:44:00","date_gmt":"2024-09-25T20:44:00","guid":{"rendered":"https:\/\/digilent.com\/blog\/?p=30983"},"modified":"2025-01-15T12:54:47","modified_gmt":"2025-01-15T20:54:47","slug":"leveraging-the-power-of-python-creating-a-custom-script-module-in-dasylab","status":"publish","type":"post","link":"https:\/\/digilent.com\/blog\/leveraging-the-power-of-python-creating-a-custom-script-module-in-dasylab\/","title":{"rendered":"Leveraging the Power of Python: Creating a Custom Script Module in DASYLab"},"content":{"rendered":"<p><span data-contrast=\"auto\">Welcome back to the Digilent Blog! You may have heard about how Digilent is building support for our Analog Discovery devices within the DASYLab software through a custom module. This post will go into some detail on how one would create their <em>own<\/em> custom script module within DASYLab to enable your own custom functionality.\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">DASYLab is a software suite that interfaces with different DAQ and Datalogging devices, letting users collect and then process the data however they need through different triggering, statistic, processing, network, and other useful click-and-drag modules.\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">One such module that we will be using is the Script module, which will allow us to create and run our own Python scripts, enabling custom data processing that isn\u2019t directly built into DASYLab. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Our simple example will integrate numpy to do a bit of averaging in our custom module \u2013 yes, averaging is included by default in DASYLab already, but I did say it was a simple example. Plus if we can successfully custom process a block of incoming data and then display the results, the rest of custom processing is \u201cjust typing\u201d. <readonly aria-label=\"Wink\" itemscope=\"\" itemtype=\"http:\/\/schema.skype.com\/Emoji\" itemid=\"wink\" title=\"Wink\" contenteditable=\"false\"><img decoding=\"async\" aria-label=\"Wink\" height=\"20px\" width=\"20px\" draggable=\"false\" alt=\"Wink\" src=\"https:\/\/statics.teams.cdn.office.net\/evergreen-assets\/personal-expressions\/v2\/assets\/emoticons\/wink\/default\/50_f.png?v=v15\" blockindent=\"1px\" \/><\/readonly>\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">To get started open up a blank workspace within DASYLab.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Within the modules tab on the left-hand side of the GUI, open the Special folder and click and drag a Script module to the empty workspace.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleBlankWorkspace-1024x535.png\" alt=\"\" width=\"735\" height=\"384\" class=\"alignnone size-large wp-image-30991\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleBlankWorkspace-1024x535.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleBlankWorkspace-600x313.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleBlankWorkspace-1536x802.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleBlankWorkspace.png 1906w\" sizes=\"auto, (max-width: 735px) 100vw, 735px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">You will be immediately presented with some configuration settings for our Script Module, namely how many inputs and outputs you wish to have on the module. Let\u2019s choose \u201c* User-defined*\u201d from the dropdown menu and set the module to have 1 input and 1 output. The maximum number of channels (ignoring jargon and technicalities for a moment, this can be thought as the amount of \u2018data streams\u2019 that can be processed) can be left at 16, though we won\u2019t be utilizing more than one input channel in this demo. The channel assignment we\u2019ll put at \u201c1 : n, n : n\u201d, to indicate that our one input will be going to all outputs. We\u2019ll set up a second output to be generated off of the input within the custom module itself.<\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModulePredefinedSettings.png\" alt=\"\" width=\"476\" height=\"432\" class=\"alignnone size-full wp-image-30992\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Once the Script Module is in your workspace, double click on it and choose the \u201cUse External Editor\u201d option. You\u2019ll be presented with a popup that informs you that you will no longer be able to edit the script directly in DASYLab anymore, but that\u2019s okay by us &#8211; I wanted to use VisualStudio Code, and you can use your own preferred editor of choice.<\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExternalEditorConfirmation-1024x535.png\" alt=\"\" width=\"735\" height=\"384\" class=\"alignnone size-large wp-image-30993\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExternalEditorConfirmation-1024x535.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExternalEditorConfirmation-600x313.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExternalEditorConfirmation-1536x802.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExternalEditorConfirmation.png 1907w\" sizes=\"auto, (max-width: 735px) 100vw, 735px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Go ahead and then click the \u201cSave\u201d button to name and save the script file to be edited somewhere on your computer that you can readily find. We\u2019ll keep DASYLab open for the moment in order to be able to reload the externally edited script to test out changes, as well as to have convenient access to the built-in Help.<\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Open the Python script file within your editor of choice (I used VS Code). Within the default script, we will find three different classes: info, pvar, and pscript. The info and pvar classes define some variables for Script window popup for end users to set their own parameters within DASYLab to be used inside the script, but this post will not utilize this feature.<\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">The pscript class is, of course, where we will be doing most of the custom work. The two methods that we will be adjusting are DlgOk and ProcessData, the first one to manage the number of connectors the module has when the configuration dialog&#8217;s &#8220;OK&#8221; button is pressed, and the latter to, unsurprisingly, do the data processing. <\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0 Why manage the connector count? We&#8217;re going to make this block take in one set of data and output *both* an average of the input and a normalized copy of the input, on two separate outputs.<\/span><\/p>\n<p><span data-contrast=\"auto\">Within DlgOK, look for the comment that states \u201c# Configure Inputs and Outputs\u201d. Below it, there is a \u201cself.SetConnectors\u201d method, which intuitively (and backed up by the DASYLab Help entry) first sets the number of input channels followed by the number of output channels. As we want to have two outputs for each input channel, we\u2019ll pass the number of channels multiplied by a scalar of 2 to the output channel count argument. <\/span><span><br \/>\n<\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>\/* <span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">self<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">.SetConnectors(<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">self<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">.<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">DlgNumChannels<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">, <\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">2<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\"> <\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">*<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\"> <\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">self<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">.<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">DlgNumChannels<\/span><\/span><span data-contrast=\"none\" xml:lang=\"EN-US\" lang=\"EN-US\" class=\"TextRun SCXW64174055 BCX8\"><span class=\"NormalTextRun SCXW64174055 BCX8\">) <\/span><\/span>*\/<\/code><\/pre>\n<\/div>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptTwoOutputChannels.png\" alt=\"\" width=\"860\" height=\"495\" class=\"alignnone size-full wp-image-30994\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptTwoOutputChannels.png 860w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptTwoOutputChannels-600x345.png 600w\" sizes=\"auto, (max-width: 860px) 100vw, 860px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Let&#8217;s save our changes to the script and observe our handiwork in the app. Double-click into the Script module and Load the externally edited script.\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleLoadExternalScript-1024x536.png\" alt=\"\" width=\"735\" height=\"385\" class=\"alignnone size-large wp-image-30995\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleLoadExternalScript-1024x536.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleLoadExternalScript-600x314.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleLoadExternalScript-1536x804.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleLoadExternalScript.png 1905w\" sizes=\"auto, (max-width: 735px) 100vw, 735px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">After hitting OK, you\u2019ll note that the Script module icon will change to have one input and two outputs. You can further verify our efforts by double clicking on the Script module and increasing the number of inputs and confirming your changes to observe that for every input there are two outputs.\u00a0Be sure to switch it back to just one input for later.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ThreeInputsSixOutputs.png\" alt=\"\" width=\"750\" height=\"663\" class=\"alignnone size-full wp-image-30996\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ThreeInputsSixOutputs.png 750w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ThreeInputsSixOutputs-600x530.png 600w\" sizes=\"auto, (max-width: 750px) 100vw, 750px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">All well and good, but now it\u2019s time to have numpy, which is not an included Python package within the base DASYLab, do some averaging for us. DASYLab comes with its own internal Python installation, so even if you already have numpy installed in another copy of Python elsewhere on your system, you need to install it again here. Save and close the DASYLab worksheet for now as we\u2019ll need to restart DASYLab for it to properly recognize the numpy installation for us. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Open up your favorite terminal to the python directory within your DASYLab installation and pip install numpy in order to have it match the internal python version used by DASYLab.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>.\/python.exe -m pip install numpy<\/code><\/pre>\n<\/div>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/PipInstallNumpy.png\" alt=\"\" width=\"581\" height=\"370\" class=\"alignnone size-full wp-image-30997\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Note: because we installed numpy ourselves, this means that other people testing out our custom script will not have this dependency in their system, so they will have to do the same.\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Back in our custom Python script, go ahead and add the \u201cimport numpy\u201d line at the top of the document and then scroll down to the ProcessData method where we will do the \u2018actual\u2019 customization.\u00a0<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">After the \u201c# Process data\u201d comment within the ProcessData method, there are two instance variables, InBuff and OutBuff, that are correspondingly associated with the blocks of data that are fed into and out of the Script module within DASYLab. As we\u2019re planning to have two outputs for every input channel, let\u2019s add that other instance variable and its error check to make sure we have its output before the code proceeds.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code># Process data \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\r\nfor channel in range(self.NumInChannel):\u00a0\r\n\u00a0 \u00a0 # Binding the various buffers to their appropriate channel numbers\u00a0\r\n\u00a0 \u00a0 InBuff = self.GetInputBlock(channel)\u00a0\r\n\u00a0 \u00a0 OutBuff = self.GetOutputBlock(2 * channel) # First output \u00a0\r\n\u00a0 \u00a0 AvgBuff = self.GetOutputBlock(2 * channel + 1) # Second output\u00a0\r\n\r\n\u00a0 \u00a0 # Prevent DASYLab from freaking out if our outputs are not populated\u00a0\r\n\u00a0 \u00a0 if (OutBuff == None):\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 self.ShowWarning(\"Could not get output block! Stopped!\")\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 Ly.StopExperiment()\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 return True\u00a0\r\n\r\n\u00a0 \u00a0 if (AvgBuff == None):\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 self.ShowWarning(\"Could not get output block! Stopped!\")\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 Ly.StopExperiment()\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 return True\u00a0\r\n\r\n<\/code><\/pre>\n<\/div>\n<h6><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptAddAvgBuff-1024x485.png\" alt=\"\" width=\"735\" height=\"348\" class=\"alignnone size-large wp-image-31003\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptAddAvgBuff-1024x485.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptAddAvgBuff-600x284.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptAddAvgBuff.png 1026w\" sizes=\"auto, (max-width: 735px) 100vw, 735px\" \/><\/h6>\n<h6><\/h6>\n<h5 style=\"padding-left: 40px;\"><span data-contrast=\"auto\">Did you know?<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/h5>\n<h6 style=\"padding-left: 40px;\">DASYLab has built-in documentation where you can look up any of the methods, properties, or other material within any Module. Just open up the Contents within the Help tab and search for what you are interested in!<\/h6>\n<p>&nbsp;<\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/DASYLabHelpMenu-1-1024x631.png\" alt=\"\" width=\"735\" height=\"453\" class=\"alignnone size-large wp-image-30998\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/DASYLabHelpMenu-1-1024x631.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/DASYLabHelpMenu-1-600x370.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/DASYLabHelpMenu-1-348x215.png 348w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/DASYLabHelpMenu-1.png 1294w\" sizes=\"auto, (max-width: 735px) 100vw, 735px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Now we\u2019ll add in the simple averaging calculation using numpy by summing all entries of the block of data that was supplied to our script block and dividing the total by the existing BlockSize property. For OutBuff, we will take the incoming data block and normalize each element in the list to be between 0 and 1. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Naturally, we\u2019ll also need to any necessary clean up so that our calculated block of data can be safely handed off to whatever downstream module within DASYLab. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>    # Calculate the average from the entire block of input data\u00a0\r\n\u00a0 \u00a0 AvgBuff[0] = numpy.sum(InBuff[0:InBuff.BlockSize]) \/ InBuff.BlockSize\u00a0\r\n    \r\n  \u00a0 # Precalculate the min and max outside of the for loop\u00a0\r\n\u00a0 \u00a0 minInput = numpy.min(InBuff[0:InBuff.BlockSize])\u00a0\r\n\u00a0 \u00a0 minOutput = numpy.max(InBuff[0:InBuff.BlockSize])\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 # Check to see if we are receiving a constant value\u00a0\r\n\u00a0 \u00a0 if (minInput == minOutput):\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 for i in range(InBuff.BlockSize):\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 OutBuff[i]= InBuff[i]# No normalization applied\u00a0\r\n\u00a0 \u00a0 # If not constant, we can safely avoid divide by zero errors\u00a0\r\n\u00a0 \u00a0 else:\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 # Normalize each individual element of the input data from 0 to 1\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 for i in range(InBuff.BlockSize):\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 OutBuff[i]= ((InBuff[i]- minInput) \/ (minOutput - minInput))\u00a0\r\n\u00a0 \u00a0 \u00a0\r\n  \u00a0 # Set the start time of the output data to start time of the input data\u00a0\r\n\u00a0 \u00a0 AvgBuff.StartTime = InBuff.StartTime\u00a0\r\n\u00a0 \u00a0 OutBuff.StartTime = InBuff.StartTime\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 # Set the length of time the output block encompasses to the \\\u00a0\r\n\u00a0 \u00a0 # same length of time the input data encompassed \u00a0\r\n\u00a0 \u00a0 AvgBuff.SampleDistance = InBuff.SampleDistance\u00a0\r\n\u00a0 \u00a0 OutBuff.SampleDistance = InBuff.SampleDistance\u00a0\r\n\u00a0 \u00a0 \u00a0\r\n\u00a0 \u00a0 # Set the blocksize of the two outputs\u00a0\r\n\u00a0 \u00a0 AvgBuff.BlockSize = 1\u00a0\r\n\u00a0 \u00a0 OutBuff.BlockSize = InBuff.BlockSize\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 # Release the DataBlockHeader of the input and output data blocks \\\u00a0\r\n\u00a0 \u00a0 # so that DASYLab knows the Script module no longer needs these blocks\u00a0\r\n\u00a0 \u00a0 InBuff.Release()\u00a0\r\n\u00a0 \u00a0 AvgBuff.Release()\u00a0\r\n\u00a0 \u00a0 OutBuff.Release()\u00a0\r\n\u00a0 \u00a0 \u00a0\r\nreturn True <\/code><\/pre>\n<\/div>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptAvgCalcCleanup.png\" alt=\"\" width=\"931\" height=\"1025\" class=\"alignnone size-full wp-image-30999\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptAvgCalcCleanup.png 931w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ExternalScriptAvgCalcCleanup-545x600.png 545w\" sizes=\"auto, (max-width: 931px) 100vw, 931px\" \/><\/p>\n<p><span data-contrast=\"auto\">Time to test our work. Re-open DASYLab, presuming you already had it closed so that it can see the numpy installation, and open the saved workspace (or create a new one if you want to practice setting up the custom script module, I\u2019m not your boss). If you\u2019re using the saved workspace, be sure to reduce the number of input channels back to one, otherwise DASYLab won\u2019t run because there isn\u2019t any data to operate on.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Of course, nothing visually happens as we don\u2019t have any data being generated or displayed. Add a Generator from the Control modules folder, and from Display folder add a Y\/t Chart and Digital Meter to your workspace. Connect the Digital Meter to the output 1 on the Script Module (where the average is assigned), the Y\/t chart to output 0, and the Generator to the input. I happened to choose a Generator with a modulated pwm input so I also added a Slider from the Control panel so I could change the pulse width at run time.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExtraModules-1024x555.png\" alt=\"\" width=\"735\" height=\"398\" class=\"alignnone size-large wp-image-31000\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExtraModules-1024x555.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExtraModules-600x325.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExtraModules-1536x832.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/ScriptModuleExtraModules.png 1920w\" sizes=\"auto, (max-width: 735px) 100vw, 735px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Note the new minimized windows in the bottom left corner of the GUI; these are how you will actually see your Y\/t chart and Digital Meter values. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Some additional adjustments will need to be made in DASYLab in order to cleanly view our data. In the top left of the GUI, click on the metronome icon to open the Time Base Setup menu. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/TimeBaseSetup.png\" alt=\"\" width=\"309\" height=\"133\" class=\"alignnone size-full wp-image-31001\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Adjust the Sampling rate to something above 10 Hz and a larger Block size. I picked 1000 Hz and a Block size of 100. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/TimeBaseSettings.png\" alt=\"\" width=\"604\" height=\"271\" class=\"alignnone size-full wp-image-31002\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/TimeBaseSettings.png 604w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/TimeBaseSettings-600x269.png 600w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><\/span><\/p>\n<p><span data-contrast=\"auto\">Double click on the Generator to adjust its Frequency to a larger value. I picked 100 Hz. You can also adjust the Amplitude, Offset, and Phase shift either now or at runtime. If you are using modulation, also adjust the Slider output to have more reasonable values; in my case where I am feeding the pulse width to my generator, I needed to adjust my Maximum value from\u00a05 to 1 (as a pulse width greater than 1 will simply be cut off). The resolution lets you set how many steps there are between your minimum and maximum values. <\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Be sure to re-load the script you have been externally editing back into the Script Module within DASYLab and then click the green triangle in the top left corner of the GUI to run your workspace. <\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">You\u2019ll be able to see the Y\/t chart adjusting the incoming square wave (which isn\u2019t fully square thanks to our sampling rate and block size compared to the rate we are generating a signal at) in relation to the pulse width slider. <\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><iframe loading=\"lazy\" title=\"Creating a Custom Script Mod in Digilent&#039;s DASYLab\" width=\"735\" height=\"413\" src=\"https:\/\/www.youtube.com\/embed\/98Qb5aFMUiU?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p><span data-contrast=\"auto\">Congratulations! You&#8217;ve successfully created a custom script module in DASYLab using Python. By leveraging the power of scripting, you&#8217;ve expanded DASYLab&#8217;s capabilities to meet your specific data processing needs and enhance your data analysis workflow.<\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><span data-contrast=\"auto\">Ready to learn more? Explore the following resources:<\/span><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/digilent.com\/reference\/software\/dasylab\/start\"><span data-contrast=\"none\">DASYLab\u00ae &#8211; Digilent Reference<\/span><\/a><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/dasylab-and-analog-discovery-a-new-option-for-code-free-data-acquisition\/\"><span data-contrast=\"none\">DASYLab and Analog Discovery: A New Option for Code-Free Data Acquisition \u2013 Digilent Blog<\/span><\/a><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/forum.digilent.com\/forum\/39-data-acquisition-daq-data-logging\/\"><span data-contrast=\"none\">Data Acquisition (DAQ) &amp; Data Logging &#8211; Digilent Forum<\/span><\/a><span data-ccp-props=\"{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;201341983&quot;:0,&quot;335551550&quot;:1,&quot;335551620&quot;:1,&quot;335559685&quot;:0,&quot;335559737&quot;:0,&quot;335559738&quot;:0,&quot;335559739&quot;:160,&quot;335559740&quot;:279}\">\u00a0<\/span><\/p>\n<div class='watch-action'><div class='watch-position align-left'><div class='action-like'><a class='lbg-style6 like-30983 jlk' data-task='like' data-post_id='30983' data-nonce='ee750c7abc' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Like' \/><span class='lc-30983 lc'>0<\/span><\/a><\/div><div class='action-unlike'><a class='unlbg-style6 unlike-30983 jlk' data-task='unlike' data-post_id='30983' data-nonce='ee750c7abc' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Unlike' \/><span class='unlc-30983 unlc'>0<\/span><\/a><\/div><\/div> <div class='status-30983 status align-left'>Be the 1st to vote.<\/div><\/div><div class='wti-clear'><\/div>","protected":false},"excerpt":{"rendered":"<p>Welcome back to the Digilent Blog! You may have heard about how Digilent is building support for our Analog Discovery devices within the DASYLab software through a custom module. This &hellip; <\/p>\n","protected":false},"author":17,"featured_media":31016,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4361,4323,4312,1563],"tags":[4744,5011,5010,4359,4363,4538,4723,4689,5012,4743,4945,4366,4626,4926,5009,4745,4547,4376],"ppma_author":[4469],"class_list":["post-30983","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-acquisition","category-software","category-usb-scopes-analyzers-generators","category-guide","tag-automation","tag-custom","tag-custom-module","tag-daq","tag-dasylab","tag-data","tag-data-analysis","tag-data-logger","tag-data-logging","tag-data-processing","tag-digital-signal","tag-digital-signal-processing","tag-python","tag-python-script","tag-script","tag-scripting","tag-signal","tag-software"],"jetpack_featured_media_url":"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/09\/2024-September-Newsletter-DASYLabScriptModule-735x400-1.png","authors":[{"term_id":4469,"user_id":17,"is_guest":0,"slug":"jamescolvin","display_name":"James Colvin","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/509febded809c5de0423909f6ae6587f?s=96&d=mm&r=g","author_category":"","user_url":"","last_name":"Colvin","last_name_2":"","first_name":"James","first_name_2":"","job_title":"Applications Engineer \/ Technical Support Engineer \/ Product Support Engineer \/ Technical Writer \/ the person to bother about T&M and JTAG when the senior design engineer is busy","description":"A local Digilent employee who is sometimes tricked into making other content besides documentation and supporting customers on the Digilent Forum, but then I get to write a little more informally so that's a plus. \r\n\r\nA sassy engineer, lover of puns and dad jokes, father and husband. \r\n\r\nI know both way too much and simultaneously almost nothing about a number of nerdy topics. If you want to hear me rant, ask me what data rate USB C operates at."}],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/30983","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/users\/17"}],"replies":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/comments?post=30983"}],"version-history":[{"count":9,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/30983\/revisions"}],"predecessor-version":[{"id":31018,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/30983\/revisions\/31018"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media\/31016"}],"wp:attachment":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media?parent=30983"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/categories?post=30983"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/tags?post=30983"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=30983"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}