News:

Let's find out together what makes a PIC Tick!

Main Menu

Something very ODD

Started by SeanG_65, Dec 14, 2023, 10:59 AM

Previous topic - Next topic

SeanG_65

I tried compiling the Amicus18 FFT_32_Element routines to have a play with and I get an error.

>Error at Line [19] In file [c:\users\sean goddard\pds\includes\fft.inc] *** "fft procedures only for use with dspic33 devices"! ***

Also, the line numbers are wrong, which has caused no end of problems  when trying to debug software. :'(

Yasin

It says that the line number causing the error is the 19th line in the "fft.inc" file.

Dompie

Yes and that line is saying:
$if _core != 33
    $error "FFT procedures only for use with dsPIC33 devices"
$else

So Les wants a dsPIC33 for that library.

Johan

RGV250

But the question is why is there an issue when the code is for an 8 bit PIC.

This is the first lines of the sample code in the folder FFT_8_Bit.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate a 32 element fixed point FFT routine
' Yielding a 16 element result. i.e. FFT_Elements / 2
'
' The spectrum is displayed on a 16x2 alphanumeric LCD
' The actual FFT routines takes approx 1.2 to complete when using a 64MHz oscillator
' Making it almost realtime
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Include "Amicus18.inc"                  ' Configure for the Amicus18 device (18F25K20) running at 64MHz
    Include "Amicus18_ADC.inc"              ' Load the Amicus18 ADC routines into the program

    $define FFT_Use_Sqr                     ' Instruct the FFT routine to use more refined real and imaginary combining
    $define FFT_Elements 32                 ' The amount of elements for the FFT routine to work on
    Include "FFT.inc"                       ' Load the 8-bit FFT routines into the program
'

Dompie

Oh I only looked in the .inc file in PDS/Includes.
Hmmmmmmm in the sample directory FFT-8bit there is also an FFT.inc and it does NOT have the test on a dsPIC. The FFT.inc listed in PDS/Include does have this test.
So it looks like Les created two versions and placed the 8-bit version of FFT.inc in the example directory. The two versions are also very different.
So FFT users pay attention.

Johan

SeanG_65

#5
Quote from: Yasin on Dec 15, 2023, 09:45 AMIt says that the line number causing the error is the 19th line in the "fft.inc" file.

You can see how much I use Positron these days. I missed that.

I was looking at extracting the dominant frequency from a doppler radar sensor to determine the ground speed of a farm vehicle. I can't justuse the doppler output ad the bloody thing reacts to lumps of earth and stones. In effect the signal returned is GROUND + (stones + weeds + clods of earth).

I need to extract the "majority" frequency to calculate the distance travelled and give a "beep" output at a user selected multiple of 100cm from 0.6m up to 1.6m spacing at 6kph. I THINK the FFT might be the tool to do it.

ALSO....it says "completes in 1.2". 1.2 What, s, ms, us, or knowing my luck years?

top204

#6
The compiler will first look for, and use, an include file that is within the folder of the ".bas" file that uses it, and if it is not in there it will look in the compiler's Sources folder then the Includes folder: "C:\Users\User Name\PDS\Includes\", so the "FFT.inc" in the Includes folder is the dsPIC33 listing that uses true DSP features and will not run on an 8-bit device.

A lot of the 8-bit compiler's sample programs were written before I wrote the 16-bit compiler or the additions to the Positron8 compiler with procedures, and I have updated quite a few of them, but logistics stopped me updating all of them for the Positron syntax and operation. However, I have just updated the 8-bit FFT programs to use the features of the Positron8 compiler and a PIC18F25K20 device (as used in the Amicus18 board), and optimised the program's operation so it is more efficient. The programs are attached in a zip file, and the listing below is the "FFT_128_element.bas" demo. But make sure the "FFT.inc" file (supplied) is within the same folder as the .bas file. Or you can rename it to "FFT_8.inc" and place it in the Includes folder: "C:\Users\User Name\PDS\Includes\", so any code listing can see it and not get confused with the dsPIC FFT library already in there.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate a 128 element fixed point FFT routine
' Yielding a 64 element result. i.e. FFT_Elements / 2
'
' The spectrum is displayed on a 16x2 alphanumeric LCD
' The actual FFT routines takes approx 6ms to complete when using a 64MHz oscillator
' Making it almost realtime
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Include "Amicus18.inc"                              ' Configure for the Amicus18 device (18F25K20) running at 64MHz
    Include "Amicus18_ADC.inc"                          ' Load the Amicus18 ADC routines into the program

    $define FFT_Use_Sqr                                 ' Instruct the FFT routine to use more refined real and imaginary combining
    $define FFT_Elements 128                            ' The amount of elements for the FFT routine to work on
    Include "FFT.inc"                                   ' Load the 8-bit FFT routines into the program
