主頁 > 後端開發 > 手把手教系列之IIR濾波器設計

手把手教系列之IIR濾波器設計

2020-09-13 20:33:48 後端開發

[導讀]:在嵌入式系統中經常需要采集模擬信號,采集模擬信號的信號鏈中難免引入干擾,那么如何濾除干擾呢?今天就來個一步一步描述如何設計部署一個IIR濾波器到你的系統,

何為IIR濾波器?

無限沖激回應(IIRInfinite Impulse Response)是一種適用于許多線性時不變系統的屬性,這些系統的特征是具有一個沖激回應h(t),該沖激回應h(t)不會在特定點上完全變為零,而是無限期地持續, 這與有限沖激回應(FIRFinite Impulse Response)系統形成對比,在有限沖激回應(FIR)系統中,對于某個有限T,在時間t> T時,沖激回應確實恰好變為零, 線性時不變系統的常見示例是大多數電子和數字濾波器, 具有此屬性的系統稱為IIR系統或IIR濾波器,

這是常見的教科書式數學嚴謹定義,很多人看到這一下就蒙了,能說人話嗎?

線性時不變系統理論俗稱LTI系統理論,源自應用數學,直接在核磁共振頻譜學、地震學、電路、信號處理和控制理論等技術領域運用,它研究的是線性、非時變系統對任意輸入信號的回應,雖然這些系統的軌跡通常會隨時間變化(例如聲學波形)來測量和跟蹤,但是應用到影像處理和場論時,LTI系統在空間維度上也有軌跡,因此,這些系統也被稱為線性非時變平移,在最一般的范圍理論給出此理論,在離散(即采樣)系統中對應的術語是線性非時變平移系統,由電阻、電容、電感組成的電路是LTI系統的一個很好的例子,比如一個運放系統在一定頻帶范圍內滿足信號的時域疊加,輸入一個100Hz和200Hz正弦信號,輸出頻率是這兩種信號的線性疊加,

用數學對LTI系統描述:

線性:輸入\(x_1(t)\),產生回應\(y_1(t)\),而輸入\(x_2(t)\),產生回應\(y_2(t)\),那么縮放和加和輸入\(a_1x_1(t)+a_2x_2(t)\),產生縮放、加和的回應\(a_1y_1(t)+a_2y_2(t)\),其中\(a_1\)\(a_2\)是標量,對于任意的有:輸入\(\sum_{k=0}^{N}a_kx_k(t)\),產生回應\(\sum_{k=0}^{N}a_ky_k(t)\)

時不變性:指如果將系統的輸入信號延遲\(\tau\)秒,那么得到的輸出回應也相應延時\(\tau\)秒,用數學描述,也即如果輸入\(x_1(t)\),產生回應\(y_1(t)\),而輸入\(x_1(t+\tau)\),產生回應\(y_1(t+\tau)\),這么描述還是不易懂,來個圖,有圖有真相:

假定一個信號放大電路對100Hz正弦信號放大2倍:

則輸出為:

而對200Hz的正弦信號,其放大倍數為1.7倍,(做過運放電路設計的朋友應該有經驗,在其同頻帶其放大倍數往往并不平坦,也即幅頻回應在頻帶內不平坦,這是比較常見的),

也即輸入為:

回應為:

那么如果輸入100Hz和200Hz的時域疊加信號,則其輸入為:

則其回應為:

由這些圖可看出,輸入信號的形狀保持不變,輸出為對應輸入的線性時域疊加,

對于時不變,就不用圖描述了,在一個真實電路中,如果輸入延遲一定時間,則回應對應延遲相同時間輸出,

上面這么多文字只是為了描述在什么場合可以使用IIR濾波器對信號進行數字濾波,總結而言,就是在線性時不變系統中適用,換言之,在大多數電路系統中我們都可以嘗試采用IIR濾波器進行數字濾波,

那么究竟什么是IIR濾波器呢?從數字信號處理的書籍中我們能看到這樣的Z變換信號流圖:

x(n-1)表示延遲一拍,在數字系統中表示對于輸入信號而言,即為上一次采樣值,對于輸出而言,即為上一次的輸出值,

在時域中對于上述流圖,用時域描述即為:

如果熟悉Z變換,則Z變換傳遞函式為:

上述數字濾波器,如果從編程的角度來看,x(n-1),表示上一次的信號,可能是來自ADC的上次采樣,而y(n-1)則為上一次濾波器的輸出值,對應就比較好理解x(n-N)就表示前第n次輸入樣本信號,而y(n-M)則為前第M次濾波器的輸出,

說了這么多,只是為了更好的理解概念,只有概念理解正確,才能用爭取, 概念理解這對工程師而言,非常之重要,

如何設計呢?

打開fdatool

MATLAB提供了非常容易使用的FDATool幫助我們設計數字濾波器,真正精彩的地方開始了,讓我們拭目以待究竟如何一步一步設計并實施一個IIR濾波器,

首先打開MATLAB,在命令列中敲fdatool

彈出表單就是fdatool了,如下:

在設計具體,有幾個相關概念需要澄清:

Fs:采樣率,單位為Hz,真實部署在系統中,請務必確保樣本是按照恒定采樣率進行采樣,否則將得不到想要的效果,

Fpass: 通頻帶,單位為Hz,即系統中期望通過的最高頻率,

Fstop: 截至頻率,即幅頻回應的-3dB處的頻率,這個如不理解,請自行查閱相關書籍,

分貝dB: 這是一個無單位反應輸出與輸入倍數的一個術語,電學中分貝與放大倍數的轉換關系為:

  • A(V)(dB)=20lg(Vo/Vi);電壓增益,Vo 為輸出電壓,Vi為輸入電壓
  • A(I)(dB)=20lg(Io/Ii);電流增益,Io 為輸出電流,Ii為輸入電流
  • A(p)(dB)=10lg(Po/Pi);功率增益,Po 為輸出功率,Pi為輸入功率

濾波器型別:這里有Butterworth(巴特沃斯)、Chebyshev Type I,Chebyshev Type II、(切比雪夫)、Elipic 等可選,

  • 巴特沃斯 Butterworth,也被稱作最大平坦濾波器,巴特沃斯濾波器的特點是通頻帶內的頻率回應曲線最大限度平坦,沒有紋波,
  • 切比雪夫 Chebyshev,是在通帶或阻帶上頻率回應幅度等波紋波動的濾波器,切比雪夫濾波器在過渡帶比巴特沃斯濾波器的衰減快,但頻率回應的幅頻特性不如后者平坦,
  • 橢圓 Elliptic,橢圓濾波器是在通帶和阻帶等波紋的一種濾波器,
  • ...這里就不一一介紹了,有興趣可以去查信號處理書籍,

就其特點,這里對其中幾種略作介紹:

  • 巴特沃斯具有最平坦的通帶,
  • 橢圓濾波器衰減最快,但是通帶、阻帶都有波紋,
  • 切比雪夫濾波器衰減比巴特沃斯快,但比橢圓濾波器慢,波紋區域可選擇,

假設我們需要設計一個IIR濾波器,采樣率為32000Hz, 有用信號頻率在2000Hz內,設計IIR濾波器對信號進行數字濾波,這里為節省算力,我們指定濾波器的階數,也即傳遞函式中N/M中的最大值,一般而言N大于M,

這里指定階數為8階,型別指定為巴特沃斯型IIR濾波器,輸入階數8階,采樣率32000Hz,截至頻率設定為2000Hz然后點擊Design Filter如下圖所示:

其相頻回應曲線如下:

除此之外,我們還可以將幅頻與相頻曲線放在一個頻率坐標上去看設計結果:

匯出濾波器引數,這里我們選擇,

選擇ASCII碼

然后就得到了一個檔案,保存2kHz_LPF.fcf,檔案名隨你喜歡,

