Difference between revisions of "DSP"

From Flowcode Help
Jump to navigationJump to search
 
(46 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 +
__TOC__
 +
 
==What is DSP==
 
==What is DSP==
  
Line 4: Line 6:
  
  
These are all potential examples of a DSP system at work:
+
These are all examples of DSP systems at work:
 +
 
 +
* Audio effects e.g. Echo, Reverb, Guitar Distortion, etc
 +
* Signal Filtering
 +
* Frequency Spectrum Analysis
 +
* Sensor Arrays e.g. Baby Monitors, Radio Telescopes, Near/Far field
 +
* Closed/Open Loop Control e.g. Speed, Position, Temperature, Height, Level, Angle, etc
 +
* Modern Digital Communications
 +
 
 +
 
 +
==DSP Component Basics==
 +
 
 +
DSP components with an arrow facing away from the component represent a memory block or buffer that can be accessed by one or more other DSP components. The number of values that can be stored and the type of values that can be stored are available via the component properties.
 +
 
 +
[[file:DSP_Input_Buffer.jpg]]
 +
 
 +
 
 +
DSP components with an arrow facing towards the component represent a reference to the memory block created by another DSP component. The link is controlled via the component properties.
 +
 
 +
[[file:DSP_Output_Reference.jpg]]
 +
 
 +
 
 +
Once DSP components are linked together a line is drawn between the components.
 +
 
 +
[[file:DSP_Components_Linked.jpg]]
 +
 
 +
 
 +
The colour of the link line indicates the type of data that is being stored in the buffer.
 +
 
 +
{| class="wikitable" style="width: 600px; background-color:#FFFFFF;"
 +
|-
 +
| width="30%"  style="background-color:#EAE1EA;" | Colour
 +
| width="30%"  style="background-color:#EAE1EA;" | Buffer Type
 +
| width="40%"  style="background-color:#EAE1EA;" | Range
 +
|-
 +
| width="30%" | Black
 +
| width="30%" | Byte
 +
| width="40%" | 0 to 255
 +
|-
 +
| width="30%" | Red
 +
| width="30%" | Unsigned Int
 +
| width="40%" | 0 to 65,535
 +
|-
 +
| width="30%" | Orange
 +
| width="30%" | Signed Int
 +
| width="40%" | -32,768 to 32,767
 +
|-
 +
| width="30%" | Green
 +
| width="30%" | Unsigned Long
 +
| width="40%" | 0 to 4,294,967,295
 +
|-
 +
| width="30%" | Blue
 +
| width="30%" | Signed Long
 +
| width="40%" | -2,147,483,648 to 2,147,483,647
 +
|-
 +
| width="30%" | Purple
 +
| width="30%" | Float
 +
| width="40%" | 32-bit approximation of a real number
 +
|-
 +
|}
 +
 
 +
 
 +
==[[Components#DSP|DSP Components]]==
 +
 
 +
More detailed explanations, examples and help can be found for each of the [[Components#DSP|DSP components]] by following the links provided below.
 +
 
 +
{| class="wikitable" style="width: 900px; background-color:#FFFFFF;"
 +
|-
 +
| colspan="3" align="center" style="background-color:#EAE1EA;" | DSP Inputs
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID fdef1c85_689b_4e44_81dc_7ab15dec21a6|Data Queue to Bits]]
 +
| width="75%" style="background-color:#e8ffec;" | Allows an data buffer to be split into bits and sent a bit at a time
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 3420d1ea_bc10_4727_8419_746101b8dc13|Input ADC]]
 +
| width="75%" style="background-color:#e8ffec;" | Inputs from an ADC enabled input pin
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 73c1c565_8d04_44dd_ab78_1997d5e3c641|Input CSV]]
 +
| width="75%" style="background-color:#e8ffec;" | Inputs data from a file
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID c73d493a_b6a0_4dbe_b4b5_79648f67d11e|Input Digital]]
 +
| width="75%" style="background-color:#e8ffec;" | Inputs generic digital data
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 8d6ffd33_4087_46b5_8dfd_f43513748755|Input Digital Pin]]
 +