'
' Setup the Alphanumeric LCD
'
    Declare LCD_DTPin = PORTB.4                         ' LCD's Data lines (D4 to D7)
    Declare LCD_ENPin = PORTB.3                         ' LCD's EN line
    Declare LCD_RSPin = PORTB.2                         ' LCD's RS line
    Declare LCD_Interface = 4                           ' 4-bit interface to LCD
    Declare LCD_Lines = 2                               ' LCD contains 2 lines
    Declare LCD_Type = Alphanumeric                     ' LCD type is alphanumeric
'
' Create some global variables
'
    Dim dHighestOfFour As Dword Access                  ' Holds four elements extracted from the FFT real array
    Dim bIndex As Byte Access                           ' General purpose index variable
    Dim bLCD_Xpos As Byte Access                        ' Holds the X position on the LCD
    Dim bBarValue As Byte Access                        ' Holds the value for the bar display on the LCD

'-------------------------------------------------------------------------
' The main program loop starts here
'
Main:
'
' Open the ADC for samples taken on AN0
' Left justify for 8-bit result
'
    OpenADC(ADC_FOSC_64 & ADC_LEFT_JUST & ADC_2_TAD, ADC_REF_VDD_VSS, ADC_1ANA)
    Cls                                                     ' Clear the LCD
    CreateBarPatterns()                                     ' Create the bit patterns that make up the LCD's bars

    Do                                                      ' Create a loop
        '
        ' Fill the real array with 8-bit ADC values
        '
        bIndex = 0                                          ' \
        Repeat                                              ' / Create a loop to fill the array with ADC readings
            FFT_bRealData[bIndex] = ReadADC(ADC_CH0)        ' Read the 8-bit ADC value into the array
            DelayUS 52                                      ' Delay for a sample rate of approx 16KHz (FFT range 0 to 8KHz)
            'DelayUS 250                                    ' Delay for a sample rate of approx 4KHz (FFT range 0 to 2KHz)
            Inc bIndex
        Until bIndex >= cFFT_NumberOfSamples                ' Repeat for n samples

        Fix_FFT()                                           ' Perform the FFT (Result in array FFT_bRealData)
'
' Display the spectrum on a 16x2 alphanumeric LCD
' As columns of vertical bars
'
        bLCD_Xpos = 1                                       ' Start at column 1 of the LCD
        bIndex = 0                                          ' \
        Repeat                                              ' / Create a loop for all the values in the real array
            '
            ' We only have 16 columns on the LCD, but 64 pieces of data from the FFT, So...
            ' Extract four values from the real array
            ' Find the maximum of the four values and use this as the bar value on the LCD
            '
            dHighestOfFour.Byte0 = FFT_bRealData[bIndex]    ' Extract the first value
            Inc bIndex                                      ' \
            dHighestOfFour.Byte1 = FFT_bRealData[bIndex]    ' / Extract the second value
            Inc bIndex                                      ' \
            dHighestOfFour.Byte2 = FFT_bRealData[bIndex]    ' / Extract the third value
            Inc bIndex                                      ' \
            dHighestOfFour.Byte3 = FFT_bRealData[bIndex]    ' / Extract the fourth value
            bBarValue = FindHighest(dHighestOfFour)         ' Find the highest byte within dHighestOfFour

            DisplayBar(bLCD_Xpos, bBarValue)                ' Display a bar on the LCD
            Inc bLCD_Xpos                                   ' Next column on the LCD
            If bLCD_Xpos > 16 Then bLCD_Xpos = 1            ' Back to column 1 when the end of the LCD is reached
            Inc bIndex                                      ' \
        Until bIndex >= cFFT_NumberOfRealElements           ' / Until all the elements of the FFT are read
    Loop                                                    ' Do it forever

'-------------------------------------------------------------------------
' Find the highest of four values
' Input     : pValue (dHighestOfFour) holds the four bytes to compare
' Output    : Returns the highest of the four bytes
' Notes     : None

Proc FindHighest(pValue As dHighestOfFour), Byte
    Result = dHighestOfFour.Byte0                           ' Default to Result = the first value
    If Result < dHighestOfFour.Byte1 Then                   ' Is Result less than the second value?
        Result = dHighestOfFour.Byte1                       ' Yes. So Result = the second value
    EndIf
    If Result < dHighestOfFour.Byte2 Then                   ' Is Result less than the third value?
        Result = dHighestOfFour.Byte2                       ' Yes. So Result = the third value
    EndIf
    If Result < dHighestOfFour.Byte3 Then                   ' Is Result less than the fourth value?
        Result = dHighestOfFour.Byte3                       ' Yes. So Result = the fourth value
    EndIf
EndProc

'-------------------------------------------------------------------------
' Scale one 8-bit value from 0 to 31 to another 8-bit value from 0 to 16
' Input     : pX holds the value to scale
' Output    : Returns the scaled value
' Notes     : Traps a zero value for extra speed
'
Proc ScaleValue(pX As Byte), Word
    If pX = 0 Then                                          ' Is the value to scale zero?
        Result = 0                                          ' Yes. So return a zero
    Else                                                    ' Otherwise...
        Result = (pX * 16) / 31                             ' Scale the value
    EndIf
EndProc

