草庐IT

vivado之FFT ip核的入门学习(已补充调用模块)

liufulim 2023-04-20 原文

一、什么是FFT

1.1      简介与我的理解

        FFT是离散傅立叶变换的快速算法,可以将一个信号变换到频域。有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了。这就是很多信号分析采用FFT变换的原因。另外,FFT可以将一个信号的频谱提取出来,这在频谱分析方面也是经常用的。

        下面说说具体物理意义。一个模拟信号,经过ADC采样之后,就变成了数字信号。采样定理告诉我们,采样频率要大于信号频率的两倍,这些我就不在此罗嗦了。采样得到的数字信号,就可以做FFT变换了。N个采样点,经过FFT之后,就可以得到N个点的FFT结果。为了方便进行FFT运算,通常N取2的整数次方。假设采样频率为Fs,信号频率F,采样点数为N。那么FFT之后结果就是一个为N点的复数。每一个点就对应着一个频率点。这个点的模值,就是该频率值下的幅度特性。

        假设FFT之后某点n用复数a+bi表示,那么这个复数的模就是An=根号a*a+b*b,相位就是Pn=atan2(b,a)。根据以上的结果,就可以计算出n点(n≠1,且n<=N/2)对应的信号的表达式为:An/(N/2)*cos(2*pi*Fn*t+Pn),即2*An/N*cos(2*pi*Fn*t+Pn)。对于n=1点的信号,是直流分量,幅度即为A1/N。    由于FFT结果的对称性,通常我们只使用前半部分的结果,即小于采样频率一半的结果。atan2(a,b)返回以弧度表示的 y/x 的反正切.相位的计算可用函数atan2(b,a)计算。atan2(b,a)是求坐标为(a,b)点的角度值,范围从-pi到pi。

1.2        实际例子介绍(网络照搬)

        以一个实际信号为例,求取其FFT。

信号为:S=2+3*cos(2*pi*50*t-pi*30/180)+1.5*cos(2*pi*75*t+pi*90/180)

        式中cos参数为弧度,所以-30度和90度要分别换算成弧度。

        我们以256Hz的采样率对这个信号进行采样,总共采样256点。按照我们上面的分析,Fn=(n-1)*Fs/N,我们可以知道,每两个点之间的间距就是1Hz,第n个点的频率就是n-1

        我们的信号有3个频率:0Hz(直流2v)、50Hz、75Hz,应该分别在第1个点、第51个点、第76个点上出现峰值,其它各点应该接近0

1点: 512+0i

2点: -2.6195E-14 - 1.4162E-13i
3点: -2.8586E-14 - 1.1898E-13i

50点:-6.2076E-13 - 2.1713E-12i
51点:332.55 - 192i
52点:-1.6707E-12 - 1.5241E-12i

75点:-2.2199E-13 -1.0076E-12i
76点:3.4315E-12 + 192i
77点:-3.0263E-14 +7.5609E-13i

         很明显,1点、51点、76点的值都比较大,它附近的点值都很小,可以认为是0,即在那些频率点上的信号幅度为0。接着,我们来计算各点的幅度值。分别计算这三个点的模值,结果如下:
1点  :  512
51点:384
76点:192

          按照公式,可以计算出直流分量为:512/N=512/256=2(第一个点是除以N其他的除2);50Hz信号的幅度为:384/(N/2)=384/(256/2)=3;75Hz信号的幅度为192/(N/2)=192/(256/2)=1.5。可见,从频谱分析出来的幅度是正确的。

         然后再来计算相位信息。直流信号没有相位可言,不用管它。先计算50Hz信号的相位,atan2(-192, 332.55)=-0.5236,结果是弧度,换算为角度就是180*-0.5236)/pi=-30.0001。再计算75Hz信号的相位,atan2(192, 3.4315E-12)=1.5708弧度,换算成角度就是180*1.5708/pi=90.0002。可见,相位也是对的。根据FFT结果以及上面的分析计算,我们就可以写出信号的表达式了,它就是我们开始提供的信号。

附上MATLAB仿真代码

close all; %先关闭所有图片
Adc=2;  %直流分量幅度
A1=3;   %频率F1信号的幅度
A2=1.5; %频率F2信号的幅度
F1=50;  %信号1频率(Hz)
F2=75;  %信号2频率(Hz)
Fs=256; %采样频率(Hz)
P1=-30; %信号1相位(度)
P2=90;  %信号相位(度)
N=256;  %采样点数
t=(0:1/Fs:N/Fs); %采样时刻

