I want to write verilog code for Clarke and Park transformations for the implementation of a foc algorithm. I am new to verilog and I am failing to understand how to write the code for such complex equations which involve cos,sin functions and real numbers. Can someone please give me a start? The verilog code I tried to write is below.
timescale 1ns/1ps
module clarke_park(iR_i,iY_i,iB_i,theta,iD_o,iQ_o);
output real iD_o;
output real iQ_o;
input real iR_i;
input real iY_i;
input real iB_i;
real k = 0.66;
output real ialpha;
output real ibeta;
output real iY_r;//real part
output real iY_c;//complex part
output real iB_r;
output real iB_c;
output real ibeta_r;
output real ibeta_c;
function sin(input real theta);
function cos(input real theta);
iY_r = -1*(iY_i)*(0.5);
iY_c = (iY_i)*(0.866);
iB_r = -1*(iB_i)*(0.5);
iB_c = -1*(iB_i)*(0.866);
ialpha = k*iR;
ibeta_r = k*(0.866)*(iY_r-iB_r);
ibeta_c = k*(0.866)*(iY_c-iB_c);
real a1 = sin(theta);
real a2 = cos(theta);
iD_r = (a1*(ialpha)) + ((sin(theta))*(ibeta_r));
iD_c = a2*(ibeta_c);
iQ_r = - (1*a2*(ialpha)) + (a1*(ibeta_r));
iQ_c = a1*(ibeta_c);
endfunction
assign iD_o = {iD_r,iD_c};
assign iQ_o = {iQ_r,iQ_c};
endmodule
I would start with something like this:
module clarke_park(
output real iD_o,
output real iQ_o,
input real iR_i,
input real iY_i,
input real iB_i,
output real ialpha,
output real ibeta,
output real iY_r,//real part
output real iY_c,//complex part
output real iB_r,
output real iB_c,
output real ibeta_r,
output real ibeta_c
);
localparam k = 0.66;
Not sure what you are trying to do with the functions. but something like:
but note you have not defined theta, it was in you port list but then not defined as input or a real.
real a1;
real a2;
always #* begin
iY_r = -1*(iY_i)*(0.5);
iY_c = (iY_i)*(0.866);
iB_r = -1*(iB_i)*(0.5);
iB_c = -1*(iB_i)*(0.866);
ialpha = k*iR;
ibeta_r = k*(0.866)*(iY_r-iB_r);
ibeta_c = k*(0.866)*(iY_c-iB_c);
a1 = $sin(theta);
a2 = $cos(theta);
iD_r = (a1*(ialpha)) + ((sin(theta))*(ibeta_r));
iD_c = a2*(ibeta_c);
iQ_r = - (1*a2*(ialpha)) + (a1*(ibeta_r));
iQ_c = a1*(ibeta_c);
end
$cos and $sin are described in section 20.8 of ieee 1800-2012.
Related
I want to create a define constant that is assigned to one of multiple otherdefine constants that has the largest value. Something like:
`define MAXWIDTH $MAX(`WIDTH0,`WIDTH1,`WIDTH2)
Is this possible in Verilog/SystemVerilog?
Depending on exactly what you need, there are a few ways to do it (there is no builtin call for maximum like in other languages):
You have some vectors and you need to get the maximum width for a new vector
$bits(v1 + v2 + v3 ...)
Use the language to your advantage, noting that the addition of vectors results in a vector that has the maximum width of all the operand vector widths and use $bits to get that size. Example:
logic [1:0] x;
logic [7:0] y;
logic [10:6] z;
...
max = $bits(x + y + z); // Result: max = 8
You have a few numbers of which you need the maximum
If you put your numbers in an array or queue, you can use the max method to get the largest:
int x[] = '{n1, n2, n3, ...};
...
max = x.max;
Note that this approach has the downside that it cannot be used at compile time for getting the maximum size. Example:
int _nums[] = '{13, 2, 17, 8, -1};
...
max = _nums.max; // Result: max = 17
Basically any other time
You'll just have to use the conditional operator, either in a macro or using let:
`define max2(v1, v2) ((v1) > (v2) ? (v1) : (v2))
`define max3(v1, v2, v3) `max2((v1), `max2((v2), (v3)))
OR
let max2(v1, v2) = (v1 > v2) ? v1 : v2;
let max3(v1, v2, v3) = max2(v1, max2(v2, v3));
The advantage of macros is that you can use them as compile-time constants in a wider range of tools, while older tools might not support let as a compile-time constant (or at all). Example:
max = `max3(10, 2, 3); // Result: max = 10
OR
max = max3(10, 2, 3); // Result: max = 10
I have [8:0] digital data inputs. I want to pre-define these values and store them with a unique address so I can access them later in my logic by just calling their address value.
Not entirely sure, I was doing something like this (Also, this is for Verilog RTL (Syntheisizable):
reg array[8:0];
array[8] = 9'b000000000;
array[7] = 9'b000000001;
array[6] = 9'b000000010;
array[5] = 9'b000000011;
array[4] = 9'b000000100;
array[3] = 9'b000000101;
array[2] = 9'b000000111;
array[1] = 9'b000001000;
array[0] = 9'b000000000;
I'm not sure, this is just something that was on top of my head.
If youre looking to create a LUT (which is basically want you are suggesting), you are on the right track:
reg [8:0] lut [8:0]; // Its an array of 9 elements (0 through 8 after the variable name), each of which is 9 bits wide (before the variable name)
assign lut[8] = 9'b000000000; // If there is a pattern to the array, use generate statement and loops to initialize it, Im just doing it one-by-one here
assign lut[7] = 9'b000000001;
assign lut[6] = 9'b000000010;
assign lut[5] = 9'b000000011;
assign lut[4] = 9'b000000100;
assign lut[3] = 9'b000000101;
assign lut[2] = 9'b000000111;
assign lut[1] = 9'b000001000;
assign lut[0] = 9'b000000000;
I am looking for a way to store a few variables in one variable so I can output a string. For example, I have variables:
int flow_val = "128";
int numb_val = "104";
int size_val = "256";
I can put them together using $display like this:
$display("32'h%0h%0h_%4h", flow_val, numb_val, size_val);
to print out:
32'h8068_0100
Is there a way to get that output and put it into a variable such as hex_val?
$sformatf can be used. Refer to IEEE Std 1800-2012, section 21.3.3 Formatting data to a string.
module tb;
int flow_val = 128;
int numb_val = 104;
int size_val = 256;
string hex_val;
initial begin
hex_val = $sformatf("32'h%0h%0h_%4h", flow_val, numb_val, size_val);
$display(hex_val);
end
endmodule
Output:
32'h8068_0100
In the following simplified Verilog code:
wire [31:0] depth;
wire mode_u2 = 1'h0;
assign depth = 'h80 + (~mode_u2);
if I do a display on depth, and simulate it with VCS (2014.12-1)
$display("depth is 0x%2x", depth);
i'm getting 0x7f, instead of expected 0x81. it seems like ~mode_u2 is treated as minus 1.
If I change ~mode_u2 to !mode_u2. I get 0x81 as expected.
what's more interesting is if i do wire mode = ~mode_u2 and then assign depth = 'h80 + (~mode) instead of 0x80, i get 0x7e
Am I missing something here?
Can someone explain why ~ behaves this way in a + operation? Or is this one of those simulation and synthesis being different situation?
Many thanks!!
Willie
The operands of the add operator need to be extended to the size of left hand side (or the max width of the two operands depending on the context) before the addition is done.
In this case mode_u2 needs to be extended to 32 bits. I wasn't able to find a reference for this, but looks like the bit extension has precedence over the ~ operator. That means:
depth = 'h80 + (~mode_u2) =
32'h0000_0080 + (~32h0000_0000) =
32'h0000_0080 + 32'hffff_ffff =
32'h0000_007f
The result of ! operator, however by definition is a single bit, and my guess is that the bit extension happens twice:
depth = 'h80 + (!mode_u2) =
32'h0000_0080 + (!32'h0000_0000) =
32'h0000_0080 + 1'h1 =
32'h0000_0080 + 32'h0000_0001 =
32'h0000_0081
Similarly for mode:
depth = 'h80 + (~mode) =
32'h0000_0080 + (~32'h0000_0001) =
32'h0000_0080 + 32'hffff_fffe =
32'h0000_007e
I am trying to create a prediction interval based on a linear model in SAS. My SAS code is
proc reg data=datain.aswells alpha=0.01;
model arsenic = latitude longitude depth_ft / clb;
run;
I wish to make a 95% prediction interval with latitude=23.75467, longitude=90.66169, and depth_ft=25. This data point does not exist in the data set, but it is in the range of values used to compute the model. Is there an easy way of accomplishing this in SAS? Shouldn't there be a way to compute this prediction interval in SAS easily?
The easiest thing to do is to add it to your input data set with a missing value for ARSENIC. Then use the OUTPUT statement to output the prediction intervals.
Here is an example:
data test;
do i=1 to 100;
x1 = rannor(123);
x2 = rannor(123)*2 + 1;
y = 1*x1 + 2*x2 + 4*rannor(123);
output;
end;
run;
data test;
set test end=last;
output;
if last then do;
y = .;
x1 = 1.5;
x2 = -1;
output;
end;
run;
proc reg data=test alpha=.01;
model y = x1 x2;
output out=test_out(where=(y=.)) p=predicted ucl=UCL_Pred lcl=LCL_Pred;
run;
quit;
The WHERE clause on the output filters the resulting set to just the missing value to be predicted. You can remove it and get all predicted values and prediction intervals.