verilog – Generate a sine wave

This ip core simply generates a sine wave according a .mem file. It is required to specify rom depth equal to number of the sine points, the init file and the data size contained in the file. The phase offset and frequency are used as control signals.

It also houses the ROM module as well as the ip core and ROM testbenches. The tcl scripts allow you to run Modelsim from the console due to the bash scripts.

https://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml – points of the sine LUT calculator.

dds.v

`timescale 1ns / 1ps

module dds #
(
    parameter integer DATA_WIDTH         = 16                    ,
    parameter integer ROM_DEPTH          = 1024                  ,
    parameter         INIT_FILE          = ""                    ,
   
    parameter integer FCW_WIDTH          = $clog2(ROM_DEPTH) + 14,
    parameter integer PHASE_OFFSET_WIDTH = 10
)
(
    input  wire                              clk_i            ,
    input  wire                              s_rst_n_i        ,
    input  wire                              en_i             ,
    
    input  wire (FCW_WIDTH - 1 : 0)          fcw_i            ,
    input  wire (PHASE_OFFSET_WIDTH - 1 : 0) phase_offset_i   , //for instance: ROM_DEPTH / 2 == (2 * pi) / 2 == pi
    input  wire                              phase_offset_wr_i,
    
    output wire (DATA_WIDTH - 1 : 0)        sinus_o
);
    localparam integer LOOKUP_TABLE_INDEX_WIDTH = $clog2(ROM_DEPTH);
    localparam integer ACCUMULATOR_WIDTH        = FCW_WIDTH;

    wire (LOOKUP_TABLE_INDEX_WIDTH - 1 : 0) lookup_table_index;
    
    rom_distributed #
    (
        .DATA_WIDTH    (DATA_WIDTH              ),
        .ROM_DEPTH     (ROM_DEPTH               ),
        .INIT_FILE     (INIT_FILE               ),
        .ADDRESS_WIDTH (LOOKUP_TABLE_INDEX_WIDTH)
    ) 
    rom_distributed_inst
    (
        .address_i (lookup_table_index),
        .data_o    (sinus_o           )
    );
    
    dds_generator # 
    (
        .LOOKUP_TABLE_INDEX_WIDTH (LOOKUP_TABLE_INDEX_WIDTH),
        .ACCUMULATOR_WIDTH        (ACCUMULATOR_WIDTH       ),
        .PHASE_OFFSET_WIDTH       (PHASE_OFFSET_WIDTH      ),
        .FCW_WIDTH                (FCW_WIDTH               )
    )
    dds_generator_inst
    (
        .clk_i                (clk_i             ),
        .s_rst_n_i            (s_rst_n_i         ),
        .en_i                 (en_i              ),
             
        .phase_offset_wr_i    (phase_offset_wr_i ),                      
        .phase_offset_i       (phase_offset_i    ),
        .fcw_i                (fcw_i             ),
                              
        .lookup_table_index_o (lookup_table_index)
     ); 
endmodule

dds_tb.v

`timescale 1ns / 1ps

//The paths need to be changed
`define MEM_FILE_0   "../dds_0.mem"
`define MEM_FILE_2   "../dds_2.mem"

