2 커밋 24e1517057 ... 0cda96bfaf

작성자 SHA1 메시지 날짜
  Anatoliy Chigirinskiy 0cda96bfaf Добавил FIR-фильтр и перевод коэффициентов в int 4 달 전
  ChStepan 24e1517057 Тестовые изменения 4 달 전

+ 5 - 7
src/src/ExtDspInterface/DspInterface.v

@@ -115,9 +115,7 @@ module	DspInterface
 	wire	signed	[AdcDataWidth-1:0]	currDataChannelDecim;
 	wire	currDataChannelDecimVal;
 	
-	wire	signed	[31:0]	filteredDecimData;
-	wire	signed	[31:0]	filteredDecimDataQ;
-
+	wire	signed	[15:0]	filteredDecimData;
 	wire 	signed [31:0]	afterFirData;
 	wire 					afterFirVal;
 	wire	filteredDecimDataVal;
@@ -433,10 +431,10 @@ MeasDataFifoInst
 	.MeasNum_i		(MeasNum_i),	
 	.StartMeasDsp_i	(StartMeasDsp_i),	
 	.DspReadyForRx_i(DspReadyForRx_i),	
-	.MeasDataBus_i	(measDataBus),
-	// .MeasDataBus_i	(dataForFifo),
-	.MeasDataVal_i	(LpOutStart_i),	
-	// .MeasDataVal_i	(dataForFifoVal),	
+	// .MeasDataBus_i	(measDataBus),
+	.MeasDataBus_i	(dataForFifo),
+	// .MeasDataVal_i	(LpOutStart_i),	
+	.MeasDataVal_i	(dataForFifoVal),	
 	
 	.MeasDataBus_o	(measDataBusTx),
 	.MeasDataVal_o	(measDataValTx)

+ 39 - 29
src/src/FftDataFiltering/TestCicFilter/CicFilterNewWrapperNoIntDiff.sv

@@ -1,9 +1,10 @@
 module CicFilterNewWrapperNoIntDiff #(
-    parameter InDataWidth = 14,
-    parameter N             = 6, // Number of stages
-    parameter M             = 4, // Differential delay
-    parameter DECIM_WIDTH   = 4, // Decimation factor width
-    parameter OutDataWidth  = 17
+    parameter InDataWidth       = 14,
+    parameter N                 = 4, // Number of stages
+    parameter M                 = 1, // Differential delay
+    parameter DECIM_WIDTH       = 4, // Decimation factor width
+    parameter MAX_DECIM_FACTOR  = 16,
+    parameter integer INTER_DATA_WIDTH  = $ceil(N*$clog2(M*MAX_DECIM_FACTOR)) + InDataWidth
 )
 (
     input logic 								    Clk_i,
@@ -14,39 +15,39 @@ module CicFilterNewWrapperNoIntDiff #(
     input logic 	signed	[InDataWidth-1:0]       Data_i,
 
     output logic 								    DataVal_o,
-    output logic 	signed	[OutDataWidth-1:0] 	    Data_o
+    output logic 	signed	[15:0] 	                Data_o
 );
-
-//================================================================================
+//======================================================================================
 //								REG/WIRE
-//================================================================================
+//======================================================================================
 /* Integrator Block */
-logic signed					[OutDataWidth-1:0] 	integratedDataIn 	[N-1:0];
-logic 										        integratedDataValIn [N-1:0];
-logic signed					[OutDataWidth-1:0] 	integratedDataOut 	[N-1:0];
-logic 											    integratedValOut 	[N-1:0];
+logic signed					[INTER_DATA_WIDTH-1:0] 	integratedDataIn 	    [N-1:0];
+logic 										            integratedDataValIn     [N-1:0];
+logic signed					[INTER_DATA_WIDTH-1:0] 	integratedDataOut 	    [N-1:0];
+logic 											        integratedValOut 	    [N-1:0];
 /* Decim Block */
-logic signed 				    [OutDataWidth-1:0] 	decimDataOut;
-logic 											    decimDataValOut;
+logic signed 				    [INTER_DATA_WIDTH-1:0] 	decimDataOut;
+logic 											        decimDataValOut;
 /* Comb Filter Block */
-logic signed					[OutDataWidth-1:0] 	combDataIn			[N-1:0];
-logic 											    combDataValIn		[N-1:0];
-logic signed					[OutDataWidth-1:0] 	combDataOut			[N-1:0];
-logic 											    combDataValOut		[N-1:0];
+logic signed					[INTER_DATA_WIDTH-1:0] 	combDataIn			    [N-1:0];
+logic 											        combDataValIn		    [N-1:0];
+logic signed					[INTER_DATA_WIDTH-1:0] 	combDataOut			    [N-1:0];
+logic 											        combDataValOut		    [N-1:0];
 
 /* ShTest */
 logic signed					[InDataWidth-1:0] 	shTest;
+/* Current MSB_POS */
+logic                           [31:0]              currentMsbPos; 
 
-//================================================================================
+//======================================================================================
 //								ASSIGNMENTS
-//================================================================================
-assign Data_o 		= combDataOut[N-1];
+//======================================================================================
+assign Data_o 		= combDataOut[N-1][currentMsbPos-1-:16];
 assign DataVal_o 	= combDataValOut[N-1];
 
-assign shTest 		= combDataOut[N-1]>>> 14;
-//================================================================================
+//======================================================================================
 //								CODING
-//================================================================================
+//======================================================================================
 genvar i;
 /* Integrators */
 generate
@@ -56,8 +57,8 @@ generate
         assign integratedDataValIn[i] = (i == 0) ? DataVal_i : integratedValOut[i-1];
 
         CicIntegrator #(
-            .InDataWidth    (OutDataWidth),
-            .OutDataWidth   (OutDataWidth)
+            .InDataWidth    (INTER_DATA_WIDTH),
+            .OutDataWidth   (INTER_DATA_WIDTH)
         ) integrator_inst (
             .Clk_i          (Clk_i),
             .Rst_i          (Rst_i),
@@ -71,7 +72,7 @@ endgenerate
 
 /* Decimation */
 CicDecimator #(
-    .InDataWidth			(OutDataWidth),
+    .InDataWidth			(INTER_DATA_WIDTH),
     .DECIM_WIDTH			(DECIM_WIDTH)
 ) decimator_inst (
     .Clk_i          		(Clk_i),
@@ -92,7 +93,7 @@ generate
         assign combDataValIn[j] = (j == 0) ? decimDataValOut : combDataValOut[j-1];
 
         CicCombFilter #(
-            .InOutDataWidth (OutDataWidth),
+            .InOutDataWidth (INTER_DATA_WIDTH),
             .M              (M)
         ) comb_filter_inst (
             .Clk_i          (Clk_i),
@@ -105,4 +106,13 @@ generate
     end
 endgenerate
 
+always_comb begin 
+    case (DecimFactor_i)
+    2: currentMsbPos = CoeffsR2pkg::MSB_POS;
+    4: currentMsbPos = CoeffsR4pkg::MSB_POS;
+    8: currentMsbPos = CoeffsR8pkg::MSB_POS;
+    default : currentMsbPos = 16;
+    endcase
+end
+
 endmodule

+ 33 - 67
src/src/FirFilter/CoeffsR2pkg.sv

@@ -1,74 +1,40 @@
 package CoeffsR2pkg;
-
-// localparam signed [15:0] COEFFS[32] = '{
-//     16'shFFFD, // -1.321922e-02
-//     16'sh0007, //  6.792858e-02
-//     16'shFFEB, // -1.293875e-01
-//     16'shFFF6, // -6.335347e-02
-//     16'sh0066, //  7.969766e-01
-//     16'shFEFA, // -1.025350e+00
-//     16'shFDDE, // -2.195201e+00
-//     16'sh0742, //  7.051171e+00
-//     16'sh0803, //  8.034728e+00
-//     16'shAA44, // -8.737157e+01
-//     16'sh0FDE, //  2.522708e+02
-//     16'sh9D13, // -4.038411e+02
-//     16'sh0F9C, //  2.497294e+02
-//     16'sh25BC, //  6.051987e+02
-//     16'sh70DC, // -2.283021e+03
-//     16'sh5BAE, //  3.510809e+03
-//     16'sh5BAE, //  3.510809e+03
-//     16'sh70DC, // -2.283021e+03
-//     16'sh25BC, //  6.051987e+02
-//     16'sh0F9C, //  2.497294e+02
-//     16'sh9D13, // -4.038411e+02
-//     16'sh0FDE, //  2.522708e+02
-//     16'shAA44, // -8.737157e+01
-//     16'sh0803, //  8.034728e+00
-//     16'sh0742, //  7.051171e+00
-//     16'shFDDE, // -2.195201e+00
-//     16'shFEFA, // -1.025350e+00
-//     16'sh0066, //  7.969766e-01
-//     16'shFFF6, // -6.335347e-02
-//     16'shFFEB, // -1.293875e-01
-//     16'sh0007, //  6.792858e-02
-//     16'shFFFD  // -1.321922e-02
-// };
-
 localparam signed [15:0] COEFFS[32] = '{
     16'sh0000,
-    16'shFFFC,
-    16'sh0017,
-    16'sh000E,
-    16'shFEF0,
-    16'sh018B,
-    16'sh035D,
-    16'shF5D9,
-    16'shF8D9,
-    16'sh3B1C,
-    16'shC34C,
-    16'sh9B0F,
-    16'sh7FFF,
-    16'sh7FFF,
-    16'sh8000,
-    16'sh7FFF,
-    16'sh7FFF,
-    16'sh8000,
-    16'sh7FFF,
-    16'sh7FFF,
-    16'sh9B0F,
-    16'shC34C,
-    16'sh3B1C,
-    16'shF8D9,
-    16'shF5D9,
-    16'sh035D,
-    16'sh018B,
-    16'shFEF0,
-    16'sh000E,
-    16'sh0017,
-    16'shFFFC,
+    16'sh0000,
+    16'sh0000,
+    16'sh0000,
+    16'shFFFD, // 0xFFFD is -3 in signed 16-bit
+    16'sh0005,
+    16'sh000A,
+    16'shFFDF, // 0xFFDF is -33 in signed 16-bit
+    16'shFFF2, // 0xFFF2 is -14 in signed 16-bit
+    16'sh00AA,
+    16'shFF49, // 0xFF49 is -183 in signed 16-bit
+    16'shFEBE, // 0xFEBE is -322 in signed 16-bit
+    16'sh0320,
+    16'sh0506,
+    16'shD9D8, // 0xD9D8 is -9768 in signed 16-bit
+    16'sh6457,
+    16'sh6457,
+    16'shD9D8, // 0xD9D8 is -9768 in signed 16-bit
+    16'sh0506,
+    16'sh0320,
+    16'shFEBE, // 0xFEBE is -322 in signed 16-bit
+    16'shFF49, // 0xFF49 is -183 in signed 16-bit
+    16'sh00AA,
+    16'shFFF2, // 0xFFF2 is -14 in signed 16-bit
+    16'shFFDF, // 0xFFDF is -33 in signed 16-bit
+    16'sh000A,
+    16'sh0005,
+    16'shFFFD, // 0xFFFD is -3 in signed 16-bit
+    16'sh0000,
+    16'sh0000,
+    16'sh0000,
     16'sh0000
 };
 