| width="75%" style="background-color:#e8ffec;" | Inputs from a digital input pin
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID c7648111_2a14_475e_980d_c7106ff9d3d0|Quadrature Generator]]
 +
| width="75%" style="background-color:#e8ffec;" | Generates two output waveforms I (cosine) and Q (sine)
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID cbe42abc_5955_44da_a6d0_03e7cbcdcaca|Waveform Generator]]
 +
| width="75%" style="background-color:#e8ffec;" | Generates cyclic or randomised waveform data
 +
|-
 +
| colspan="3" align="center" style="background-color:#EAE1EA;" | DSP Outputs
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 44e22c6d_4e79_4eb3_b2e1_7ff2fecb3e08|Bits to Data Queue]]
 +
| width="75%" style="background-color:#e8ffec;" | Captures data a bit at a time and stores into a data buffer
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID e648c3de_ec39_4a3f_bbd9_46e45cce4a63|Level]]
 +
| width="75%" style="background-color:#e8ffec;" | Monitors data statistics like peaks and troughs
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 5142bd81_abad_444b_b6db_36a87dce5835|Output CSV]]
 +
| width="75%" style="background-color:#e8ffec;" | Outputs to a file
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 4483da18_fa5a_4436_9edb_0cfb55a4bce1|Output DAC]]
 +
| width="75%" style="background-color:#e8ffec;" | Outputs to a DAC enabled output pin
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 1392d5c3_35ba_4c7f_a539_7f30a09758e4|Output Digital]]
 +
| width="75%" style="background-color:#e8ffec;" | Outputs generic digital data
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 0d048c7d_18d5_4bce_83f1_7e429c0d86b6|Output Digital Pin]]
 +
| width="75%" style="background-color:#e8ffec;" | Outputs to a digital output pin
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 649f4bc2_1360_4629_82aa_62e2fc32d4e4|Output PWM]]
 +
| width="75%" style="background-color:#e8ffec;" | Outputs to a PWM enabled output pin
 +
|-
 +
| colspan="3" align="center" style="background-color:#EAE1EA;" | DSP Operators
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 104899e2_8b2e_4854_923c_5a614c1b8a3c|Adder]]
 +
| width="75%" style="background-color:#e8ffec;" | Adds together two or more DSP signals
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID d347e8eb_a0f2_45d5_8f31_7aba7f4e56b7|Averager]]
 +
| width="75%" style="background-color:#e8ffec;" | Takes an average of two or more DSP signals
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 0b1d97c1_ee89_45a5_8c39_114cd6d552ad|Deinterlace]]
 +
| width="75%" style="background-color:#e8ffec;" | Breaks apart a single interlaced DSP signal into sub signals
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID e0ddc704_6bab_4d08_8f10_19a14c6683ef|Delay]]
 +
| width="75%" style="background-color:#e8ffec;" | Adds a fixed or variable delay in the DSP signal
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID f804a7bd_0280_4ff7_ab75_63be77fb2af3|Fast Fourier Transform (FFT)]]
 +
| width="75%" style="background-color:#e8ffec;" | Converts time based DSP signal data into Frequency based
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 317efb6a_2bad_4f83_a0bc_4ada0f4cd51e|Filter]]
 +
| width="75%" style="background-color:#e8ffec;" | Provides digital filtering on a DSP signal
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 23b8de7f_5214_4f77_9bac_4982123b8d4b|Interlace]]
 +
| width="75%" style="background-color:#e8ffec;" | Combines multiple DSP signals into a single DSP signal
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 83fac7ac_b7b5_4cc4_890a_394cbf16cf71|Kalman Filter]]
 +
| width="75%" style="background-color:#e8ffec;" | Provides predictive digital filtering on a DSP signal
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 82872714_f0f0_4758_91ec_bd39d2cdddc8|Math]]
 +
| width="75%" style="background-color:#e8ffec;" | Mathematical operations with two DSP signals (+,-,/,* etc)
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID facc8c89_963a_408e_985e_ed768a52b01a|Median]]
 +
| width="75%" style="background-color:#e8ffec;" | Provides median filtering on a DSP signal to get rid of spurious data samples
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID a9e01aa0_f224_4902_a558_6a199fc039c5|Multiplex]]
 +