%信号
S=Adc+A1*cos(2*pi*F1*t+pi*P1/180)+A2*cos(2*pi*F2*t+pi*P2/180);
%显示原始信号
plot(S);
title('原始信号');

figure;
Y = fft(S,N); %做FFT变换
Ayy = (abs(Y)); %取模
plot(Ayy(1:N)); %显示原始的FFT模值结果
title('FFT 模值');

figure;
Ayy=Ayy/(N/2);   %换算成实际的幅度
Ayy(1)=Ayy(1)/2;
F=([1:N]-1)*Fs/N; %换算成实际的频率值
plot(F(1:N/2),Ayy(1:N/2));   %显示换算后的FFT模值结果
title('幅度-频率曲线图');

1.3总结

        假设采样频率为Fs,采样点数为N,做FFT之后,某一点n(n从1开始)表示的频率为:Fn=(n-1)*Fs/N;该点的模值除以N/2就是对应该频率下的信号的幅度(对于直流信号是除以N);该点的相位即是对应该频率下的信号的相位。相位的计算可用函数atan2(b,a)计算。atan2(b,a)是求坐标为(a,b)点的角度值,范围从-pi到pi。要精确到xHz,则需要采样长度为1/x秒的信号,并做FFT。要提高频率分辨率,就需要增加采样点数,这在一些实际的应用中是不现实的,需要在较短的时间内完成分析。解决这个问题的方法有频率细分法,比较简单的方法是采样比较短时间的信号,然后在后面补充一定数量的0,使其长度达到需要的点数,再做FFT,这在一定程度上能够提高频率分辨力。

二、VIVADO之FFT   ip核使用

         fft的ip核使用对新手来说显得十分复杂。这里直接从ip核设置每个地方开始介绍。

2.1 调出ip核设置

 

接下来是具体参数介绍

 

 

 (1)number  of  channels :变换通道,可以选择多通道,实现多帧数据同时进行FFT运算

 (2)transform  lenfgth   : FFT变换长度,如果选择了最下面的‘run time configurable transdorm legth’,则该参数是FFT变化的最大长度,一般不选。

 (3)采样时钟核数据时钟:这个设置越大速度越快,且可以fft测得clk/2大小的频率,如100mhz时钟可以算出50M以内得频率。

 (4)architecure  choice:FFT架构选择,消耗资源依次递减。第一个是自动选择。选完架构可以从左边框中的latency(隐藏起来了)看一次FFT需要的时间,即求完这N个点(FFT变换长度)的时间。资源消耗越高耗时越短,根据工程需求选择。一般选中间的。

 

 (5)data format:1. 定点全精度  2. 定点缩减位宽    一般就默认Fixed Point

   (6)   scaling optios :缩放选项 :

            1、 block floating point :不管输入的格式如何,FFT变化内部都采用浮点,会根据每一级的的数据情况自动缩放。 这个模式的输入输出位宽一致,便于调用没有特殊需求就用这个

            2、scaled :在m_axis_data_tuser中会有5BIT表示每一级的缩放情况,在s_axis_config_data中会有相应的字段配置配置缩放因子.每一级别包含2个stage ,2个bit 表示一级缩放,一般0-3可选,如果log(NFFT)不是2的倍数,则最高一级的缩放只能在0-1之间选取。 

           3、unscaled :不用担心变化过程中会出现溢出,但是输入是32bit的话,输出是64bit。


   (7)  Aresten : 复位信号要勾选,至少保持两个时钟的低电平。FFT IP核的复位引脚(ARESETn)最好使用,怎么使用?–把时钟IP核输出的locked引脚赋给FFT的复位引脚,并且在locked引脚为低时给FFT IP核一系列输入引脚均赋予初值。时钟IP核locked引脚代表意义:时钟IP核输出的时钟是否稳定有效,低时不稳定,高时表明时钟IP核输出时钟稳定


  (8)  output odering options:默认是倒序但是我们一般选自然输出

(9)optional output fileds :选项输出字段:

          1、xk_index:FFT 变幻的结果索引,在m_axis_data_user中有相应的字段。

          2、OVFLO是变换中溢出的指示信号,对应event_fft_overflow.
 