module dds_tb;

    localparam integer                        CLOCK_PERIOD         = 100                                  ;
    localparam integer                        ITERATION_NUM        = 4 * 1000000                          ;

    localparam integer                        DATA_WIDTH           = 16                                   ;
    localparam integer                        LUT_INDEX_REST       = 14                                   ;
   
    localparam integer                        ROM_DEPTH_0          = 1024                                 ;
    localparam integer                        PHASE_OFFSET_WIDTH_0 = 10                                   ;
    localparam integer                        FCW_WIDTH_0          = PHASE_OFFSET_WIDTH_0 + LUT_INDEX_REST;
    localparam (FCW_WIDTH_0 - 1 : 0)          PI_0                 = 10'h200                              ;
    localparam (FCW_WIDTH_0 - 1 : 0)          SINE_FREQ_0          = {FCW_WIDTH_0{1'h0}} + 9'h100         ;
    localparam (PHASE_OFFSET_WIDTH_0 - 1 : 0) PHASE_OFFSET_0       = {PHASE_OFFSET_WIDTH_0{1'h0}}         ;
    localparam (PHASE_OFFSET_WIDTH_0 - 1 : 0) PHASE_OFFSET_1       = {PHASE_OFFSET_WIDTH_0{1'h0}} + PI_0  ;       
   
    localparam integer                        ROM_DEPTH_2          = 512                                  ;
    localparam integer                        PHASE_OFFSET_WIDTH_2 = 9                                    ;
    localparam integer                        FCW_WIDTH_2          = PHASE_OFFSET_WIDTH_2 + LUT_INDEX_REST;
    localparam (FCW_WIDTH_0 - 1 : 0)          PI_2                 = 9'h100                               ;
    localparam (FCW_WIDTH_0 - 1 : 0)          SINE_FREQ_2          = {FCW_WIDTH_0{1'h0}} + 13'h1000       ;
    localparam (PHASE_OFFSET_WIDTH_0 - 1 : 0) PHASE_OFFSET_2       = {PHASE_OFFSET_WIDTH_2{1'h0}}         ; 
    localparam (PHASE_OFFSET_WIDTH_0 - 1 : 0) PHASE_OFFSET_3       = {PHASE_OFFSET_WIDTH_2{1'h0}} + PI_2  ; 
    
    wire (DATA_WIDTH - 1 : 0) sinus_0;
    wire (DATA_WIDTH - 1 : 0) sinus_1;
    wire (DATA_WIDTH - 1 : 0) sinus_2;
    wire (DATA_WIDTH - 1 : 0) sinus_3;

    reg                       clk               = 1'h0;
    reg                       s_rst_n           = 1'h0;
    reg                       en                = 1'h0;
    reg                       phase_offset_wr_0 = 1'h0;
    reg                       phase_offset_wr_1 = 1'h0;
    reg                       phase_offset_wr_2 = 1'h0;
    reg                       phase_offset_wr_3 = 1'h0;
    reg (FCW_WIDTH_0 - 1 : 0) fcw_0             = SINE_FREQ_0;
    reg (FCW_WIDTH_0 - 1 : 0) fcw_1             = SINE_FREQ_0;
    reg (FCW_WIDTH_2 - 1 : 0) fcw_2             = SINE_FREQ_2;
    reg (FCW_WIDTH_2 - 1 : 0) fcw_3             = SINE_FREQ_2;
    
    reg (PHASE_OFFSET_WIDTH_0 - 1 : 0) phase_offset_0 = PHASE_OFFSET_0; 
    reg (PHASE_OFFSET_WIDTH_0 - 1 : 0) phase_offset_1 = PHASE_OFFSET_1; 
    reg (PHASE_OFFSET_WIDTH_2 - 1 : 0) phase_offset_2 = PHASE_OFFSET_2; 
    reg (PHASE_OFFSET_WIDTH_2 - 1 : 0) phase_offset_3 = PHASE_OFFSET_3;

    dds # 
    ( 
        .DATA_WIDTH         (DATA_WIDTH          ),
        .ROM_DEPTH          (ROM_DEPTH_0         ),
        .INIT_FILE          (`MEM_FILE_0         ),
        .FCW_WIDTH          (FCW_WIDTH_0         ),
        .PHASE_OFFSET_WIDTH (PHASE_OFFSET_WIDTH_0)
    )
    sinus_generator_dut_0
    (
        .clk_i             (clk              ),
        .s_rst_n_i         (s_rst_n          ),
        .en_i              (en               ),
       
        .fcw_i             (fcw_0            ),
        .phase_offset_i    (phase_offset_0   ),
        .phase_offset_wr_i (phase_offset_wr_0),
        .sinus_o           (sinus_0          )
    );
    
    dds # 
    ( 
        .DATA_WIDTH         (DATA_WIDTH          ),
        .ROM_DEPTH          (ROM_DEPTH_0         ),
        .INIT_FILE          (`MEM_FILE_0         ),
        .FCW_WIDTH          (FCW_WIDTH_0         ),
        .PHASE_OFFSET_WIDTH (PHASE_OFFSET_WIDTH_0)
    )
    sinus_generator_dut_1
    (
        .clk_i             (clk              ),
        .s_rst_n_i         (s_rst_n          ),
        .en_i              (en               ),
     
        .fcw_i             (fcw_1            ),
        .phase_offset_i    (phase_offset_1   ),
        .phase_offset_wr_i (phase_offset_wr_1),
        .sinus_o           (sinus_1          )    
    );    
    
    dds # 
    ( 
        .DATA_WIDTH         (DATA_WIDTH          ),
        .ROM_DEPTH          (ROM_DEPTH_2         ),
        .INIT_FILE          (`MEM_FILE_2         ),
        .FCW_WIDTH          (FCW_WIDTH_2         ),
        .PHASE_OFFSET_WIDTH (PHASE_OFFSET_WIDTH_2)
    )
    sinus_generator_dut_2
    (
        .clk_i             (clk              ),
        .s_rst_n_i         (s_rst_n          ),
        .en_i              (en               ),
     
        .fcw_i             (fcw_2            ),
        .phase_offset_i    (phase_offset_2   ),
        .phase_offset_wr_i (phase_offset_wr_2),
        .sinus_o           (sinus_2          )    
    );                                   
    
    dds # 
    ( 
        .DATA_WIDTH         (DATA_WIDTH          ),
        .ROM_DEPTH          (ROM_DEPTH_2         ),
        .INIT_FILE          (`MEM_FILE_2         ),
        .FCW_WIDTH          (FCW_WIDTH_2         ),
        .PHASE_OFFSET_WIDTH (PHASE_OFFSET_WIDTH_2)
    )
    sinus_generator_dut_3
    (
        .clk_i             (clk              ),
        .s_rst_n_i         (s_rst_n          ),
        .en_i              (en               ),
     
        .fcw_i             (fcw_3            ),
        .phase_offset_i    (phase_offset_3   ),
        .phase_offset_wr_i (phase_offset_wr_3),
        .sinus_o           (sinus_3          )    
    );
    
    initial begin
        forever begin
            #(CLOCK_PERIOD / 2) clk = !clk;
        end 
    end

    initial begin
        @(posedge clk);
        
        s_rst_n <= 1'h1;
        en      <= 1'h1;
        @(posedge clk);
        
       repeat(ITERATION_NUM) begin
           @(posedge clk);  
       end
       
       phase_offset_wr_0 <= 1'h1;
       phase_offset_0    <= PHASE_OFFSET_1;
       phase_offset_wr_2 <= 1'h1;
       phase_offset_2    <= PHASE_OFFSET_3;
       @(posedge clk);
       phase_offset_wr_0 <= 1'h0;
       phase_offset_wr_2 <= 1'h0;
       
       repeat(ITERATION_NUM) begin
           @(posedge clk);  
       end

        $stop();
    end

endmodule

rom_distributed.v

`timescale 1ns / 1ps

module rom_distributed #
(
    parameter integer DATA_WIDTH    = 8                ,
    parameter integer ROM_DEPTH     = 256              ,
    parameter         INIT_FILE     = "",
    parameter integer ADDRESS_WIDTH = $clog2(ROM_DEPTH)
) 
(
    input  wire (ADDRESS_WIDTH - 1 : 0) address_i,
    output wire (DATA_WIDTH - 1 : 0)    data_o
);
    reg (DATA_WIDTH - 1 : 0) rom_memory (ROM_DEPTH - 1 : 0);

    initial begin
        if ("" != INIT_FILE) begin
            $readmemh(INIT_FILE, rom_memory);
        end
        else begin
            $error("A rom init file is not specified.");
        end
    end

    assign data_o = rom_memory(address_i);
endmodule 

rom_distributed_tb.v

`timescale 1ns / 1ps

 //The path needs to be changed
`define INIT_FILE      "../rom_async.mem"

module rom_distributed_tb;
    localparam integer DATA_WIDTH = 16                   ;
    localparam integer ROM_DEPTH  = 1024                 ;
    localparam integer ADDRESS_WIDTH  = $clog2(ROM_DEPTH);   
     
    wire (DATA_WIDTH - 1 : 0) dut_value;
    
    reg (DATA_WIDTH - 1 : 0)    file_value;
    reg (ADDRESS_WIDTH - 1 : 0) address   ;
    
    integer file   = 0;
    integer errors = 0;
 
    rom_distributed #
    (
        .DATA_WIDTH    (DATA_WIDTH   ),
        .ROM_DEPTH     (ROM_DEPTH    ),
        .INIT_FILE     (`INIT_FILE   ),
        .ADDRESS_WIDTH (ADDRESS_WIDTH)
    ) 
    rom_distributed_dut
    (
        .address_i (address  ),
        .data_o    (dut_value)
    );
    
    initial begin
        file_value = 0;
        address    = 0;
        
        file = $fopen(`INIT_FILE, "r");
        
        if (0 != file) begin
            repeat(ROM_DEPTH) begin
                $fscanf(file, "%h", file_value); 
                 
                #100 if (file_value !== dut_value) begin
                    errors = errors + 1;
                end
                 
                 address = address + 1;   
            end
            
            if (0 == errors) begin
                $display("The test passed.n");
            end
            else begin
                $display("The test failed with %d errors.n", errors);
            end
        end
        else begin
            $display("A descripter of a '%s' file is 0.n", `INIT_FILE);
        end
        
        $stop();
    end
endmodule

dds_generator.v

`timescale 1ns / 1ps

module dds_generator # 
(
    parameter integer LOOKUP_TABLE_INDEX_WIDTH = 10,
    parameter integer ACCUMULATOR_WIDTH        = 24,
    parameter integer PHASE_OFFSET_WIDTH       = 10,
    parameter integer FCW_WIDTH                = 8        
)
(
    input  wire                                    clk_i               ,
    input  wire                                    s_rst_n_i           ,
    input  wire                                    en_i                ,
    
    input  wire                                    phase_offset_wr_i   ,
    input  wire (PHASE_OFFSET_WIDTH - 1 : 0)       phase_offset_i      ,
    input  wire (FCW_WIDTH - 1 : 0)                fcw_i               ,
    
    output wire (LOOKUP_TABLE_INDEX_WIDTH - 1 : 0) lookup_table_index_o
);
    localparam integer ACCUMULATOR_WIDTH_LSB = ACCUMULATOR_WIDTH - LOOKUP_TABLE_INDEX_WIDTH;
    
    reg (ACCUMULATOR_WIDTH - 1:0) accumulator;

    always @ (posedge clk_i) begin
        if(1'h0 == s_rst_n_i ) begin
            accumulator(ACCUMULATOR_WIDTH_LSB - 1 : 0)             <= 0;
            accumulator(ACCUMULATOR_WIDTH : ACCUMULATOR_WIDTH_LSB) <=  phase_offset_i;              
        end
        else if (1'h1 ==  phase_offset_wr_i) begin
            accumulator(ACCUMULATOR_WIDTH_LSB - 1 : 0)             <= 0;
            accumulator(ACCUMULATOR_WIDTH : ACCUMULATOR_WIDTH_LSB) <=  phase_offset_i;
        end else if (1'h1 == en_i) begin
            if (({10{1'h1}} - 2) == accumulator(ACCUMULATOR_WIDTH : ACCUMULATOR_WIDTH_LSB)) begin
                accumulator(ACCUMULATOR_WIDTH : ACCUMULATOR_WIDTH_LSB) <= 0;
            end
            else begin
                accumulator <= accumulator + fcw_i;
            end
        end
    end
    
    assign lookup_table_index_o = accumulator(ACCUMULATOR_WIDTH : ACCUMULATOR_WIDTH_LSB);
endmodule

dds_tb

#!/bin/bash

#change the vivado_path to yours if required.
modelsim_path=/opt/modelsim/modelsim_ase/bin
tb_tcl_file_name=dds_tb.tcl

$modelsim_path/vsim -do $tb_tcl_file_name

dds_tb.tcl

transcript on
vlib work
vmap work work

# variables---------
set dut   ../../hdl/dds.v
set var_1 ../../hdl/dds_generator.v
set var_2 ../../hdl/rom_distributed.v
set tb    dds_tb.v
# ------------------

vlog $dut $tb $var_1 $var_2

 
vsim -t 100ns -voptargs="+acc" dds_tb

# waves    ---------
add wave /dds_tb/clk


add wave -radix hex -format  analog-step -max 65535 -min -65535 -height 100 /dds_tb/sinus_0
add wave -radix hex -format  analog-step -max 65535 -min -65535 -height 100 /dds_tb/sinus_1
add wave -radix hex -format  analog-step -max 32767 -min -32767 -height 100 /dds_tb/sinus_2
add wave -radix hex -format  analog-step -max 32767 -min -32767 -height 100 /dds_tb/sinus_3

add wave -radix hex /dds_tb/fcw_0
add wave -radix hex /dds_tb/phase_offset_0
add wave -radix hex /dds_tb/phase_offset_wr_0

add wave -radix hex /dds_tb/fcw_1
add wave -radix hex /dds_tb/phase_offset_1
add wave -radix hex /dds_tb/phase_offset_wr_1

add wave -radix hex /dds_tb/fcw_2
add wave -radix hex /dds_tb/phase_offset_2
add wave -radix hex /dds_tb/phase_offset_wr_2

add wave -radix hex /dds_tb/fcw_3
add wave -radix hex /dds_tb/phase_offset_3
add wave -radix hex /dds_tb/phase_offset_wr_3
# ------------------

configure wave -timelineunits us

run -all 
wave zoom full

rom_distributed_tb

#!/bin/bash

#change the vivado_path to yours if required.
modelsim_path=/opt/modelsim/modelsim_ase/bin
tb_tcl_file_name=rom_distributed_tb.tcl

$modelsim_path/vsim modelsim.ini -do $tb_tcl_file_name

rom_distributed_tb.tcl

transcript on
vlib work
vmap work work

# variables---------
set dut ../../hdl/rom_distributed.v
set tb rom_distributed_tb.v
# ------------------

vlog $dut $tb
 
vsim -t 100ns -voptargs="+acc" rom_distributed_tb

# waves    ---------
add wave -radix hex /rom_distributed_tb/dut_value
add wave -radix hex /rom_distributed_tb/file_value
add wave -radix hex /rom_distributed_tb/errors
# ------------------

configure wave -timelineunits us

run -all 
wave zoom full

clear

#!/bin/bash

rm transcript modelsim.ini *vsim.wlf -r work

c++ – Calculation of the sine function

I have been attempting to implement a function calculating values of the sine function.
I know that there are several similar threads regarding this topic but my goal was to try
to implement such function in my own way as an excercise.

In the time being I have below given code in C++ language which seems to be working (I have
compared the outputs of that code with the sine values calculated by the Excel).

#define PI         3.14
#define TABLE_SIZE 256
#define STEP_SIZE (2*PI/255)

double lut(TABLE_SIZE) = {
    0.0000, 0.0245, 0.0490, 0.0735, 0.0980, 0.1223, 0.1467, 0.1709, 
    0.1950, 0.2190, 0.2429, 0.2666, 0.2901, 0.3135, 0.3367, 0.3597, 
    0.3825, 0.4050, 0.4274, 0.4494, 0.4712, 0.4927, 0.5139, 0.5348, 
    0.5553, 0.5756, 0.5954, 0.6150, 0.6341, 0.6529, 0.6713, 0.6893, 
    0.7068, 0.7240, 0.7407, 0.7569, 0.7727, 0.7881, 0.8029, 0.8173, 
    0.8312, 0.8446, 0.8575, 0.8698, 0.8817, 0.8930, 0.9037, 0.9140, 
    0.9237, 0.9328, 0.9413, 0.9493, 0.9568, 0.9636, 0.9699, 0.9756, 
    0.9806, 0.9852, 0.9891, 0.9924, 0.9951, 0.9972, 0.9988, 0.9997, 
    1.0000, 0.9997, 0.9988, 0.9974, 0.9953, 0.9926, 0.9893, 0.9854, 
    0.9810, 0.9759, 0.9703, 0.9640, 0.9572, 0.9498, 0.9419, 0.9333, 
    0.9243, 0.9146, 0.9044, 0.8937, 0.8824, 0.8706, 0.8583, 0.8454, 
    0.8321, 0.8182, 0.8039, 0.7890, 0.7737, 0.7580, 0.7417, 0.7251, 
    0.7080, 0.6904, 0.6725, 0.6541, 0.6354, 0.6162, 0.5967, 0.5769, 
    0.5566, 0.5361, 0.5152, 0.4941, 0.4726, 0.4508, 0.4288, 0.4065, 
    0.3840, 0.3612, 0.3382, 0.3150, 0.2917, 0.2681, 0.2444, 0.2205, 
    0.1966, 0.1724, 0.1482, 0.1239, 0.0996, 0.0751, 0.0506, 0.0261, 
    0.0016, -0.0229, -0.0475, -0.0719, -0.0964, -0.1208, -0.1451, -0.1693, 
    -0.1934, -0.2174, -0.2413, -0.2650, -0.2886, -0.3120, -0.3352, -0.3582, 
    -0.3810, -0.4036, -0.4259, -0.4480, -0.4698, -0.4913, -0.5125, -0.5334, 
    -0.5540, -0.5743, -0.5942, -0.6137, -0.6329, -0.6517, -0.6701, -0.6881, 
    -0.7057, -0.7229, -0.7396, -0.7559, -0.7717, -0.7871, -0.8020, -0.8164, 
    -0.8303, -0.8437, -0.8566, -0.8690, -0.8809, -0.8923, -0.9031, -0.9133, 
    -0.9230, -0.9322, -0.9408, -0.9488, -0.9563, -0.9632, -0.9695, -0.9752, 
    -0.9803, -0.9849, -0.9888, -0.9922, -0.9950, -0.9971, -0.9987, -0.9996, 
    -1.0000, -0.9998, -0.9989, -0.9975, -0.9954, -0.9928, -0.9895, -0.9857, 
    -0.9813, -0.9762, -0.9706, -0.9644, -0.9577, -0.9503, -0.9424, -0.9339, 
    -0.9249, -0.9153, -0.9051, -0.8944, -0.8832, -0.8714, -0.8591, -0.8463, 
    -0.8330, -0.8191, -0.8048, -0.7900, -0.7747, -0.7590, -0.7428, -0.7262, 
    -0.7091, -0.6916, -0.6736, -0.6553, -0.6366, -0.6175, -0.5980, -0.5782, 
    -0.5580, -0.5374, -0.5166, -0.4954, -0.4740, -0.4522, -0.4302, -0.4080, 
    -0.3854, -0.3627, -0.3397, -0.3166, -0.2932, -0.2696, -0.2459, -0.2221, 
    -0.1981, -0.1740, -0.1498, -0.1255, -0.1011, -0.0767, -0.0522, -0.0277
};

double sine(double x, double lut(TABLE_SIZE))
{
  bool negateTableValue = false;
  if (x < 0) {
    // sin(-x) = -sin(x)
    x = -x;
    negateTableValue = true;
  }
  
  uint8_t index_01 = x/STEP_SIZE;
  uint8_t index_02 = (index_01 + 1);
      
  double aux = (lut(index_02) - lut(index_01))/STEP_SIZE*(x - index_01*STEP_SIZE) + lut(index_01);
  
  if (negateTableValue) {
    return -aux;
  } else {
    return aux;
  } 
}

The sine values calculation is based on the look-up table containing the pre-computed values of the sine function covering the whole period $left<0, 2piright>$ with 256 values. I have decided to use the linear interpolation method for improving the precision.

I have one doubt regarding the linear interpolation. Namely I have been using table with 256
entries but most of the solutions exploiting the linear interpolation use look-up table with one additional entry. I would say that it isn’t necessary in my case because the index variables are uint8_t type i.e. they can store values from range 0-255. But I would like to know other ones opinion. Thank you in advance.

unity – How to decay sine or cosine wave so it takes one additional period to reach equilibrium

In many shmups, when enemies arrive, they accelerate onto screen, decelerate, and overshoot their static arrival position slightly, before backing up slowly to the position. This can be seen in many shmups, including those by Cave & Raizing.

I tried implementing this behavior using normal steering arrival behavior, but it was too finicky and the effect wasn’t right, so I am now trying to use a decaying sine or cosine wave to encode the enemy’s distance to their destination.

In particular, I am trying to create a parametrized decaying sine or cosine wave (or, alternatively, any kind of parameterized overshoot wave) so that arriving enemies overshoot their destination slightly before returning to it, without additional oscillation.

Ideally, I’d like for the first peak of the sine or cosine wave to be the full amplitude and for it to take one additional period for the wave to decay sufficiently close to 0 (say, within some epsilon).

The ideal curve looks something like:

enter image description here

I have looked at some articles on decaying trig waves (for example, here and here) and know that there’s an infinite number of ways to specify decay in a parametrized curve.

For example, the equation for exponentially decaying cosine wave is the following:

y(t) = amplitude * e^(-lambda * t) * cos(frequency * t + initial angle offset)

where lambda is the decay rate.

I can’t seem to fathom how you’d specify that it’d decay over exactly one additional period, however.

It would also be nice to be able to specify the amplitude of the decayed peak, so that you can granularly control the overshoot distance proportional to the full amplitude. It would also be nice to be able to specify that the resolution of the overshoot happens faster than the initial period (for example takes 0.25 * initial period, rather than the full period).

Does anyone have any tips or tricks for implementing this kind of curve in order to approximate overshoot movement?

NOTE: I know that certain Tween libraries like DOTween have ease types that represent overshoot, but I’d like to implement it myself for more control & flexibility.

I tried the following, gradually increasing amplitude by a certain step once the curve reaches 0 (which happens at PI/2), as well as decreasing speed once the curve reaches the nadir of -1 (which happens at PI). But the results weren’t very good. The overshoot does resolve, but not in a smooth way. Rather, the enemy quickly stops when it reaches its final position.

private IEnumerator MoveAlongCurve()
{
    // walk through curve using parametrized form, w/ parameter t
    while (t < Mathf.PI/2)
    {
        t += Time.deltaTime * speed;
        pos_on_curve.x = origin.x;
        pos_on_curve.y = origin.y + Mathf.Cos(t * 2 * Mathf.PI) * amplitude;
        
        transform.position = pos_on_curve;
        yield return new WaitForEndOfFrame(); // wait for end of frame
    }

    while (t >= Mathf.PI / 2)
    {
        if (t >= Mathf.PI)
        {
            speed = 0.5f;
        }
        amplitude -= 0.25f;
        amplitude = Mathf.Clamp(amplitude, 0, float.PositiveInfinity);
        t += Time.deltaTime * speed;
        pos_on_curve.x = origin.x;
        pos_on_curve.y = origin.y + Mathf.Cos(t * 2 * Mathf.PI) * amplitude;

        transform.position = pos_on_curve;
        yield return new WaitForEndOfFrame(); // wait for end of frame
    }
}

integration – Gaussian integral with a sine in the exponential

This Gaussian integral came up while working on a likelihood analysis for pulsar timing arrays:

$$
int_{-pi}^{pi} expleft( -(x-y sin{gamma} )^2 right) mathrm{d}gamma
$$

I’ve tried everything I can think of, but I can’t get an analytic solution.

If you expand the square, the cross term can be written in terms of a cosh, but I don’t know where to go from there. That gives the integrand as $exp{(-x^2)} exp{(-y^2 sin^2gamma)} cosh{(2 x y sin{gamma})}$.

The substitution $betaequivsin{gamma}$ leads to
$$
oint_0^0 frac{expleft( -(x-y beta )^2 right)}{sqrt{1-beta^2}} mathrm{d}beta
$$

I also tried $arctan alpha equiv gamma$, which gives

$$
int frac{expleft(-left( x- frac{alpha y}{sqrt{1+alpha^2}} right)^2right)}{1+alpha^2} mathrm{d}alpha
$$

Neither Mathematica nor Rubi are able to evaluate any of these integrals. I was hoping the residue theorem might be applicable, or one of these substitutions might get into a form that Mathematica knows. Any help will be greatly appreciated and certainly land you in the acknowledgements of the paper my collaborators and I are working on:)

Inconsistent boundary and initial conditions when solving sine Gordon equation

I have been trying to solve the following sine Gordon equation

$partial_{x,x} u(x,t) – partial_{t,t} u(x,t) – sin (u(x,t)) – alpha partial_t u(x,t) + gamma = 0$,

for $x in (0,15)$ and $t in (0,20)$ with the boundary conditions

$partial_x u(x,t)vert_{x=0} = h, hspace{2cm} partial_x u(x,t)vert_{x=15} = h + a_{mathrm{ext}} sin(omega_{mathrm{ext}}t), $

and the initial conditions

$partial_t u(x,t)vert_{t=0} = 0, hspace{2cm} u(x,t)vert_{t=0} = h x$.

Here is my Mathematica code

const = {al -> 0.08, (Gamma) -> 0.01, h -> 6,  ax -> 2.5, (Omega)x -> 1.4};

NDSolveValue(({D(u(x, t), x, x) - D(u(x, t), t, t) - Sin(u(x, t)) - al D(u(x, t), t) + (Gamma) == 0,
    
(D(u(x, t), x) /. {x -> 0}) == h, (D(u(x, t), x) /. {x -> 15}) == h +  ax Sin((Omega)x  t), 
    u(x, 0) == h*x, (D(u(x, t), t) /. {t -> 0}) == 0} /.const), u, {x, 0, 15}, {t, 0, 20},
 
 Method -> {"PDEDiscretization" -> {"MethodOfLines", 
     "SpatialDiscretization" -> {"TensorProductGrid", 
       "MinPoints" -> 200}}})

The code works and gives a solution, but there appears an error message like this

NDSolveValue::ibcinc: Warning: boundary and initial conditions are inconsistent.

From the second initial condition we have $partial_x u(x,0) = h$, which are consistent with the two boundary conditions at $t=0$. So I don’t understand why the above error occurs.

I have read many posts related to this problem. One of the solutions is to increase the “MinPoints” in the “Method”. I tried so, but it still did not not get rid of the error.

Any advice is very much appreciated.

Dat.

shaders – Any fast alternative to sine in GLSL?

Should I just use the built-in sin() function or my custom sine function?
I’m concerned about performance here. I don’t care about accuracy much here because I use it to just get wave effects in my shader.

The shader is for mobile platforms (OpenGL ES)

Here’s my code

float customSin(float x){
   x = fract( 0.75 + x*0.159155 )*2.0 - 1.0; 
   return x*x * (6.0 - 4.0*x) - 1.0;
}

Here’s my algorithm

x is the input, y is the output

r = 0.75 + x/(π*2)
a = | r- floor(r) – 0.5 |*2
y = ( 3(a^2) – 2(a^3) )*2 – 1

I checked the graph, and it’s pretty close to the actual sine.

Which one should I go with?

unity – How to displace a segmented line along a sine wave with Shader Graph?

I have a mesh made of three identical cylinders (conceptually just line segments with a non-zero thickness) crossed over each other at 60 degree angles, so the ends describe the points of a regular hexagon. The cylinders are divided into a lot of segments, which I’d like to displace in a sinewave pattern. The pivot is in the center of the mesh.

My concept is pretty straightforward:

  • Subtract object position from vertex position to get vertex position relative to the pivot (VPR).
  • Normalize VPR and swap the X and Y to get a vector in the XY plane perpendicular to the orientation of the cylinder.
  • Take the magnitude of VPR, multiply by a V1 parameter (Waviness), then take the sine.
  • Multiply the sine by the perpendicular orientation vector to get the displacement.
  • Add the displacement to the vertex position. Assign result to master node’s vertex position.

This really feels like it should work. Each cylinder should be distorted along a sine wave, with the magnitude of the distortion increasing the further it gets from the center, so I end up with three wavy lines crossed over each other at 60 degree angles. Increasing Waviness should increase the frequency of the wave, as the base value is multiplied by it before feeding into the sine node.

Instead, things curve just a little bit at a low Waviness, but as I increase it the cylinders get both thicker and longer, neither of which should be happening, and start wrapping themselves around the mesh in weird patterns. I have no idea what I’m doing wrong!

Here’s my graph setup, with the mesh assigned to the preview so you can see what a mess it’s making of it:
enter image description here

Any ideas how I can fix this?

unity – Why is my sine based scale animation not changing?

I followed the code at this YouTube channel: https://www.youtube.com/watch?v=OR0e-1UBEOU&t=4178s, and did some modification on the code so that the scale of the bird will change during projectile using the absolute sine function under the if statement.

I’m using the scale (16/20)*|sin(distance)| for my x and y component. However, when I launch the game, the scale stays as 0 along the path. Why is my scale staying as a constant zero?

using UnityEngine;
using UnityEngine.Assertions.Must;
using UnityEngine.SceneManagement;

public class Bird : MonoBehaviour
{   
    Vector3 OldPosition;
    Vector3 DistanceDifference;
    float TotalDistance = 0;
    Vector3 _initialPosition;
    private bool _birdWasLaunched;
    (SerializeField) private float _launchPower = 500;

    void start()
    {
        OldPosition = transform.position; 
    }
    
    private void Awake()
    {
        _initialPosition = transform.position;

    }

    void Update()
    {   
        if (_birdWasLaunched && GetComponent<Rigidbody2D>().velocity.magnitude > 0.1)
        {
            DistanceDifference = transform.position - OldPosition;
            TotalDistance += DistanceDifference.magnitude;
            OldPosition = transform.position;
            transform.localScale = new Vector3((16/20)*Mathf.Abs(Mathf.Sin(TotalDistance/5)), (16/20)*Math.Abs(Mathf.Sin(TotalDistance /5)) , Mathf.Sin(TotalDistance /5));   
        }

        if (transform.position.y > 15.00 || transform.position.y < -15.00 || transform.position.x > 18 || transform.position.x < -18)
        {
            string currentSceneName = SceneManager.GetActiveScene().name;
            SceneManager.LoadScene(currentSceneName);
        }
    }

    void OnMouseDown()
    {
        GetComponent<SpriteRenderer>().color = Color.red;
    }

    private void OnMouseUp()
    {
        GetComponent<SpriteRenderer>().color = Color.white;
        Vector2 directionToInitialPosition = _initialPosition - transform.position;
        GetComponent<Rigidbody2D>().AddForce(directionToInitialPosition * _launchPower);
        GetComponent<Rigidbody2D>().gravityScale = 1;
        _birdWasLaunched = true;
    }

    private void OnMouseDrag()
    {
        Vector3 newPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        transform.position = new Vector3(newPosition.x, newPosition.y);
    }
}