檔案內容如下:

% Generated by MATLAB(R) 8.4 and the Signal Processing Toolbox 6.22.
% Generated on: 27-Mar-2020 21:27:06

% Coefficient Format: Decimal

% Discrete-Time IIR Filter (real)                            
% -------------------------------                            
% Filter Structure    : Direct-Form II, Second-Order Sections
% Number of Sections  : 4                                    
% Stable              : Yes                                  
% Linear Phase        : No                                   

                                                            
SOS Matrix:                                                  
1  2  1  1  -1.7193929141691948  0.8610574795347461          
1  2  1  1  -1.5237898734101736  0.64933827386370635         
1  2  1  1  -1.4017399331200424  0.51723237044751591         
1  2  1  1  -1.3435020629061745  0.45419615396638446         
                                                             
Scale Values:                                                
0.035416141341387819                                         
0.031387100113383172                                         
0.028873109331868367                                         
0.027673522765052503                                          
 

至此設計作業就結束了,馬上進入濾波器的部署測驗階段,

部署測驗濾波器

到這里,沒有經驗的朋友可能會說,這么一堆引數我該咋用呢?

需要自己去寫前面描述的計算公式嗎?當然你也可以這么做,這里就不寫了,ARM的CMSIS庫已經幫大家設計好了種類繁多的數字信號處理函式實作了,而且經過了測驗,這里直接拿來用即可,有興趣自己寫也不難,只要理解Z傳遞函式概念內涵,非常容易實作,這里我們采用32位浮點實作函式:arm_biquad_cascade_df1_f32,

該函式位于:CMSIS\DSP\Source\FilteringFunctions\arm_biquad_cascade_df1_init_f32.c中

以及CMSIS\DSP\Source\FilteringFunctions\arm_biquad_cascade_df1_f32.c

我們來看一看這個函式:

arm_biquad_cascade_df1_init_f32.c:

/*
*作用      :初始化濾波器
*S        :指向浮點SOS級聯結構的實體,
*numStages:濾波器中二階SOS的數量
*pCoeffs  :濾波器引數指標,引數按下列順序存盤
*          {b10, b11, b12, a11, a12, b20, b21, b22, a21, a22, ...}
*pState   :歷史狀態緩沖區指標
*/
void arm_biquad_cascade_df1_init_f32(
        arm_biquad_casd_df1_inst_f32 * S,
        uint8_t numStages,
  const float32_t * pCoeffs,
        float32_t * pState)
{
  /* Assign filter stages */
  S->numStages = numStages;

  /* Assign coefficient pointer */
  S->pCoeffs = pCoeffs;

  /* Clear state buffer and size is always 4 * numStages */
  memset(pState, 0, (4U * (uint32_t) numStages) * sizeof(float32_t));

  /* Assign state pointer */
  S->pState = pState;
}

arm_math.h 定義了須用到的結構體,對于本例相關的結構體為arm_biquad_casd_df1_inst_f32

typedef struct
{
  unsigned int numStages; /*2階節的個數,應為2*numStages.        */
  float *pState;          /*狀態系數陣列指標,陣列長度為4*numStages*/
  float *pCoeffs;         /*系數陣列指標, 陣列的長度為5*numStages.*/
} arm_biquad_casd_df1_inst_f32;

濾波器具體濾波函式為arm_biquad_cascade_df1_f32

/**
 *  *S       :指向浮點Biquad級聯結構的實體.
 *  *pSrc    :指向輸入資料塊,
 *  *pDst    :指向輸出資料塊,
 *  blockSize:每次呼叫要處理的樣本數,
 *  回傳值    :無.
 */