其他的一般不用设置。

    我们可以看到假设我们输入的数据位宽是10,则FFT之后,还有虚数部分,[9:0]是实数,[25:16]是虚数。一共有2048个点,一次FFT。

2.2  IP核参数的意义

        

 这里面引脚很多,最重要的当然就是输入输出了。

.aclk(aclk),   输入时钟                                             
.aresetn(aresetn),   复位 ,接PLL的locked

Input[N:0]:  s_axis_config_tdata:控制输入模式,最低位控制。1fft   0ifft。如果我们只需要FFT就直接设置N'b1就ok

Input:          s_axis_config_tvalid:拉高两个时钟周期之后,将端口s_axis_data_tvalid和s_axis_data_tready拉高。 这个就是输入有效,当它拉高时,才表示输入数据是我们有效数据同时输出也是有效的。比如上位模块输出的数据一直是有效的我们可以直接一直拉高它

Output:       s_axis_config_tready:s_axis_config_tvalid拉高两个时钟周期后,该口给1输出;若干个时钟周期后,自动归零。一般不管它直接接出去wire就好

Output:       s_axis_data_tready:aresetn拉高两个时钟周期后,该口给1输出;此时ip核初始化完成,可进行数据输入。 

Input:          s_axis_data_tvalid数据有效  当s_axis_data_tready高电平后,将s_axis_data_tvalid拉高L个周期,输入L个数据进行fft;L是FFT的点数。