| width="75%" style="background-color:#e8ffec;" | Allows a number of DSP signals to be selected and switched between
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 88a7dbc4_af92_4205_8943_abaa77504462|Offset]]
 +
| width="75%" style="background-color:#e8ffec;" | Adds a fixed or variable offset to a DSP signal
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 34b6f31b_7e33_4beb_891e_defacbee8587|On/Off Control]]
 +
| width="75%" style="background-color:#e8ffec;" | Provides simple on/off closed loop control
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID e6dd1315_4acf_4fb5_abd9_5743d3715cbe|PID Control]]
 +
| width="75%" style="background-color:#e8ffec;" | Provides P/PI/PID closed loop control
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 939a5d54_28c7_488d_af39_46f7c5d2c429|Rectifier]]
 +
| width="75%" style="background-color:#e8ffec;" | Allows a DSP signal to be flipped below a certain threshold
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID f1af5256_1dee_491c_b43f_fdc8f33279fb|Scale]]
 +
| width="75%" style="background-color:#e8ffec;" | Applies a scaler to a DSP signal
 +
|-
 +
| width="25%" style="background-color:#e8ffec;" | [[Component: ID 907f24e9_a8a3_46ea_942d_67dc55f7eb44|Simulated Control Load]]
 +
| width="75%" style="background-color:#e8ffec;" | Simulates an active load such as a heater or motor to allow simulation of closed loop systems
 +
|-
 +
|}
 +
 
 +
==Component Macros==
 +
 
 +
A typical DSP system will use a timer interrupt macro to maintain a steady rate on which everything happens. The timer interrupt will do things like any analogue sampling and may also call the DSP component functions in order. Based on this methodology we have created two variants of most of the DSP component macros in the form of Function and FunctionArray. These allow two different ways of working with the DSP component. These methods can be mixed and matched as necessary to allow your program to run at the optimum speed and throughput.
 +
 
 +
 
 +
===Single===
 +
 
 +
The Function type macros allow a single value in the DSP buffer to be processed. Behind the scenes this performs the hardware macro functionality on the next buffer value.
  
Guitar Distortion
 
  
Audio effects e.g. Echo, Reverb, etc.
+
The tick based functions are designed to operate inside the interrupt function at sample rate. This allows your DSP code to utilize more of the system runtime but means you have less time for other functions such as refreshing a display. Because you are only processing a single value in a buffer rather then an entire buffer the function code is much shorter. This also has a second impact that there is a minimal delay in data being held in the buffer before being processed. The location inside the buffer is automatically tracked for you by the master buffer index.  
  
Digital Filtering
+
[[File:DSP8.jpg]]
  
Frequency Spectrum Analysis
 
  
Baby Monitors
+
===Array===
  
Covert Listening Devices (Bugs)
+
The Array type macros allow the entire DSP buffer to be processed at once. Behind the scenes this involves a loop and we cycle through all of the values in the buffer performing the macro function. Some components such as the [[Component: ID f804a7bd_0280_4ff7_ab75_63be77fb2af3|Fast Fourier Transform (FFT)]] only have the Array version of the macro as the FFT calculations can only work with a buffer full of data.
  
Speed Control
 
  
Position Control
+
The standard array based functions are designed to process a complete buffer in one operation. Care should be taken that the processing time is no longer then a single interrupt period.
  
Temperature Control
+
[[File:DSP6.jpg]]
  
  
==The DSP System Component==
+
This method gives you free time between interrupts where other functions can be performed such as  updating the GUI on a display. The longer the buffers, the more time you get between having to process the trigger code but the downside is that the trigger code will take more time to process.
  
There are a number of components built into Flowcode to help you to create a DSP system specific for what you need.
 
  
 +
For systems with higher sample rates where missing some data is not important the interrupt can be halted by disabling the timer interrupt within the trigger code and then re-enabling when you are done.
  
