Desenvolvimento de SDR multicanal

Vou contar sobre minha experiência no desenvolvimento de um receptor de banda larga digital multicanal.

Por muitos anos, trabalho na criação de meios para capturar e processar sinais de radares de navegação aérea e costeira. Há cerca de dois anos, lancei a versão mais recente, até o momento, de nosso quadro RVAQ (Radar Video AcQuisition) e me perguntei o que fazer a seguir na vida. Eu queria algo novo e desconhecido. A escolha recaiu sobre a área que ainda não cobri - o rádio digital com fácil entrada na região de microondas.

Este é o primeiro capítulo dedicado à formulação inicial do problema.

Por onde começar, se você nunca esteve profissionalmente envolvido na recepção de rádio digital, exceto pelo receptor Mishutka montado na infância? Claro, com um refresco na leitura de Polyakov e o modelo no MATLAB. A idéia inicial era criar um receptor multicanal na faixa de 156-162 MHz para monitorar e gravar todas as conversas ativas na banda VHF marinha. Vou listar as propriedades desejadas para esse receptor:
1. A banda de recepção é de pelo menos 6 MHz (162-156 = 6)
2. A sensibilidade não é pior que -110 dBm, caso contrário eles rirão.
3. Uma ampla faixa dinâmica, pois quando você ouve um navio na costa no mar por 48 quilômetros, alguém definitivamente grita nas proximidades com seus 25 watts. Para receptores decentes, o nível de bloqueio deve ser de pelo menos 70dB. Seguindo um pouco à frente, direi que resultou em mais de 90dB de bloqueio. Em suma, o RTL-SDR fortemente não atendeu às expectativas. Por mais estranho que pareça, comecei com a escolha do ADC. Como se na natureza não houver ADCs correspondentes (pelo menos em teoria), não vale a pena tomar. Esse ADC foi encontrado.

Agora você precisa escolher a arquitetura do receptor. Uma análise das soluções relevantes, o estudo da base dos elementos e a intuição tornaram possível a reflexão sobre o receptor de conversão direta. Também foi decidido transferir a região de interesse do espectro usando o desmodulador de quadratura para a frequência zero e trabalhar na primeira zona de Nyquist, a fim de maximizar a utilização de todas as qualidades do ADC selecionado.

Modelo inicial para estimativa de parâmetros
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; 
		



Agora eu quero fotos
%       
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;



Bem, o modelo mostrou a viabilidade da ideia - sensibilidade -115dBm, bloqueando abaixo de 90dB.

Além disso, no FPGA, usando o bloco de normalização de sinais em quadratura, removemos o componente constante, lidamos com o canal de espelho e aplicamos o sinal à entrada DDC . Após o desvio da frequência de interesse para zero, o sinal irá para uma cadeia de filtros digitais CIC - e FIR - , formando uma banda de canal. Obviamente, se queremos receber simultaneamente mais de um canal, precisamos ter um monte de DDC e filtros.

No próximo artigo, se o público estiver interessado, falarei sobre os próximos passos na modelagem e na avaliação dos recursos de hardware do FPGA.

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


All Articles