'-------------------------------------------------------------------------
' Display a vertical bar on the alphanumeric LCD
' Input     : pXpos is the X position on the LCD to display the bar
'           : pValue holds the value to display as a vertical bar on the LCD
' Output    : Prints a bar on the LCD
' Notes     : None
'
Proc DisplayBar(pXpos As Byte, pValue As Byte)
    Dim wCharData As Word Access                            ' Holds the two individual LCD bar patterns
    Dim bBarValue As Byte Access                            ' Holds the value for the bar display on the LCD
'
' Table of LCD bars required for a given value
'
    Dim BarTable As Flash8 = 32, 32,_
                             32, 08, 32, 09, 32, 10, 32, 11, 32, 12, 32, 13, 32, 14, 32, 15,_
                             08, 15, 09, 15, 10, 15, 11, 15, 12, 15, 13, 15, 14, 15, 15, 15

    If pValue > 0 Then                                      ' Is there a bar to display?
        If pValue >= 32 Then pValue = 32                    ' Yes. So make sure a maximum is reached
        bBarValue = ScaleValue(pValue)                      ' Scale the value from (0 to 31) to (0 to 16)
        wCharData = CRead16 BarTable[bBarValue]             ' Read top and bottom bar pattern from the table
        Print At 1, pXpos, wCharData.Byte0,                 ' \
              At 2, pXpos, wCharData.Byte1                  ' / Display the bar on the LCD
    Else                                                    ' Otherwise...
        Print At 1, pXpos, " ", At 2, pXpos, " "            ' Clear the bar
    EndIf
EndProc

'-------------------------------------------------------------------------
' Create the bit patterns that make up the bars in the LCD's CGRAM.
' Input     : None
' Output    : None
' Notes     : None
'
Proc CreateBarPatterns()
    Dim bIndex As Byte                                      ' Index variable
'
' Table of bit patterns for the bars on the LCD
'
    Dim CharTable As Flash8 = $FE, $40,_
                              %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00011111,_
                              %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00011111, %00011111,_
                              %00000000, %00000000, %00000000, %00000000, %00000000, %00011111, %00011111, %00011111,_
                              %00000000, %00000000, %00000000, %00000000, %00011111, %00011111, %00011111, %00011111,_
                              %00000000, %00000000, %00000000, %00011111, %00011111, %00011111, %00011111, %00011111,_
                              %00000000, %00000000, %00011111, %00011111, %00011111, %00011111, %00011111, %00011111,_
                              %00000000, %00011111, %00011111, %00011111, %00011111, %00011111, %00011111, %00011111,_
                              %00011111, %00011111, %00011111, %00011111, %00011111, %00011111, %00011111, %00011111

    bIndex = 0
    Repeat                                                  ' Create a loop to read from the data table
        Print CRead8 CharTable[bIndex]                      ' Transfer the table values to the LCD's CGRAM
        Inc bIndex                                          ' Move up a byte
    Until bIndex >= 66                                      ' Until all GCGRAM is filled
EndProc


SeanG_65

Coming BACK to this.....Does anyone have a Proteus schematic I can try with it please?

top204

Real Time FFT Display and Tone Decoder

The page has the source codes and a Proteus .dsn file at the end of it.

SeanG_65

#9
One more question on this then I'm done.

Is it possible to fix a frequence range to process, as I ONLY need DC to 400Hz in the applocation I have in mind?

I Added this about three hours after I played with the FFT. I FIGURED OUT HOW TO DO IT.

top204

#10
The FFT mechanism does not actually care what frequencies it is analysing, it is just looking at data in an array and separating it into a type of frequency spectrum based upon what it has to analyse. i.e. Lower to Higher. So for a low frequency FFT result, sample the ADC data into the array slower. For example, a 500Hz FFT result will require a sample time for 1000Hz:

'
' Fill the real array with 8-bit ADC values
'
bIndex = 0                                          ' \
Repeat                                              ' / Create a loop to fill the array with ADC readings
    FFT_bRealData[bIndex] = ReadADC(ADC_CH0)        ' Read the 8-bit ADC value into the array
    DelayMs 1                                       ' Delay for a sample rate of approx 1000Hz (FFT range 0 to 500Hz)
    Inc bIndex
Until bIndex >= cFFT_NumberOfSamples                ' Repeat for n samples

The delay in the sampling rate caters for the halving of the array performed by FFT (real and complex values, which actually means phase differences in FFT), so the ADC samples are twice as fast as the actual FFT spectrum range.

Then call the FFT procedure and the array will be seperated into frequency blocks. You can also set how many blocks to analyse using the $define FFT_NWave in the main program, with the minumum being 16 and the maximum being 256. 256 will take longer to analyse, but give a slightly better resolution, while 16 will give a fast response but very little resolution. Again, see the sample programs for the different elements. It all depends on what the FFT blocks are to be used for.

If you have Proteus, you can use the sample programs in it and see what will happen with different values.

SeanG_65

BRILLIANT, Thanks Les. I'm having LOADS of fun using this to analyse the returned signal from a Pulse Induction metal detector the results are VERY promising.

I'm also looking at the doppler output of a 24GHz module to determine speed.