تطوير SDR متعدد القنوات

سأخبرك عن تجربتي في تطوير جهاز استقبال رقمي متعدد القنوات.

لقد عملت لسنوات عديدة في مجال إنشاء وسائل لالتقاط ومعالجة الإشارات من رادارات الملاحة المحمولة جواً والساحلية. منذ حوالي عامين ، أصدرت أحدث إصدار حتى الآن من لوحة RVAQ (Radar Video AcQuisition) وتساءلت ماذا أفعل بعد ذلك في الحياة. كنت أرغب في شيء جديد وغير معروف. وقع الاختيار على المنطقة التي لم أقم بتغطيتها بعد - الراديو الرقمي مع سهولة الدخول إلى منطقة الميكروويف.

هذا هو الفصل الأول المخصص للصياغة الأولية للمشكلة.

من أين تبدأ إذا لم تكن مهنيًا أبدًا في استقبال الراديو الرقمي ، باستثناء جهاز استقبال Mishutka الذي تم تجميعه في مرحلة الطفولة؟ بالطبع ، مع المرطبات في قراءة Polyakov والنموذج في MATLAB. كانت الفكرة الأولية هي إنشاء جهاز استقبال متعدد القنوات في النطاق 156-162 MHz لمراقبة وتسجيل جميع المحادثات النشطة في نطاق VHF البحري.
وسأذكر الخصائص المطلوبة لهذا المستقبِل: 1. نطاق الاستقبال لا يقل عن MHz 6 (162-156 = 6)
2. الحساسية ليست أسوأ من 110 dBm ، وإلا فإنها تضحك.
3. نطاق ديناميكي كبير ، حيث عندما تستمع إلى سفينة على الشاطئ في البحر لمسافة 30 ميلًا ، سيصرخ شخص ما بالتأكيد في مكان قريب ب 25 وات. بالنسبة للمستقبلات اللائقة ، يجب أن يكون مستوى الحظر 70dB على الأقل. بسير إلى الأمام قليلاً ، سأقول أنه اتضح تحقيق أكثر من 90 ديسيبل من الحظر. باختصار ، لم تلب RTL-SDR بقوة التوقعات. غريب كما قد يبدو ، لقد بدأت باختيار ADC. نظرًا لأنه في الطبيعة لا توجد ADC مقابلة (على الأقل نظريًا) ، فإنه لا يستحق أخذها. تم العثور على هذا ADC .

تحتاج الآن إلى اختيار بنية جهاز الاستقبال. مراجعة للحلول ذات الصلة ، دراسة قاعدة العنصر والحدس جعلت من الممكن التفكير في مستقبل التحويل المباشر. كما تقرر نقل المنطقة ذات الأهمية من الطيف باستخدام مزيل التربيع التربيعي إلى تردد صفر والعمل في منطقة Nyquist الأولى من أجل الاستفادة القصوى من جميع صفات ADC المحددة.

النموذج الأولي لتقدير المعلمات
clear all;
k				= 1.381e-23;	% Joule/K 	- Boltzmann's Constant
T0				= 290;			% K			- temperature
% Encoding Windows-1251

% 1.     
% 1010          -       
% 1011          -    
% 1012          -     (/.)
% 1013          -      
% 1014          -      
% 1015          -    
% 1021, 1022    -     .
% 1031, 1032    -    
% 1041, 1042    -      
% 1051, 1052    -   

% 2.            

		Rrf_inp_ohm			= 50;		% Ohm	- 	 .

% 2011  -    
        BWrf_ekv_prf_hz   	= 20.0e6;   % Hz	-	    
        Lrf_max_prf_db      =  1.0;     % dB 	- 	        (insertion loss)
        
% 2012  -    
% (    Agilent MGA-71543    )
        Grf_lna_db     	    = 16.0;     % dB 	- 	   
        NFrf_lna_db         = 1.0;      % dB		- 	   
        
% 2013  -      
        BWrf_ekv_fms_hz   	=  6.0e6;   % Hz	-	     
        Lrf_max_fms_db      =  4.0;    % dB 	- 	         (insertion loss)
        