void arm_biquad_cascade_df1_f32(
  const arm_biquad_casd_df1_inst_f32 * S,
  float * pSrc,
  float * pDst,
  unsigned int blockSize)
{
  float *pIn = pSrc;                         /*源指標     */
  float *pOut = pDst;                        /*目的指標    */
  float *pState = S->pState;                 /*狀態指標    */
  float *pCoeffs = S->pCoeffs;               /*引數指標    */
  float acc;                                 /*累加器      */
  float b0, b1, b2, a1, a2;                  /*濾波器引數   */
  float Xn1, Xn2, Yn1, Yn2;                  /*濾波器狀態變數*/
  float Xn;                                  /*臨時輸入     */
  unsigned int sample, stage = S->numStages; /*回圈計數     */

  do
  {
    /* Reading the coefficients */
    b0 = *pCoeffs++;
    b1 = *pCoeffs++;
    b2 = *pCoeffs++;
    a1 = *pCoeffs++;
    a2 = *pCoeffs++;

    Xn1 = pState[0];
    Xn2 = pState[1];
    Yn1 = pState[2];
    Yn2 = pState[3];

    sample = blockSize >> 2u;

    while(sample > 0u)
    {
      /* 讀第一個輸入 */
      Xn = *pIn++;

      /* acc =  b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2] */
      Yn2 = (b0 * Xn) + (b1 * Xn1) + (b2 * Xn2) + (a1 * Yn1) + (a2 * Yn2);

      /* Store the result in the accumulator in the destination buffer. */
      *pOut++ = Yn2;

      /* 每次計算輸出后,狀態都應更新. */
      /* 狀態應更新為:  */
      /* Xn2 = Xn1    */
      /* Xn1 = Xn     */
      /* Yn2 = Yn1    */
      /* Yn1 = acc   */

      /* Read the second input */
      Xn2 = *pIn++;

      /* acc =  b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2] */
      Yn1 = (b0 * Xn2) + (b1 * Xn) + (b2 * Xn1) + (a1 * Yn2) + (a2 * Yn1);

      /* 將結果存盤在目標緩沖區的累加器中. */
      *pOut++ = Yn1;

      /* 每次計算輸出后,狀態都應更新. */
      /* 狀態應更新為:  */
      /* Xn2 = Xn1    */
      /* Xn1 = Xn     */
      /* Yn2 = Yn1    */
      /* Yn1 = acc   */

      /*讀第三個輸入 */
      Xn1 = *pIn++;

      /* acc =  b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2] */
      Yn2 = (b0 * Xn1) + (b1 * Xn2) + (b2 * Xn) + (a1 * Yn1) + (a2 * Yn2);

      /* 將結果存盤在目標緩沖區的累加器中. */
      *pOut++ = Yn2;

      /* 每次計算輸出后,狀態都應更新. */
      /* 狀態應更新為: */
      /* Xn2 = Xn1    */
      /* Xn1 = Xn     */
      /* Yn2 = Yn1    */
      /* Yn1 = acc   */
      /* 讀第四個輸入 */
      Xn = *pIn++;

      /* acc =  b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2] */
      Yn1 = (b0 * Xn) + (b1 * Xn1) + (b2 * Xn2) + (a1 * Yn2) + (a2 * Yn1);

      /* 將結果存盤在目標緩沖區的累加器中. */
      *pOut++ = Yn1;

      /* 每次計算輸出后,狀態都應更新. */
      /* 狀態應更新為:  */
      /* Xn2 = Xn1    */
      /* Xn1 = Xn     */
      /* Yn2 = Yn1    */
      /* Yn1 = acc   */
      Xn2 = Xn1;
      Xn1 = Xn;

      /* 遞級訓圈計數器 */
      sample--;
    }

    /* 如果blockSize不是4的倍數,
    *請在此處計算任何剩余的輸出樣本,
    *不使用回圈展開. */
    sample = blockSize & 0x3u;

    while(sample > 0u)
    {
      /* 讀取輸入 */
      Xn = *pIn++;

      /* acc =  b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2] */
      acc = (b0 * Xn) + (b1 * Xn1) + (b2 * Xn2) + (a1 * Yn1) + (a2 * Yn2);

      /* 將結果存盤在目標緩沖區的累加器中. */
      *pOut++ = acc;

      /* 每次計算輸出后,狀態都應更新, */
      /* 狀態應更新為:    */
      /* Xn2 = Xn1    */
      /* Xn1 = Xn     */
      /* Yn2 = Yn1    */
      /* Yn1 = acc   */
      Xn2 = Xn1;
      Xn1 = Xn;
      Yn2 = Yn1;
      Yn1 = acc;

      /* d遞級訓圈計數器 */
      sample--;
    }

    /*  將更新后的狀態變數存盤回pState陣列中 */
    *pState++ = Xn1;
    *pState++ = Xn2;
    *pState++ = Yn1;
    *pState++ = Yn2;

    /*第一階段從輸入緩沖區到輸出緩沖區.     */
    /*隨后的numStages在輸出緩沖區中就地發生*/
    pIn = pDst;

    /* 重置輸出指標 */
    pOut = pDst;

    /* 遞級訓圈計數器 */
    stage--;

  } while(stage > 0u);
}