+localparam integer MSB_POS = $ceil(4*$clog2(1*2))+14;
+
 
-endpackage
+endpackage

+ 33 - 67
src/src/FirFilter/CoeffsR4pkg.sv

@@ -1,74 +1,40 @@
 package CoeffsR4pkg;
-
-// localparam signed [15:0] COEFFS[32] = '{
-//     16'shFFFD, // -1.321922e-02
-//     16'sh0007, //  6.792858e-02
-//     16'shFFEB, // -1.293875e-01
-//     16'shFFF6, // -6.335347e-02
-//     16'sh0066, //  7.969766e-01
-//     16'shFEFA, // -1.025350e+00
-//     16'shFDDE, // -2.195201e+00
-//     16'sh0742, //  7.051171e+00
-//     16'sh0803, //  8.034728e+00
-//     16'shAA44, // -8.737157e+01
-//     16'sh0FDE, //  2.522708e+02
-//     16'sh9D13, // -4.038411e+02
-//     16'sh0F9C, //  2.497294e+02
-//     16'sh25BC, //  6.051987e+02
-//     16'sh70DC, // -2.283021e+03
-//     16'sh5BAE, //  3.510809e+03
-//     16'sh5BAE, //  3.510809e+03
-//     16'sh70DC, // -2.283021e+03
-//     16'sh25BC, //  6.051987e+02
-//     16'sh0F9C, //  2.497294e+02
-//     16'sh9D13, // -4.038411e+02
-//     16'sh0FDE, //  2.522708e+02
-//     16'shAA44, // -8.737157e+01
-//     16'sh0803, //  8.034728e+00
-//     16'sh0742, //  7.051171e+00
-//     16'shFDDE, // -2.195201e+00
-//     16'shFEFA, // -1.025350e+00
-//     16'sh0066, //  7.969766e-01
-//     16'shFFF6, // -6.335347e-02
-//     16'shFFEB, // -1.293875e-01
-//     16'sh0007, //  6.792858e-02
-//     16'shFFFD  // -1.321922e-02
-// };
-
 localparam signed [15:0] COEFFS[32] = '{
     16'sh0000,
-    16'shFFFC,
-    16'sh0017,
-    16'sh000E,
-    16'shFEF0,
-    16'sh018B,
-    16'sh035D,
-    16'shF5D9,
-    16'shF8D9,
-    16'sh3B1C,
-    16'shC34C,
-    16'sh9B0F,
-    16'sh7FFF,
-    16'sh7FFF,
-    16'sh8000,
-    16'sh7FFF,
-    16'sh7FFF,
-    16'sh8000,
-    16'sh7FFF,
-    16'sh7FFF,
-    16'sh9B0F,
-    16'shC34C,
-    16'sh3B1C,
-    16'shF8D9,
-    16'shF5D9,
-    16'sh035D,
-    16'sh018B,
-    16'shFEF0,
-    16'sh000E,
-    16'sh0017,
-    16'shFFFC,
+    16'sh0000,
+    16'shFFFF, // 0xFFFF is -1 in signed 16-bit
+    16'sh0000,
+    16'sh0004,
+    16'shFFFA, // 0xFFFA is -6 in signed 16-bit
+    16'shFFF3, // 0xFFF3 is -13 in signed 16-bit
+    16'sh002C,
+    16'sh001F,
+    16'shFE27, // 0xFE27 is -473 in signed 16-bit
+    16'sh05A7,
+    16'shF64E, // 0xF64E is -2482 in signed 16-bit
+    16'sh07AE,
+    16'sh0A4E,
+    16'shCB04, // 0xCB04 is -13564 in signed 16-bit
+    16'sh6DB6,
+    16'sh6DB6,
+    16'shCB04, // 0xCB04 is -13564 in signed 16-bit
+    16'sh0A4E,
+    16'sh07AE,
+    16'shF64E, // 0xF64E is -2482 in signed 16-bit
+    16'sh05A7,
+    16'shFE27, // 0xFE27 is -473 in signed 16-bit
+    16'sh001F,
+    16'sh002C,
+    16'shFFF3, // 0xFFF3 is -13 in signed 16-bit
+    16'shFFFA, // 0xFFFA is -6 in signed 16-bit
+    16'sh0004,
+    16'sh0000,
+    16'shFFFF, // 0xFFFF is -1 in signed 16-bit
+    16'sh0000,
     16'sh0000
 };
 
+localparam integer MSB_POS = $ceil(4*$clog2(1*4))+14;
+
 
-endpackage
+endpackage

+ 35 - 34
src/src/FirFilter/CoeffsR8pkg.sv

@@ -1,39 +1,40 @@
 package CoeffsR8pkg;
-
 localparam signed [15:0] COEFFS[32] = '{
-    16'shFFFD, // -1.321922e-02
-    16'sh0007, //  6.792858e-02
-    16'shFFEB, // -1.293875e-01
-    16'shFFF6, // -6.335347e-02
-    16'sh0066, //  7.969766e-01
-    16'shFEFA, // -1.025350e+00
-    16'shFDDE, // -2.195201e+00
-    16'sh0742, //  7.051171e+00
-    16'sh0803, //  8.034728e+00
-    16'shAA44, // -8.737157e+01
-    16'h0FDE, //  2.522708e+02
-    16'h9D13, // -4.038411e+02
-    16'h0F9C, //  2.497294e+02
-    16'h25BC, //  6.051987e+02
-    16'h70DC, // -2.283021e+03
-    16'h5BAE, //  3.510809e+03
-    16'h5BAE, //  3.510809e+03
-    16'h70DC, // -2.283021e+03
-    16'h25BC, //  6.051987e+02
-    16'h0F9C, //  2.497294e+02
-    16'h9D13, // -4.038411e+02
-    16'h0FDE, //  2.522708e+02
-    16'hAA44, // -8.737157e+01
-    16'h0803, //  8.034728e+00
-    16'h0742, //  7.051171e+00
-    16'hFDDE, // -2.195201e+00
-    16'hFEFA, // -1.025350e+00
-    16'h0066, //  7.969766e-01
-    16'hFFF6, // -6.335347e-02
-    16'hFFEB, // -1.293875e-01
-    16'h0007, //  6.792858e-02
-    16'hFFFD  // -1.321922e-02
+    16'sh0000,
+    16'sh0000,
+    16'sh0001,
+    16'sh0000,
+    16'shFFF1, // 0xFFF1 is -15 in signed 16-bit
+    16'sh003A,
+    16'shFF80, // 0xFF80 is -128 in signed 16-bit
+    16'sh0094,
+    16'sh0042,
+    16'shFD35, // 0xFD35 is -715 in signed 16-bit
+    16'sh06D8,
+    16'shF60A, // 0xF60A is -2550 in signed 16-bit
+    16'sh06E6,
+    16'sh0911,
+    16'shD533, // 0xD533 is -10957 in signed 16-bit
+    16'sh53C0,
+    16'sh53C0,
+    16'shD533, // 0xD533 is -10957 in signed 16-bit
+    16'sh0911,
+    16'sh06E6,
+    16'shF60A, // 0xF60A is -2550 in signed 16-bit
+    16'sh06D8,
+    16'shFD35, // 0xFD35 is -715 in signed 16-bit
+    16'sh0042,
+    16'sh0094,
+    16'shFF80, // 0xFF80 is -128 in signed 16-bit
+    16'sh003A,
+    16'shFFF1, // 0xFFF1 is -15 in signed 16-bit
+    16'sh0000,
+    16'sh0001,
+    16'sh0000,
+    16'sh0000
 };
 
+localparam integer MSB_POS = $ceil(4*$clog2(1*8))+14;
+
 
-endpackage
+endpackage

+ 7 - 7
src/src/FirFilter/FirFilter.sv

@@ -17,14 +17,14 @@ module FirFilter #(
     output logic [RESULT_WIDTH-1:0] Data_o,
     output logic                    Val_o
 );
-//================================================================================
+//=======================================================================================
 //								REG/WIRE
-//================================================================================
+//=======================================================================================
 logic signed [DATA_WIDTH-1:0]   shiftReg        [0:NUM_TAPS-1];
 /* MAC */
 logic signed [RESULT_WIDTH-1:0] macResult;
 /* Coeffs */
-logic signed [COEFF_WIDTH-1:0]  coeffs          [0:NUM_TAPS - 1];
+logic signed [COEFF_WIDTH-1:0]  coeffs          [0:NUM_TAPS-1];
 
 /* Phase Counter */
 logic        [$clog2(8)-1:0]    phaseCounter;
@@ -36,13 +36,13 @@ logic                           val2Cycle;
 logic signed [DATA_WIDTH-1:0]   delayedData;
 logic                           delayedVal;
 logic                           delayedValR;
-//================================================================================
+//========================================================================================
 //								ASSIGNMENTS
-//================================================================================
+//========================================================================================
 assign Data_o = macResult;
-//================================================================================
+//========================================================================================
 //								CODING
-//================================================================================
+//========================================================================================
 /* Delayed Data_i */
 always_ff @(posedge Clk_i) begin 
     if (Rst_i) begin 

+ 16 - 0
src/src/FirFilter/Utilspkg.sv

@@ -0,0 +1,16 @@
+package Utilspkg;
+//========================================================================================
+//								FUNCTIONS
+//========================================================================================
+function automatic findMaxValue (input logic signed [15:0] data [0:31]);
+    logic signed [15:0] maxValue;
+    maxValue = data[0];
+    for (int i = 1; i < 32; i++) begin
+        if (data[i] > maxValue) begin
+            maxValue = data[i];
+        end
+    end
+    return maxValue;
+endfunction
+
+endpackage

+ 3 - 3
src/src/MeasDataFifo/OscDataFormer.v

@@ -2,10 +2,10 @@
 (* keep_hierarchy = "yes" *)	
 module OscDataFormer
 #(	
-	parameter	AdcDataWidth		=	32,	
+	parameter	AdcDataWidth		=	16,	
 	parameter	ExtAdcDataWidth		=	AdcDataWidth+2,	
 	parameter	ChNum				=	1,