% 2014  -      
% (    Agilent MGA-71543    )
        Grf_amp_db      	=  16.0;    % dB 	- 	   
        NFrf_amp_db     	=  1.0;     % dB    - 	  
		
% 2015  -    
% (    Analog Devices ADL5387)
        Grf_mix_db      	=   4.5;    	% dB 	- 	    
        NFrf_mix_db     	=  15.0;    	% dB    - 	   
		IP1dBrf_mix_dbw		=  13.0 - 30.0; % dBW	- 	Input P1dB (IP1dB)

% 3.                
% 3011	-	
%    (db)
        NFrf_sys_db = pow2db( ( db2pow(  Lrf_max_prf_db )       ) + ...                   
                              ( db2pow( NFrf_lna_db     ) + 1 ) / ( db2pow( -Lrf_max_prf_db )) + ...
                              ( db2pow(  Lrf_max_fms_db ) + 1 ) / ( db2pow( -Lrf_max_prf_db ) * db2pow(  Grf_lna_db )) + ...
                              ( db2pow( NFrf_amp_db     ) + 1 ) / ( db2pow( -Lrf_max_prf_db ) * db2pow(  Grf_lna_db ) * db2pow( -Lrf_max_fms_db )) + ...
							  ( db2pow( NFrf_mix_db     ) + 1 ) / ( db2pow( -Lrf_max_prf_db ) * db2pow(  Grf_lna_db ) * db2pow( -Lrf_max_fms_db ) * db2pow(  Grf_amp_db )) ...
                            );

%    (dB)
		Grf_sys_db	= ( Grf_lna_db + Grf_amp_db + Grf_mix_db ) - ( Lrf_max_prf_db + Lrf_max_fms_db );
		
%      (Hz)
		BWrf_sys_hz = BWrf_ekv_fms_hz;

% 3012	-	Baseband LPF
		Lbb_lpf_db		= 9;		% dB			-	   Baseband LPF    (insertion loss)
		
% 3013	-	Baseband  (LTC6400-14)
		Gbb_opa_db		= 0;		% dB			-	  
		NFbb_opa_db     = 0;      % dB			-	  	

%    ,      (dB)
		Gbb_lfa_db		= Gbb_opa_db - Lbb_lpf_db;
		
%         (dB) -   . 
		NFbb_sys_db     = pow2db( ( db2pow( NFrf_sys_db         )     ) + ...                   
                                  ( db2pow( NFbb_opa_db         ) + 1 ) / ( db2pow( Grf_sys_db )) ...
					    		);
							
%         (dB)
		Gbb_sys_db	    = Grf_sys_db + Gbb_lfa_db; 

%       (Hz) -  
		BWbb_sys_hz		= BWrf_sys_hz;
		
%         (dBW)		
		PNbb_out_dbw	= pow2db( k * T0 * BWrf_sys_hz ) + NFbb_sys_db + Gbb_sys_db;	

% 3014	-	 
% (    1  Linear Technology LTC2271)
		FSadc_hz		= 20.0e6;	% Hz	-	Sampling rate		
		SNadc_fs_db		= 84;		% dB	-	SNR 
		NBadc_fs_bits	= 16;		% bits 	-	Full scale bits
		Vadc_fs_v		= 2;		% V		-	Full scale voltage
		Radc_inp_ohm	= 1000;		% Ohm	-	Input ADC resistance	

%            (dBW)			
		PFSadc_inp_dbw	= pow2db( 2.0 * (( Vadc_fs_v * 0.5 * sqrt( 0.5 )) ^ 2 ) / Radc_inp_ohm );  
		
%      (dBW)			
		PNadc_snr_dbw	= PFSadc_inp_dbw - SNadc_fs_db;
		
%      (dBW)
		PNadc_qan_dbw	= PFSadc_inp_dbw - ( NBadc_fs_bits * mag2db( 2 ) + mag2db( sqrt( 6 ) / 2 )); % adding correction factor for sinusoidal signal			
					
