Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] How do you use variable real numbers?

Status
Not open for further replies.

hobbskw

Junior Member level 3
Joined
Oct 19, 2021
Messages
25
Helped
1
Reputation
2
Reaction score
1
Trophy points
3
Activity points
197
Greetings,
I am using a sinewave lookup table to generate an SPWM signal. I am adding a soft-start feature where the modulation index starts at 0, then after after 10 seconds it starts to gradually increase to 0.1 over 20 seconds. The problem is it does not like having a variable real number (except in simulations). My goal is to increment the modulation index by 0.0001 a thousand times, so it would be a very smooth increase. How can I change this to work? I have heard of the floating point and fixed point libraries. Are there any good examples of people using these to make variable real numbers?

Also, if it helps, the sinewaves themselves are integers. So in a sense my goal is really a variable integer, but the problem is I have to scale them down which requires multiplying by a decimal.

Here is the code:

Code:
`timescale 1ns / 1ps

module sine_LUT(
        input clk,
        input rst_n,
        output pwm1PT,
        output pwm2PT,
        output pwm3PT,
        output pwm1NT,
        output pwm2NT,
        output pwm3NT,
        output pwm1PB,
        output pwm2PB,
        output pwm3PB,
        output pwm1NB,
        output pwm2NB,
        output pwm3NB,
        output en_rst1H,
        output en_pwr1H,
        output en_rst1L,
        output en_pwr1L,
        output en_rst2H,
        output en_pwr2H,
        output en_rst2L,
        output en_pwr2L,
        output en_rst3H,
        output en_pwr3H,
        output en_rst3L,
        output en_pwr3L
    );

// initialize the sinewave lookup table
reg [12:0] sineLUT[0:47];
integer addr=0;
localparam res = 47; // res is the highest index number of the lookup table
localparam  D = 1250; // D is the midpoint
real M = 0; // M is the modulation index
always @* begin
    case (addr)
        0: sineLUT[0] = 1413;
        1: sineLUT[1] = 1574;
        2: sineLUT[2] = 1728;
        3: sineLUT[3] = 1875;
        4: sineLUT[4] = 2011;
        5: sineLUT[5] = 2134;
        6: sineLUT[6] = 2242;
        7: sineLUT[7] = 2333;
        8: sineLUT[8] = 2405;
        9: sineLUT[9] = 2457;
        10: sineLUT[10] = 2489;
        11: sineLUT[11] = 2500;
        12: sineLUT[12] = 2489;
        13: sineLUT[13] = 2457;
        14: sineLUT[14] = 2405;
        15: sineLUT[15] = 2333;
        16: sineLUT[16] = 2242;
        17: sineLUT[17] = 2134;
        18: sineLUT[18] = 2011;
        19: sineLUT[19] = 1875;
        20: sineLUT[20] = 1728;
        21: sineLUT[21] = 1574;
        22: sineLUT[22] = 1413;
        23: sineLUT[23] = 1250;
        24: sineLUT[24] = 1087;
        25: sineLUT[25] = 926;
        26: sineLUT[26] = 772;
        27: sineLUT[27] = 625;
        28: sineLUT[28] = 489;
        29: sineLUT[29] = 366;
        30: sineLUT[30] = 258;
        31: sineLUT[31] = 167;
        32: sineLUT[32] = 95;
        33: sineLUT[33] = 43;
        34: sineLUT[34] = 11;
        35: sineLUT[35] = 0;
        36: sineLUT[36] = 11;
        37: sineLUT[37] = 43;
        38: sineLUT[38] = 95;
        39: sineLUT[39] = 167;
        40: sineLUT[40] = 258;
        41: sineLUT[41] = 366;
        42: sineLUT[42] = 489;
        43: sineLUT[43] = 625;
        44: sineLUT[44] = 772;
        45: sineLUT[45] = 926;
        46: sineLUT[46] = 1087;
        47: sineLUT[47] = 1250;
    endcase;
end

// Wait for lookup table to initialize
integer start = 0;

// when active == 0, the SPWM signals will all be set to 0. This is for implementing safety features (UNFINISHED)
integer active = 1;

// these are used to detect the negative edges of he PWM signals, in order to trigger the deadtime timers
integer T1P = 0;
integer T1N = 0;
integer T2P = 0;
integer T2N = 0;
integer T3P = 0;
integer T3N = 0;

// the Side variable ensures the top and bottom mosfets take turns. One can not turn on twice in a row (UNFINISHED)
integer Side1 = 1;
integer Side2 = 1;
integer Side3 = 1;

// the magnitude of triangle and sinewave is from 0 to 2*D, with the midpoints being equal to D
integer triangle = D;
integer sinewave = D;

// updown tells what direction the triangle wave counter should be going
integer updown = 1;

// sineCount1 and 2 are counters for the fundamental frequency
// There are two: sineCount2 increments when sineCount1 reaches its limit
integer sineCount1 = 0;
integer sineCount2 = 0;

// each sinewave is shifted up by D. Addr1, 2, and 3 effectively phase shift the sinewaves
integer sinewave1 = D;
integer sinewave2 = D;
integer sinewave3 = D;
integer addr1 = 0;
integer addr2 = 16;
integer addr3 = 32;

// Soft start timer
integer SS_counter1 = 0; // pulses (up to 100)
integer SS_counter2 = 0; // microseconds (up to 1000)
integer SS_counter3 = 0; // milliseconds (up to 200)
integer SS_counter4 = 0; // milliseconds (up to 1000)
integer SS_counter5 = 0; // seconds (up to 120)
// Soft start times and modulation indexes
integer SST1 = 5; // seconds for first increment
integer M1 = 0.01;
integer SST2 = 20; // seconds for second increment
integer M2 = 0.15;
integer SST3 = 30; // seconds for third increment
integer M3 = 0.3;
integer SST4 = 35; // seconds for fourth increment
integer M4 = 0.4;

// each mosfets has their own deadtime timer, which count down from the deadtime (100 = 1 microsecond)
integer deadtime = 100/2; // 100/2 = 500 ns
integer deadtimer1P = 0;
integer deadtimer1N = 0;
integer deadtimer2P = 0;
integer deadtimer2N = 0;
integer deadtimer3P = 0;
integer deadtimer3N = 0;

always@(posedge clk) begin
    if(sineCount1 == 100)
    begin // increment sineCount2
        sineCount1 = 0;
        sineCount2 = sineCount2 + 1;
    end
    sineCount1 = sineCount1 + 1;
    if(sineCount2 == 333) // trial and error showed 333 gave a 60Hz fundamental frequency
    begin // increment addr values
        sineCount2 = 0;
        if (addr == res)
        begin
            addr = 0;
            //
        end
        else begin
            addr = addr + 1;
        end
        if (addr1 == res)
        begin
            addr1 = 0;
        end
        else begin
            addr1 = addr1 + 1;
        end
        if (addr2 == res)
        begin
            addr2 = 0;
        end
        else begin
            addr2 = addr2 + 1;
        end
        if (addr3 == res)
        begin
            addr3 = 0;
        end
        else begin
            addr3 = addr3 + 1;
        end
    end

    // deadtime timer triggers / negative edge detection
    if ((pwm1PT == 0) && (T1P == 0))
    begin
        T1P = 1;
        deadtimer1N = deadtime;
    end
    if ((pwm1NT == 0) && (T1N == 0))
    begin
        T1N = 1;
        deadtimer1P = deadtime;
    end
    if ((pwm2PT == 0) && (T2P == 0))
    begin
        T2P = 1;
        deadtimer2N = deadtime;
    end
    if ((pwm2NT == 0) && (T2N == 0))
    begin
        T2N = 1;
        deadtimer2P = deadtime;
    end
    if ((pwm3PT == 0) && (T3P == 0))
    begin
        T3P = 1;
        deadtimer3N = deadtime;
    end
    if ((pwm3NT == 0) && (T3N == 0))
    begin
        T3N = 1;
        deadtimer3P = deadtime;
    end
 
    // when a PWM signal == 1, its T variable = 0, which allows the above if-statement to trigger when PWM signal == 0 (edge detection)
    if (pwm1PT == 1)
    begin
        T1P = 0;
    end
    if (pwm1NT == 1)
    begin
        T1N = 0;
    end
    if (pwm2PT == 1)
    begin
        T2P = 0;
    end
    if (pwm2NT == 1)
    begin
        T2N = 0;
    end
    if (pwm3PT == 1)
    begin
        T3P = 0;
    end
    if (pwm3NT == 1)
    begin
        T3N = 0;
    end
 
    // decrement the deadtime timers if they are not == 0
    if (deadtimer1P != 0)
    begin
        deadtimer1P <= deadtimer1P - 1;
    end
    if (deadtimer2P != 0)
    begin
        deadtimer2P <= deadtimer2P - 1;
    end
    if (deadtimer3P != 0)
    begin
        deadtimer3P <= deadtimer3P - 1;
    end
    if (deadtimer1N != 0)
    begin
        deadtimer1N <= deadtimer1N - 1;
    end
    if (deadtimer2N != 0)
    begin
        deadtimer2N <= deadtimer2N - 1;
    end
    if (deadtimer3N != 0)
    begin
        deadtimer3N <= deadtimer3N - 1;
    end
 
    // update the values of the sinewaves from the lookup table
    sinewave = sineLUT[addr];
    sinewave1 = (M*sineLUT[addr1]/1+D*(1-M))/1;
    sinewave2 = (M*sineLUT[addr2]/1+D*(1-M))/1;
    sinewave3 = (M*sineLUT[addr3]/1+D*(1-M))/1;
 
    // Soft start timer
    // SS_counter1 == pulses
    // SS_counter2 == microseconds
    // SS_counter3 == milliseconds (for increasing M)
    // SS_counter4 == milliseconds (for counting seconds)
    // SS_counter5 == seconds
    if (SS_counter1 < 101) // count 100 pulses
        begin
        SS_counter1 = SS_counter1 + 1; // increment pulses count
        end
        else begin
        SS_counter1 = 0;
        SS_counter2 = SS_counter2+1; // increment microseconds
        end
    if (SS_counter2 > 1000) // count 1000 microseconds
        begin
        SS_counter2 = 0;
        SS_counter3 = SS_counter3 + 1; // increment milliseconds
        SS_counter4 = SS_counter4 + 1; // increment milliseconds
        end
    if (SS_counter3 > 200) // count 200 milliseconds
        begin
        SS_counter3 = 0;
        if (start && M<0.1) // increase to 0.1 over 20 seconds
            begin
            M = M + 0.0001;
            end
        end
    if (SS_counter4 > 1000) // count 1000 milliseconds
        begin
        SS_counter4 = 0;
        if (SS_counter5 < 15)
            begin
            SS_counter5 = SS_counter5 + 1; // increment seconds
            end
        end
    if (SS_counter5 == 10)
        begin
        start = 1; // begin incrementing the modulation index at 10 seconds
        end
 
    // generation of the triangle wave
    if (triangle == 2*D)
        begin
            updown <= -1;
        end
    if (triangle == 1)
        begin
            updown <= 1;
        end
    triangle <= triangle + updown;
 
end

// generation of SPWM signals
assign pwm1PT = ((start && deadtimer1P == 0)&&(sinewave1 > triangle))?1:0;
assign pwm2PT = ((start && deadtimer2P == 0)&&(sinewave2 > triangle))?1:0;
assign pwm3PT = ((start && deadtimer3P == 0)&&(sinewave3 > triangle))?1:0;
assign pwm1NT = ((start && deadtimer1N == 0)&&(sinewave1 < triangle))?1:0;
assign pwm2NT = ((start && deadtimer2N == 0)&&(sinewave2 < triangle))?1:0;
assign pwm3NT = ((start && deadtimer3N == 0)&&(sinewave3 < triangle))?1:0;
// each gate driver requires both the upper and lower gate signals to prevent short-circuits
assign pwm1PB = pwm1NT;
assign pwm2PB = pwm2NT;
assign pwm3PB = pwm3NT;
assign pwm1NB = pwm1PT;
assign pwm2NB = pwm2PT;
assign pwm3NB = pwm3PT;
// enable bits
assign en_rst1H = 1;
assign en_pwr1H = 1;
assign en_rst1L = 1;
assign en_pwr1L = 1;
assign en_rst2H = 1;
assign en_pwr2H = 1;
assign en_rst2L = 1;
assign en_pwr2L = 1;
assign en_rst3H = 1;
assign en_pwr3H = 1;
assign en_rst3L = 1;
assign en_pwr3L = 1;

endmodule

Here is the error it is producing:
1652459713604.png


Line 283 is this:
1652459761733.png


I divide by 1 because that seems to round/change the output of the equation to an integer, which is what sinewave1/2/3 are, thus getting rid of an earlier error from setting an integer to a real.
--- Updated ---

Also, please ignore this part:

Code:
// Soft start times and modulation indexes
integer SST1 = 5; // seconds for first increment
integer M1 = 0.01;
integer SST2 = 20; // seconds for second increment
integer M2 = 0.15;
integer SST3 = 30; // seconds for third increment
integer M3 = 0.3;
integer SST4 = 35; // seconds for fourth increment
integer M4 = 0.4;

This is old and was written to implement a more stepping increase of the modulation index.
I should have deleted this bit.
 
Last edited:

Hi,

I guess there are many thousands of good SPWM tutorials/example/code/videos...
Almost any manufacturer for inverter semiconductors provides application notes.
A lot of threads here in the forum and in the internet..

We don´t know MCU/PLD/PSoC, language, compiler ... so thus we can´t give detailed infromations.

I personally see no need for fixed point nor floating point variables here, because the PWM module will only accept integer values.

You say "softstart" but I as far as I understand you just increase frequency ... I guess it´s a better strategy to increase amplitude.

"Dividing" is the most complicated of the 4 basic operations. I avoid it - if possible.. and if not hardware divider available.
"making integer" for a fixed point value means just "shift" or "truncate".
In a PLD it´s nothing.. just using the signals you need.

My recommendation:
* read, read, read .. watch videos
* then show what you want to do. Draw a sketch.
* then focus on one problem. Solve it. Test it.
* Then go to the next problem

Klaus
 

After some messing around with the code I found a solution. Unfortunately there are timing errors with my implementation, but it removed the error I was struggling with. My solution was to change the values inside of the lookup table by dividing each by 1000. So I hard-coded those decimal values. I mean, I just typed a decimal point in each value of the lookup table, like I changed "0: sineLUT[0] = 1413;" to "0: sineLUT[0] = 1.413;". Then I increase M from 1 to 1000, so it is an integer now. I hope this is helpful to someone else who having this issue.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top