The DSP components all centre around the [[Component:_ID_917f243e_4102_4bee_9998_81f18bc6ca9d|DSP System]] component which is basically the buffer manager for the system. For each link between components we need a buffer, think of each buffer as a pipe that the data can flow along. The size of each buffer dictates the number of operations or "ticks" that have to happen before the data reaches the end of the buffer. If we know the "tick" rate of the system and the size of the buffer then we know the delay that will be presented when the data is travelling through the buffer.
+
[[File:DSP7.jpg]]
  
  
For example if we have an input component connected directly to an output component then we need only one buffer.  
+
If the processing time is longer then a single interrupt period and the interrupt is not disabled then you are likely to get corruption in the data buffer. You may be able to circumvent this by processing the buffers that may get corrupted by the interrupt first. Here you would have to ensure that the entire DSP operations are processed before the trigger mechanism is fired again or data corruption is inevitable. You can test this in your application by checking to see if the trigger variable has been set again at the end of the trigger code.  
  
[[File:DSP1.jpg]]
 
  
  
If we have two input components connected via a sum component and then onto an output component then we need three buffers. Naming the buffers can help when it comes to connecting everything up.
+
===Combining Single and Array Calls===
  
[[File:DSP3.jpg]]
+
Both methods of DSP processing have upsides and downsides which cause problems and headaches when dealing with a finite amount of processing runtime and RAM. Before designing a entire DSP system it is important to play around with the individual components to get a feel for what is needed.  
  
  
By default all the buffers have the same bit depth and sign but by disabling the simple mode property these can be manually edited for each individual buffer.
+
For example a system which performs a FFT and then plots the signal data onto a display needs to sample data regularly when populating the buffer so the tick method is ideal. When performing the FFT conversion and writing to the display we no longer need to have constant data and so the trigger approach can be used.  
  
[[File:DSP4.jpg]]
 
  
 +
Alternatively an audio system producing an effect onto an output stream needs to have fairly high sample rates, constant data and minimal lag so the tick style approach is more suited.
  
Components are connected up to the buffers by specifying the buffer manager and then selecting the buffer.
 
  
[[File:DSP2.jpg]]
+
The single style approach is similar to using the trigger style approach with a buffer size of one so really the design of the system is entirely up to what you feel most comfortable with and what best suits your application.

Latest revision as of 11:03, 23 October 2023

What is DSP

DSP or Digital Signal Processing is a way of processing data in way that provides some kind of additional functionality. DSP usually takes the form of an input, a process on the input and an output corresponding to the process. As microcontrollers are generally quite fast devices it is the act of repeating the process at high speed that allows us to perform the task in hand.


These are all examples of DSP systems at work:

  • Audio effects e.g. Echo, Reverb, Guitar Distortion, etc
  • Signal Filtering
  • Frequency Spectrum Analysis
  • Sensor Arrays e.g. Baby Monitors, Radio Telescopes, Near/Far field
  • Closed/Open Loop Control e.g. Speed, Position, Temperature, Height, Level, Angle, etc
  • Modern Digital Communications


DSP Component Basics

DSP components with an arrow facing away from the component represent a memory block or buffer that can be accessed by one or more other DSP components. The number of values that can be stored and the type of values that can be stored are available via the component properties.

DSP Input Buffer.jpg


DSP components with an arrow facing towards the component represent a reference to the memory block created by another DSP component. The link is controlled via the component properties.

DSP Output Reference.jpg


Once DSP components are linked together a line is drawn between the components.

DSP Components Linked.jpg


The colour of the link line indicates the type of data that is being stored in the buffer.

Colour Buffer Type Range
Black Byte 0 to 255
Red Unsigned Int 0 to 65,535
Orange Signed Int -32,768 to 32,767
Green Unsigned Long 0 to 4,294,967,295
Blue Signed Long -2,147,483,648 to 2,147,483,647
Purple Float 32-bit approximation of a real number


DSP Components

More detailed explanations, examples and help can be found for each of the DSP components by following the links provided below.