% 3015	-	     
        SNfm_min_db		= 12.0;		% dB  		-   -       
		BWfm_max_hz		= 25.0e3;	% Hz 		-    ,    		
		BWfm_min_hz		= 6.25e3;	% Hz 		-      ,    

%   (dBW)         (     )	
		Pfm_min_dbw		= pow2db( k * T0 * BWfm_max_hz ) + NFbb_sys_db + SNfm_min_db;		
		
%         ,      (dBW)
		Pfm_min_bb_sys_dbw 	= Pfm_min_dbw + Gbb_sys_db;		

%     .        
%        (dBW)
		PFSmix_inp_dbw = PFSadc_inp_dbw - Gbb_lfa_db - Grf_mix_db;		

%       ( )
		deltaPmix_inp_lin = IP1dBrf_mix_dbw - PFSmix_inp_dbw; 
		



الآن أريد صور
%       
Nfft = 2 * (( FSadc_hz / 2 ) / BWfm_min_hz ); 
Nsmp = Nfft;

tmp_fft_buf = zeros( 1, Nfft );
tmp_acc_buf = zeros( 1, Nfft );
tmp_smp_buf = zeros( 1, Nsmp );

max_acc = 30;

for acc = 1:max_acc
%   1 
%     -      
%    -       

  PS1 = db2pow( Pfm_min_bb_sys_dbw );
  WS1 = 25.0e3;
  FS1 =  1.0e6;
  
  Fstart = FS1;
  Fstop  = Fstart + WS1 - BWfm_min_hz;
  Pstep  = PS1 / ( WS1 / BWfm_min_hz ); 
  PS1_smp_buf = zeros( 1, Nsmp );
  
  for f = Fstart:BWfm_min_hz:Fstop
      phi_acc = 2.0 * pi * rand( 1 ); % random phase
      phi_stp =       pi * ( f / ( FSadc_hz / 2 ));
      
      for k = 1:Nsmp
          PS1_smp_buf( k ) = PS1_smp_buf( k ) + sqrt( Pstep ) * exp( j * phi_acc );
          phi_acc = phi_acc + phi_stp;
          
          if( phi_acc > (  2.0 * pi ))
              phi_acc = phi_acc - 2.0 * pi;
          else
              if( phi_acc < ( -2.0 * pi ))
                  phi_acc = phi_acc + 2.0 * pi;
              end
          end
      end
  end

%   2 
%     -       
%    -       

  PS2 = db2pow( PFSadc_inp_dbw - 1.0 ); % -1 dB back off 
  WS2 = 25.0e3;
  FS2 = -2.0e6;
  
  Fstart = FS2;
  Fstop  = Fstart + WS2 - BWfm_min_hz;
  Pstep  = PS2; 
  PS2_smp_buf = zeros( 1, Nsmp );
  
  for f = Fstart:BWfm_min_hz:Fstop
      phi_acc = 2.0 * pi * rand( 1 ); % random phase
      phi_stp =       pi * ( f / ( FSadc_hz / 2 ));
      
      for k = 1:Nsmp
          PS2_smp_buf( k ) = PS2_smp_buf( k ) + sqrt( Pstep ) * exp( j * phi_acc );
          phi_acc = phi_acc + phi_stp;
          
          if( phi_acc > (  2.0 * pi ))
              phi_acc = phi_acc - 2.0 * pi;
          else
              if( phi_acc < ( -2.0 * pi ))
                  phi_acc = phi_acc + 2.0 * pi;
              end
          end
      end
  end

%      
  PN1 = db2pow( PNbb_out_dbw );
  WN1 = BWbb_sys_hz;
  
  Pfull_bw = PN1 * ( FSadc_hz / WN1 );
  
  PN1_smp_buf = sqrt( 0.5 * Pfull_bw ) * complex( randn( 1, Nsmp ), randn( 1, Nsmp ));
  tmp_fft_buf = fftshift( fft( PN1_smp_buf ));
  tmp_msk_buf = zeros( 1, Nfft );
  tmp_msk_buf((( Nfft / 2 ) - (( WN1 / FSadc_hz ) * ( Nfft / 2 )) + 1 ) : (( Nfft / 2 ) + (( WN1 / FSadc_hz ) * ( Nfft / 2 )))) = ... 
              ones( 1, (( WN1 / FSadc_hz ) * Nfft ));
  
  tmp_fft_buf = tmp_fft_buf .* tmp_msk_buf;
  PN1_smp_buf = ifft( fftshift( tmp_fft_buf ));