開始測驗:

#include <stdio.h>
#include <math.h>
/*
SOS Matrix:                                                  
1  2  1  1  -1.7193929141691948  0.8610574795347461          
1  2  1  1  -1.5237898734101736  0.64933827386370635         
1  2  1  1  -1.4017399331200424  0.51723237044751591         
1  2  1  1  -1.3435020629061745  0.45419615396638446         
                                                             
Scale Values:                                                
0.035416141341387819                                         
0.031387100113383172                                         
0.028873109331868367                                         
0.027673522765052503  
做如下轉換:
1.縮放
[1  2  1] * 0.035416141341387819
[1  2  1] * 0.031387100113383172
[1  2  1] * 0.028873109331868367
[1  2  1] * 0.027673522765052503
得到:
[0.035416141341387819  2*0.035416141341387819  0.035416141341387819]
[0.031387100113383172  2*0.031387100113383172  0.031387100113383172] 
[0.028873109331868367  2*0.028873109331868367  0.028873109331868367] 
[0.027673522765052503  2*0.027673522765052503  0.027673522765052503]
2.舍掉第四列引數
3.將后兩列分別乘以-1,即:
0.035416141341387819  2*0.035416141341387819  0.035416141341387819  -1.7193929141691948  0.8610574795347461          
0.031387100113383172  2*0.031387100113383172  0.031387100113383172  -1.5237898734101736  0.64933827386370635         
0.028873109331868367  2*0.028873109331868367  0.028873109331868367  -1.4017399331200424  0.51723237044751591         
0.027673522765052503  2*0.027673522765052503  0.027673522765052503  -1.3435020629061745  0.45419615396638446 
這樣就得到了濾波器系陣列了
*/
#define IIR_SECTION 4                /*見前面設計輸出為4個SOS塊*/
static float iir_state[4*IIR_SECTION];/*歷史狀態緩沖區         */
const float iir_coeffs[5*IIR_SECTION]={
    0.035416141341387819,2*0.035416141341387819,0.035416141341387819,1.7193929141691948,-0.8610574795347461,    0.031387100113383172,2*0.031387100113383172,0.031387100113383172,1.5237898734101736,-0.64933827386370635,    0.028873109331868367,2*0.028873109331868367,0.028873109331868367,1.4017399331200424,-0.51723237044751591,    0.027673522765052503,2*0.027673522765052503,0.027673522765052503,1.3435020629061745,-0.45419615396638446
};
static arm_biquad_casd_df1_inst_f32 S;
/*假定采樣512個點*/
#define BUF_SIZE 512
#define PI 3.1415926
#define SAMPLE_RATE  32000 /*32000Hz*/
int main()
{
    float raw[BUF_SIZE];
    float raw_4k[BUF_SIZE];
    float raw_out[BUF_SIZE];

    float raw_noise[BUF_SIZE];
    float raw_noise_out[BUF_SIZE];

    arm_biquad_casd_df1_inst_f32 S;
    FILE *pFile=fopen("./simulation.csv","wt+");
    if(pFile==NULL)
    {
        printf("file opened failed");
        return -1;
    }

    for(int i=0;i<BUF_SIZE;i++)
    {
    /*模擬9000Hz輸入信號         */
        raw[i] = 0.5*1024.0/3*sin(2*PI*800*i/32000.0f)+rand()%50;
        raw_4k[i] = 0.5*1024.0/3*sin(2*PI*4000*i/32000.0f);
    /*模擬9000Hz +11000Hz疊加輸入*/
        raw_noise[i] = raw[i] + raw_4k[i];
    }

    arm_biquad_cascade_df1_init_f32(&S, IIR_SECTION, (float *)&iir_coeffs[0], (float *)&iir_state[0]);
    arm_biquad_cascade_df1_f32(&S, raw, raw_out, BUF_SIZE);

    for(int i=0;i<BUF_SIZE;i++)
    {
       fprintf(pFile,"%f,",raw[i]);
    }

    fprintf(pFile,"\n");
    for(int i=0;i<BUF_SIZE;i++)
    {
        fprintf(pFile,"%f,",raw_4k[i]);
    }
    fprintf(pFile,"\n");
    for(int i=0;i<BUF_SIZE;i++)
    {
        fprintf(pFile,"%f,",raw_out[i]);
    }

    /*重新初始化*/
    arm_biquad_cascade_df1_init_f32(&S, IIR_SECTION, (float *)&iir_coeffs[0], (float *)&iir_state[0]);
    arm_biquad_cascade_df1_f32(&S, raw_noise, raw_noise_out, BUF_SIZE);

    fprintf(pFile,"\n");
    for(int i=0;i<BUF_SIZE;i++)
    {
        fprintf(pFile,"%f,",raw_noise[i]);
    }

    fprintf(pFile,"\n");
    for(int i=0;i<BUF_SIZE;i++)
    {
        fprintf(pFile,"%f,",raw_noise_out[i]);
    }

    fclose(pFile);

    return 0;
}