DSP Inputs
Data Queue to Bits Allows an data buffer to be split into bits and sent a bit at a time
Input ADC Inputs from an ADC enabled input pin
Input CSV Inputs data from a file
Input Digital Inputs generic digital data
Input Digital Pin Inputs from a digital input pin
Quadrature Generator Generates two output waveforms I (cosine) and Q (sine)
Waveform Generator Generates cyclic or randomised waveform data
DSP Outputs
Bits to Data Queue Captures data a bit at a time and stores into a data buffer
Level Monitors data statistics like peaks and troughs
Output CSV Outputs to a file
Output DAC Outputs to a DAC enabled output pin
Output Digital Outputs generic digital data
Output Digital Pin Outputs to a digital output pin
Output PWM Outputs to a PWM enabled output pin
DSP Operators
Adder Adds together two or more DSP signals
Averager Takes an average of two or more DSP signals
Deinterlace Breaks apart a single interlaced DSP signal into sub signals
Delay Adds a fixed or variable delay in the DSP signal
Fast Fourier Transform (FFT) Converts time based DSP signal data into Frequency based
Filter Provides digital filtering on a DSP signal
Interlace Combines multiple DSP signals into a single DSP signal
Kalman Filter Provides predictive digital filtering on a DSP signal
Math Mathematical operations with two DSP signals (+,-,/,* etc)
Median Provides median filtering on a DSP signal to get rid of spurious data samples
Multiplex Allows a number of DSP signals to be selected and switched between
Offset Adds a fixed or variable offset to a DSP signal
On/Off Control Provides simple on/off closed loop control
PID Control Provides P/PI/PID closed loop control
Rectifier Allows a DSP signal to be flipped below a certain threshold
Scale Applies a scaler to a DSP signal
Simulated Control Load Simulates an active load such as a heater or motor to allow simulation of closed loop systems

Component Macros

A typical DSP system will use a timer interrupt macro to maintain a steady rate on which everything happens. The timer interrupt will do things like any analogue sampling and may also call the DSP component functions in order. Based on this methodology we have created two variants of most of the DSP component macros in the form of Function and FunctionArray. These allow two different ways of working with the DSP component. These methods can be mixed and matched as necessary to allow your program to run at the optimum speed and throughput.


Single

The Function type macros allow a single value in the DSP buffer to be processed. Behind the scenes this performs the hardware macro functionality on the next buffer value.


The tick based functions are designed to operate inside the interrupt function at sample rate. This allows your DSP code to utilize more of the system runtime but means you have less time for other functions such as refreshing a display. Because you are only processing a single value in a buffer rather then an entire buffer the function code is much shorter. This also has a second impact that there is a minimal delay in data being held in the buffer before being processed. The location inside the buffer is automatically tracked for you by the master buffer index.

DSP8.jpg


Array

The Array type macros allow the entire DSP buffer to be processed at once. Behind the scenes this involves a loop and we cycle through all of the values in the buffer performing the macro function. Some components such as the Fast Fourier Transform (FFT) only have the Array version of the macro as the FFT calculations can only work with a buffer full of data.


The standard array based functions are designed to process a complete buffer in one operation. Care should be taken that the processing time is no longer then a single interrupt period.

DSP6.jpg


This method gives you free time between interrupts where other functions can be performed such as updating the GUI on a display. The longer the buffers, the more time you get between having to process the trigger code but the downside is that the trigger code will take more time to process.


For systems with higher sample rates where missing some data is not important the interrupt can be halted by disabling the timer interrupt within the trigger code and then re-enabling when you are done.

DSP7.jpg


If the processing time is longer then a single interrupt period and the interrupt is not disabled then you are likely to get corruption in the data buffer. You may be able to circumvent this by processing the buffers that may get corrupted by the interrupt first. Here you would have to ensure that the entire DSP operations are processed before the trigger mechanism is fired again or data corruption is inevitable. You can test this in your application by checking to see if the trigger variable has been set again at the end of the trigger code.


Combining Single and Array Calls

Both methods of DSP processing have upsides and downsides which cause problems and headaches when dealing with a finite amount of processing runtime and RAM. Before designing a entire DSP system it is important to play around with the individual components to get a feel for what is needed.


For example a system which performs a FFT and then plots the signal data onto a display needs to sample data regularly when populating the buffer so the tick method is ideal. When performing the FFT conversion and writing to the display we no longer need to have constant data and so the trigger approach can be used.


Alternatively an audio system producing an effect onto an output stream needs to have fairly high sample rates, constant data and minimal lag so the tick style approach is more suited.


The single style approach is similar to using the trigger style approach with a buffer size of one so really the design of the system is entirely up to what you feel most comfortable with and what best suits your application.