-	parameter	DataValCycles		=	8,
+	parameter	DataValCycles		=	256/AdcDataWidth,
 	parameter	OutDataWidth		=	(AdcDataWidth*ChNum)*DataValCycles
 )	
 (
@@ -67,7 +67,7 @@ module OscDataFormer
 		if	(!Rst_i)	begin
 			if	(OscWind_i)	begin
 				if	(oscDataBusValReg)	begin
-					oscDataBusRegReg	<=	{oscDataBusReg[32*6-1-:64],oscDataBusReg[32*2-1-:64],oscDataBusReg[32*8-1-:64],oscDataBusReg[32*4-1-:64]};
+					oscDataBusRegReg	<=	{oscDataBusReg[AdcDataWidth*12-1-:64],oscDataBusReg[AdcDataWidth*4-1-:64],oscDataBusReg[AdcDataWidth*16-1-:64],oscDataBusReg[AdcDataWidth*8-1-:64]};
 					// oscDataBusRegReg	<=	{oscDataBusReg[127:0], oscDataBusReg[OutDataWidth-1:128]};
 					// oscDataBusRegReg	<=	oscDataBusReg;
 					// oscDataBusRegReg	<=	{16'h7,16'h6,16'h5,16'h4,16'h3,16'h2,16'h1,16'h0,16'hF,16'hE,16'hD,16'hC,16'hB,16'hA,16'h9,16'h8};

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 512 - 512
src/src/Sim/AfterFir.txt


+ 91 - 51
src/src/Sim/DecimFilterWrapperTb.sv

@@ -7,14 +7,29 @@ module DecimFilterWrapperTb	();
 //================================================================================
 
 parameter	N	=   4; // Order of the filter
-parameter	M	=	2;// Delay in CIC filter
+parameter	M	=	1;// Delay in CIC filter
+// parameter   M2nd = (M/2)*M; // Delay in 2nd CIC filter
+parameter   R = 4; // Decimation factor
+parameter  	M2nd = M*R; // Delay in 2nd CIC filter
+parameter   M3rd = M*R;
+// parameter   M3rd = (M/2)**2*M; // Delay in 3rd CIC filter
 parameter	InDataWidth	=	14;
 parameter	integer DECIM_WIDTH	=	$ceil($clog2(2*M)) + 4; // Decimation factor width
 
 parameter	K = N*20*($log10(M));
 parameter	BitGworth = $ceil(2**(K/20));
-parameter	integer BitGrowth = $ceil($clog2(((M/2*M)**N)/(M/2)));
-parameter	integer MaxWidth = InDataWidth+BitGrowth+5;
+
+// parameter	integer BitGrowth = $ceil(N*$clog2((M/2)*M));
+parameter   integer BitGrowth =   $ceil(N*$clog2(M*R));
+// parameter 	integer BitGrowth2nd = $ceil(N*$clog2(M2nd*(M/2)));
+// parameter 	integer BitGrowth3rd = $ceil(N*$clog2(M3rd*(M/2)));
+
+parameter  integer BitGrowth2nd = $ceil(N*$clog2(M*R));
+parameter  integer BitGrowth3rd = $ceil(N*$clog2(M*R));
+
+parameter	integer MaxWidth = InDataWidth+BitGrowth;
+parameter	integer MaxWidth2nd = InDataWidth+BitGrowth2nd;
+parameter	integer MaxWidth3rd = InDataWidth+BitGrowth3rd;
 
 // parameter	[31:0]	Nco1PhaseInc	=	32'h40000000;//12.5 MHz 
 parameter	[31:0]	Nco1PhaseInc	=	32'h23d70a3d;//7 MHz 
@@ -45,10 +60,11 @@ wire	signed	[InDataWidth-1:0]	ncoSin2;
 wire	signed	[InDataWidth-1:0]	ncoSin3;
 
 wire	signed	[MaxWidth-1:0]		filteredDataOut;
-logic 	signed	[MaxWidth-1:0]		firDataOut;
+logic 	signed	[31:0]				firDataOut;
+logic 	signed 	[15:0]				firDataOut16;
 wire	signed	[MaxWidth-1:0]		impResponse;
 wire 	signed	[31:0]				impResp32;
-assign 	impResp32 = impResponse[53:53-32]; // Cut to 32 bits
+assign 	impResp32 = impResponse[MaxWidth-1:MaxWidth-32];
 
 wire	signed	[InDataWidth*2-1:0]	adcDataMixed	=	(ncoSin1*ncoSin2);
 wire	signed	[InDataWidth-1:0]	adcDataMixedCut	=	adcDataMixed[26-:14];
@@ -58,34 +74,37 @@ wire    signed  [2*InDataWidth-1:0] sinMultFull = (ncoSin2*ncoSin1);
 wire	signed	[InDataWidth-1:0]	sinMult =	sinMultFull[(2*InDataWidth-1)-:InDataWidth];
 
 wire	signed	[InDataWidth-1:0]	singlePulse	=	(tbCnt==100)?	14'h1fff:14'h0;
+wire    signed  [15:0] 				singlePulse16 = (tbCnt==100) ? 16'h1fff : 16'h0;
 
 // wire signed [(MaxWidth < 32 ? MaxWidth : InDataWidth+18)-1:0] impRespCut;
 // assign impRespCut = MaxWidth < 32 ? impResponse : 
 //                                    impResponse[MaxWidth-1:MaxWidth-(InDataWidth+18)];
 wire signed [InDataWidth -1 : 0] impRespCut = impResponse [MaxWidth-1:MaxWidth-InDataWidth];
 
-longint inSignal,filteredData, impResp, afterFir;
+longint inSignal,filteredData, impResp,impResp2,impResp3, afterFir;
 
 /* 2nd CIC */
-wire signed [2*MaxWidth-1:0] impResponse2nd;
+wire signed [MaxWidth-1:0] impResponse2nd;
 
 // wire signed [(MaxWidth < 32 ? MaxWidth : InDataWidth+18)-1:0] impResp2ndCut;
 // assign impResp2ndCut = MaxWidth < 32 ? impResponse2nd : 
 //                                    impResponse2nd[MaxWidth-1:MaxWidth-(InDataWidth+18)];
-wire signed [31:0] impResp2ndCut = impResponse2nd [39:39-32]; // 32 bits for 2nd stage
+wire signed [31:0] impResp2ndCut32 = (MaxWidth < 32) ? impResponse2nd : 
+									impResponse2nd[MaxWidth-1:MaxWidth-32];
 // wire signed [InDataWidth -1 : 0] impResp2ndCut = impResponse2nd [MaxWidth-1:MaxWidth-InDataWidth];
+wire signed [InDataWidth -1 : 0] impResp2ndCut = impResponse2nd [MaxWidth-1:MaxWidth-InDataWidth];
 wire impResp2ndVal;
 
 /* 3rd CIC */
-wire signed [MaxWidth-1:0] impResponse3rd;
+wire signed [MaxWidth3rd-1:0] impResponse3rd;
 
-wire signed [(MaxWidth < 32 ? MaxWidth : InDataWidth+18)-1:0] impResp3rdCut;
-assign impResp3rdCut = MaxWidth < 32 ? impResponse3rd : 
-                                   impResponse3rd[MaxWidth-1:MaxWidth-(InDataWidth+18)];
+wire signed [31:0] impResp3rd32;
+assign impResp3rd32 = (MaxWidth3rd < 32) ? impResponse3rd : 
+									impResponse3rd[MaxWidth3rd-1:MaxWidth3rd-32];
 wire impResp3rdVal;
 
 /* FIR Filt */
-wire signed [31:0] firFiltTestData;
+wire signed [35:0] firFiltTestData;
 wire 					firFiltVal;  
 
 //================================================================================
@@ -116,7 +135,7 @@ end
 always	@(posedge	Clk50)	begin
 	if	(!Rst)	begin
 		if (tbCnt == 100) begin
-			decimFactor	<= 4;
+			decimFactor	<= R;
 		end
 		// end else if (tbCnt == 5400) begin
 			// decimFactor	<= 1;
@@ -134,7 +153,7 @@ always	@(posedge	Clk50)	begin
 			// decimFactor	<= 7;
 		// end
 	end else begin
-	 decimFactor <= 4; // 
+	 decimFactor <= R; // 
 	end 
 end
 
@@ -206,8 +225,8 @@ CicFilterNewWrapperNoIntDiff
 	.InDataWidth	(InDataWidth),
 	.N	(N),
 	.M	(M),
-	.DECIM_WIDTH	(DECIM_WIDTH),
-	.OutDataWidth	(MaxWidth)
+	.DECIM_WIDTH	(DECIM_WIDTH)
+	// .OutDataWidth	(MaxWidth)
 )
 ImpulseResponseFilter
 (
@@ -222,36 +241,34 @@ ImpulseResponseFilter
 	.DataVal_o		(impResponseVal)
 );
 
-CicFilterNewWrapperNoIntDiff	
-#(
-	.InDataWidth	(MaxWidth),
-	.N	(N),
-	.M	(M),
-	.DECIM_WIDTH	(DECIM_WIDTH),
-	.OutDataWidth	(2*MaxWidth)
-)
-ImpulseResponseFilter2ndStage
-(
-	.Clk_i			(Clk50),
-	.DecimFactor_i	(decimFactor),
-	.Rst_i			(Rst),
-	.DataVal_i		(impResponseVal),
-	// .DataVal_i		(oscWind),
+// CicFilterNewWrapperNoIntDiff	
+// #(
+// 	.InDataWidth	(InDataWidth),
+// 	.N	(N),
+// 	.M	((M/2)*M),
+// 	.DECIM_WIDTH	(DECIM_WIDTH),
+// 	.OutDataWidth	(MaxWidth)
+// )
+// ImpulseResponseFilter2ndStage
+// (
+// 	.Clk_i			(Clk50),
+// 	.DecimFactor_i	(decimFactor),
+// 	.Rst_i			(Rst),
+// 	.DataVal_i		(impResponseVal),
 
-	.Data_i			(impResponse),
-	// .Data_i			(singlePulse),
+// 	.Data_i			(impRespCut),
 	
-	.Data_o			(impResponse2nd),
-	.DataVal_o		(impResp2ndVal)
-);
+// 	.Data_o			(impResponse2nd),
+// 	.DataVal_o		(impResp2ndVal)
+// );
 
 // CicFilterNewWrapperNoIntDiff	
 // #(
 // 	.InDataWidth	(InDataWidth),
 // 	.N	(N),
-// 	.M	(M),
+// 	.M	((M/2)**2*M),
 // 	.DECIM_WIDTH	(DECIM_WIDTH),
-// 	.OutDataWidth	(MaxWidth)
+// 	.OutDataWidth	(MaxWidth3rd)
 // )
 // ImpulseResponseFilter3rdStage
 // (
@@ -276,7 +293,7 @@ FirFiltTest
 	.Clk_i			(Clk50),
 	.Rst_i			(Rst),
 	.DecimFactor_i	(decimFactor),
-	.Data_i			(impResponse[MaxWidth-1:MaxWidth-16]), // 16 bits for FIR filter
+	.Data_i			(impResponse), // 16 bits for FIR filter
 	.Val_i			(impResponseVal),
 
 	.Data_o			(firFiltTestData),
@@ -307,7 +324,7 @@ always_ff @(posedge Clk50) begin
 	end
 	else begin 
 		if (firFiltVal) begin
-			firDataOut <= firFiltTestData;
+			firDataOut <= firFiltTestData[35:35-32];
 		end
 	end
 end
@@ -331,26 +348,47 @@ always	@(posedge	Clk50)	begin
 		filteredData = $fopen("C:/S5243_FFT_REPO/src/src/Sim/FilteredData.txt","w");
 	end	else	begin
 		if	(resultVal)	begin
-			$fwrite(filteredData,"%d\n",   filteredDataOut);
+			$fwrite(filteredData,"%d\n",   filteredDataOut[15:0]);
 			// $fwrite(filteredData,"%d\n",   firDataOut);
 		end	
 	end	
 end
- 
 