利用csv檔案,將模擬資料存盤,直接用excel打開,將行資料生成曲線圖如下:

  • 第一幅圖,為800Hz信號混入隨機噪聲的波形
  • 第二幅圖,為4000Hz信號,對假定系統為無用干擾信號
  • 第三幅圖, 為800Hz 混入隨機噪聲過濾后,已經很好的還原有用信號頻率
  • 第四幅圖, 為800Hz信號混入隨機噪聲,同時疊加4000Hz干擾的波形,對系統而言,從時域中,明顯可見,有用信號已經完全扭曲
  • 第五幅圖,為800Hz信號混入隨機噪聲,同時疊加4000Hz干擾的輸入,經過該低通濾波器后的波形,與第三幅圖基本一樣,已經非常好的濾除了干擾信號,

總結

  • IIR濾波器在線性時不變系統中可以很好的解決工程中一般噪聲問題

  • 如果需要設計帶通、高通濾波器其步驟基本類似,只是濾波器的引數以及SOS塊個數可能不一樣而已

  • 需要提醒的時,IIR的相頻回應不線性,如果系統對相頻回應有嚴格要求,就需要采用其他的數字濾波器拓撲形式了

  • 實際應用中,如果階數不高時,現在算力強勁的單片機或者DSP以及可以直接使用浮點處理,

  • 如果對處理速度有嚴格的實時要求,需要在極短時間進行濾波處理,可以考慮降低階數,或采用定點IIR濾波演算法實作,也或者將文中函式進行匯編級優化,

文章出自微信公眾號:嵌入式客堆疊,著作權所有,嚴禁商用,關注公眾號,獲取更新更多內容

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/27304.html

標籤:C

上一篇:手把手教系列之移動平均濾波器實作

下一篇:推箱子游戲-C語言

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more