%    
  PN2 = db2pow( PNadc_snr_dbw ) - db2pow( PNadc_qan_dbw );
  %PN2 = db2pow( PNadc_snr_dbw );
  
  Pfull_bw = PN2;
  
  PN2_smp_buf = sqrt( 0.5 * Pfull_bw ) * complex( randn( 1, Nsmp ), randn( 1, Nsmp ));

%    
  QAN_smp_buf = PS1_smp_buf + PS2_smp_buf + PN1_smp_buf + PN2_smp_buf;
  
  QAN_delta = Vadc_fs_v / ( 2 ^ NBadc_fs_bits );
  
  QAN_smp_buf = round( QAN_smp_buf ./ QAN_delta ) .* QAN_delta;
  
  QAN_smp_buf_re = real( QAN_smp_buf );
  QAN_smp_buf_re( find( QAN_smp_buf_re > (  Vadc_fs_v / 2.0 ))) =  Vadc_fs_v / 2.0;
  QAN_smp_buf_re( find( QAN_smp_buf_re < ( -Vadc_fs_v / 2.0 ))) = -Vadc_fs_v / 2.0;
  
  QAN_smp_buf_im = imag( QAN_smp_buf );
  QAN_smp_buf_im( find( QAN_smp_buf_im > (  Vadc_fs_v / 2.0 ))) =  Vadc_fs_v / 2.0;
  QAN_smp_buf_im( find( QAN_smp_buf_im < ( -Vadc_fs_v / 2.0 ))) = -Vadc_fs_v / 2.0;
  
  QAN_smp_buf = complex( QAN_smp_buf_re, QAN_smp_buf_im );

%   ADC

  tmp_smp_buf = QAN_smp_buf;
  %tmp_smp_buf = PS1_smp_buf + PS2_smp_buf + PN1_smp_buf + PN2_smp_buf;
  
  tmp_fft_buf = fft( tmp_smp_buf ) / Nfft;
  tmp_acc_buf = tmp_acc_buf + ( tmp_fft_buf .* conj( tmp_fft_buf ));
end  

tmp_acc_buf = tmp_acc_buf ./ max_acc;

f = linspace(( -FSadc_hz / 2 ) + BWfm_min_hz, FSadc_hz / 2, Nfft );

plot( f, pow2db( fftshift( tmp_acc_buf ))); 
xlim( [( -FSadc_hz / 2 ), ( FSadc_hz / 2 )] ); 
ylim( [-150.0, -20.0] ); 
title('Power Spectrum')
xlabel('Frequency (Hz)')
ylabel('P(f) dBW')
drawnow;



حسنًا ، أظهر النموذج جدوى الفكرة - حساسية -115dBm ، حجب تحت 90dB.

علاوة على ذلك ، في FPGA ، باستخدام كتلة تطبيع الإشارات التربيعية ، نقوم بإزالة المكون الثابت والتعامل مع قناة المرآة وتطبيق الإشارة على إدخال DDC . بعد انحراف التردد المطلوب إلى الصفر ، ستنتقل الإشارة إلى سلسلة من المرشحات الرقمية CIC - و FIR - لتشكيل نطاق قناة. بالطبع ، إذا أردنا تلقي أكثر من قناة في نفس الوقت ، فيجب أن يكون لدينا مجموعة من المرشحات DDC والفلاتر.

في المقالة التالية ، إذا كان الجمهور مهتمًا ، فسأتحدث عن الخطوات التالية في النمذجة ، وتقييم موارد أجهزة FPGA.

Source: https://habr.com/ru/post/ar395853/


All Articles