-always	@(posedge	Clk50)	begin
-	if	(tbCnt==32'd1)	begin
-		impResp = $fopen("C:/S5243_FFT_REPO/src/src/Sim/ImpResp.txt","w");
-	end	else	begin
-		// if	(impResp2ndVal)	begin
-		if	(impResponseVal)	begin
+always @(posedge Clk50) begin
+	if (tbCnt == 32'd1) begin
+		impResp = $fopen("C:/S5243_FFT_REPO/src/src/Sim/ImpResp1.txt","w");
+	end
+	else begin 
+		if (impResponseVal) begin
+			// $fwrite(impResp,"%d\n",   impResponse);
+			$fwrite(impResp,"%d\n",   impResponse[15:0]);
+		end
+	end
+end
+
+always @(posedge Clk50) begin
+	if (tbCnt == 32'd1) begin
+		impResp2 = $fopen("C:/S5243_FFT_REPO/src/src/Sim/ImpResp2.txt","w");
+	end else begin
+		if (impResp2ndVal) begin
 			// $fwrite(impResp,"%d\n",   firRespout);
-			$fwrite(impResp,"%d\n",   impResponse);
-			// $fwrite(impResp,"%d\n",   impResponse2nd);
+			$fwrite(impResp2,"%d\n",   impResp2ndCut32);
 		end	
 	end
 end
 
+always @(posedge Clk50) begin
+	if (tbCnt == 32'd1) begin
+		impResp3 = $fopen("C:/S5243_FFT_REPO/src/src/Sim/ImpResp3.txt","w");
+	end else begin
+		if (impResp3rdVal) begin
+			// $fwrite(impResp,"%d\n",   firRespout);
+			$fwrite(impResp3,"%d\n",   impResponse3rd);
+		end	
+	end
+end
+
+
 
 always @(posedge Clk50) begin 
 	if (tbCnt == 32'd1) begin
@@ -369,6 +407,8 @@ always @(posedge Clk50) begin
 		$fclose(inSignal);
 		$fclose(filteredData);
 		$fclose(impResp);
+		$fclose(impResp2);
+		$fclose(impResp3);
 		$fclose(afterFir);
 		$finish;
 	end

+ 0 - 197
src/src/Sim/FFTTest.asv

@@ -1,197 +0,0 @@
-FormatSpec = '%d';
-
-N = 4;
-R = 2;
-B = 14;
-M = 1;
-
-PointsNum = 100;
-
-Bmax = ceil(log2(((R*M)^N)/R)+B);
-MaxWidthR2 = ceil(log2(((2*M)^N)/2)+B);
-MaxWidthR4 = ceil(log2(((4*M)^N)/4)+B);
-
-K = N*20*log10(M);
-BitGrowth = ceil(2^(K/20));
-Bnew = B+BitGrowth;
-
-x = 1:1:PointsNum;
-xDecim = 1:1:PointsNum/R;
-
-Fc = 3;
-Fs = 50;
-
-DeltaPulse = [1, zeros(1, PointsNum*R-1)];
-DeltaPulseTransposed = transpose(DeltaPulse);
-
-IdealCicDecim = dsp.CICDecimator(R,M,N);
-ImpResp = IdealCicDecim(DeltaPulseTransposed);
-
-FftPNum = 50000;
-Step = 1 / FftPNum;
-f = linspace(1e-10, 1 - Step, FftPNum);
-H = ones(1,50000);
-
-for i = 1:50000
-    H(i) = abs(sin(pi * M * R * f(i)) / sin(pi * f(i)))^N;
-end
-
-Hdb = 20 * log10(abs(H));
-Hdb = Hdb - max(Hdb);
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ReadInDataId = fopen('C:/S5243_FFT_REPO/src/src/Sim/InputSignal.txt','r');
-InDataSignal = fscanf(ReadInDataId,FormatSpec);
-fclose(ReadInDataId);
-
-ReadFilteredDataId = fopen('C:/S5243_FFT_REPO/src/src/Sim/FilteredData.txt','r');
-FilteredData = fscanf(ReadFilteredDataId,FormatSpec);
-fclose(ReadFilteredDataId);
-
-ReadImpulseRestId = fopen('C:\S5243_FFT_REPO\src\src\Sim\ImpResp.txt','r');
-ImpulseResp = fscanf(ReadImpulseRestId,FormatSpec);
-fclose(ReadImpulseRestId);
-
-ReadFilterCoefsId = fopen('C:\S5243_FFT_REPO\src\src\Sim\CorrFilterCoefs.txt','r');
-FilterCoefs = fscanf(ReadFilterCoefsId,FormatSpec);
-fclose(ReadFilterCoefsId);
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FreqBandOrig = Fs*(1:(PointsNum))/PointsNum;
-FreqbandDecim = (Fs/2*R)*(1:(PointsNum))/PointsNum;
-
-InDataFft = abs(fft(InDataSignal+randn(size(InDataSignal)))/PointsNum);
-InDataFftDb = 20*log10(InDataFft);
-
-IdealCicFFt = abs(fft(ImpResp));
-IdealCicFFtDb = 20*log10(IdealCicFFt);
-IdealCicFFtDb = IdealCicFFtDb-max(IdealCicFFtDb);
-
-CalcCicFft = abs(fft(ImpResp));
-CalcCicFftDb = 20*log10(IdealCicFFt);
-CalcCicFftDb = IdealCicFFtDb-max(IdealCicFFtDb);
-
-FilteredDataFft = abs(fft(FilteredData+randn(size(FilteredData)))/PointsNum);
-% FilteredDataFft = abs(fft(FilteredData)/PointsNum);
-FilteredDataFftDb = 20*log10(FilteredDataFft);
-FilteredDataFftDb = FilteredDataFftDb-max(FilteredDataFftDb);
-
-ImpuseRespFft = abs(fft(ImpulseResp));
-ImpuseRespFftDb = 20*log10(ImpuseRespFft);
-ImpuseRespFftDb = ImpuseRespFftDb-max(ImpuseRespFftDb);
-
-Fband = 0:(Fs/R)/(PointsNum/R):(Fs/R)-1/(PointsNum/R);
-FbandOrig = 0:Fs/PointsNum:Fs-1/PointsNum;
-
-%InDataFftDb = InDataFftDb(1:length(Fband));
-%FilteredDataFftDb = FilteredDataFftDb(1:length(Fband));
-%ImpuseRespFftDb = ImpuseRespFftDb(1:length(Fband));
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% figure('name','In Data Time/Freq', 'Numbertitle', 'off')
-% subplot(2,1,1)
-% plot(InDataSignal)
-% grid on;
-% grid minor;
-% title('In Signal')
-% xlabel('Time')
-% ylabel('Amp')
-% 
-% subplot(2,1,2)
-% plot(FilteredData)
-% grid on;
-% grid minor;
-% title('Filtered Data')
-% xlabel('Time')
-% ylabel('Amp')
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% figure('name','Frequency compare', 'Numbertitle', 'off')
-% subplot(3,1,1)
-% plot(FbandOrig,InDataFftDb)
-% grid on;
-% grid minor;
-% title('Single-Sided Amplitude Spectrum of Data before filter')
-% xlabel('Time')
-% ylabel('Amp')
-% 
-% subplot(3,1,2)
-% plot(FbandOrig,ImpuseRespFftDb)
-% grid on;
-% grid minor;
-% title('Cic Frequency response')
-% xlabel('f (Hz)')
-% ylabel('Amp')
-% 
-% subplot(3,1,3)
-% plot(Fband,FilteredDataFftDb)
-% grid on;
-% grid minor;
-% title('Single-Sided Amplitude Spectrum of Data after filter')
-% xlabel('f (Hz)')
-% ylabel('Amp')
-% 
-% figure('name','Impulse Response Time/Freq', 'Numbertitle', 'off')
-% subplot(2,1,1)
-% plot(FbandOrig,ImpulseResp)
-% grid on;
-% grid minor;
-% title('In Signal')
-% xlabel('Time')
-% ylabel('Amp')
-% 
-% subplot(2,1,2)
-% plot(FbandOrig,ImpuseRespFftDb)
-% grid on;
-% grid minor;
-% title('Single-Sided Amplitude Spectrum of InData')
-% xlabel('f (Hz)')
-% ylabel('Amp')
-
-
-figure('name','In Data Time/Freq', 'Numbertitle', 'off')
-plot(Hdb)
-grid on;
-grid minor;
-title('In Signal')
-xlabel('Time')
-ylabel('Amp')
-
-% figure(2)
-% plot(IdealCicFFtDb)
-% grid on;
-% grid minor;
-% title('Filtered Data')
-% xlabel('Time')
-% ylabel('Amp')
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

+ 1 - 1
src/src/Sim/FFTTest.m

@@ -1,7 +1,7 @@
 FormatSpec = '%d';
 
 N = 4;
-R = 2;
+R = 4;
 B = 14;
 M = 1;
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 512 - 512
src/src/Sim/FilteredData.txt


+ 206 - 74
src/src/Sim/FreqDomainCicFilt.py

@@ -1,13 +1,12 @@
+
 import os
 import sys
 import numpy as np
-import matplotlib
 import matplotlib.pyplot as plt
-matplotlib.use('TkAgg')
-
-
-R = 4  # Decimation factor
 
+R = 4 # Decimation factor
+M = 1 # Delay in CIC filter
+N = 4 # Order of the filter
 
 # Open the input file and read the impulse response data
 def read_impulse_response(file_path):
@@ -28,80 +27,216 @@ def read_impulse_response(file_path):
 
     return np.array(impulse_response)
 
-
 def convert_to_frequency_domain(impulse_response):
     # Perform FFT
     frequency_response = np.fft.fft(impulse_response)
-
+    
     frequency_response /= np.max(np.abs(frequency_response))
-
+    
     return frequency_response
 
+def get_theoretical_freq_resp(decimation_factor, delay, order, num_points=1024, fs=50e6):
+    freq = np.fft.fftfreq(num_points, d=1/fs)
+    # Вычисляем нормализованные частоты
+    f_norm = np.abs(freq) / fs
+    # Расчет по формуле
+    R = decimation_factor
+    M = delay
+    N = order
+    # Избегаем деления на ноль при f=0
+    mag = np.ones(num_points)
+    nonzero = f_norm != 0
+    # Угол для sin(π*f*R*M)
+    angle_num = np.pi * f_norm[nonzero] * R * M
+    # Угол для sin(π*f*M)
+    angle_den = np.pi * f_norm[nonzero] 
+    # |H(f)| = |sin(π*f*R*M)/(R*sin(π*f*M))|^N
+    mag[nonzero] = np.abs(np.sin(angle_num) / ( np.sin(angle_den))) ** N
+    # Нормализуем амплитудную характеристику
+    mag /= np.max(mag)
+    return freq, mag
 
 # Plot the frequency response
 def plot_frequency_response(frequency_response, input_signal_time_domain, fs=50e6):
-    normalized_freq = np.fft.fftfreq(len(input_signal_time_domain), 1 / fs) / fs
-
+    normalized_freq = np.fft.fftfreq(len(input_signal_time_domain), 1/fs) / fs
+    
     plt.figure(figsize=(10, 6))
     half_len = len(normalized_freq) // 2
-    plt.plot(normalized_freq[:half_len], np.abs(frequency_response[:half_len]),
+    plt.plot(normalized_freq[:half_len], np.abs(frequency_response[:half_len]), 
              label='Signal Frequency Response')
     plt.title('Frequency Response')
     plt.xlabel('Normalized Frequency (f/fs)')
     # Magnitude in dB
     plt.plot(normalized_freq[:half_len], 20 * np.log10(np.abs(frequency_response[:half_len])), label='Magnitude (dB)')
     plt.ylabel('Magnitude (dB)')
-    plt.ylim(-150, 10)
+    plt.ylim(-150, 10) 
     plt.grid(True)
     plt.legend()
     plt.xlim(0, 0.5)
     plt.show()
 
+def convert_to_fixed_point(R):
+    # Read File with coefficients
+    with open(f'C:\\S5243_FFT_REPO\\src\\src\\Sim\\fir_filter_R{R}.coe', 'r') as file:
+        lines = file.readlines()
+        # skip first 3 lines
+        coeffs = []
+        for line in lines[3:]:
+            # Удалить запятую в конце строки, если есть или точку с запятой
+            line = line.strip().rstrip(',;')
+            if line.strip():
+                coeffs.append(float(line.strip()))
+    coeffs = np.array(coeffs)
+    # Get rid of the exponent notation. Show in the normal float format
+    np.set_printoptions(suppress=True, precision=6)
+    print("Coefficients in float format:")
+    print(coeffs)
+    # find the maximum absolute value and it's width
+    max_abs_value = np.max(np.abs(coeffs))
+    print(f"Maximum absolute value of coefficients: {max_abs_value}")
+    #number of bits needed to represent the coefficients
+    num_bits = int(np.ceil(np.log2(max_abs_value + 1)))
+    print(f"Number of bits needed to represent the coefficients: {num_bits}")
+    # Convert to integer format Q.1.12.3 - 1 bit for sign, 12 bits for integer part, 3 bits for fractional part
+    fixed_point_coeffs = np.round(coeffs * (2 ** (16-(num_bits + 1)))).astype(np.int16)  # Q.1.12.3
+    print(f"Fixed point coefficients (Q.1.{15-(16-(num_bits + 1))}.{(16-(num_bits + 1))}):")
+    # Вставляем запятую после каждого значения
+    print(", ".join(str(coeff) for coeff in fixed_point_coeffs))
+
+    # Convert to hexadecimal format
+    hex_coeffs = [f"{int(coeff) & 0xFFFF:04X}" for coeff in fixed_point_coeffs]
+    print("Fixed point coefficients in hexadecimal format:")
+    print(hex_coeffs)
+    # Edit the Coeffs package file 
+    with open(f'C:\\S5243_FFT_REPO\\src\\src\\FirFilter\\CoeffsR{R}pkg.sv', 'w') as file:
+        # Запись заголовка и объявления массива
+        file.write(f"package CoeffsR{R}pkg;\n")
+        file.write(f"localparam signed [15:0] COEFFS[{len(fixed_point_coeffs)}] = '{{\n")
+
+        # Запись коэффициентов в формате 16'sh<HEX_VALUE>
+        for i, hex_coeff in enumerate(hex_coeffs):
+            comment = ""
+            # Добавляем комментарий для отрицательных чисел
+            if fixed_point_coeffs[i] < 0:
+                comment = f" // 0x{hex_coeff} is {fixed_point_coeffs[i]} in signed 16-bit"
+
+            # Добавляем запятую для всех строк кроме последней
+            comma = "," if i < len(hex_coeffs) - 1 else ""
+
+            # Записываем строку с коэффициентом
+            file.write(f"    16'sh{hex_coeff}{comma}{comment}\n")
+        # Skip the line with MSB_POS
+        file.write("};\n\n")
+        file.write(f"localparam integer MSB_POS = $ceil(4*$clog2(1*{R}))+14;")
+        file.write("\n\n\nendpackage\n")
 
 # Main function to execute the conversion
 def main():
-    impulse_response_file = r'C:\S5243_FFT_REPO\src\src\Sim\FilteredData.txt'
+    impulse_response_file = 'C:\S5243_FFT_REPO\src\src\Sim\FilteredData.txt'
 
+    convert_to_fixed_point(4)
+    convert_to_fixed_point(2)
+    convert_to_fixed_point(8)
     filt_data_impulse_response = read_impulse_response(impulse_response_file)
     filt_data_frequency_response = convert_to_frequency_domain(filt_data_impulse_response)
-    plot_frequency_response(filt_data_frequency_response, filt_data_impulse_response)
+    plot_frequency_response(filt_data_frequency_response,filt_data_impulse_response)
     print("Frequency response conversion completed successfully.")
     # Show the input signal 
-    input_signal_time_domain = read_impulse_response(r'C:\S5243_FFT_REPO\src\src\Sim\InputSignal.txt')
+    input_signal_time_domain = read_impulse_response('C:\S5243_FFT_REPO\src\src\Sim\InputSignal.txt')
     input_signal_frequency_response = convert_to_frequency_domain(input_signal_time_domain)
-    fs = 50e6
-    freq_axis = np.fft.fftfreq(len(input_signal_time_domain), 1 / fs) / 1e6
-
-    plt.figure(figsize=(10, 6))
-    half_R = R // 2
-    Denominator = R if R > 1 else 2
+    fs = 50e6  
+    # freq_axis = np.fft.fftfreq(len(input_signal_time_domain), 1/fs) / 1e6
+    freq_axis = np.fft.fftfreq(len(input_signal_time_domain), 1/fs)
+    
+    # plt.figure(figsize=(10, 6))
+    Denominator = R if R > 1 else 2  
     half_len = len(freq_axis) // Denominator
-    plt.plot(freq_axis[:half_len], np.abs(input_signal_frequency_response[:half_len]),
-             label='Input Signal Frequency Response')
-    plt.title('Input Signal Frequency Response')
-    plt.xlabel('Frequency (MHz)')
-    plt.ylabel('Magnitude')
-    plt.grid()
-    plt.legend()
-    plt.xlim(0, fs / (2 * 1e6))
-    plt.show()
+    # plt.plot(freq_axis[:half_len], np.abs(input_signal_frequency_response[:half_len]), label='Input Signal Frequency Response')
+    # plt.title('Input Signal Frequency Response')
+    # plt.xlabel('Frequency (MHz)')
+    # plt.ylabel('Magnitude')
+    # plt.grid()
+    # plt.legend()
+    # plt.xlim(0, fs/(2*1e6)) 
+    # # plt.show()
 
-    cic_filter_impulse_response = read_impulse_response(r'C:\S5243_FFT_REPO\src\src\Sim\ImpResp.txt')
+
+    cic_filter_impulse_response = read_impulse_response('C:\S5243_FFT_REPO\src\src\Sim\ImpResp1.txt')
     cic_filter_frequency_response = convert_to_frequency_domain(cic_filter_impulse_response)
-    # plot the frequency response of the CIC filter in dB
-    plt.figure(figsize=(10, 6))
-    plt.plot(freq_axis[:half_len], 20 * np.log10(np.abs(cic_filter_frequency_response[:half_len])),
-             label='CIC Filter Frequency Response (dB)')
-    # Show the current R   
-    plt.title(f'CIC Filter Frequency Response (R={R})')
-    plt.xlabel('Frequency (MHz)')
-    plt.ylabel('Magnitude (dB)')
-    plt.ylim(-300, 10)
-    plt.grid()
+
+    
+    # Получаем теоретическую частотную характеристику CIC фильтра ( весь диапазон)
+    theory_freq, theory_mag = get_theoretical_freq_resp(R, M, N, num_points=len(cic_filter_impulse_response), fs=fs)
+
+
+    plt.figure(figsize=(12, 8))
+
+    # Выделяем положительные частоты для теоретической АЧХ
+    mask_pos = theory_freq >= 0
+    theory_freq_pos = theory_freq[mask_pos]
+    theory_mag_pos = theory_mag[mask_pos]
+    
+    # Новая частота Найквиста после децимации
+    nyquist_new = fs/(2*R)
+
+      # Выделяем частоты для АЧХ после децимации только до новой частоты Найквиста
+    freq_after_dec = np.fft.fftfreq(len(cic_filter_impulse_response), d=1/fs*R)
+    resp_after_dec = cic_filter_frequency_response
+    mask_nyquist = (freq_after_dec >= 0) & (freq_after_dec <= nyquist_new)
+    freq_pos_after = freq_after_dec[mask_nyquist]
+    resp_pos_after = resp_after_dec[mask_nyquist]
+
+    db_theory = 20 * np.log10(np.maximum(theory_mag_pos, 1e-10))
+    plt.plot(theory_freq_pos, db_theory, 'r-', label='Теоретическая АЧХ (весь диапазон)')
+    plt.plot(freq_axis[:half_len], 20 * np.log10(np.abs(cic_filter_frequency_response[:half_len])), 'b-', linewidth=2, label='АЧХ после децимации')
+
+    # Отмечаем новую частоту Найквиста
+    plt.axvline(x=nyquist_new, color='k', linestyle=':',
+                label=f'Новая частота Найквиста ({nyquist_new/1e6:.2f} МГц)')
+    
+    # Затеняем область выше новой частоты Найквиста
+    plt.axvspan(nyquist_new, fs/2, alpha=0.2, color='gray',
+                label='Область наложения спектра (aliasing)')
+    plt.title(f'Сравнение частотных характеристик CIC-фильтра R={R}, D={M}, N={N}')
+    plt.xlabel('Частота [Гц]')
+    plt.ylabel('Амплитуда [дБ]')
+    plt.grid(True)
     plt.legend()
-    plt.xlim(0, fs / (2 * R * 1e6))
+    plt.xlim(0, fs/2)  # Отображаем только до fs/2
+    plt.ylim(-300, 10)
+    plt.tight_layout()
     plt.show()
 
+    # # 2nd stage CIC filter
+    # cic_filter_impulse_response_2nd = read_impulse_response('C:\S5243_FFT_REPO\src\src\Sim\ImpResp2.txt')
+    # cic_filter_frequency_response_2nd = convert_to_frequency_domain(cic_filter_impulse_response_2nd)
+    # # plot the frequency response of the CIC filter in dB
+    # plt.figure(figsize=(10, 6))
+    # plt.plot(freq_axis[:half_len], 20 * np.log10(np.abs(cic_filter_frequency_response_2nd[:half_len])), label='CIC Filter Frequency Response 2nd Stage (dB)')
+    # plt.title(f'CIC Filter Frequency Response 2nd Stage (R={np.cbrt(R)*np.cbrt(R)})')
+    # plt.xlabel('Frequency (MHz)')
+    # plt.ylabel('Magnitude (dB)')
+    # plt.ylim(-300, 10)
+    # plt.grid()
+    # plt.legend()
+    # plt.xlim(0, fs/(2*(np.cbrt(R)**2)*1e6))
+    # plt.show()
+
+    # # 3rd stage CIC filter
+    # cic_filter_impulse_response_3rd = read_impulse_response('C:\S5243_FFT_REPO\src\src\Sim\ImpResp3.txt')
+    # cic_filter_frequency_response_3rd = convert_to_frequency_domain(cic_filter_impulse_response_3rd)
+    # # plot the frequency response of the CIC filter in dB
+    # plt.figure(figsize=(10, 6))
+    # plt.plot(freq_axis[:half_len], 20 * np.log10(np.abs(cic_filter_frequency_response_3rd[:half_len])), label='CIC Filter Frequency Response 3rd Stage (dB)')
+    # plt.title(f'CIC Filter Frequency Response 3rd Stage (R={R})')
+    # plt.xlabel('Frequency (MHz)')
+    # plt.ylabel('Magnitude (dB)')
+    # plt.ylim(-400, 10)
+    # plt.grid()
+    # plt.legend()
+    # plt.xlim(0, fs/(2*R*1e6))
+    # plt.show()
+
     # fir_filter_impulse_response = read_impulse_response('C:\S5243_FFT_REPO\src\src\Sim\AfterFir.txt')
     # fir_filter_frequency_response = convert_to_frequency_domain(fir_filter_impulse_response)
     # # plot the frequency response of the FIR filter in dB
@@ -116,48 +251,45 @@ def main():
     # plt.xlim(0, fs/(2*R*1e6))
     # plt.show()
 
-    fir_comp_resp = read_impulse_response(r'C:\S5243_FFT_REPO\src\src\Sim\FirFilt.txt')
+    fir_comp_resp = read_impulse_response('C:\S5243_FFT_REPO\src\src\Sim\FirFilt.txt')
     # Plot in time domain
-    plt.figure(figsize=(10, 6))
-    plt.plot(fir_comp_resp, label='FIR Compensator Impulse Response')
-    plt.title('FIR Compensator Impulse Response')
-    plt.xlabel('Sample Index')
-    plt.ylabel('Amplitude')
-    plt.grid()
-    plt.legend()
-    plt.xlim(0, len(fir_comp_resp))
-    plt.show()
+    # plt.figure(figsize=(10, 6))
+    # plt.plot(fir_comp_resp, label='FIR Compensator Impulse Response')
+    # plt.title('FIR Compensator Impulse Response')
+    # plt.xlabel('Sample Index')
+    # plt.ylabel('Amplitude')
+    # plt.grid()
+    # plt.legend()
+    # plt.xlim(0, len(fir_comp_resp))
+    # plt.show()
 
     # After FIR time domain
-    after_fir_resp = read_impulse_response(r'C:\S5243_FFT_REPO\src\src\Sim\AfterFir.txt')
-    plt.figure(figsize=(10, 6))
-    plt.plot(after_fir_resp, label='After FIR Impulse Response')
-    plt.title('After FIR Impulse Response')
-    plt.xlabel('Sample Index')
-    plt.ylabel('Amplitude')
-    plt.grid()
-    plt.legend()
-    plt.xlim(0, len(after_fir_resp))
-    plt.show()
+    after_fir_resp = read_impulse_response('C:\S5243_FFT_REPO\src\src\Sim\AfterFir.txt')
+    # plt.figure(figsize=(10, 6))
+    # plt.plot(after_fir_resp, label='After FIR Impulse Response')
+    # plt.title('After FIR Impulse Response')
+    # plt.xlabel('Sample Index')
+    # plt.ylabel('Amplitude')
+    # plt.grid()
+    # plt.legend()
+    # plt.xlim(0, len(after_fir_resp))
+    # plt.show()
     # Plot the frequency response of the FIR compensator
     fir_compensation_response = convert_to_frequency_domain(after_fir_resp)
     plt.figure(figsize=(10, 6))
-    plt.plot(freq_axis[:half_len], 20 * np.log10(np.abs(fir_compensation_response[:half_len])),
-             label='FIR Compensation Frequency Response (dB)')
+    plt.plot(freq_axis[:half_len], 20 * np.log10(np.abs(fir_compensation_response[:half_len])), label='FIR Compensation Frequency Response (dB)')
+    # Plot the original CIC filter frequency response for comparison
+    plt.plot(freq_axis[:half_len], 20 * np.log10(np.abs(cic_filter_frequency_response[:half_len])), 'b-', linewidth=2, label='АЧХ после децимации')
     plt.title('FIR Compensation Frequency Response')
-    plt.xlabel('Frequency (MHz)')
+    plt.xlabel('Frequency (Hz)')
     plt.ylabel('Magnitude (dB)')
-    plt.ylim(-300, 10)
+    plt.ylim(-100, 10)
     plt.grid()
     plt.legend()
-    plt.xlim(0, fs / (2 * R * 1e6))
+    plt.xlim(0, fs/(2*R))
     plt.show()
-
-    # # FIR compensation filter
-    # Order = 64  # FIR filter order
-    # fir_compensation_response = fir_compensation_filt(cic_filter_frequency_response, Order)
-    # print("FIR compensation filter created successfully.")
-
-
+  
+    
 if __name__ == "__main__":
     main()
+

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1280 - 512
src/src/Sim/ImpResp.txt


+ 512 - 0
src/src/Sim/ImpResp1.txt

@@ -0,0 +1,512 @@
+ 2559
+ 5119
+  511
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0
+    0

+ 0 - 512
src/src/Sim/ImpResp2.txt

@@ -1,512 +0,0 @@
-              163820
-              982920
-             2981524
-             6683856
-            12614140
-            21296600
-            33255460
-            49014944
-            69099276
-            94032680
-           124339380
-           160543600
-           202514284
-           248809816
-           297857524
-           348084736
-           397918780
-           445786984
-           490116676
-           529335184
-           561869836
-           586147960
-           600596884
-           603643936
-           594699364
-           575139256
-           546536284
-           510463120
-           468492436
-           422196904
-           373149196
-           322921984
-           273087940
-           225219736
-           180890044
-           141671536
-           108481604
-            80927080
-            58483740
-            40627360
-            26833716
-            16578584
-             9337740
-             4586960
-             1802020
-              458696
-               32764
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0
-                   0

+ 0 - 0
src/src/Sim/ImpResp3.txt


+ 64 - 32
src/src/Sim/fir_filter.coe

@@ -1,35 +1,67 @@
 Radix = 10;
 Coefficient_Width = 16;
 Coefdata =
--3.146938e-03,
--1.637730e-02,
-9.263435e-02,
-5.488382e-02,
--1.063949e+00,
-1.545263e+00,
-3.364367e+00,
--1.015506e+01,
--7.154154e+00,
-5.911076e+01,
--6.070495e+01,
--1.009447e+02,
-2.094813e+02,
-5.751169e+02,
--3.197977e+03,
-6.421861e+03,
-6.421861e+03,
--3.197977e+03,
-5.751169e+02,
-2.094813e+02,
--1.009447e+02,
--6.070495e+01,
-5.911076e+01,
--7.154154e+00,
--1.015506e+01,
-3.364367e+00,
-1.545263e+00,
--1.063949e+00,
-5.488382e-02,
-9.263435e-02,
--1.637730e-02,
--3.146938e-03;
+5.902131e-04,
+-8.181819e-04,
+-1.730631e-03,
+5.991654e-03,
+3.975577e-04,
+-4.240916e-02,
+1.319543e-01,
+-2.222310e-01,
+2.000909e-01,
+1.092495e-02,
+-2.776451e-01,
+2.309313e-01,
+3.412163e-01,
+-8.692632e-01,
+-1.397466e-01,
+3.980868e+00,
+-9.698724e+00,
+1.318560e+01,
+-9.600546e+00,
+-1.220238e+00,
+1.113542e+01,
+-8.018406e+00,
+-1.053346e+01,
+2.346819e+01,
+1.133012e+01,
+-1.279204e+02,
+3.043196e+02,
+-4.255645e+02,
+2.876855e+02,
+3.435104e+02,
+-1.635723e+03,
+3.260626e+03,
+3.260626e+03,
+-1.635723e+03,
+3.435104e+02,
+2.876855e+02,
+-4.255645e+02,
+3.043196e+02,
+-1.279204e+02,
+1.133012e+01,
+2.346819e+01,
+-1.053346e+01,
+-8.018406e+00,
+1.113542e+01,
+-1.220238e+00,
+-9.600546e+00,
+1.318560e+01,
+-9.698724e+00,
+3.980868e+00,
+-1.397466e-01,
+-8.692632e-01,
+3.412163e-01,
+2.309313e-01,
+-2.776451e-01,
+1.092495e-02,
+2.000909e-01,
+-2.222310e-01,
+1.319543e-01,
+-4.240916e-02,
+3.975577e-04,
+5.991654e-03,
+-1.730631e-03,
+-8.181819e-04,
+5.902131e-04;

+ 34 - 0
src/src/Sim/fir_filter.h

@@ -0,0 +1,34 @@
+const int BL = 32;
+const int B[32] = {
+-9.325184e-03,
+4.885275e-02,
+-9.718188e-02,
+-2.924006e-02,
+5.441013e-01,
+-7.251412e-01,
+-1.600419e+00,
+5.523508e+00,
+3.851040e+00,
+-5.909314e+01,
+1.809315e+02,
+-3.101968e+02,
+2.457609e+02,
+3.297557e+02,
+-1.695513e+03,
+3.510809e+03,
+3.510809e+03,
+-1.695513e+03,
+3.297557e+02,
+2.457609e+02,
+-3.101968e+02,
+1.809315e+02,
+-5.909314e+01,
+3.851040e+00,
+5.523508e+00,
+-1.600419e+00,
+-7.251412e-01,
+5.441013e-01,
+-2.924006e-02,
+-9.718188e-02,
+4.885275e-02,
+-9.325184e-03}

+ 35 - 0
src/src/Sim/fir_filter_R2.coe

@@ -0,0 +1,35 @@
+Radix = 10;
+Coefficient_Width = 16;
+Coefdata =
+-2.360203e-03,
+-1.246831e-02,
+7.268234e-02,
+2.680373e-02,
+-7.712644e-01,
+1.155299e+00,
+2.577891e+00,
+-8.226315e+00,
+-3.585454e+00,
+4.242981e+01,
+-4.577083e+01,
+-8.042295e+01,
+1.999567e+02,
+3.214466e+02,
+-2.441875e+03,
+6.421861e+03,
+6.421861e+03,
+-2.441875e+03,
+3.214466e+02,
+1.999567e+02,
+-8.042295e+01,
+-4.577083e+01,
+4.242981e+01,
+-3.585454e+00,
+-8.226315e+00,
+2.577891e+00,
+1.155299e+00,
+-7.712644e-01,
+2.680373e-02,
+7.268234e-02,
+-1.246831e-02,
+-2.360203e-03;

+ 35 - 0
src/src/Sim/fir_filter_R4.coe

@@ -0,0 +1,35 @@
+Radix = 10;
+Coefficient_Width = 16;
+Coefdata =
+-9.325184e-03,
+4.885275e-02,
+-9.718188e-02,
+-2.924006e-02,
+5.441013e-01,
+-7.251412e-01,
+-1.600419e+00,
+5.523508e+00,
+3.851040e+00,
+-5.909314e+01,
+1.809315e+02,
+-3.101968e+02,
+2.457609e+02,
+3.297557e+02,
+-1.695513e+03,
+3.510809e+03,
+3.510809e+03,
+-1.695513e+03,
+3.297557e+02,
+2.457609e+02,
+-3.101968e+02,
+1.809315e+02,
+-5.909314e+01,
+3.851040e+00,
+5.523508e+00,
+-1.600419e+00,
+-7.251412e-01,
+5.441013e-01,
+-2.924006e-02,
+-9.718188e-02,
+4.885275e-02,
+-9.325184e-03;

+ 35 - 0
src/src/Sim/fir_filter_R8.coe

@@ -0,0 +1,35 @@
+Radix = 10;
+Coefficient_Width = 16;
+Coefdata =
+9.640316e-03,
+-5.915316e-02,
+1.456592e-01,
+6.202407e-02,
+-1.840147e+00,
+7.272651e+00,
+-1.600982e+01,
+1.846701e+01,
+8.268907e+00,
+-8.941747e+01,
+2.190460e+02,
+-3.187659e+02,
+2.207680e+02,
+2.900723e+02,
+-1.369590e+03,
+2.680038e+03,
+2.680038e+03,
+-1.369590e+03,
+2.900723e+02,
+2.207680e+02,
+-3.187659e+02,
+2.190460e+02,
+-8.941747e+01,
+8.268907e+00,
+1.846701e+01,
+-1.600982e+01,
+7.272651e+00,
+-1.840147e+00,
+6.202407e-02,
+1.456592e-01,
+-5.915316e-02,
+9.640316e-03;

+ 252 - 0
src/src/Sim/test_cic.m

@@ -0,0 +1,252 @@
+%% ------------------------------------------------------------------------
+%
+% Title       : test_cic.m
+% Author      : Alexander Kapitanov
+% E-mail      : sallador@bk.ru 
+% Version     : 1.0	 
+%
+% -------------------------------------------------------------------------
+%
+% Description : 
+% 
+%    FIR filter compensator to correct freq response after CIC filter.
+%
+% -------------------------------------------------------------------------
+%
+% Version     : 1.0 
+% Date        : 2017.06.03 
+%
+%% ------------------------------------------------------------------------
+%
+%	GNU GENERAL PUBLIC LICENSE
+% Version 3, 29 June 2007
+%
+%	Copyright (c) 2018 Kapitanov Alexander
+%
+% This program is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program.  If not, see <http://www.gnu.org/licenses/>.
+%
+% THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+% APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 
+% HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 
+% OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 
+% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
+% PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 
+% IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 
+%  ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 
+%
+%% ------------------------------------------------------------------------
+  
+set(0, 'DefaultAxesFontSize', 11, 'DefaultAxesFontName', 'Times New Roman');
+set(0, 'DefaultTextFontSize', 11, 'DefaultTextFontName', 'Times New Roman'); 
+
+close all;
+clear all;
+
+%% ------------------------------------------------------------------------
+%  ---- CIC Filter Parameters
+%  ------------------------------------------------------------------------
+
+R = 4;         % Decimation factor
+N = 4;         % Number of stages
+M = 1;         % Differential delay (only 1)
+
+%% ------------------------------------------------------------------------
+%  ---- FIR filter parameters
+%  ------------------------------------------------------------------------
+
+NFIR  = 64;     % Filter order, must be odd when Fo = 0.5 !!!
+Bc    = 16;     % Coef. Bit-width
+Fo    = 0.4;    % Normalized Cutoff: 0.2 < Fo < 0.5;
+BETA  = 8;      % BETA parameter for Kaiser window (if IS_WIND = 'Y') 
+
+%% ------------------------------------------------------------------------
+%  ---- Save data parameters
+%  ------------------------------------------------------------------------
+
+IS_COE      = 'Y'; % create *.COE Xilinx file
+IS_HDR      = 'N'; % create *.H file (header)
+IS_WIND     = 'Y'; % use Kaiser Window for FIR corrector
+
+IS_PLOT_IDL = 'N'; % plot ideal response
+IS_PLOT_FIR = 'N'; % plot FIR filter IR
+IS_PLOT_ERR = 'Y'; % plot total error response in passband
+
+%% ------------------------------------------------------------------------
+%  ---- CIC Compensator Design
+%  ------------------------------------------------------------------------
+
+NFFT  = 2^16;  % FFT points for Freq Response (spectrum)
+STEP = 1/NFFT;   % Step size
+w = -pi:2*pi/NFFT:pi-2*pi/NFFT;
+ff = 0:1/NFFT:1-1/NFFT;
+z = exp(1j * w);
+
+Fc = 1/(2*R);
+Fr = Fo/R;
+
+% 1 way:
+%HCIC = (1/R * (1-z.^(-R*M))./(1-z.^(-1))).^ N;
+% 2 way:
+HCIC = (R^-N*abs(1*M*sin(pi*M*R*ff) ./ sin(pi*ff)).^N);
+HCICdb = 20 * log10(abs(HCIC));
+
+fp = [0:STEP:Fo]; % Pass band frequency dots
+fs = [(Fo+STEP):STEP:0.5]; % Stop band frequency dots
+f = [fp fs]*2; % Normalized frequency dots
+f(end) = 1;
+
+% Calculate ideal response
+Mp = ones(1, length(fp)); % Pass band response; Mp(1) = 1
+Mp(2:end) = abs(M * R * sin(pi*fp(2:end)/R) ./ sin(pi*M*fp(2:end))).^(N);
+Mf = [Mp zeros(1, length(fs))];
+
+if (IS_PLOT_IDL == 'Y') 
+  figure('name','FIR Ideal Response', 'Numbertitle', 'off')
+    plot(f/2, Mf, '-.', 'LineWidth', 2, 'Color',[0 0 1]);
+
+    title([{'FIR Ideal Response'};{sprintf('Fo = %i',Fo)}]);
+    xlabel ('Freq (\pi x rad / samples)');
+    ylabel ('Magnitude');  
+    axis tight; 
+    legend([{sprintf('Fo = %i',Fo)}]);  
+    grid on;  
+end
+
+% Calculate FIR
+hFIR = fir2(NFIR-1, f, Mf); % Filter length NFIR
+hFIR = hFIR / max(hFIR); % Double coefficients
+hCOE = round(hFIR*(2^(Bc-1)-1)); % Fixed point coefficients
+
+% Windowed FIR (Kaiser with BETA) 
+if (IS_WIND == 'Y')
+  WIND = kaiser(NFIR, BETA); % KAISER WINDOW IS USED!
+  hWIND = fir1(NFIR-1, Fo/R, 'low', WIND);
+  hNEW = hCOE .* hWIND;% conv2(hCOE,Hwind);
+  hCOE = hNEW;
+end
+
+if (IS_PLOT_FIR == 'Y')   
+  figure('name','FIR Response', 'Numbertitle', 'off')
+    plot(hFIR, '-', 'LineWidth', 2, 'Color',[1 0 0]);
+
+    title([{'FIR Response'};{sprintf('Order = %i',NFIR)}]);
+    xlabel ('Samples');
+    ylabel ('Magnitude');  
+    axis tight; 
+    legend([{sprintf('Order = %i',NFIR)}]);    
+    grid on;   
+end
+
+hFFT = 20 * log10(abs(fft(hCOE, ceil(NFFT/R))));
+hFFT = hFFT - max(hFFT);
+
+H_amp = repmat(hFFT, 1, R);
+H_amp = H_amp(1:length(ff));
+H_amp = H_amp - max(H_amp);
+
+H_comp = HCICdb + H_amp;
+H_comp = H_comp - max(H_comp);
+
+%% ------------------------------------------------------------------------
+%  ---- Plot results 
+%  ------------------------------------------------------------------------
+
+% ---- Figure #1
+figure('name','CIC/FIR Frequency Response', 'Numbertitle', 'off')
+  plot(ff, HCICdb - max(HCICdb), '-.', 'LineWidth', 2, 'Color',[0 0 1]);
+  hold on;
+
+  plot(ff, H_amp, '--', 'LineWidth', 2, 'Color',[0 0.4 0]);
+  hold on;
+  
+  plot(ff, H_comp, '-', 'LineWidth', 2, 'Color',[1 0 0]);
+  hold on;  
+  
+  title([{'CIC, Comp. FIR and Result'};{sprintf('Filter Order = %i, Coef. width = %i',NFIR,Bc)}]);
+  xlabel ('Freq (\pi x rad / samples)');
+  ylabel ('Magnitude (dB)');  
+  axis([0 ff(NFFT)/2 -100 5]); 
+  line([Fr Fr], [-400 200], 'LineWidth', 1, 'linestyle', '--', 'Color', [0 0 0]);  
+  line([Fc Fc], [-400 200], 'LineWidth', 1, 'linestyle', '--', 'Color', [0 0 0]);
+  line([2*Fc 2*Fc], [-400 200], 'LineWidth', 1, 'linestyle', '--', 'Color', [0 0 0]);  
+  legend('CIC filter','Comp. FIR','Sum Response','location','northeast');
+  grid on;  
+  
+% ---- Figure #2
+figure('name', 'CIC/FIR Frequency Response (Zoom)', 'Numbertitle', 'off')
+  plot(ff, HCICdb - max(HCICdb), '-.', 'LineWidth', 2, 'Color',[0 0 1]); 
+  hold on;
+
+  plot(ff, H_amp, '--', 'LineWidth', 2, 'Color',[0 0.4 0]); 
+  hold on;
+  
+  plot(ff, H_comp, '-', 'LineWidth', 2, 'Color',[1 0 0]);
+  hold on; 
+
+  title([{'CIC, Comp. FIR and Result'};{sprintf('Filter Order = %i, Coef. width = %i',NFIR,Bc)}]);
+  xlabel ('Freq (\pi x rad / samples)');
+  ylabel ('Magnitude (dB)'); 
+  axis([0 ff(NFFT)/(2*R) -7 1]);    
+  line([Fr Fr], [-400 200], 'LineWidth', 1, 'linestyle', '--', 'Color', [0 0 0]);  
+  grid on;  
+  
+%% ------------------------------------------------------------------------
+% ---- Passband irregularity
+%  ------------------------------------------------------------------------  
+if (IS_PLOT_ERR == 'Y')  
+  pass = ceil(0.85*length(H_comp)*Fr);
+  stp = 0:(0.9*Fr)/pass:(0.9*Fr)-(0.9*Fr)/pass;
+  stp = stp(2:pass);
+  Irr = H_comp(2:pass);
+  Ism = mean(Irr);
+  Iav = (max(Irr)-min(Irr))/2;
+  
+  figure('name', 'Passband irregularity', 'Numbertitle', 'off')
+    plot(stp, Irr, '--', 'LineWidth', 2, 'Color',[0 0 1]); 
+    line([0 (0.9*Fr)], [Ism Ism], 'LineWidth', 2, 'linestyle', '-', 'Color', [0 0 0]);   
+    grid on;  
+    title([{'Passband irregularity'};{sprintf('Mean value = %f',Ism)};{sprintf('Freq error = %f (dB)',Iav)}]);
+    xlabel ('Freq (\pi x rad / samples)');
+    ylabel ('Magnitude (dB)'); 
+    axis tight;    
+    %axis([0 ff(NFFT)/(2*R) -0.05 1]);
+end
+
+%% ------------------------------------------------------------------------
+%  ---- Save coe data to files
+%  ------------------------------------------------------------------------  
+if (IS_COE == 'Y') 
+  fid = fopen ('fir_filter.coe', 'w');
+  fprintf(fid, 'Radix = 10;\n');
+  fprintf(fid, 'Coefficient_Width = %d;\n', Bc);
+  fprintf(fid, 'Coefdata =\n');
+  for i = 1:NFIR
+    if (i == NFIR)
+      fprintf(fid, '%d;\n', hCOE(1,i));
+    else
+      fprintf(fid, '%d,\n', hCOE(1,i));
+    end
+  end
+  fclose(fid);
+end
+
+if (IS_HDR == 'Y') 
+  fid = fopen ('fir_filter.h', 'w');
+  fprintf(fid, 'const int BL = %d;\n',  NFIR);
+  fprintf(fid, 'const int B[%d] = {\n', NFIR);
+  for i = 1:NFIR
+    if (i == NFIR)
+      fprintf(fid, '%d}\n', hCOE(1,i));
+    else
+      fprintf(fid, '%d,\n', hCOE(1,i));
+    end
+  end
+  fclose(fid);
+end
+  

+ 96 - 116
src/src/Sim/СicFilter.py

@@ -48,147 +48,127 @@ class CICFilter:
     
 
     
-    def get_filter_freq_resp(self, num_points=1024, is_cascade=False, num_filters=1):
+    def get_filter_freq_resp(self, num_points=1024, is_cascade=False, num_filters=1, show_before_decimation=False):
         # Подаём дельта-функцию на вход фильтру
         impulse = np.zeros(num_points)
         impulse[0] = 1.0  # Дельта-функция
-        if is_cascade:
-            output_signal = self.cascade_multiple_cic_filters(impulse, num_filters)
+
+        if show_before_decimation:
+            # Получаем только характеристику интеграторов без децимации и Comb-фильтров
+            output_signal = np.copy(impulse)
+            for _ in range(num_filters):
+                output_signal = self.integrate(output_signal)
         else:
-            output_signal = self.filter(impulse)
+            # Стандартная реализация - полный CIC фильтр с децимацией
+            if is_cascade:
+                output_signal = self.cascade_multiple_cic_filters(impulse, num_filters)
+            else:
+                output_signal = self.filter(impulse)
+
+        # Дополняем выходной сигнал нулями до исходной длины
+        if len(output_signal) < num_points:
+            padded_output = np.zeros(num_points)
+            padded_output[:len(output_signal)] = output_signal
+            output_signal = padded_output
+
         # Вычисляем частотную характеристику с помощью БПФ
         freq_response = np.fft.fft(output_signal, num_points)
+
         # Нормализуем частотную характеристику
         freq_response /= np.max(np.abs(freq_response))
-        # Создаем массив частот
-        if is_cascade:
-            freq = np.fft.fftfreq(num_points, d=1/(50e6/self.decimation_factor * num_filters))
-        else:
-            freq = np.fft.fftfreq(num_points, d=1/(50e6/self.decimation_factor))
+
+        # Создаем массив частот с исходной частотой дискретизации fs=50e6
+        fs = 50e6
+        freq = np.fft.fftfreq(num_points, d=1/fs*self.decimation_factor)
+
         # Возвращаем частоты и амплитуду частотной характеристики
         return freq, np.abs(freq_response)
     
-    # # Calculate coefficients for the FIR filter to compensate the CIC frequency response
-    # def get_compensation_coefficients(self, cic_freq_response, target_freq_response):
-
-    def calculate_fir_compensator_coeffs(self, cic_freq_response, order, fs=50e6, compensation_factor=0.95):
-        """
-        Synthesizes FIR compensator coefficients for the CIC filter
-        
-        Args:
-            cic_freq_response: frequency response of the CIC filter
-            order: order of the compensator filter
-            fs: sampling frequency in Hz
-            compensation_factor: degree of compensation (0-1)
-        """
-        # Create ideal frequency response for the compensator filter
-        half_len = len(cic_freq_response) // 2
-        desired_response = np.ones(len(cic_freq_response), dtype=complex)
-        
-        # Define passband edge up to which compensation is needed (approximately 0.4*fs/R)
-        passband_edge = int(0.4 * half_len)
-        
-        # Apply compensation only in the passband
-        min_magnitude = 1e-12
-        for i in range(passband_edge):
-            if np.abs(cic_freq_response[i]) > min_magnitude:
-                desired_response[i] = (1.0 / cic_freq_response[i]) ** compensation_factor
-            else:
-                desired_response[i] = (1.0 / min_magnitude) ** compensation_factor
-        
-        # Symmetry for real filter
-        for i in range(1, passband_edge):
-            desired_response[len(cic_freq_response) - i] = np.conj(desired_response[i])
-        
-           # Get impulse response
-        imp_resp = np.real(np.fft.ifft(desired_response))
+    def get_theoretical_freq_resp(self, num_points=1024, fs=50e6):
+        freq = np.fft.fftfreq(num_points, d=1/fs)
+
+        # Вычисляем нормализованные частоты
+        f_norm = np.abs(freq) / fs
+
+        # Расчет по формуле
+        R = self.decimation_factor
+        M = self.delay
+        N = self.order
 
-        # Center and trim to the required length
-        imp_resp = np.roll(imp_resp, -len(imp_resp) // 2)[:order + 1]
+        # Избегаем деления на ноль при f=0
+        mag = np.ones(num_points)
+        nonzero = f_norm != 0
 
-        # Apply window function
-        window = np.hamming(len(imp_resp))
-        imp_resp = imp_resp * window
+        # Угол для sin(π*f*R*M)
+        angle_num = np.pi * f_norm[nonzero] * R * M
+        # Угол для sin(π*f*M)
+        angle_den = np.pi * f_norm[nonzero] 
 
-        # Normalize for unity gain
-        imp_resp /= np.sum(imp_resp)
+        # |H(f)| = |sin(π*f*R*M)/(R*sin(π*f*M))|^N
+        mag[nonzero] = np.abs(np.sin(angle_num) / ( np.sin(angle_den))) ** N
 
-        return imp_resp
+        # Нормализуем амплитудную характеристику
+        mag /= np.max(mag)
 
+        return freq, mag
 
 
 def main():
-    decimation_factor = 10
-    delay = 2*decimation_factor
+    decimation_factor = 4
+    delay = 2
     order = 4
-    num_samples = 100
-    # Input signal - multiplication of a 3 MHz sine and 6 MHz sine
+    num_samples = 10000
     fs = 50e6  # Sampling frequency
-    f1 = 7e6  # Frequency of first sine wave
-    f2 = 3e6  # Frequency of second sine wave
-    t = np.arange(num_samples) / fs
-    input_signal = (np.sin(2 * np.pi * f1 * t) * np.sin(2 * np.pi * f2 * t))
-    # Plot the input signal in the frequency domain
-    plt.figure(figsize=(10, 6))
-    plt.magnitude_spectrum(input_signal, Fs=fs, scale='dB', color='C0')
-    plt.title('Input Signal in Frequency Domain')
-    plt.xlabel('Frequency [Hz]')
-    plt.ylabel('Magnitude [dB]')
-    plt.grid()
-    plt.tight_layout()
-    plt.show()
-    # Create CIC filter instance
+    
+    # Создаем CIC фильтр
     cic_filter = CICFilter(decimation_factor, delay, order)
-    # Filter the input signal
-    output_signal = cic_filter.cascade_multiple_cic_filters(input_signal, 1)
-    # Plot the output signal in the frequency domain
-    plt.magnitude_spectrum(output_signal, Fs=fs/decimation_factor, scale='dB', color='C1')
-    plt.title('Output Signal in Frequency Domain')
-    plt.xlabel('Frequency [Hz]')
-    plt.ylabel('Magnitude [dB]')
-    plt.grid()
-    plt.tight_layout()
-    plt.show()
-    # Get frequency response of the CIC filter
-    freq, freq_response = cic_filter.get_filter_freq_resp(is_cascade=False, num_filters=1)
-    # Plot the frequency response
-    plt.figure(figsize=(10, 6))
-    # Normalize frequency axis to 1
-    freq_normalized = freq[:len(freq)//2]
-    plt.plot(freq_normalized, 20 * np.log10(freq_response[:len(freq)//2]), label='CIC Filter Frequency Response (Normalized)')
-    plt.title('CIC Filter Frequency Response')
-    plt.xlabel('Frequency [Hz]')
-    plt.ylabel('Magnitude [dB]')
-    plt.grid()
+    
+    # Получаем теоретическую АЧХ (весь диапазон)
+    theory_freq, theory_mag = cic_filter.get_theoretical_freq_resp(num_points=2048, fs=fs)
+    
+    # Получаем АЧХ после децимации
+    freq_after_dec, resp_after_dec = cic_filter.get_filter_freq_resp( num_points=2048, is_cascade=False, num_filters=1)
+    
+    # Строим график
+    plt.figure(figsize=(12, 8))
+    
+    # Выделяем положительные частоты для теоретической АЧХ
+    mask_pos = theory_freq >= 0
+    theory_freq_pos = theory_freq[mask_pos]
+    theory_mag_pos = theory_mag[mask_pos]
+    
+    # Новая частота Найквиста после децимации
+    nyquist_new = fs/(2*decimation_factor)
+    
+    # Выделяем частоты для АЧХ после децимации только до новой частоты Найквиста
+    mask_nyquist = (freq_after_dec >= 0) & (freq_after_dec <= nyquist_new)
+    freq_pos_after = freq_after_dec[mask_nyquist]
+    resp_pos_after = resp_after_dec[mask_nyquist]
+    
+    # Преобразуем в дБ с защитой от нуля
+    db_theory = 20 * np.log10(np.maximum(theory_mag_pos, 1e-10))
+    db_after = 20 * np.log10(np.maximum(resp_pos_after, 1e-10))
+    plt.plot(theory_freq_pos, db_theory, 'r-', label='Теоретическая АЧХ (весь диапазон)')
+    plt.plot(freq_pos_after, db_after, 'b-', linewidth=2, label='АЧХ после децимации')
+    
+    # Отмечаем новую частоту Найквиста
+    plt.axvline(x=nyquist_new, color='k', linestyle=':', 
+                label=f'Новая частота Найквиста ({nyquist_new/1e6:.2f} МГц)')
+    
+    # Затеняем область выше новой частоты Найквиста
+    plt.axvspan(nyquist_new, fs/2, alpha=0.2, color='gray', 
+                label='Область наложения спектра (aliasing)')
+    
+    plt.title(f'Сравнение частотных характеристик CIC-фильтра R={decimation_factor}, D={delay}, N={order}')
+    plt.xlabel('Частота [Гц]')
+    plt.ylabel('Амплитуда [дБ]')
+    plt.grid(True)
     plt.legend()
+    plt.xlim(0, fs/2)  # Отображаем только до fs/2
+    plt.ylim(-300, 10)
     plt.tight_layout()
     plt.show()
-
-    # # Calculate FIR compensator coefficients
-    # fir_coeffs = cic_filter.calculate_fir_compensator_coeffs(freq_response, 64, fs=fs, compensation_factor=0.95)
-
-    # fir_freq_response = np.fft.fft(fir_coeffs, len(freq_response))
-    # plt.figure(figsize=(10, 6))
-    # plt.plot(freq_normalized, 20 * np.log10(np.abs(fir_freq_response[:len(freq)//2])), label='FIR Compensator Frequency Response (Normalized)')
-    # plt.title('FIR Compensator Frequency Response')
-    # plt.xlabel('Frequncy [Hz]')
-    # plt.ylabel('Magnitugde [dB]')
-    # plt.grid()
-    # plt.tight_layout()
-    # plt.show()
-
-    # # Final Response 
-    # final_response = fir_freq_response * freq_response
-    # plt.figure(figsize=(10, 6))
-    # plt.plot(freq_normalized, 20 * np.log10(np.abs(final_response[:len(freq)//2])), label='Final Response (CIC + FIR Compensator)')
-
-    # plt.title('Final Response of CIC Filter with FIR Compensator')
-    # plt.xlabel('Frequency [Hz]')
-    # plt.ylabel('Magnitude [dB]')
-    # plt.grid()
-    # plt.legend()
-    # plt.tight_layout()
-    # plt.show()
+ 
     
 if __name__ == "__main__":
     main()