Input[M:0]:  s_axis_data_tdata:将数据输入进行FFT运算。如果我们是实数可以将高位输入为0比如   .s_axis_data_tdata({8'b0},data);我设输入数据是10位,也就是本来应该包括虚数就是20位,但是ip和数据输入通道不能是任意数,只能是8的整数倍,此时为32bit,其中低16位为输入数据的实部,高16位为输入数据的虚部。

Input:          s_axis_data_tlast:输入L个数据后拉高,停止数据输入。TLAST是起到一个输入数据末端指示作用,比如你作8点FFT运算,你要给8个数据给IP核吧,在最后一个数据期间你把TLAST拉高就行了,意思是告诉IP核,这一组的8个数据都给你带过来了,这是最后一个。IP核一验算,整整齐齐8个,就不会找你麻烦了。

做fft需要耗费的时钟周期计算如下s_axis_data_tlast- s_axis_data_tvalid

Output[M1:0]:m_axis_data_tdata:高位为虚部,低位为实部。(经过测试发现的,implementation也有定义)  在FPGA里不好开方所以我们一般求他的功率谱即实部和虚部平方相加。而不是幅度谱,我们可以定义两个reg寄存实部和虚部

Output:          m_axis_data_tvalid:当fft结果输出时拉高,输出2048个点的数据后拉低。

Output[M2:0]:m_axis_data_tuser:输出fft的地址值,输出值*fs/L为对应频点采样频率/变换点数,这里要注意也是有虚数的坐标。我们选2048个点,则会有24位地址,高12位是虚数,不看。看低12位。其实2^11=2048,而我们地址不是从0开始吗?2047那11位就够了?不过多一位也不是坏事。最重要的是通过地址算出对应得频率点

Input:             m_axis_data_tready:需保持高电平,保证FFT单元处在计算模式,并且能够输出结算结果;接   1 .m_axis_data_tready(1)

Output:          m_axis_data_tlast:当fft结果输出到最后一个结果时拉高,紧接着下一个时钟就拉低。

主要就是时钟、复位、配置、数据、和事件报告。s是从机,m是主机,也好理解,对于FPGA来说是要接受主句的输出来作为输入数据,去FFT。

转自 数字信号处理(三):Xilinx FFT IP核详解(二) - 知乎 (zhihu.com)

 

20230109补充代码和解释

本代码是把FFTIP例化在模块内方便调用。

要注意的是,我输入datach1是无符号补码,都是正数。在送给fft ip时,实际上要补上一个符号位0,s_axis_data_tdata <= {22'd0,input_data_ch1};这里面就是我补了0,实际使用根据你的输入来自己设置。总之,ip输入带符号。而输出肯定也是带符号的。用ILA看的时候设置为有符号数看。

我下面还例化了别的IP,自行去除。本模块只需要设置好你的输入,即可跑出fft 后的实部和虚部。

 

 

 

module	fft_fix_4096(
		input 				        aclk               ,
        input 				        aresetn            ,

        input  		    [9:0]       input_data_ch1     ,		//adc数据输入
        output 	signed	[15:0]      fft_real           ,
        output 	signed	[15:0]      fft_imag           ,
        output  signed  [32:0]      amp                ,    //输出平方和,可以不要
		output   reg   	[11:0]	    freq               ,    //由于multisine fs/N=1,谱线间隔为1HZ
        output 			            fft_out_valid      ,   //fft输出有效。可以通过这个接口取4096个值。
        output          [23:0]      abs_fft            ,    //开方
        output                      abs_tvalid              //开方数据输出有效

);
//配置数据
	reg [10:0] input_data_ch1_reg;    		//和ADC输出格式有关,总之ip core 需要带符号位
    wire [7:0] s_axis_config_tdata;			
    reg s_axis_config_tvalid;
//输入数据
    wire s_axis_data_tready;
    reg [31:0] s_axis_data_tdata;
    reg s_axis_data_tvalid;
    reg s_axis_data_tlast;
//输出数据
    wire [31:0] m_axis_data_tdata;
    wire [23:0] m_axis_data_tuser;
    wire m_axis_data_tvalid;
    wire m_axis_data_tlast;
    reg [7:0]   cfg_cnt;
    reg [13:0]  sink_ctl_cnt;   
    reg [15:0]  fft_real,fft_imag; 
    reg 	fft_out_valid;
	wire [7:0] m_axis_status_tdata;
	wire 	   m_axis_status_tvalid;
    wire       event_frame_started;
    wire       event_tlast_unexpected;
    wire       event_tlast_missing;
    wire       event_data_in_channel_halt;

    wire       s_axis_config_tready; 



xfft_0 fixed_fft (
  .aclk(aclk),                                              // input wire aclk
  .aresetn(aresetn),                                        // input wire aresetn
  
  .s_axis_config_tdata(s_axis_config_tdata),                // input wire [7 : 0] s_axis_config_tdata
  .s_axis_config_tvalid(s_axis_config_tvalid),              // input wire s_axis_config_tvalid
  .s_axis_config_tready(s_axis_config_tready),              					// output wire s_axis_config_tready
  
  .s_axis_data_tdata(s_axis_data_tdata),                    // input wire [31 : 0] s_axis_data_tdata
  .s_axis_data_tvalid(s_axis_data_tvalid),                  // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),                  					// output wire s_axis_data_tready
  .s_axis_data_tlast(s_axis_data_tlast),                    // input wire s_axis_data_tlast
  
  .m_axis_data_tdata(m_axis_data_tdata),                    // output wire [31 : 0] m_axis_data_tdata
  .m_axis_data_tuser(m_axis_data_tuser),                    // output wire [23 : 0] m_axis_data_tuser
  .m_axis_data_tvalid(m_axis_data_tvalid),                  // output wire m_axis_data_tvalid
  .m_axis_data_tlast(m_axis_data_tlast),                    // output wire m_axis_data_tlast
  
  .m_axis_status_tdata(m_axis_status_tdata),                // output wire [7 : 0] m_axis_status_tdata
  .m_axis_status_tvalid(m_axis_status_tvalid),              // output wire m_axis_status_tvalid
  
  .event_frame_started(event_frame_started),                // output wire event_frame_started 
  .event_tlast_unexpected(event_tlast_unexpected),          // output wire event_tlast_unexpected
  .event_tlast_missing(event_tlast_missing),                // output wire event_tlast_missing
  .event_data_in_channel_halt(event_data_in_channel_halt)  // output wire event_data_in_channel_halt
);

//fft core config
    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            cfg_cnt <= 8'd0;
        else
        begin
            if(cfg_cnt < 8'd200)
                cfg_cnt <= cfg_cnt + 1'b1;
            else
                cfg_cnt <= cfg_cnt;
        end
    end

    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            s_axis_config_tvalid <= 1'b0;
        else
        begin
            if(cfg_cnt < 8'd200)
                s_axis_config_tvalid <= 1'b1;
            else
                s_axis_config_tvalid <= 1'b0;
        end
    end
assign s_axis_config_tdata = 8'd1;

//fft sink_in ctl//
    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            s_axis_data_tdata <= 32'b0;
        else
            s_axis_data_tdata <= {22'd0,input_data_ch1};	//本人adc 10位无符号补码,补一位符号位0,ip设置11位输入
    end

    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            sink_ctl_cnt <= 14'd8194;
        else if(s_axis_config_tvalid)
            sink_ctl_cnt <= 14'd0;
        else if(sink_ctl_cnt == 14'd8192)
            sink_ctl_cnt <= 14'd1;
        else
            sink_ctl_cnt <= sink_ctl_cnt + 1'b1;
    end 

    //s_axis_data_tvalid
    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            s_axis_data_tvalid <= 1'b0;
        else if(sink_ctl_cnt < 14'd1)
            s_axis_data_tvalid <= 1'b0;
        else if(sink_ctl_cnt < 14'd4097)
            s_axis_data_tvalid <= 1'b1;
        else
            s_axis_data_tvalid <= 1'b0;
    end

    //s_axis_data_tlast
    always@(posedge aclk or negedge aresetn)
        begin
        if(!aresetn)
            s_axis_data_tlast <= 1'b0;
        else
        begin
            if(sink_ctl_cnt == 14'd4096)
                s_axis_data_tlast <= 1'b1;
            else
                s_axis_data_tlast <= 1'b0;
        end
    end
//fft sink_in ctl/ /   对齐
    always@(posedge aclk)
    begin
        fft_real <= m_axis_data_tdata[15:0];
    end

    always@(posedge aclk)
    begin
        fft_imag <= m_axis_data_tdata[31:16];
    end

    always@(posedge aclk)
    begin
        fft_out_valid <= m_axis_data_tvalid;
    end
    
        always@(posedge aclk)
    begin
        freq <= m_axis_data_tuser[11:0];     //这个位宽取n-1个,2^n=N,由于MATLAB里FS=N,所以谱线间隔是1HZ
    end

    /********** 计算频谱的幅值信号 **********/
wire    [31:0]      xkre_square, xkim_square;
mult_gen_0 inst1 (
  .CLK(aclk),  // input wire CLK
  .A(fft_real),      // input wire [15 : 0] A
  .B(fft_real),      // input wire [15 : 0] B
  .P(xkre_square)      // output wire [31 : 0] P
);
mult_gen_0 inst2 (
  .CLK(aclk),  // input wire CLK
  .A(fft_imag),      // input wire [15 : 0] A
  .B(fft_imag),      // input wire [15 : 0] B
  .P(xkim_square)      // output wire [31 : 0] P
);
 assign     amp = xkre_square+ xkim_square;
 wire       abs_tvalid;
cordic_0 your_instance_name (
  .aclk(aclk),                                        // input wire aclk
  .aresetn(aresetn),                                  // input wire aresetn
  .s_axis_cartesian_tvalid(m_axis_data_tvalid),  // input wire s_axis_cartesian_tvalid
  .s_axis_cartesian_tdata(amp[31:0]),    // input wire [31 : 0] s_axis_cartesian_tdata
  .m_axis_dout_tvalid(abs_tvalid),            // output wire m_axis_dout_tvalid
  .m_axis_dout_tdata(abs_fft)              // output wire [23 : 0] m_axis_dout_tdata
);

endmodule

注意事项补充:

1.始终均可拉高的引脚:S_AXIS_CONFIG_TVALID,S_AXIS_DATA_TREADY。别问,问就是不知道。(后者是输出,表示以准备接收数据)

2.我们要注意采样频率和FFT采样点数,这两个关系到分辨率,而且采样频率还得满足奈奎斯特定理。FFT采样点数越大越好,即分辨率会高。但是太大了运算时间就会长,分辨率分辨的就是频率,第m个点对应频率m*FS/N。

3.当FFT计算结果输出完成后,信号fft_m_data_tlast变为高电平,代表数据输出结束,并在延时一小段时间后,fft_s_data_tready重新变为低电平,代表IP核重新进入到空闲状态。可以进行对IP核下一组数据的输入。

4.输入输出如果不到8bit会补上,例如12bit的实数输入,输出会有32位,[11:0]是实数部分[25:16]是虚数,实数虚数前各补4个0,输出也是一样的

有关vivado之FFT ip核的入门学习(已补充调用模块)的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  5. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  6. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  7. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  8. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  9. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  10. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

随机推荐