├── .gitignore ├── README.md ├── SECURITY.md ├── license.txt ├── mvdr_beamformer ├── FPGA_Adaptive_Beamforming_with_HDL_Coder_and_Zynq_RFSoC.pdf ├── README.md ├── common │ ├── compareData.m │ ├── deinterleave_complex.m │ ├── generate_qpsk_signal.m │ ├── interleave_complex.m │ ├── maxabs.m │ ├── plot_beam_patterns.m │ ├── qpsk_receive.m │ ├── sim_with_progress.m │ └── unpack_complex.m ├── mvdr_app.png ├── mvdr_hdl_sim │ └── mvdr_4x4 │ │ ├── model_init.m │ │ ├── mvdr_4x4_partial_systolic.slx │ │ ├── mvdr_reference.m │ │ └── tb_mvdr_4x4_partial_systolic.m ├── xm500_wiring.png └── zcu111_mvdr_demo │ ├── RFSoCMVDRDemo.m │ ├── RFSoC_MVDR_Demo.mlapp │ ├── TxSteering_RxMVDR_4x4_HDL_IQ.slx │ ├── calibrate_channels.m │ ├── model_init.m │ ├── prebuilt │ ├── RF_Init.cfg │ └── zcu111_mvdr.bit │ ├── program_board.m │ ├── setup_fpgaio.m │ └── setup_rfsoc.m └── rangedoppler └── hw_only ├── 2dFFT.jpg ├── README.md ├── RangeDoppler.jpg ├── bandwidth_cornerturn.jpg ├── partA_TransposeMatrix ├── part0_SoCB │ ├── MatrixWrRd_transpose_SoCB_TopLevel.slx │ ├── hdlcoder_external_memory_read_ctrl_custom.m │ ├── hdlcoder_external_memory_write_ctrl_custom.m │ ├── matrix_init.m │ ├── matrix_rdwr_transpose_fpga.slx │ └── validate_matrix_out.m ├── part1_hdl_wrready │ ├── matrix_init.m │ ├── validate_matrix_out.m │ └── wrQueue_RFSoC_MatrixTranspose.slx └── part2_hdl_bram_burst │ ├── AXIBusObjects.m │ ├── bramBurst_TransposeMatrix.slx │ ├── matrix_init.m │ ├── model_init_sim.m │ ├── run_fpgaIO.m │ ├── transpose_fpgaIO_setup.m │ └── validateTranspose.m └── partB_MatchedFilterFFTTranspose ├── MatchedFilterFFT_Transpose.prj ├── part0_rangedoppler_ml └── run_Range_Doppler.m ├── part1_transpose_radar_cube ├── BramBurst_FFT2D_validate_matrix_out.m ├── bramBurst_TransposeMatrix.slx ├── matrix_init.m ├── socmemlib.slx └── validateTranspose.m ├── part2_rangedoppler_hdl ├── BramBurst_FFT2D_validate_matrix_out.m ├── RangeDopplerLoop_fpgaIO.m ├── bramBurst_TransposeMatrix.slx ├── matched_filter_fft_hdl_init.m ├── setup_fpgaIO.m ├── simCheckOutput_rangeDoppler.m ├── socmemlib.slx ├── validateTranspose.m └── writeDopplerInput_fpgaIO.m ├── resources └── project │ ├── 1AK6k8_2MMsrq1VagZS1umPpphk │ ├── -LsZ8HXJj2Q_3Mm_5RR2W21dUukd.xml │ ├── -LsZ8HXJj2Q_3Mm_5RR2W21dUukp.xml │ ├── 0avZ0B7B9QBO8c3kVcoPdfvh0a4d.xml │ ├── 0avZ0B7B9QBO8c3kVcoPdfvh0a4p.xml │ ├── 4SII37bbmPr-uDt2KwUOF17LD3Md.xml │ ├── 4SII37bbmPr-uDt2KwUOF17LD3Mp.xml │ ├── hVqQ-9HgOfR-miUHZ1Olro2oO1Ed.xml │ ├── hVqQ-9HgOfR-miUHZ1Olro2oO1Ep.xml │ ├── tKvNkHTpbT6GAm3k-7n7cooRcn0d.xml │ ├── tKvNkHTpbT6GAm3k-7n7cooRcn0p.xml │ ├── ySwxmLB6i3-U3ibpDX9G5VF_qIkd.xml │ └── ySwxmLB6i3-U3ibpDX9G5VF_qIkp.xml │ ├── CAsOFWEXbRicMJSXkpnan34QAz4 │ ├── 4SVYQZsILIuEyZXh7AZiBXaAzWId.xml │ ├── 4SVYQZsILIuEyZXh7AZiBXaAzWIp.xml │ ├── TDGNiicbXqPcaT25VpzQ4PfNaGEd.xml │ ├── TDGNiicbXqPcaT25VpzQ4PfNaGEp.xml │ ├── TnMVnPKCYgLFQp-huKXjIUP3g50d.xml │ ├── TnMVnPKCYgLFQp-huKXjIUP3g50p.xml │ ├── XI63F3DpcFZVEmLxabCze_1yGYUd.xml │ ├── XI63F3DpcFZVEmLxabCze_1yGYUp.xml │ ├── u09gIjf84mrcY04PvVsIqz_A2nId.xml │ ├── u09gIjf84mrcY04PvVsIqz_A2nIp.xml │ ├── ytXa1Px-hQUhxMW6RexuadiW05Md.xml │ └── ytXa1Px-hQUhxMW6RexuadiW05Mp.xml │ ├── EEtUlUb-dLAdf0KpMVivaUlztwA │ ├── EP7gYHkiKJzsbwl1Kmg0OEWqO4od.xml │ ├── EP7gYHkiKJzsbwl1Kmg0OEWqO4op.xml │ ├── fSmbuBCUit5i5wOBPuJA2g5w9NId.xml │ ├── fSmbuBCUit5i5wOBPuJA2g5w9NIp.xml │ ├── lJnjawKd-WsGvgvgCWqsl0Tg_aUd.xml │ ├── lJnjawKd-WsGvgvgCWqsl0Tg_aUp.xml │ ├── pJPJd6FiWRygNl9o0EVnymaY7Ykd.xml │ └── pJPJd6FiWRygNl9o0EVnymaY7Ykp.xml │ ├── NwDM1JfMyUKVVWcp71u8HzQ1GJc │ ├── ErjdZpt4SMkWn8v-1ahF4A3siMMd.xml │ ├── ErjdZpt4SMkWn8v-1ahF4A3siMMp.xml │ ├── MnQp2l-5jErytlj-zxMUdpGpr5cd.xml │ └── MnQp2l-5jErytlj-zxMUdpGpr5cp.xml │ ├── WZRuNzqc-Db7NcQAZO8Y-R8U9cc │ ├── 66WgGCcF5RIH9MCEgPmgjZK9k3Ud.xml │ ├── 66WgGCcF5RIH9MCEgPmgjZK9k3Up.xml │ ├── AtMjXDrOSm8YDv3_4UFXiyrWqNEd.xml │ └── AtMjXDrOSm8YDv3_4UFXiyrWqNEp.xml │ ├── qaw0eS1zuuY1ar9TdPn1GMfrjbQ │ ├── 1AK6k8_2MMsrq1VagZS1umPpphkd.xml │ ├── 1AK6k8_2MMsrq1VagZS1umPpphkp.xml │ ├── CAsOFWEXbRicMJSXkpnan34QAz4d.xml │ ├── CAsOFWEXbRicMJSXkpnan34QAz4p.xml │ ├── NwDM1JfMyUKVVWcp71u8HzQ1GJcd.xml │ ├── NwDM1JfMyUKVVWcp71u8HzQ1GJcp.xml │ ├── tczr9cMCNMOtxnSsL6yRolFxYBId.xml │ └── tczr9cMCNMOtxnSsL6yRolFxYBIp.xml │ ├── root │ ├── EEtUlUb-dLAdf0KpMVivaUlztwAp.xml │ └── WZRuNzqc-Db7NcQAZO8Y-R8U9ccp.xml │ └── tczr9cMCNMOtxnSsL6yRolFxYBI │ ├── EGS-wA3-Ks6urVqBkUEHtwtFE_Ed.xml │ ├── EGS-wA3-Ks6urVqBkUEHtwtFE_Ep.xml │ ├── KRklbgq8aG-kfYmOgOLRLkm3QDId.xml │ ├── KRklbgq8aG-kfYmOgOLRLkm3QDIp.xml │ ├── Q6dDcsN2OKbQzgD58TRr8ONsFJMd.xml │ ├── Q6dDcsN2OKbQzgD58TRr8ONsFJMp.xml │ ├── WSzvG5f_5Cvt8a1ZYLPc6xfuSq4d.xml │ ├── WSzvG5f_5Cvt8a1ZYLPc6xfuSq4p.xml │ ├── Xi_uJVws7Ulmwu5Gll1EDSreybMd.xml │ ├── Xi_uJVws7Ulmwu5Gll1EDSreybMp.xml │ ├── b9vcJ5kLPMvo3kZz_IJEYIN8Z6cd.xml │ ├── b9vcJ5kLPMvo3kZz_IJEYIN8Z6cp.xml │ ├── haKPcoVMP6OfLpW27bivJk-zciAd.xml │ ├── haKPcoVMP6OfLpW27bivJk-zciAp.xml │ ├── rKuGYAHY8-cXC9XRh5EcCRlNuEQd.xml │ ├── rKuGYAHY8-cXC9XRh5EcCRlNuEQp.xml │ ├── uPQ5MtfZJq79kMUTlWx4p0q_8hod.xml │ └── uPQ5MtfZJq79kMUTlWx4p0q_8hop.xml └── shared_files ├── AXIBusObjects.m ├── createRadarDataCubeMod.m ├── getLogged.m ├── range_doppler_system_param_init.m └── window_taper.slx /.gitignore: -------------------------------------------------------------------------------- 1 | **/slprj/ 2 | *.mexw64 3 | **/*_ert_rtw 4 | **/hdl_prj 5 | *.asv 6 | *.bak 7 | *.exp 8 | *.lib 9 | *.slxc 10 | *.zip 11 | *.pdf 12 | RFTool_Log.txt 13 | init.sh -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FPGA Adaptive Beamforming and Radar Examples with HDL Coder and Zynq RFSoC 2 | 3 | ## Overview 4 | 5 | This repository contains FPGA/HDL demonstrations several beamforming and 6 | radar designs. Simulink models and MATLAB reference code are provided to showcase 7 | high-level simulation and HDL designs of various radar and array processing algorithms. 8 | 9 | The license is available in the License.txt file in this GitHub repository. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting Security Vulnerabilities 2 | 3 | If you believe you have discovered a security vulnerability, please report it to 4 | [security@mathworks.com](mailto:security@mathworks.com). Please see 5 | [MathWorks Vulnerability Disclosure Policy for Security Researchers](https://www.mathworks.com/company/aboutus/policies_statements/vulnerability-disclosure-policy.html) 6 | for additional information. -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021, The MathWorks, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 3. In all cases, the software is, and all modifications and derivatives of the software shall be, licensed to you solely for use in conjunction with MathWorks products and service offerings. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /mvdr_beamformer/FPGA_Adaptive_Beamforming_with_HDL_Coder_and_Zynq_RFSoC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/mvdr_beamformer/FPGA_Adaptive_Beamforming_with_HDL_Coder_and_Zynq_RFSoC.pdf -------------------------------------------------------------------------------- /mvdr_beamformer/README.md: -------------------------------------------------------------------------------- 1 | # FPGA Adaptive Beamforming with HDL Coder and Zynq RFSoC 2 | 3 | ## Overview 4 | 5 | These models will demonstrate how to design and implement the minimum-variance 6 | distortionless-response (MVDR) adaptive beamforming algorithm on the Xilinx® 7 | Zynq UltraScale+™ RFSoC platform. By following a Model-Based Design strategy, 8 | we show how the MVDR beamformer can be articulated in MATLAB, Simulink, 9 | Fixed-Point and HDL. We further demonstrate a prototyping workflow by deploying 10 | the beamformer to the ZCU111 RFSoC evaluation board for run-time testing, 11 | debugging and visualization. 12 | 13 | 14 | ## MVDR Demo Files 15 | 16 | ### mvdr_hdl_sim ### 17 | 18 | This model uses the phased array toolbox to demonstrate high-level modeling 19 | of adaptive beamforming processing. Comparisons are made to various elaborated 20 | versions of the same design starting originally in floating point then 21 | to eventual fixed-point HDL. Blocks from the fixed-point toolbox were used 22 | to aid in this design for computing the adaptive weights using QR decomposition. 23 | 24 | Two examples for 4x4 and 16x16 MVDR matrix solves have been provided. 25 | 26 | ### zcu111_mvdr_demo ### 27 | 28 | This HDL model uses the same algorithm from the previous design but now integrates 29 | it for a ZCU111 RFSoC evaluation kit. Using 4 channels of ADC and DAC looped 30 | back on itself, a beam is electronically steered out the DAC and then processed 31 | by the ADC. Using four inputs, a 4x4 covariance matrix is composed and then 32 | QR decomposition is applied to yield optimal steering weights that augment the 33 | desired steering angle. A QPSK signal of interest is resolved in the presence of 34 | interference which is artificially introduced in the transmit signal. 35 | 36 | ##### Required software ##### 37 | 38 | Xilinx Vivado 2020.2 39 | 40 | MATLAB R2023a with the following add-ons: 41 | - Simulink 42 | - HDL Coder 43 | - Fixed-Point Designer 44 | - DSP System Toolbox 45 | - DSP HDL Toolbox 46 | - Communications Toolbox 47 | - Phased Array System Toolbox 48 | - [HDL Coder Support Package for Xilinx RFSoC Devices](https://www.mathworks.com/hardware-support/rfsoc-hdl-coder.html ) 49 | 50 | ##### Run the demo ##### 51 | 52 | 1. Ensure the ZCU111 board has been configured with the SD card provided by the HDL Coder RFSoC Support Package. 53 | See [this page](https://www.mathworks.com/help/releases/R2021b/supportpkg/xilinxrfsocdevices/ug/guided-sd-card-setup.html) for more information. 54 | 55 | 2. On the XM500 balun card, connect the differential ADC cables for the ADC Tile 2 (Channel 0 and 1) and Tile 3 (Channel 0 and 1) 56 | to the DAC Tile 0 Channel 0 1 2 and 3. See [section below](#adcdac-loopback-wiring-details) for more details. 57 | 58 | 3. Power-on the board and program the prebuilt FPGA bitstream: 59 | 60 | `>> program_board('BitfilePath','prebuilt/zcu111_mvdr.bit')` 61 | 62 | 4. After the board reboots, run the setup script to configure the RF Data Converter: 63 | 64 | `>> setup_rfsoc` 65 | 66 | 5. Run "RFSoC_MVDR_Demo.mlapp" by right clicking on it and selecting "run" or running it from the MATLAB command prompt: 67 | 68 | `>> RFSoC_MVDR_Demo` 69 | 70 | 71 | 72 | You can use this UI app to adjust the angle of arrival for the signal of interest and the interference. 73 | To regain stable constellation, change the "Azimuth Angle" value to the signal of interest by adjusting the slider 74 | to the same angle. Measurements from the MVDR optimized weights are read back from the device to show the beamforming 75 | response and how nulls are placed to minimize interference. 76 | 77 | ##### Build the demo ##### 78 | 79 | To rebuild the bitstream from scratch, follow these instructions. 80 | 81 | 1. Open "TxSteering_RxMVDR_4x4_HDL_IQ.slx" 82 | 83 | 2. Right-click on the "DUT" subsystem, then click HDL Code → HDL Workflow Advisor 84 | 85 | 3. In the HDL Workflow Advisor, right-click on step 4.3, then click "Run to selected task". 86 | For more details on the individual steps of HDLWFA, please see this [example](https://www.mathworks.com/help/releases/R2021b/supportpkg/xilinxrfsocdevices/ug/DACAndADCLoopbackDataCaptureExample.html). 87 | 88 | 4. Wait for the Vivado command window to show that bitstream generation has finished. 89 | 90 | 5. Run provided utility function to program the board: 91 | 92 | NOTE: You must use this to program the board instead of HDL WFA step 4.4. 93 | 94 | `>> program_board` 95 | 96 | 6. Proceed from step 4 in the Demo instructions. 97 | 98 | 99 | ##### ADC/DAC Loopback Wiring Details ##### 100 | 101 | To loop back the 4 DAC and ADC channels with the XM500 board you will need to make the following connections: 102 | 103 | 104 | 105 | Because these connections are differential, you will need SMA DC Blocks. 106 | 107 | Connection details: 108 | - RFMC_ADC_04 connects to RFMC_DAC_00 109 | - RFMC_ADC_05 connects to RFMC_DAC_01 110 | - RFMC_ADC_06 connects to RFMC_DAC_02 111 | - RFMC_ADC_07 connects to RFMC_DAC_03 112 | 113 | The above names refer to labels on the XM500. Match the SMA connectors to the above physical labels of the XM500. 114 | Each label represents a specific tile/channel: 115 | - ADC Tile 2 Ch0 maps to RFMC_ADC_04 116 | - ADC Tile 2 Ch1 maps to RFMC_ADC_05 117 | - ADC Tile 3 Ch0 maps to RFMC_ADC_06 118 | - ADC Tile 3 Ch1 maps to RFMC_ADC_07 119 | - DAC Tile 0 Ch0 maps to RFMC_DAC_00 120 | - DAC Tile 0 Ch1 maps to RFMC_DAC_01 121 | - DAC Tile 0 Ch2 maps to RFMC_DAC_02 122 | - DAC Tile 0 Ch3 maps to RFMC_DAC_03 123 | 124 | Note that the PN differential connections pair up such that P connects to N. 125 | 126 | 127 | ## Documentation: Background Theory of Operation ## 128 | A PDF file "FPGA_Adaptive_Beamforming_with_HDL_Coder_and_Zynq_RFSoC.pdf" has been included. 129 | 130 | ### Introduction: Motivation and Challenges 131 | - Applications: Radar, Comms and Wireless (5G) 132 | - Hardware FPGA challenges 133 | 134 | ### Theory and Implementation 135 | - Linear algebra 136 | - QR Decomposition 137 | - Matrix Divide 138 | 139 | ### Zynq RFSoC and HDL Coder Implementation 140 | - MATLAB MVDR reference code 141 | - HDL Coder implementation 142 | - Hardware Prototyping – live demo 143 | 144 | The license used in this contribution is the XSLA license, which is the most common license for MathWorks staff contributions. 145 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/compareData.m: -------------------------------------------------------------------------------- 1 | function err_vec = compareData(reference,actual,figure_number,textstring) 2 | 3 | % Vector input only 4 | if ~isvector(reference) || ~isvector(actual) 5 | error('Input signals must be vector'); 6 | else 7 | if isrow(reference) 8 | reference = transpose(reference); 9 | end 10 | if isrow(actual) 11 | actual = transpose(actual); 12 | end 13 | end 14 | 15 | % Make signals same length if necessary 16 | if length(reference) ~= length(actual) 17 | warning(['Length of reference (%d) is not the same as actual signal (%d).'... 18 | ' Truncating the longer input.'],length(reference),length(actual)); 19 | len = 1:min(length(reference),length(actual)); 20 | reference = reference(len); 21 | actual = actual(len); 22 | end 23 | 24 | % Turn complex into vector 25 | if xor(isreal(reference),isreal(actual)) 26 | error('Input signals are not both real or both complex'); 27 | elseif ~isreal(reference) 28 | ref_vec = double([real(reference) imag(reference)]); 29 | act_vec = double([real(actual) imag(actual)]); 30 | tag = {'(Real)','(Imag)'}; 31 | cmplx = 1; 32 | else 33 | ref_vec = double(reference); 34 | act_vec = double(actual); 35 | tag = {''}; 36 | cmplx = 0; 37 | end 38 | 39 | % Configure figure 40 | if iscell(figure_number) 41 | if size(figure_number,2) == 3 42 | figure(figure_number{3}); 43 | else 44 | figure(1); % for backward compatability 45 | end 46 | else 47 | figure(figure_number); 48 | end 49 | c = get(groot,'defaultAxesColorOrder'); 50 | 51 | % Compute error 52 | err_vec = ref_vec - act_vec; 53 | max_err = max(abs(err_vec)); 54 | max_ref = max(abs(ref_vec)); 55 | fprintf('\nMaximum error for %s out of %d values\n',textstring,length(actual)); 56 | 57 | % 4 layouts: 58 | % fig = #, signal = real: subplot(111) 59 | % fig = #, signal = cmplx: subplot(211) & (212) 60 | % fig = {X,Y}, signal = real: subplot(X1Y) 61 | % fig = {X,Y}, signal = cmplx: subplot(X,1,Y*2-1) & (X,2,Y*2) 62 | 63 | for n = 1:size(ref_vec,2) 64 | fprintf('%s %d (absolute), %d (percentage)\n',tag{n},max_err(n),max_err(n)/max_ref(n)*100); 65 | if isnumeric(figure_number) 66 | row_num = size(ref_vec,2); 67 | col_num = 1; 68 | plot_num = n; 69 | else 70 | row_num = figure_number{1}; 71 | col_num = size(ref_vec,2); 72 | plot_num = figure_number{2}; 73 | if cmplx 74 | plot_num = (figure_number{2}-1)*2+n; 75 | end 76 | end 77 | subplot(row_num,col_num,plot_num); 78 | plot(ref_vec(:,n),'Color',c(3,:)); 79 | hold on 80 | plot(act_vec(:,n),'Color',c(1,:)); 81 | plot(err_vec(:,n),'Color',c(2,:)); 82 | legend('Reference','Actual','Error') 83 | hold off 84 | title(sprintf('%s %s\n max error = %.3d',textstring,tag{n},max_err(n))); 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/deinterleave_complex.m: -------------------------------------------------------------------------------- 1 | function out = deinterleave_complex(in) 2 | %DEINTERLEAVE_COMPLEX Deinterleave real and imaginary components from input vector. 3 | % Output is a vector with half the length of the input. 4 | 5 | out = complex(in(1:2:end),in(2:2:end)); 6 | 7 | end 8 | 9 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/generate_qpsk_signal.m: -------------------------------------------------------------------------------- 1 | function [txData,matchedFilterCoeffs,rrcFilterCoeffs] = generate_qpsk_signal( ... 2 | NFrames,FrameLength,PreambleLength,SamplesPerSymbol) 3 | % QPSK signal generation 4 | % 5 | % Copyright 2021 The MathWorks, Inc. 6 | 7 | % Use QPSK modulation 8 | M=4; 9 | 10 | % Calculate payload length 11 | NPayloadLength=FrameLength-PreambleLength; 12 | 13 | % use Barker code for preamble 14 | barkerCode = step(comm.BarkerCode('Length',PreambleLength,'SamplesPerFrame',PreambleLength)); 15 | 16 | % map preamble to Gray code symbols. 17 | % -1 -> 1, +1 -> 0 18 | temp = (-barkerCode + 1) / 2; 19 | temp = [temp temp]'; 20 | temp = temp(:); 21 | preamble = bit2int(temp,2); 22 | 23 | % copy preamble so it can be inserted at start of each frame 24 | preamble_frames=preamble*ones(1,NFrames); 25 | 26 | % QPSK payload data 27 | payload=randi([0 M-1],NPayloadLength,NFrames); 28 | 29 | % append preamble to payload data 30 | txdata=[preamble_frames;payload]; 31 | 32 | % QPSK modulation data 33 | txconstdata=pskmod(txdata(:),M,pi/M); 34 | 35 | % upsample constellation data 36 | txconstdata_up=upsample(txconstdata,SamplesPerSymbol); 37 | 38 | % generate Root Raised Cosine (RRC) Tx/Rx Filer 39 | rrcFilterCoeffs = rcosdesign(0.25,6,SamplesPerSymbol); 40 | 41 | % apply RRC on tx data 42 | txData=filter(rrcFilterCoeffs,1,txconstdata_up); 43 | 44 | % extract preamble 45 | preamble_temp=filter(rrcFilterCoeffs,1,txconstdata_up(1:PreambleLength*SamplesPerSymbol)); 46 | 47 | % convert to matched filter 48 | matchedFilterCoeffs=conj(flipud(preamble_temp)); 49 | 50 | end 51 | 52 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/interleave_complex.m: -------------------------------------------------------------------------------- 1 | function out = interleave_complex(in) 2 | %INTERLEAVE_COMPLEX Interleave real and imaginary components. 3 | % Output is a vector with twice the length of the input. 4 | 5 | temp = reshape(in,1,[]); 6 | temp = vertcat(real(temp),imag(temp)); 7 | out = reshape(temp,[],1); 8 | if isrow(in) 9 | out = out.'; 10 | end 11 | 12 | end 13 | 14 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/maxabs.m: -------------------------------------------------------------------------------- 1 | function val = maxabs(in) 2 | %MAXABS Get the maximum absolute value of the input data 3 | 4 | val = max([max(abs(real(in)),[],'all') max(abs(imag(in)),[],'all')]); 5 | 6 | end 7 | 8 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/plot_beam_patterns.m: -------------------------------------------------------------------------------- 1 | function plot_beam_patterns(hAxes,mvdrResponse,phaseShiftResponse,signalAngle,interfererAngle) 2 | % Helper function for beam-pattern plotting 3 | % 4 | % Copyright 2021 The MathWorks, Inc. 5 | 6 | az = -90:90; 7 | sigAzIdx = find(az==signalAngle,1); 8 | intAzIdx = find(az==interfererAngle,1); 9 | sigLevel = mvdrResponse(sigAzIdx); 10 | intLevel = mvdrResponse(intAzIdx); 11 | 12 | mvdrValid = ~isinf(sigLevel) && ~isinf(intLevel); 13 | 14 | hold(hAxes,'off'); 15 | plot(hAxes,az,mvdrResponse,'Color','#0072BD','LineStyle','-','LineWidth',2); 16 | hold(hAxes,'on'); 17 | plot(hAxes,az,phaseShiftResponse,'Color','#0072BD','LineStyle','--'); 18 | 19 | if mvdrValid 20 | yregion(hAxes,sigLevel,intLevel,'FaceColor','#faf5d4'); 21 | end 22 | 23 | xline(hAxes,signalAngle,'g'); 24 | xline(hAxes,interfererAngle,'r'); 25 | 26 | if mvdrValid 27 | yline(hAxes,sigLevel,'--','Color',[0.5 0.5 0.5]); 28 | yline(hAxes,intLevel,'--','Color',[0.5 0.5 0.5]); 29 | end 30 | 31 | xlim(hAxes,[az(1) az(end)]); 32 | ylim(hAxes,[-50 10]); 33 | title(hAxes,'Beamforming Pattern'); 34 | xlabel(hAxes,'Azimuth Angle (degrees)'); 35 | ylabel(hAxes,'Normalized Power (dB)'); 36 | legend(hAxes,{'MVDR','PhaseShift'},'Location','SouthWest'); 37 | 38 | end 39 | 40 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/qpsk_receive.m: -------------------------------------------------------------------------------- 1 | function dataOut = qpsk_receive(dataIn, varargin) 2 | % QPSK symbol alignment and decoding 3 | % 4 | % Copyright 2021 The MathWorks, Inc. 5 | 6 | if nargin == 2 7 | assert(isstruct(varargin{1}),'Second argument must be a parameter struct'); 8 | paramStruct = varargin{1}; 9 | FrameLength = paramStruct.FrameLength; 10 | SamplesPerSymbol = paramStruct.SamplesPerSymbol; 11 | PreambleLength = paramStruct.PreambleLength; 12 | mfCoeffs = paramStruct.mfCoeffs; 13 | rrcCoeffs = paramStruct.rrcCoeffs; 14 | else 15 | assert(nargin == 6,'Invalid number of arguments'); 16 | FrameLength = varargin{1}; 17 | SamplesPerSymbol = varargin{2}; 18 | PreambleLength = varargin{3}; 19 | mfCoeffs = varargin{4}; 20 | rrcCoeffs = varargin{5}; 21 | end 22 | 23 | % Upsampled Frame/Preamble lengths 24 | FrameLengthUp = FrameLength*SamplesPerSymbol; 25 | PreambleLengthUp = PreambleLength*SamplesPerSymbol; 26 | 27 | % match filter against preamble 28 | correlatorOut = filter(mfCoeffs,1,dataIn); 29 | 30 | % compute magnitude squared 31 | correlatorMagSq = real(correlatorOut).^2+imag(correlatorOut).^2; 32 | 33 | % Input contains 3 frames of data. 34 | % Search through 1st+2nd frame to avoid OOB alignment in 3rd frame 35 | searchIdx = 1:(2*FrameLengthUp); 36 | 37 | % find max correlator location 38 | maxIdx = find(correlatorMagSq==max(correlatorMagSq(searchIdx)),1); 39 | if isempty(maxIdx) 40 | maxIdx = 1; 41 | else 42 | maxIdx = maxIdx(1); 43 | end 44 | 45 | % rotation angle to correct 46 | rotationAngle=angle(correlatorOut(maxIdx)); 47 | 48 | % index of aligned frame 49 | idxOut = (1:FrameLengthUp) + maxIdx - PreambleLengthUp/2 - 1; 50 | 51 | % get aligned rx frame and correct rotation 52 | rxDataAligned = dataIn(idxOut); 53 | 54 | % apply rotation correction 55 | rxRotated = rxDataAligned*conj(exp(1j*rotationAngle)); 56 | 57 | % Apply RRC filter 58 | rxFiltered = filter(rrcCoeffs,1,rxRotated); 59 | 60 | % Downsample after RRC filter (and discard filter transient) 61 | dataOut = rxFiltered((SamplesPerSymbol*8):SamplesPerSymbol:end); 62 | 63 | end 64 | 65 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/sim_with_progress.m: -------------------------------------------------------------------------------- 1 | function varargout = sim_with_progress(model) 2 | % Opens and runs a Simulink model from MATLAB. During simulation dots, ".", 3 | % are displayed in the MATLAB command window indicating simulation progress. 4 | % Each dot represents 10% of the simulation. 5 | 6 | open_system(model); 7 | [~,name,ext] = fileparts(which(model)); 8 | disp(['Running ' name ext]); 9 | 10 | stopTime = evalin('base',get_param(model,'StopTime')); 11 | 12 | % Stop and delete timer if it's still running. 13 | t = timerfind('name','simProgress'); 14 | if ~isempty(t) 15 | stop(t); 16 | delete(t); 17 | end 18 | 19 | l_showProgress(0,true); 20 | 21 | % Create and start timer. 22 | t = timer('name','simProgress'); 23 | t.Period = 0.2; 24 | t.ExecutionMode = 'fixedRate'; 25 | t.TimerFcn = @(myTimerObj,thisEvent)l_showProgress(get_param(model,'SimulationTime')/stopTime); 26 | start(t); 27 | 28 | % Run Simulink model. 29 | try 30 | if nargout > 0 31 | simout = sim(model); 32 | varargout{1} = simout; 33 | else 34 | sim(model); 35 | % assign logged signals to base workspace 36 | vars = whos; 37 | for ii=1:numel(vars) 38 | var = vars(ii); 39 | if ~any(strcmp(var.name,{'t','stopTime','model','name','ext'})) 40 | assignin('base',var.name,eval(var.name)); 41 | end 42 | end 43 | end 44 | l_showProgress(1); 45 | catch me 46 | % Stop and delete timer. 47 | stop(t); delete(t); 48 | throw(me); 49 | end 50 | 51 | stop(t); delete(t); 52 | 53 | fprintf(newline); 54 | 55 | end 56 | 57 | function l_assignVarsInBase() 58 | 59 | end 60 | 61 | function l_showProgress(progress, initialize) 62 | if nargin < 2 63 | initialize = false; 64 | end 65 | 66 | length = 30; 67 | returnStr = char(8*ones(1,length+11,'uint8')); 68 | 69 | if initialize 70 | prefix = char([]); 71 | else 72 | % Clear previous line 73 | prefix=returnStr; 74 | end 75 | progmark = round(length*progress); 76 | pct = progress*100; 77 | pct_int = floor(pct); 78 | pct_frac = round(100*(pct-pct_int)); 79 | if pct_frac>=100 80 | pct_frac=0; 81 | end 82 | str = [prefix '[' repmat('■',1,progmark) repmat('-',1,length-progmark) '] ' sprintf('%3d',pct_int) '.' sprintf('%02d',pct_frac) '%%' newline]; 83 | fprintf(str); 84 | end 85 | -------------------------------------------------------------------------------- /mvdr_beamformer/common/unpack_complex.m: -------------------------------------------------------------------------------- 1 | function y = unpack_complex(u) 2 | % UNPACK_COMPLEX Unpack uint32 to int16 complex 3 | % 4 | % Copyright 2021 The MathWorks, Inc. 5 | 6 | 7 | u_16 = typecast(u,'int16'); 8 | 9 | y = complex(u_16(1:2:end),u_16(2:2:end)); 10 | 11 | end 12 | 13 | -------------------------------------------------------------------------------- /mvdr_beamformer/mvdr_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/mvdr_beamformer/mvdr_app.png -------------------------------------------------------------------------------- /mvdr_beamformer/mvdr_hdl_sim/mvdr_4x4/model_init.m: -------------------------------------------------------------------------------- 1 | % model_init Setup for MVDR HDL models and testbench 2 | 3 | %% Add common folder to path 4 | thisDir = fileparts(mfilename('fullpath')); 5 | addpath(fullfile(thisDir,'..','..','common')); 6 | 7 | %% Sampling rate 8 | fs = 245.76e6; 9 | Ts = 1/fs; 10 | 11 | %% Environment 12 | propSpeed = physconst('LightSpeed'); % Propagation speed 13 | fc = 860.16e6; % Operating frequency 14 | lambda = propSpeed/fc; 15 | 16 | %% Beamformer parameters 17 | 18 | % Number of array elements 19 | numArrayElements = 4; 20 | 21 | % Uniform linar array 22 | sensorArray = phased.ULA('NumElements',numArrayElements,'ElementSpacing',0.5*lambda); 23 | 24 | % Steering vector computation for array 25 | steeringVector = phased.SteeringVector('SensorArray',sensorArray); 26 | 27 | % Moving average window size 28 | windowSize = 4096; 29 | 30 | % Diagonal loading value 31 | diagLoading = 5e-3; 32 | 33 | %% Generate signal of interest and interferer 34 | 35 | rng('default'); 36 | 37 | testSrc1 = struct(); 38 | testSrc1.NFrames=15; 39 | testSrc1.FrameLength=256; 40 | testSrc1.PreambleLength=13; 41 | testSrc1.SamplesPerSymbol=4; 42 | 43 | [testSrc1.Data,testSrc1.mfCoeffs,testSrc1.rrcCoeffs] = ... 44 | generate_qpsk_signal(testSrc1.NFrames,testSrc1.FrameLength,... 45 | testSrc1.PreambleLength,testSrc1.SamplesPerSymbol); 46 | 47 | testSrc2 = struct(); 48 | testSrc2.NFrames=7; 49 | testSrc2.FrameLength=128; 50 | testSrc2.PreambleLength=13; 51 | testSrc2.SamplesPerSymbol=16; 52 | testSrc2.Data = ... 53 | generate_qpsk_signal(testSrc2.NFrames,testSrc2.FrameLength,... 54 | testSrc2.PreambleLength,testSrc2.SamplesPerSymbol); 55 | 56 | %% Fixed point datatypes 57 | 58 | % RFSoC ADC is 12 bits 59 | adc_dt = fixdt(1,12,11); 60 | 61 | % RF Data converter interface pads to 16 bits 62 | input_dt = fixdt(1,16,15); 63 | 64 | % Covariance Matrix 65 | covmat_dt = fixdt(1,18,16); 66 | 67 | % Moving average 68 | movavg_bitgrowth = nextpow2(windowSize); 69 | movavg_accum_dt = fixdt(1,covmat_dt.WordLength+movavg_bitgrowth,covmat_dt.FractionLength); 70 | movavg_bitshift = nextpow2(windowSize); 71 | movavg_out_dt = fixdt(1,movavg_accum_dt.WordLength-movavg_bitshift,movavg_accum_dt.FractionLength); 72 | 73 | % Use helper function to select types for matrix solver 74 | max_abs_A = sqrt(2); % Upper bound on max(abs(A(:)) 75 | max_abs_B = sqrt(2); % Upper bound on max(abs(B(:)) 76 | matrix_solve_precision = 18; % Number of bits of precision 77 | T = fixed.complexQRMatrixSolveFixedpointTypes(numArrayElements,numArrayElements,... 78 | max_abs_A,max_abs_B,matrix_solve_precision); 79 | 80 | % Matrix solve input 81 | matrixdivin_dt = fixed.extractNumericType(T.A); 82 | 83 | % Matrix solve back-substitition 84 | matrixdivbacksub_dt = fixed.extractNumericType(T.X); 85 | 86 | % Matrix solve output 87 | matrixdivout_dt = fixdt(1,24,matrix_solve_precision); 88 | 89 | % Steering vector 90 | sv_dt = fixdt(1,18,16); 91 | 92 | % Inner product bit growth 93 | ip_bitgrowth = (matrixdivout_dt.WordLength-matrixdivout_dt.FractionLength) + ... 94 | (sv_dt.WordLength - sv_dt.FractionLength) + 2; 95 | 96 | % Reciprocal input 97 | reciprocalin_wl = 26; 98 | reciprocalin_dt = fixdt(1,reciprocalin_wl,reciprocalin_wl-ip_bitgrowth); 99 | 100 | % Reciprocal output 101 | reciprocalout_dt = fixdt(1,reciprocalin_dt.WordLength,reciprocalin_dt.WordLength-4); 102 | 103 | % Weight vector 104 | w_dt = fixdt(1,26,22); 105 | 106 | % Output 107 | output_dt = fixdt(1,32,26); 108 | 109 | %% CORDIC matrix solve parameters 110 | 111 | % N size(data,1)) 9 | data = data.'; 10 | end 11 | 12 | % FFT each channel 13 | f = fft(double(data),length(data),1); 14 | 15 | % Get the peak for each channel 16 | [~,idx] = max(abs(f),[],1); 17 | peak = f(idx,:); 18 | peak = peak(1,:); 19 | 20 | % Normalize everything to channel 1 21 | coeffs = transpose(peak(1)./peak); 22 | 23 | end 24 | -------------------------------------------------------------------------------- /mvdr_beamformer/zcu111_mvdr_demo/model_init.m: -------------------------------------------------------------------------------- 1 | %model_init Setup for TxSteering_RxMVDR_4x4_HDL_IQ.slx 2 | % 3 | % Copyright 2021-2023 The MathWorks, Inc. 4 | 5 | %% Add common folder to path 6 | thisDir = fileparts(mfilename('fullpath')); 7 | addpath(fullfile(thisDir,'..','common')); 8 | 9 | %% RF Data Converter parameters 10 | 11 | % RF ADC/DAC sampling rate 12 | ConverterSampleRate = 1966.08e6; 13 | 14 | % DDC/DUC factor 15 | DecimInterpFactor = 8; 16 | 17 | % Effective data sampling rate 18 | DataSampleRate = ConverterSampleRate/DecimInterpFactor; 19 | Ts = 1/DataSampleRate; 20 | 21 | % Samples per clock cycle 22 | VectorSamplingFactor = 1; 23 | 24 | % FPGA clock rate 25 | FPGAClkRate = DataSampleRate/VectorSamplingFactor; 26 | 27 | % Number of ADC/DAC channels 28 | NumChan = 4; 29 | 30 | % Sample data width 31 | SampleDataWidth = 16*2; % 16-bit I/Q samples 32 | 33 | % Channel data width 34 | ChannelDataWidth = SampleDataWidth*VectorSamplingFactor; 35 | 36 | %% Create test source data 37 | 38 | rng('default'); 39 | 40 | testSrc1 = struct(); 41 | testSrc1.NFrames=15; 42 | testSrc1.FrameLength=256; 43 | testSrc1.PreambleLength=13; 44 | testSrc1.SamplesPerSymbol=4; 45 | 46 | [testSrc1.Data,testSrc1.mfCoeffs,testSrc1.rrcCoeffs] = ... 47 | generate_qpsk_signal(testSrc1.NFrames,testSrc1.FrameLength,... 48 | testSrc1.PreambleLength,testSrc1.SamplesPerSymbol); 49 | 50 | testSrc2 = struct(); 51 | testSrc2.NFrames=7; 52 | testSrc2.FrameLength=128; 53 | testSrc2.PreambleLength=13; 54 | testSrc2.SamplesPerSymbol=16; 55 | testSrc2.Data = ... 56 | generate_qpsk_signal(testSrc2.NFrames,testSrc2.FrameLength,... 57 | testSrc2.PreambleLength,testSrc2.SamplesPerSymbol); 58 | 59 | %% DMA capture parameters 60 | 61 | % For QPSK demod we capture 3 frames of data so that it contains at least 62 | % one full contigious frame 63 | 64 | % S2MM DMA frame size 65 | s2mmFrameSize = testSrc1.FrameLength*testSrc1.SamplesPerSymbol*3; 66 | 67 | % Length of FIFO to handle backpressure from DMA 68 | dmaFIFOLength = 2^nextpow2(testSrc1.FrameLength*testSrc1.SamplesPerSymbol*2); 69 | 70 | %% Environment 71 | propSpeed = physconst('LightSpeed'); % Propagation speed 72 | fc = ConverterSampleRate*7/16; % Operating frequency 73 | lambda = propSpeed/fc; 74 | 75 | %% Beamformer parameters 76 | 77 | % Number of array elements 78 | numArrayElements = 4; 79 | 80 | % Uniform linar array 81 | sensorArray = phased.ULA('NumElements',numArrayElements,'ElementSpacing',0.5*lambda); 82 | 83 | % Steering vector computation for array 84 | steeringVector = phased.SteeringVector('SensorArray',sensorArray); 85 | 86 | % Moving average window size 87 | windowSize = 4096; 88 | 89 | % Diagonal loading value 90 | diagLoading = 5e-3; 91 | 92 | % Use internal directivity object for pattern calculation 93 | elemPosition = sensorArray.getElementPosition(); 94 | angstep = phased.internal.getPatternIntegrationStepSize(elemPosition,lambda); 95 | beamPattern = phased.internal.Directivity('Sensor',sensorArray,... 96 | 'PropagationSpeed',propSpeed,'WeightsInputPort',true,... 97 | 'AzimuthAngleStepSize',angstep,'ElevationAngleStepSize',angstep); 98 | 99 | %% Calibration Tx NCO parameters 100 | 101 | NCO_bits = 14; 102 | NCO_default_freq = 10e6; 103 | NCO_default_inc = fi(floor(NCO_default_freq*2^NCO_bits/DataSampleRate), 1,NCO_bits,0); 104 | 105 | %% Fixed point datatypes 106 | 107 | % RFSoC ADC is 12 bits 108 | adc_dt = fixdt(1,12,11); 109 | 110 | % RF Data converter interface pads to 16 bits 111 | input_dt = fixdt(1,16,15); 112 | 113 | % Covariance Matrix 114 | covmat_dt = fixdt(1,18,16); 115 | 116 | % Moving average 117 | movavg_bitgrowth = nextpow2(windowSize); 118 | movavg_accum_dt = fixdt(1,covmat_dt.WordLength+movavg_bitgrowth,covmat_dt.FractionLength); 119 | movavg_bitshift = nextpow2(windowSize); 120 | movavg_out_dt = fixdt(1,movavg_accum_dt.WordLength-movavg_bitshift,movavg_accum_dt.FractionLength); 121 | 122 | % Use helper function to select types for matrix solver 123 | max_abs_A = sqrt(2); % Upper bound on max(abs(A(:)) 124 | max_abs_B = sqrt(2); % Upper bound on max(abs(B(:)) 125 | matrix_solve_precision = 18; % Number of bits of precision 126 | T = fixed.complexQRMatrixSolveFixedpointTypes(numArrayElements,numArrayElements,... 127 | max_abs_A,max_abs_B,matrix_solve_precision); 128 | 129 | % Matrix solve input 130 | matrixdivin_dt = fixed.extractNumericType(T.A); 131 | 132 | % Matrix solve back-substitition 133 | matrixdivbacksub_dt = fixed.extractNumericType(T.X); 134 | 135 | % Matrix solve output 136 | matrixdivout_dt = fixdt(1,24,matrix_solve_precision); 137 | 138 | % Steering vector 139 | sv_dt = fixdt(1,18,16); 140 | 141 | % Inner product bit growth 142 | ip_bitgrowth = (matrixdivout_dt.WordLength-matrixdivout_dt.FractionLength) + ... 143 | (sv_dt.WordLength - sv_dt.FractionLength) + 2; 144 | 145 | % Reciprocal input 146 | reciprocalin_wl = 26; 147 | reciprocalin_dt = fixdt(1,reciprocalin_wl,reciprocalin_wl-ip_bitgrowth); 148 | 149 | % Reciprocal output 150 | reciprocalout_dt = fixdt(1,reciprocalin_dt.WordLength,reciprocalin_dt.WordLength-4); 151 | 152 | % Weight vector 153 | w_dt = fixdt(1,26,22); 154 | 155 | % Rx/Tx channel coefficients 156 | coeff_dt = fixdt(1,18,16); 157 | 158 | % Output 159 | output_dt = fixdt(1,32,26); 160 | 161 | % Tx output gain 162 | tx_gain_dt = fixdt(1,16,14); 163 | 164 | %% Rx magnitude measurement parameters 165 | 166 | rx_mag_window_size = 256; 167 | rx_mag_sum_growth = nextpow2(rx_mag_window_size); 168 | 169 | rx_mag_dt = fixdt(0,input_dt.WordLength,input_dt.FractionLength); 170 | rx_mag_inv_dt = fixdt(1,27,16); 171 | rx_gain_dt = fixdt(1,rx_mag_inv_dt.WordLength-1,rx_mag_inv_dt.FractionLength); 172 | 173 | rx_mag_delay = input_dt.WordLength + 2 + ceil(log2(NumChan)) + 1 + rx_mag_window_size; 174 | rx_mag_inverse_delay = nextpow2(rx_mag_dt.WordLength) + 1 + rx_mag_dt.WordLength + 2 + 7; 175 | 176 | %% CORDIC matrix solve parameters 177 | 178 | % N 245.76 30 | warning('Selected FPGA rate %3.3f MHz exceeds the timing that was used during synthesis (%3.3f MHz) for this design! Timing failures may occur which can lead to unexpected behavior. Re-synthesizing your design may be required to achieve faster rates.',... 31 | FPGAClockRate,245.76); 32 | end 33 | 34 | %% Establish TCP/IP connection 35 | setup(rfobj) 36 | 37 | %% Tile / Channels 38 | 39 | %% Set External Clocking Options 40 | %% Set required clocks for MTS 41 | rfobj.LMKClkSelect = 'SYSREF'; 42 | rfobj.configureLMXPLL(ReferenceClock); 43 | 44 | 45 | 46 | %% Setup ADC/DAC Tile sampling and PLL rates 47 | for TileId = 0:(rfobj.TotalADCTiles-1) 48 | rfobj.configureADCTile(TileId,PLLSrc,ReferenceClock,ADCSamplingRate); 49 | for ChId = 0:(rfobj.ADCChannelsPerTile-1) 50 | rfobj.configureADCChannel(TileId,ChId,DecimationFactor); 51 | end 52 | end 53 | 54 | for TileId = 0:(rfobj.TotalDACTiles-1) 55 | rfobj.configureDACTile(TileId,PLLSrc,ReferenceClock,DACSamplingRate); 56 | for ChId = 0:(rfobj.DACChannelsPerTile-1) 57 | rfobj.configureDACChannel(TileId,ChId,InterpolationFactor); 58 | end 59 | end 60 | 61 | %% ADC IQ mode settings 62 | 63 | ADC_DDC_LO = -DDC_DUC_LO; 64 | ADC_MixingScale = '1'; 65 | ADC_MixerPhase = 0.0; 66 | 67 | if rfobj.MTSConfigure 68 | EventMode = 'Sysref'; 69 | else 70 | EventMode = 'Tile'; 71 | end 72 | 73 | for TileId = 0:(rfobj.TotalADCTiles-1) 74 | for ChId = 0:(rfobj.ADCChannelsPerTile-1) 75 | if FineMixMode %Fine Mixing Mode 76 | configureADCMixer(rfobj, TileId, ChId, 'Fine', ADC_DDC_LO, EventMode, ADC_MixerPhase, ADC_MixingScale); 77 | else %Coarse Mixing Mode 78 | configureADCMixer(rfobj, TileId, ChId, 'Coarse', '-Fs/4', EventMode, ADC_MixerPhase, ADC_MixingScale); 79 | end 80 | end 81 | end 82 | 83 | %% DAC IQ mode settings 84 | 85 | DAC_DDC_LO = DDC_DUC_LO; 86 | DAC_MixingScale = '1'; 87 | DAC_MixerPhase = 0.0; 88 | 89 | if rfobj.MTSConfigure 90 | EventMode = 'Sysref'; 91 | else 92 | EventMode = 'Immediate'; 93 | end 94 | 95 | for TileId = 0:(rfobj.TotalDACTiles-1) 96 | for ChId = 0:(rfobj.DACChannelsPerTile-1) 97 | if FineMixMode %Fine Mixing Mode 98 | configureDACMixer(rfobj, TileId, ChId, 'Fine', DAC_DDC_LO, EventMode, DAC_MixerPhase, DAC_MixingScale); 99 | else %Coarse Mixing Mode 100 | configureDACMixer(rfobj, TileId, ChId, 'Coarse', 'Fs/4', EventMode, DAC_MixerPhase, ADC_MixingScale); 101 | end 102 | end 103 | 104 | end 105 | 106 | 107 | 108 | 109 | %% Apply settings to RFTool 110 | applyConfiguration(rfobj) 111 | 112 | 113 | 114 | %% Perform MTS capture 115 | rfobj.enableMTS() 116 | 117 | %% Disconnect and clear system object 118 | %release(rfobj) 119 | 120 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/2dFFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/2dFFT.jpg -------------------------------------------------------------------------------- /rangedoppler/hw_only/README.md: -------------------------------------------------------------------------------- 1 | # Range-Doppler FPGA Examples 2 | 3 | ## Overview 4 | 5 | These models demonstrate how two-dimensional transpose using external DDR4 6 | memory can be used for range-doppler processing for radar applications such as 7 | range-doppler. Some examples will require SoC Blockset for memory simulation. 8 | 9 | ## Demo Files 10 | 11 | ### partA_TransposeMatrix ### 12 | 13 | State-machine logic simulation for handling matrix transpose. Examples in these folders use SoC Blockset for simulating PL-DDR4 access and HDL Coder for deploying a matrix transpose example on the ZCU111. Incremental improvements to DDR4 corner turn memory access is shown by taking advantage of "wr-ready" and using a BRAM memory burst approach instead of bursting in one sample into memory at a time. 14 | 15 | 16 | 17 | 18 | In the BRAM burst approach, several rows of the matrix is stored in block ram first. After accumulation of several rows, a column of data is bursted in. Management of these blockram memory "banks" is done with state machine logic. The above plot comes from analyzing the throughputs of writing memory using BRAM burst transposed then reading it back out. 19 | 20 | ### partB_MatchedFilterFFTTranspose ### 21 | 22 | Building on top of the previous example, this demo shows how a two-dimensional range-doppler processing example can be accomplished on an FPGA using HDL Coder. Similar to the previous example, this can also run on the ZCU111. BRAM Burst writes into memory are done to increase memory write throughputs. 23 | 24 | 25 | 26 | This demo will start with MATLAB code first of running a matched FIR filter then transposing the data and performing an FFT over several radar cubes. An HDL implementation of this is then done to compute the FIR and FFT along with the transpose. 27 | 28 | The license used in this contribution is the XSLA license, which is the most common license for MathWorks staff contributions. 29 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/RangeDoppler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/RangeDoppler.jpg -------------------------------------------------------------------------------- /rangedoppler/hw_only/bandwidth_cornerturn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/bandwidth_cornerturn.jpg -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/MatrixWrRd_transpose_SoCB_TopLevel.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/MatrixWrRd_transpose_SoCB_TopLevel.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/hdlcoder_external_memory_read_ctrl_custom.m: -------------------------------------------------------------------------------- 1 | function [valid_out, count_out, ddr_read_done, rd_addr, rd_len, rd_avalid,ToggleTLAST,debug_state] = ... 2 | hdlcoder_external_memory_read_ctrl_custom(burst_len, start, rd_aready, rd_dvalid) 3 | %% hdlcoder_external_memory_read_ctrl_custom 4 | % 5 | % % State-machine behavior for reading DDR4 6 | 7 | % Copyright 2017 The MathWorks, Inc. 8 | 9 | % create persistent variables (registers) 10 | persistent rstate burst_stop burst_count 11 | if isempty(rstate) 12 | rstate = fi(0, 0, 4, 0); 13 | burst_stop = uint32(0); 14 | burst_count = uint32(0); 15 | debug_state = cast(0,'like',rstate); 16 | end 17 | 18 | % state Memory Encoding 19 | IDLE = fi(0, 0, 4, 0); 20 | READ_BURST_START = fi(1, 0, 4, 0); 21 | READ_BURST_REQUEST = fi(2, 0, 4, 0); 22 | DATA_COUNT = fi(3, 0, 4, 0); 23 | 24 | ToggleTLAST = false; 25 | 26 | % state machine logic 27 | switch (rstate) 28 | case IDLE 29 | % output to AXI4 Master 30 | rd_addr = uint32(0); 31 | rd_len = uint32(0); 32 | rd_avalid = false; 33 | 34 | % output to DUT logic 35 | valid_out = false; 36 | count_out = uint32(0); 37 | ddr_read_done = true; 38 | 39 | % State vars 40 | burst_stop = uint32(burst_len); 41 | burst_count = uint32(0); 42 | 43 | if start 44 | rstate(:) = READ_BURST_START; 45 | else 46 | rstate(:) = IDLE; 47 | end 48 | 49 | case READ_BURST_START 50 | % Daren Notes: the two pieces of information below is a read request 51 | % 52 | % rd_addr: Starting address for the read transaction that is sampled at 53 | % the first cycle of the transaction. 54 | % rd_len: The number of data values that you want to read, 55 | % sampled at the first cycle of the transaction. 56 | % 57 | % We only move to READ_BURST_REQUST if rd_aready is HIGH to confirm 58 | % DDR is ready for a readback request 59 | 60 | % output to AXI4 Master 61 | rd_addr = uint32(0); 62 | rd_len = uint32(burst_stop); 63 | rd_avalid = false; 64 | 65 | % output to DUT logic 66 | valid_out = false; 67 | count_out = uint32(0); 68 | ddr_read_done = false; 69 | 70 | if rd_aready 71 | rstate(:) = READ_BURST_REQUEST; 72 | else 73 | rstate(:) = READ_BURST_START; 74 | end 75 | 76 | case READ_BURST_REQUEST 77 | % Daren Notes: read request 78 | % 79 | % rd_avalid: Control signal that specifies whether the read request is valid. 80 | % 81 | % 82 | 83 | % output to AXI4 Master 84 | rd_addr = uint32(0); 85 | rd_len = uint32(burst_stop); 86 | rd_avalid = true; 87 | 88 | % output to DUT logic 89 | valid_out = false; 90 | count_out = uint32(0); 91 | ddr_read_done = false; 92 | 93 | rstate(:) = DATA_COUNT; 94 | 95 | case DATA_COUNT 96 | % output to AXI4 Master 97 | rd_addr = uint32(0); 98 | rd_len = uint32(burst_stop); 99 | rd_avalid = false; 100 | 101 | % output to DUT logic 102 | valid_out = rd_dvalid; 103 | count_out = uint32(burst_count); 104 | ddr_read_done = false; 105 | 106 | % State vars 107 | if ( rd_dvalid ) 108 | burst_count = uint32(burst_count + 1); 109 | end 110 | 111 | if ( burst_count == burst_stop ) 112 | rstate(:) = IDLE; 113 | if rd_dvalid 114 | ToggleTLAST = true; 115 | end 116 | else 117 | rstate(:) = DATA_COUNT; 118 | end 119 | 120 | otherwise 121 | % output to AXI4 Master 122 | rd_addr = uint32(0); 123 | rd_len = uint32(0); 124 | rd_avalid = false; 125 | 126 | % output to DUT logic 127 | valid_out = false; 128 | count_out = uint32(0); 129 | ddr_read_done = false; 130 | 131 | rstate(:) = IDLE; 132 | end 133 | 134 | debug_state(:) = rstate; 135 | 136 | end 137 | 138 | % LocalWords: AXI 139 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/hdlcoder_external_memory_write_ctrl_custom.m: -------------------------------------------------------------------------------- 1 | function [ram_addr, ddr_write_done, wr_addr, wr_len, wr_valid, wasted_cycle_cnt, matrix_wr_done] = ... 2 | hdlcoder_external_memory_write_ctrl_custom(addr_in,burst_len, start, wr_ready, wr_complete) 3 | %% hdlcoder_external_memory_write_ctrl_custom 4 | % 5 | % % State-machine behavior for writing to DDR4 6 | 7 | % Copyright 2017 The MathWorks, Inc. 8 | 9 | % create persistent variables (registers) 10 | persistent wstate burst_stop burst_count wasted_cycle_count 11 | persistent addr_value addr_offset_add 12 | if(isempty(wstate)) 13 | wstate = fi(0, 0, 4, 0); 14 | burst_stop = uint32(0); 15 | burst_count = uint32(0); 16 | wasted_cycle_count = uint32(0); 17 | addr_value = uint32(0); 18 | addr_offset_add = uint32(0); 19 | end 20 | wasted_cycle_cnt = cast(0,'like',wasted_cycle_count); 21 | 22 | % state machine encoding 23 | IDLE = fi(0, 0, 4, 0); 24 | WRITE_BURST_START = fi(1, 0, 4, 0); 25 | DATA_COUNT = fi(2, 0, 4, 0); 26 | ACK_WAIT = fi(3, 0, 4, 0); 27 | 28 | % state machine logic 29 | switch (wstate) 30 | case IDLE 31 | % output to AXI4 Master 32 | wr_addr = uint32(0); % 4-byte address 33 | wr_len = uint32(0); 34 | wr_valid = false; 35 | 36 | % output to DUT logic 37 | ram_addr = uint32(0); 38 | ddr_write_done = true; 39 | matrix_wr_done = false; 40 | 41 | % state variables 42 | burst_stop = uint32(burst_len); 43 | burst_count = uint32(0); 44 | 45 | if start 46 | wstate(:) = WRITE_BURST_START; 47 | else 48 | wstate(:) = IDLE; 49 | end 50 | 51 | 52 | case WRITE_BURST_START 53 | % output to AXI4 Master 54 | wr_addr = uint32(addr_value*4); 55 | wr_len = uint32(burst_stop); 56 | wr_valid = false; 57 | 58 | % output to DUT logic 59 | ram_addr = uint32(burst_count); 60 | ddr_write_done = false; 61 | matrix_wr_done = false; 62 | 63 | if wr_ready 64 | wstate(:) = DATA_COUNT; 65 | else 66 | wstate(:) = WRITE_BURST_START; 67 | wasted_cycle_count = uint32(wasted_cycle_count+1); 68 | end 69 | 70 | 71 | case DATA_COUNT 72 | % output to AXI4 Master 73 | wr_addr = uint32(addr_value*4); 74 | wr_len = uint32(burst_stop); 75 | wr_valid = true; 76 | 77 | % state variables 78 | burst_count = uint32(burst_count + 1); 79 | 80 | % output to DUT logic 81 | ram_addr = uint32(burst_count); 82 | ddr_write_done = false; 83 | matrix_wr_done = false; 84 | 85 | if ( burst_count == burst_stop ) 86 | wstate(:) = ACK_WAIT; 87 | else 88 | if ( wr_ready ) 89 | wstate(:) = DATA_COUNT; 90 | else 91 | wstate(:) = WRITE_BURST_START; 92 | end 93 | end 94 | 95 | 96 | case ACK_WAIT 97 | % output to AXI4 Master 98 | wr_addr = uint32(0); 99 | wr_len = uint32(0); 100 | wr_valid = false; 101 | 102 | % output to DUT logic 103 | ram_addr = uint32(0); 104 | ddr_write_done = false; 105 | matrix_wr_done = false; 106 | 107 | if wr_complete 108 | wstate(:) = IDLE; 109 | 110 | % will need to throw in additional checks here for ping-poing 111 | % buffer 112 | % ie: first buffer addr offset = 0 113 | % 2nd buffer addr offset = 24*16 + 1 114 | % 115 | if addr_value < (24*16 - 16) % N1 * N2 116 | addr_value(:) = addr_value + 16 + addr_offset_add ; 117 | else 118 | addr_value(:) = 0; % perform reset on address 119 | matrix_wr_done = true; 120 | end 121 | else 122 | wstate(:) = ACK_WAIT; 123 | end 124 | 125 | otherwise 126 | % output to AXI4 Master 127 | wr_addr = uint32(0); 128 | wr_len = uint32(0); 129 | wr_valid = false; 130 | matrix_wr_done = false; 131 | 132 | % output to DUT logic 133 | ram_addr = uint32(0); 134 | ddr_write_done = false; 135 | 136 | wstate(:) = IDLE; 137 | 138 | end 139 | 140 | % For AXI4 MM Diagonstics 141 | wasted_cycle_cnt(:) = wasted_cycle_count; 142 | 143 | end 144 | 145 | % LocalWords: AXI 146 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/matrix_init.m: -------------------------------------------------------------------------------- 1 | %% Model coefficients 2 | N1 = 20; % row 3 | N2 = 20; % columns 4 | 5 | MatrixInputArr = [1:N1*N2]; 6 | MatrixInput = reshape(MatrixInputArr,[N1,N2]); 7 | 8 | 9 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/matrix_rdwr_transpose_fpga.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/matrix_rdwr_transpose_fpga.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part0_SoCB/validate_matrix_out.m: -------------------------------------------------------------------------------- 1 | %% Run this after reading matrix value out 2 | rdMat = MatrixRd.signals(1).values(MatrixRd.signals(2).values); 3 | rdOut = reshape(rdMat(1:N1*N2),[N2,N1]); 4 | 5 | fprintf('Matrix written to DDR4: \n'); 6 | disp(MatrixInput); 7 | disp('------') 8 | 9 | fprintf('Matrix read out of DDR4: \n'); 10 | disp(rdOut); 11 | disp('------') 12 | 13 | if rdOut ~= transpose(MatrixInput) 14 | error('Bad transpose!'); 15 | end 16 | 17 | if length(rdMat(:)) > N2*N1 18 | rdMatFormat = reshape(rdMat,[N2 N1 length(rdMat)/(N2*N1)]); 19 | three_dim_diff = diff(rdMatFormat,3); 20 | if any(three_dim_diff(:) ~= 0) 21 | error('Matrix values inconsistent across time!'); 22 | end 23 | end -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part1_hdl_wrready/matrix_init.m: -------------------------------------------------------------------------------- 1 | %% Model coefficients 2 | N1 = 7; % row 3 | N2 = 6; % columns 4 | 5 | MatrixInputArr = [1:N1*N2]; 6 | MatrixInput = reshape(MatrixInputArr,[N1,N2]); 7 | 8 | 9 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part1_hdl_wrready/validate_matrix_out.m: -------------------------------------------------------------------------------- 1 | %% Run this after reading matrix value out 2 | MatrixRd = out.ScopeData; 3 | Valid = MatrixRd.signals(2).values(:); 4 | rdMat = MatrixRd.signals(1).values(:); 5 | 6 | rdMat = rdMat(Valid); 7 | 8 | iter = length(rdMat)/(N1*N2); 9 | 10 | for ii = 1:iter 11 | range = (1:N1*N2) + (ii-1)*(N1*N2); 12 | rdOut = reshape(rdMat(range),[N2,N1]); 13 | 14 | fprintf('Matrix read out of DDR4: \n'); 15 | disp(rdOut); 16 | disp('------') 17 | 18 | 19 | fprintf('Matrix written to DDR4: \n'); 20 | disp(MatrixInput); 21 | disp('------') 22 | 23 | compare = transpose(MatrixInput); 24 | if any(rdOut(:) ~= compare(:)) 25 | error('Bad transpose!'); 26 | end 27 | end -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part1_hdl_wrready/wrQueue_RFSoC_MatrixTranspose.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partA_TransposeMatrix/part1_hdl_wrready/wrQueue_RFSoC_MatrixTranspose.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/AXIBusObjects.m: -------------------------------------------------------------------------------- 1 | function AXIBusObjects() 2 | % AXIBUSOBJECTS initializes a set of bus objects in the MATLAB base workspace 3 | 4 | % Bus object: BusAXIWriteCtrlM2S 5 | clear elems; 6 | elems(1) = Simulink.BusElement; 7 | elems(1).Name = 'wr_addr'; 8 | elems(1).Dimensions = 1; 9 | elems(1).DimensionsMode = 'Fixed'; 10 | elems(1).DataType = 'uint32'; 11 | elems(1).SampleTime = -1; 12 | elems(1).Complexity = 'real'; 13 | elems(1).Min = []; 14 | elems(1).Max = []; 15 | elems(1).DocUnits = ''; 16 | elems(1).Description = ''; 17 | 18 | elems(2) = Simulink.BusElement; 19 | elems(2).Name = 'wr_len'; 20 | elems(2).Dimensions = 1; 21 | elems(2).DimensionsMode = 'Fixed'; 22 | elems(2).DataType = 'uint32'; 23 | elems(2).SampleTime = -1; 24 | elems(2).Complexity = 'real'; 25 | elems(2).Min = []; 26 | elems(2).Max = []; 27 | elems(2).DocUnits = ''; 28 | elems(2).Description = ''; 29 | 30 | elems(3) = Simulink.BusElement; 31 | elems(3).Name = 'wr_valid'; 32 | elems(3).Dimensions = 1; 33 | elems(3).DimensionsMode = 'Fixed'; 34 | elems(3).DataType = 'boolean'; 35 | elems(3).SampleTime = -1; 36 | elems(3).Complexity = 'real'; 37 | elems(3).Min = []; 38 | elems(3).Max = []; 39 | elems(3).DocUnits = ''; 40 | elems(3).Description = ''; 41 | 42 | BusAXIWriteCtrlM2S = Simulink.Bus; 43 | BusAXIWriteCtrlM2S.HeaderFile = ''; 44 | BusAXIWriteCtrlM2S.Description = ''; 45 | BusAXIWriteCtrlM2S.DataScope = 'Auto'; 46 | BusAXIWriteCtrlM2S.Alignment = -1; 47 | BusAXIWriteCtrlM2S.Elements = elems; 48 | clear elems; 49 | assignin('base','BusAXIWriteCtrlM2S', BusAXIWriteCtrlM2S); 50 | 51 | % Bus object: BusAXIWriteCtrlS2M 52 | clear elems; 53 | elems(1) = Simulink.BusElement; 54 | elems(1).Name = 'wr_ready'; 55 | elems(1).Dimensions = 1; 56 | elems(1).DimensionsMode = 'Fixed'; 57 | elems(1).DataType = 'boolean'; 58 | elems(1).SampleTime = -1; 59 | elems(1).Complexity = 'real'; 60 | elems(1).Min = []; 61 | elems(1).Max = []; 62 | elems(1).DocUnits = ''; 63 | elems(1).Description = ''; 64 | 65 | elems(2) = Simulink.BusElement; 66 | elems(2).Name = 'wr_complete'; 67 | elems(2).Dimensions = 1; 68 | elems(2).DimensionsMode = 'Fixed'; 69 | elems(2).DataType = 'boolean'; 70 | elems(2).SampleTime = -1; 71 | elems(2).Complexity = 'real'; 72 | elems(2).Min = []; 73 | elems(2).Max = []; 74 | elems(2).DocUnits = ''; 75 | elems(2).Description = ''; 76 | 77 | BusAXIWriteCtrlS2M = Simulink.Bus; 78 | BusAXIWriteCtrlS2M.HeaderFile = ''; 79 | BusAXIWriteCtrlS2M.Description = ''; 80 | BusAXIWriteCtrlS2M.DataScope = 'Auto'; 81 | BusAXIWriteCtrlS2M.Alignment = -1; 82 | BusAXIWriteCtrlS2M.Elements = elems; 83 | clear elems; 84 | assignin('base','BusAXIWriteCtrlS2M', BusAXIWriteCtrlS2M); 85 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/bramBurst_TransposeMatrix.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/bramBurst_TransposeMatrix.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/matrix_init.m: -------------------------------------------------------------------------------- 1 | %% Model coefficients 2 | N1 = 65; % row 3 | N2 = 60; % columns 4 | Ts = 1; 5 | MatrixInputArr = [1:N1*N2]; 6 | MatrixInput = reshape(MatrixInputArr,[N1,N2]); 7 | 8 | 9 | pNumCols = N1; 10 | pNumRows = N2; 11 | run AXIBusObjects; 12 | pAXIDataWidthBytes = 8; % number of bytes (64 bits) for AXI Data-Width 13 | pMaxBankLines = 6; 14 | pMaxNumBanks = 3; 15 | 16 | %Bram address width 17 | pBramAddrWidth = ceil(log2(pMaxBankLines*pMaxNumBanks*pNumCols)); 18 | 19 | %% BRAM savings 20 | 21 | bramSaving = ( 1 - pMaxBankLines*pMaxNumBanks*pNumCols / (pNumCols*pNumRows))*100; 22 | fprintf('By using DDR4 memory we reduced BRAM usage of the transpose by %2.1f percent. Address width is %d-bits \n',bramSaving,pBramAddrWidth); 23 | 24 | %% State machine labeling 25 | % LINEBUFFER = fi(1,0,4,0); 26 | % LINESTART = fi(3,0,4,0); 27 | Simulink.defineIntEnumType('stateBRAMfsm', {'IDLE','LINEBUFFER', 'LINESTART'}, [0 1 3]); 28 | 29 | 30 | % BURSTSTART = fi(1,0,4,0); 31 | % BURSTNEXT = fi(3,0,4,0); 32 | % WAITBURSTCOMPLETE = fi(4,0,4,0); 33 | % WAITBURSTREADY = fi(5,0,4,0); 34 | % WAITONBANKRDY =fi(2,0,4,0); 35 | Simulink.defineIntEnumType('stateAXI4Mfsm', {'IDLE',... 36 | 'BURSTSTART',... 37 | 'WAITONBANKRDY',... 38 | 'BURSTNEXT',... 39 | 'WAITBURSTCOMPLETE',... 40 | 'WAITBURSTREADY'}, [0 1 2 3 4 5]); 41 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/model_init_sim.m: -------------------------------------------------------------------------------- 1 | % model_init for DL model 2 | if ~exist('numCols','var') 3 | numCols = 320; 4 | numRows = 200; 5 | end 6 | pixelcontrolbus; 7 | frm2pix = visionhdl.FrameToPixels; 8 | frm2pix.VideoFormat = '1080p'; 9 | [~, ~, totalPixels] = getparamfromfrm2pix(frm2pix); 10 | Ts = 1/(totalPixels*60); 11 | clear frm2pix; 12 | 13 | run AXIBusObjects; 14 | pAXIDataWidthBytes = 4; % number of bytes (128 bits) for AXI Data-Width 15 | inputImageDDROffset = uint32(hex2dec('00000000')); % addr = 0x8000-0000 16 | 17 | pMaxBankLines = 8; 18 | pMaxNumBanks = 3; 19 | 20 | pNumCols = 30; 21 | pNumRows = 30; 22 | % Note: based on a 1080p frame and the pNumRows/Cols are sub-ROI 23 | % dimensions, define blanking vars to simulate this 24 | % hBlank = frm2pix.TotalPixelsPerLine - pNumCols; 25 | % vBlank = frm2pix.TotalVideoLines - pNumRows; 26 | 27 | % Note: for demonstration purposes, re-define blanking vars 28 | hBlank = 20; 29 | vBlank = 8; 30 | 31 | %% create input image in case you want defined data to push 32 | clear imageIn; 33 | 34 | % uncomment these lines to just see integers in the LA 35 | imageIn(:,:,1) = repmat(zeros(pNumRows,1,'uint8'),1,pNumCols); 36 | imageIn(:,:,2) = repmat(zeros(pNumRows,1,'uint8'),1,pNumCols); 37 | imageIn(:,:,3) = repmat(uint8([1:pNumRows]'),1,pNumCols); 38 | 39 | % uncomment these lines to just see a yellow gradient in the video viewer 40 | % imageIn(:,:,1) = repmat(linspace(0,255,pNumRows)',1,pNumCols); 41 | % imageIn(:,:,2) = repmat(linspace(0,255,pNumRows)',1,pNumCols); 42 | % imageIn(:,:,3) = repmat([1:pNumRows]',1,pNumCols); 43 | 44 | % testImage = uint8([repmat(1:pNumCols,pNumRows,1,3)]); 45 | 46 | %% BRAM savings 47 | bramAddrWidth = ceil(log2(pMaxBankLines*pMaxNumBanks*pNumCols)); 48 | bramSaving = ( 1 - pMaxBankLines*pMaxNumBanks*pNumCols / (pNumCols*pNumRows))*100; 49 | fprintf('By using DDR4 memory we reduced BRAM usage of the transpose by %2.1f percent. Address width is %d-bits \n',bramSaving,bramAddrWidth); 50 | 51 | %% State machine labeling 52 | % LINEBUFFER = fi(1,0,4,0); 53 | % LINESTART = fi(3,0,4,0); 54 | Simulink.defineIntEnumType('stateBRAMfsm', {'IDLE','LINEBUFFER', 'LINESTART'}, [0 1 3]); 55 | 56 | 57 | % BURSTSTART = fi(1,0,4,0); 58 | % BURSTNEXT = fi(3,0,4,0); 59 | % WAITBURSTCOMPLETE = fi(4,0,4,0); 60 | % WAITBURSTREADY = fi(5,0,4,0); 61 | % WAITONBANKRDY =fi(2,0,4,0); 62 | Simulink.defineIntEnumType('stateAXI4Mfsm', {'IDLE',... 63 | 'BURSTSTART',... 64 | 'WAITONBANKRDY',... 65 | 'BURSTNEXT',... 66 | 'WAITBURSTCOMPLETE',... 67 | 'WAITBURSTREADY'}, [0 1 2 3 4 5]); 68 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/run_fpgaIO.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % Software Interface Script 3 | % 4 | % Generated with MATLAB 9.10 (R2021a) at 19:37:54 on 13/06/2021. 5 | % This script was created for the IP Core generated from design 'ddrxpose_21a_generic_fft_rdy2'. 6 | % 7 | % Use this script to access DUT ports in the design that were mapped to compatible IP core interfaces. 8 | % You can write to input ports in the design and read from output ports directly from MATLAB. 9 | % To write to input ports, use the "writePort" command and specify the port name and input data. The input data will be cast to the DUT port's data type before writing. 10 | % To read from output ports, use the "readPort" command and specify the port name. The output data will be returned with the same data type as the DUT port. 11 | % Use the "release" command to release MATLAB's control of the hardware resources. 12 | %-------------------------------------------------------------------------- 13 | 14 | %% Create fpga object 15 | hFPGA = fpga("Xilinx"); 16 | 17 | %% Setup fpga object 18 | % This function configures the "fpga" object with the same interfaces as the generated IP core 19 | N1 = 65; 20 | N2 = 60; 21 | frameSize = 65*60; 22 | transpose_fpgaIO_setup(hFPGA,frameSize); 23 | 24 | %% Write/read DUT ports 25 | % Uncomment the following lines to write/read DUT ports in the generated IP Core. 26 | % Update the example data in the write commands with meaningful data to write to the DUT. 27 | %% AXI4 28 | % writePort(hFPGA, "inputImageDDROffset", zeros([1 1])); 29 | % data_ddrDoneCounter = readPort(hFPGA, "ddrDoneCounter"); 30 | % data_fifo_full_event = readPort(hFPGA, "fifo_full_event"); 31 | 32 | %% AXI4-Stream DMA 33 | % writePort(hFPGA, "DataIn", zeros([1 1024])); 34 | % data_tdata_o = readPort(hFPGA, "tdata_o"); 35 | for ii = 1:50 36 | MatrixInputArr = [1:N1*N2]*ii; 37 | MatrixInput = reshape(MatrixInputArr,[N1,N2]); 38 | 39 | 40 | writePort(hFPGA, "DataIn", MatrixInput); 41 | 42 | % pause(1); 43 | data_ddrDoneCounter = readPort(hFPGA, "ddrDoneCounter"); 44 | fprintf('DDR4 write done count = %d \n',data_ddrDoneCounter); 45 | data_tdata_o = readPort(hFPGA, "tdata_o"); 46 | c = reshape(data_tdata_o,N2,N1); %<--- note we swap N2 and N1 because this is transposed.. 47 | diff_data = double(MatrixInput.') - double(c(:,:)); 48 | % plot(diff(:)) 49 | if any(diff_data~=0) 50 | warning('bad transpose!') 51 | end 52 | end 53 | %% Release hardware resources 54 | release(hFPGA); 55 | 56 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/transpose_fpgaIO_setup.m: -------------------------------------------------------------------------------- 1 | function transpose_fpgaIO_setup(hFPGA,frameSize) 2 | %-------------------------------------------------------------------------- 3 | % Software Interface Script Setup 4 | % 5 | % Generated with MATLAB 9.10 (R2021a) at 19:37:54 on 13/06/2021. 6 | % This function was created for the IP Core generated from design 'ddrxpose_21a_generic_fft_rdy2'. 7 | % 8 | % Run this function on an "fpga" object to configure it with the same interfaces as the generated IP core. 9 | %-------------------------------------------------------------------------- 10 | 11 | %% AXI4 12 | addAXI4SlaveInterface(hFPGA, ... 13 | "InterfaceID", "AXI4", ... 14 | "BaseAddress", 0xA0000000, ... 15 | "AddressRange", 0x10000); 16 | 17 | hPort_inputImageDDROffset = hdlcoder.DUTPort("inputImageDDROffset", ... 18 | "Direction", "IN", ... 19 | "DataType", numerictype(0,32,0), ... 20 | "Dimension", [1 1], ... 21 | "IOInterface", "AXI4", ... 22 | "IOInterfaceMapping", "0x100"); 23 | 24 | hPort_ddrDoneCounter = hdlcoder.DUTPort("ddrDoneCounter", ... 25 | "Direction", "OUT", ... 26 | "DataType", numerictype(1,32,0), ... 27 | "Dimension", [1 1], ... 28 | "IOInterface", "AXI4", ... 29 | "IOInterfaceMapping", "0x104"); 30 | 31 | hPort_fifo_full_event = hdlcoder.DUTPort("fifo_full_event", ... 32 | "Direction", "OUT", ... 33 | "DataType", numerictype(0,32,0), ... 34 | "Dimension", [1 1], ... 35 | "IOInterface", "AXI4", ... 36 | "IOInterfaceMapping", "0x108"); 37 | 38 | mapPort(hFPGA, [hPort_inputImageDDROffset, hPort_ddrDoneCounter, hPort_fifo_full_event]); 39 | 40 | %% AXI4-Stream DMA 41 | addAXI4StreamInterface(hFPGA, ... 42 | "InterfaceID", "AXI4-Stream DMA", ... 43 | "WriteEnable", true, ... 44 | "WriteDataWidth", 64, ... 45 | "WriteFrameLength", frameSize, ... 46 | "ReadEnable", true, ... 47 | "ReadDataWidth", 64, ... 48 | "ReadFrameLength", frameSize,... 49 | 'WriteTimeout',0,... 50 | 'ReadTimeout',0); 51 | 52 | hPort_DataIn = hdlcoder.DUTPort("DataIn", ... 53 | "Direction", "IN", ... 54 | "DataType", numerictype(1,64,0), ... 55 | "Dimension", [1 1], ... 56 | "IOInterface", "AXI4-Stream DMA"); 57 | 58 | hPort_tdata_o = hdlcoder.DUTPort("tdata_o", ... 59 | "Direction", "OUT", ... 60 | "DataType", numerictype(1,64,0), ... 61 | "Dimension", [1 1], ... 62 | "IOInterface", "AXI4-Stream DMA"); 63 | 64 | mapPort(hFPGA, [hPort_DataIn, hPort_tdata_o]); 65 | 66 | end 67 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partA_TransposeMatrix/part2_hdl_bram_burst/validateTranspose.m: -------------------------------------------------------------------------------- 1 | dataOut = out.logsout.find('axi4mrd_dataOut').Values.Data; 2 | dataValid = out.logsout.find('axi4mrd_validOut').Values.Data; 3 | % validLength = sum(dataValid == 1) - mod(length(dataValid),N1*N2); 4 | % matrixExtract = dataOut(dataValid(1:validLength)); 5 | % numMatrices = length(matrixExtract)/(N1*N2); 6 | matrixExtract = dataOut(dataValid); 7 | trimLen = mod(length(matrixExtract),N1*N2); 8 | matrixExtract = matrixExtract(1:(length(matrixExtract) - trimLen)); 9 | c = reshape(matrixExtract,N2,N1,[]); %<--- note we swap N2 and N1 because this is transposed.. 10 | 11 | numMatrices = length(matrixExtract)/(N1*N2); 12 | for ii = 1:numMatrices 13 | diff = double(MatrixInput.') - double(c(:,:,ii)); 14 | if ~any(diff(:)~=0) 15 | fprintf('transpose good = %d \n',ii); 16 | else 17 | warning('bad transpose!') 18 | end 19 | end -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/MatchedFilterFFT_Transpose.prj: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part0_rangedoppler_ml/run_Range_Doppler.m: -------------------------------------------------------------------------------- 1 | %run_Range_Doppler Testbench for Range Doppler processing 2 | 3 | %% Parameters 4 | 5 | % Common parameters 6 | range_doppler_system_param_init; 7 | 8 | % Number of coherent processing intervals (CPI) to run 9 | NumCPI = 10; 10 | 11 | %% Setup processing blocks 12 | % Create radar data cube 13 | radarDataCube = createRadarDataCubeMod(... 14 | txSignalFullPeriod,antennaElement,Fs,Fc, ... 15 | targetPos, targetVel, targetRCS, ... 16 | RngMax, RxActiveTime, RngGate, ... 17 | CPILength, NumCPI, CPILength*pulsePeriod); 18 | 19 | % Range Doppler processing 20 | RangeDopplerResponse = phased.RangeDopplerResponse( ... 21 | 'OperatingFrequency', Fc, ... 22 | 'RangeMethod','Matched filter', ... 23 | 'PropagationSpeed', propSpeed, ... 24 | 'SampleRate', Fs, ... 25 | 'DopplerFFTLengthSource','Property', ... 26 | 'DopplerFFTLength', VelDimLen, ... 27 | 'DopplerWindow', 'Hamming', ... 28 | 'DopplerOutput', 'Speed'); 29 | 30 | 31 | %% Simulate radar targets and run Range Doppler processing 32 | 33 | hd = dfilt.dffir(matchingCoeff.'); 34 | for CPIIdx = 1:NumCPI 35 | cubeSegment = radarDataCube(:,:,CPIIdx); 36 | cubeSegmentMatched = zeros(RxActiveSamples,CPILength); 37 | 38 | % Matched Filter 39 | for ii = 1:CPILength 40 | cubeSegmentMatched(:,ii) = filter(hd,cubeSegment(:,ii)); 41 | end 42 | 43 | % Transpose 44 | cubeTranspose = transpose(cubeSegmentMatched); 45 | 46 | % FFT 47 | cubeTransposeFFT = fft(cubeTranspose.*hamming(64),64,1); 48 | cubeOutput = fftshift(transpose(cubeTransposeFFT),2); 49 | cubeOutput = 20*log10(abs(cubeOutput)); 50 | 51 | % Display Targets 52 | displayTargets(VelMax, RngMin, RngMax, cubeOutput); 53 | 54 | pause(0.5); 55 | end 56 | 57 | 58 | function displayTargets(VelMax, RngMin, RngMax, rangeDopplerInput) 59 | imagesc([-VelMax VelMax],[RngMin RngMax],rangeDopplerInput); 60 | title('Range-Doppler'); 61 | xlabel('Velocity'); 62 | ylabel('Range'); 63 | end 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part1_transpose_radar_cube/BramBurst_FFT2D_validate_matrix_out.m: -------------------------------------------------------------------------------- 1 | %% Run this after reading matrix value out 2 | 3 | % pNumCols = N1; 4 | % pNumRows = N2; 5 | Valid = out.rdValid(:); 6 | rdMat = out.rdMat(:); 7 | rdMat = rdMat(Valid); 8 | iter = length(rdMat)/(pNumCols*pNumRows); 9 | 10 | 11 | 12 | %% Compare against original radar data cube 13 | 14 | outputReshape = reshape(rdMat,pNumCols,pNumRows); 15 | expectedOutput = radarDataCube.'; 16 | plot(imag(outputReshape(:) - expectedOutput(:))) 17 | 18 | 19 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part1_transpose_radar_cube/bramBurst_TransposeMatrix.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part1_transpose_radar_cube/bramBurst_TransposeMatrix.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part1_transpose_radar_cube/matrix_init.m: -------------------------------------------------------------------------------- 1 | %% Model coefficients 2 | N1 = 256; % row 3 | N2 = 64; % columns 4 | Ts = 1; 5 | MatrixInputArr = [1:N1*N2]; 6 | MatrixInput = reshape(MatrixInputArr,[N1,N2]); 7 | 8 | 9 | pNumCols = N1; 10 | pNumRows = N2; 11 | run AXIBusObjects; 12 | pAXIDataWidthBytes = 8; % number of bytes (64 bits) for AXI Data-Width 13 | pMaxBankLines = 6; 14 | pMaxNumBanks = 3; 15 | 16 | %Bram address width 17 | pBramAddrWidth = ceil(log2(pMaxBankLines*pMaxNumBanks*pNumCols)); 18 | 19 | %% BRAM savings 20 | 21 | bramSaving = ( 1 - pMaxBankLines*pMaxNumBanks*pNumCols / (pNumCols*pNumRows))*100; 22 | fprintf('By using DDR4 memory we reduced BRAM usage of the transpose by %2.1f percent. Address width is %d-bits \n',bramSaving,pBramAddrWidth); 23 | 24 | %% State machine labeling 25 | % LINEBUFFER = fi(1,0,4,0); 26 | % LINESTART = fi(3,0,4,0); 27 | Simulink.defineIntEnumType('stateBRAMfsm', {'IDLE','LINEBUFFER', 'LINESTART'}, [0 1 3]); 28 | 29 | 30 | % BURSTSTART = fi(1,0,4,0); 31 | % BURSTNEXT = fi(3,0,4,0); 32 | % WAITBURSTCOMPLETE = fi(4,0,4,0); 33 | % WAITBURSTREADY = fi(5,0,4,0); 34 | % WAITONBANKRDY =fi(2,0,4,0); 35 | Simulink.defineIntEnumType('stateAXI4Mfsm', {'IDLE',... 36 | 'BURSTSTART',... 37 | 'WAITONBANKRDY',... 38 | 'BURSTNEXT',... 39 | 'WAITBURSTCOMPLETE',... 40 | 'WAITBURSTREADY'}, [0 1 2 3 4 5]); 41 | 42 | 43 | %% Radar cube 44 | 45 | % init parameters 46 | range_doppler_system_param_init; 47 | 48 | % Number of coherent processing intervals (CPI) to run 49 | NumCPI = 1; 50 | 51 | 52 | % Create radar data cube 53 | radarDataCube = createRadarDataCubeMod(... 54 | txSignalFullPeriod,antennaElement,Fs,Fc, ... 55 | targetPos, targetVel, targetRCS, ... 56 | RngMax, RxActiveTime, RngGate, ... 57 | CPILength, NumCPI, CPILength*pulsePeriod); 58 | 59 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part1_transpose_radar_cube/socmemlib.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part1_transpose_radar_cube/socmemlib.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part1_transpose_radar_cube/validateTranspose.m: -------------------------------------------------------------------------------- 1 | 2 | warning('only run this if you are comparing integer non-complex values for the 256x64 transpose'); 3 | 4 | dataOut = out.logsout.find('axi4mrd_dataOut').Values.Data; 5 | dataValid = out.logsout.find('axi4mrd_validOut').Values.Data; 6 | % validLength = sum(dataValid == 1) - mod(length(dataValid),N1*N2); 7 | % matrixExtract = dataOut(dataValid(1:validLength)); 8 | % numMatrices = length(matrixExtract)/(N1*N2); 9 | matrixExtract = dataOut(dataValid); 10 | trimLen = mod(length(matrixExtract),N1*N2); 11 | matrixExtract = matrixExtract(1:(length(matrixExtract) - trimLen)); 12 | c = reshape(matrixExtract,N2,N1,[]); %<--- note we swap N2 and N1 because this is transposed.. 13 | 14 | numMatrices = length(matrixExtract)/(N1*N2); 15 | for ii = 1:numMatrices 16 | diff = double(MatrixInput.') - double(c(:,:,ii)); 17 | if ~any(diff(:)~=0) 18 | fprintf('transpose good = %d \n',ii); 19 | else 20 | warning('bad transpose!') 21 | end 22 | end -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/BramBurst_FFT2D_validate_matrix_out.m: -------------------------------------------------------------------------------- 1 | %% Run this after reading matrix value out 2 | 3 | % pNumCols = N1; 4 | % pNumRows = N2; 5 | Valid = out.rdValid(:); 6 | rdMat = out.rdMat(:); 7 | rdMat = rdMat(Valid); 8 | iter = length(rdMat)/(N1*N2); 9 | 10 | 11 | 12 | %% Compare against original radar data cube 13 | 14 | % outputReshape = reshape(rdMat,pNumCols,pNumRows,iter); 15 | % expectedOutput = radarDataCube.'; 16 | % 17 | % for ii = 1:iter 18 | % matrix_subset = outputReshape(:,:,ii); 19 | % plot(imag(matrix_subset(:) - expectedOutput(:))) 20 | % end 21 | 22 | 23 | %% Compare raw int64 inputs 24 | 25 | int64_matrix_dataIn=getLogged(out.logsout,'int64_raw_transpose_dataIn'); 26 | int64_matrix_validIn=getLogged(out.logsout,'int64_raw_transpose_validIn'); 27 | transpose_input = int64_matrix_dataIn(int64_matrix_validIn); 28 | 29 | transpose_input_arr = reshape(transpose_input(1:(N1*N2*iter)),N1,N2,iter); 30 | % expected_output = transpose_input_arr.'; 31 | 32 | int64_matrix_dataOut=getLogged(out.logsout,'int64_raw_transpose_dataOut'); 33 | int64_matrix_validOut=getLogged(out.logsout,'int64_raw_transpose_validOut'); 34 | transpose_output = int64_matrix_dataOut(int64_matrix_validOut); 35 | transpose_output_arr = reshape(transpose_output(1:(N1*N2*iter)),N2,N1,iter); 36 | 37 | % plot(expected_output(:) - transpose_output_arr(:)) 38 | for ii = 1:iter 39 | expected_output_arr = transpose_input_arr(:,:,ii).'; 40 | output_arr = transpose_output_arr(:,:,ii); 41 | plot(expected_output_arr(:) - output_arr(:)); 42 | end 43 | 44 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/RangeDopplerLoop_fpgaIO.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % Constant Design parameters 3 | % 4 | %-------------------------------------------------------------------------- 5 | N1 = 256; % row 6 | N2 = 64; % columns 7 | 8 | 9 | %-------------------------------------------------------------------------- 10 | % Adjustable Design parameters 11 | % 12 | %-------------------------------------------------------------------------- 13 | % init parameters 14 | range_doppler_system_param_init; 15 | 16 | % Number of coherent processing intervals (CPI) to run 17 | NumCPI = 10; 18 | 19 | % Create radar data cube 20 | radarDataCube = createRadarDataCubeMod(... 21 | txSignalFullPeriod,antennaElement,Fs,Fc, ... 22 | targetPos, targetVel, targetRCS, ... 23 | RngMax, RxActiveTime, RngGate, ... 24 | CPILength, NumCPI, CPILength*pulsePeriod); 25 | 26 | enableFullMatrixWrite = true; 27 | debugInputFrame = false; 28 | 29 | %% Create fpga object 30 | hFPGA = fpga("Xilinx"); 31 | 32 | 33 | %% Setup fpga object 34 | % This function configures the "fpga" object with the same interfaces as the generated IP core 35 | frameLenWrite = 256*64; 36 | frameLenRead = 256*64; 37 | 38 | setup_fpgaIO(hFPGA,frameLenWrite,frameLenRead); 39 | writePort(hFPGA, "resetIP", true); 40 | 41 | debugRegInput.bypassFFT = false; 42 | debugRegInput.bypassMatchedFilter = false; 43 | writePort(hFPGA, "debugRegInput", debugRegInput); 44 | 45 | %% Create Radar Cube frame 46 | radarDataCube_fi = packBits(radarDataCube); 47 | radarDataCube_fi_mat = reshape(radarDataCube_fi,256,64,NumCPI); 48 | radarDataCube_fi_mat = fi(radarDataCube_fi_mat,0,64,0); 49 | 50 | %% Setup Rx DMA 51 | % setup rx dma by invoking a read. If this is not done then the DMA will 52 | % NOT be setup to get data correctly and the first frame will get 53 | % corrupted! 54 | data_any = readPort(hFPGA, "axis_s2mm_tdata"); 55 | 56 | %% Write frame 57 | for ii = 1:NumCPI 58 | 59 | % Extract a radar cube slice 60 | waveformExtract = radarDataCube_fi_mat(:,:,ii); 61 | 62 | % Write the radar cube slice to FPGA as DMA data 63 | writePort(hFPGA, "axis_mm2s_tdata", waveformExtract(:)); 64 | 65 | % Print some debug messages 66 | data_debugRead = readPort(hFPGA, "debugRead"); 67 | data_ddrDoneCounter = readPort(hFPGA, "ddrDoneCounter"); 68 | measuredValidCount = data_debugRead.FIFO_ValidWriteCount; 69 | fprintf('Total samples written to PL DDR4 memory = %d \n',double(measuredValidCount)); 70 | fprintf('DDR4 write count = %d \n', uint32(data_ddrDoneCounter)); 71 | 72 | % Read back result of range-doppler data 73 | rangeDopplerRead = readPort(hFPGA, "axis_s2mm_tdata"); 74 | 75 | % Format data to expected fixed-point complex data type format 76 | re = reinterpretcast(bitsliceget(rangeDopplerRead,32,1),numerictype(1,32,21)) ; 77 | imag = reinterpretcast(bitsliceget(rangeDopplerRead,64,33),numerictype(1,32,21)) ; 78 | rdMat = complex(re,imag); 79 | 80 | % Plot range-doppler 81 | img = reshape(double(rdMat),64,256); 82 | cubeOutput = fftshift(transpose(img),2); 83 | cubeOutput = 20*log10(abs(cubeOutput)); 84 | 85 | imagesc([-VelMax VelMax],[RngMin RngMax],cubeOutput); 86 | title('Range-Doppler'); 87 | xlabel('Velocity'); 88 | ylabel('Range'); 89 | colorbar; 90 | drawnow 91 | end 92 | 93 | %% Some debug port statements 94 | data_debugRead = readPort(hFPGA, "debugRead"); 95 | fprintf('Number of samples FIFO outputted = %d \n',data_debugRead.FIFO_ValidWriteCount); 96 | fprintf('Number of DDR4 write bursts completed = %d \n',data_debugRead.AXI4M_WrValidCnt); 97 | fprintf('Number of times BRAM FSM paused input FIFO = %d \n',data_debugRead.BRAM_FSM_StoppingFIFO_Counter); 98 | fprintf('Number of lost samples = %d \n',data_debugRead.FIFO_LostSampleCount); 99 | fprintf('Number of times back-pressure applied on MM2S DMA = %d \n',data_debugRead.FIFO_BackPressureAppliedOnMM2S); 100 | fprintf('Number of times input FIFO was full = %d \n',data_debugRead.FIFO_FullEventCount); 101 | 102 | 103 | 104 | %% Release hardware resources 105 | release(hFPGA); 106 | 107 | 108 | %% Helper functions 109 | 110 | function output = packBits(waveformInput) 111 | 112 | waveformInput_fi = fi(waveformInput,1,20,18); 113 | % [real(waveformInput_fi) imag(waveformInput_fi)] 114 | output = bitconcat(real(waveformInput_fi(:)),imag(waveformInput_fi(:))); 115 | 116 | end 117 | 118 | 119 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/bramBurst_TransposeMatrix.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/bramBurst_TransposeMatrix.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/matched_filter_fft_hdl_init.m: -------------------------------------------------------------------------------- 1 | %% Model coefficients 2 | N1 = 256; % row 3 | N2 = 64; % columns 4 | Ts = 1; 5 | MatrixInputArr = [1:N1*N2]; 6 | MatrixInput = reshape(MatrixInputArr,[N1,N2]); 7 | 8 | %% Burst Transpose parameters 9 | 10 | hdlbramBurst.pNumCols = N1; %NOTE: the convention here is BRAM burst writes along the column and 11 | hdlbramBurst.pNumRows = N2; % will burst along the rows, hence why N1 and N2 are swapped around... 12 | run AXIBusObjects; 13 | hdlbramBurst.pAXIDataWidthBytes = 8; % number of bytes (64 bits) for AXI Data-Width 14 | hdlbramBurst.pMaxBankLines = 6; 15 | hdlbramBurst.pMaxNumBanks = 3; 16 | 17 | %Bram address width 18 | hdlbramBurst.pBramAddrWidth = ceil(log2(hdlbramBurst.pMaxBankLines*hdlbramBurst.pMaxNumBanks*hdlbramBurst.pNumCols)); 19 | 20 | %BRAM savings 21 | bramSaving = ( 1 - hdlbramBurst.pMaxBankLines*hdlbramBurst.pMaxNumBanks*hdlbramBurst.pNumCols / (hdlbramBurst.pNumCols*hdlbramBurst.pNumRows))*100; 22 | fprintf('By using DDR4 memory we reduced BRAM usage of the transpose by %2.1f percent. Address width is %d-bits \n',bramSaving,hdlbramBurst.pBramAddrWidth); 23 | 24 | % State machine labeling 25 | % LINEBUFFER = fi(1,0,4,0); 26 | % LINESTART = fi(3,0,4,0); 27 | Simulink.defineIntEnumType('stateBRAMfsm', {'IDLE','LINEBUFFER', 'LINESTART'}, [0 1 3]); 28 | 29 | 30 | % BURSTSTART = fi(1,0,4,0); 31 | % BURSTNEXT = fi(3,0,4,0); 32 | % WAITBURSTCOMPLETE = fi(4,0,4,0); 33 | % WAITBURSTREADY = fi(5,0,4,0); 34 | % WAITONBANKRDY =fi(2,0,4,0); 35 | Simulink.defineIntEnumType('stateAXI4Mfsm', {'IDLE',... 36 | 'BURSTSTART',... 37 | 'WAITONBANKRDY',... 38 | 'BURSTNEXT',... 39 | 'WAITBURSTCOMPLETE',... 40 | 'WAITBURSTREADY'}, [0 1 2 3 4 5]); 41 | 42 | 43 | %% Radar cube 44 | 45 | % init parameters 46 | range_doppler_system_param_init; 47 | 48 | % Number of coherent processing intervals (CPI) to run 49 | NumCPI = 1; 50 | 51 | 52 | % Create radar data cube 53 | radarDataCube = createRadarDataCubeMod(... 54 | txSignalFullPeriod,antennaElement,Fs,Fc, ... 55 | targetPos, targetVel, targetRCS, ... 56 | RngMax, RxActiveTime, RngGate, ... 57 | CPILength, NumCPI, CPILength*pulsePeriod); 58 | 59 | 60 | %% Windowing parameters for FFT/Matched Filter 61 | 62 | columnWindowFun = taylorwin(N2,10,-40);%.*(-1.^(1:nCols)'); 63 | 64 | DTWindowFun = numerictype(1,16+4,13+4); 65 | DTsig_in = numerictype(1,20,18); 66 | DToutput = numerictype(1,32,22); 67 | DTTransposeInOut = numerictype(1,32,24); 68 | DT_fftColOutput = numerictype(1,32,21); 69 | 70 | 71 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/setup_fpgaIO.m: -------------------------------------------------------------------------------- 1 | function setup_fpgaIO(hFPGA,framesize_wr, framesize_rd) 2 | %-------------------------------------------------------------------------- 3 | % Software Interface Script Setup 4 | % 5 | % Generated with MATLAB 9.10 (R2021a) at 02:53:28 on 20/06/2021. 6 | % This function was created for the IP Core generated from design 'bramBurst_TransposeMatrix'. 7 | % 8 | % Run this function on an "fpga" object to configure it with the same interfaces as the generated IP core. 9 | %-------------------------------------------------------------------------- 10 | 11 | %% AXI4 12 | addAXI4SlaveInterface(hFPGA, ... 13 | "InterfaceID", "AXI4", ... 14 | "BaseAddress", 0xA0000000, ... 15 | "AddressRange", 0x10000); 16 | 17 | hPort_resetIPCore = hdlcoder.DUTPort("resetIP", ... 18 | "Direction", "IN", ... 19 | "DataType", numerictype(0,32,0), ... 20 | "Dimension", [1 1], ... 21 | "IOInterface", "AXI4", ... 22 | "IOInterfaceMapping", "0x0"); 23 | 24 | hPort_inputImageDDROffset = hdlcoder.DUTPort("inputImageDDROffset", ... 25 | "Direction", "IN", ... 26 | "DataType", numerictype(0,32,0), ... 27 | "Dimension", [1 1], ... 28 | "IOInterface", "AXI4", ... 29 | "IOInterfaceMapping", "0x100"); 30 | 31 | hPort_debugRegInput_bypassFFT = hdlcoder.DUTPort("bypassFFT", ... 32 | "Direction", "IN", ... 33 | "DataType", numerictype('boolean'), ... 34 | "Dimension", [1 1], ... 35 | "IOInterface", "AXI4", ... 36 | "IOInterfaceMapping", "0x104"); 37 | 38 | hPort_debugRegInput_bypassMatchedFilter = hdlcoder.DUTPort("bypassMatchedFilter", ... 39 | "Direction", "IN", ... 40 | "DataType", numerictype('boolean'), ... 41 | "Dimension", [1 1], ... 42 | "IOInterface", "AXI4", ... 43 | "IOInterfaceMapping", "0x130"); 44 | 45 | hPort_debugRegInput = hdlcoder.DUTPort("debugRegInput", ... 46 | "Direction", "IN", ... 47 | "DataType", "Bus", ... 48 | "Dimension", [1 1], ... 49 | "IOInterface", "AXI4", ... 50 | "SubPorts", [hPort_debugRegInput_bypassFFT, hPort_debugRegInput_bypassMatchedFilter]); 51 | 52 | hPort_ddrDoneCounter = hdlcoder.DUTPort("ddrDoneCounter", ... 53 | "Direction", "OUT", ... 54 | "DataType", numerictype(1,32,0), ... 55 | "Dimension", [1 1], ... 56 | "IOInterface", "AXI4", ... 57 | "IOInterfaceMapping", "0x108"); 58 | 59 | hPort_fifo_full_event = hdlcoder.DUTPort("fifo_full_event", ... 60 | "Direction", "OUT", ... 61 | "DataType", numerictype(0,32,0), ... 62 | "Dimension", [1 1], ... 63 | "IOInterface", "AXI4", ... 64 | "IOInterfaceMapping", "0x10C"); 65 | 66 | hPort_debugRead_AXI4M_WrValidCnt = hdlcoder.DUTPort("AXI4M_WrValidCnt", ... 67 | "Direction", "OUT", ... 68 | "DataType", numerictype(0,32,0), ... 69 | "Dimension", [1 1], ... 70 | "IOInterface", "AXI4", ... 71 | "IOInterfaceMapping", "0x110"); 72 | 73 | hPort_debugRead_BRAM_FSM_BankRdCompleteCnt = hdlcoder.DUTPort("BRAM_FSM_BankRdCompleteCnt", ... 74 | "Direction", "OUT", ... 75 | "DataType", numerictype(0,32,0), ... 76 | "Dimension", [1 1], ... 77 | "IOInterface", "AXI4", ... 78 | "IOInterfaceMapping", "0x114"); 79 | 80 | hPort_debugRead_BRAM_FSM_StoppingFIFO_Counter = hdlcoder.DUTPort("BRAM_FSM_StoppingFIFO_Counter", ... 81 | "Direction", "OUT", ... 82 | "DataType", numerictype(0,32,0), ... 83 | "Dimension", [1 1], ... 84 | "IOInterface", "AXI4", ... 85 | "IOInterfaceMapping", "0x118"); 86 | 87 | hPort_debugRead_AXI4M_WriteCounter = hdlcoder.DUTPort("AXI4M_WriteCounter", ... 88 | "Direction", "OUT", ... 89 | "DataType", numerictype(0,32,0), ... 90 | "Dimension", [1 1], ... 91 | "IOInterface", "AXI4", ... 92 | "IOInterfaceMapping", "0x11C"); 93 | 94 | hPort_debugRead_BRAM_FSM_Concat = hdlcoder.DUTPort("BRAM_FSM_Concat", ... 95 | "Direction", "OUT", ... 96 | "DataType", numerictype(0,8,0), ... 97 | "Dimension", [1 1], ... 98 | "IOInterface", "AXI4", ... 99 | "IOInterfaceMapping", "0x120"); 100 | 101 | hPort_debugRead_FIFO_FullEventCount = hdlcoder.DUTPort("FIFO_FullEventCount", ... 102 | "Direction", "OUT", ... 103 | "DataType", numerictype(0,32,0), ... 104 | "Dimension", [1 1], ... 105 | "IOInterface", "AXI4", ... 106 | "IOInterfaceMapping", "0x124"); 107 | 108 | hPort_debugRead_FIFO_LostSampleCount = hdlcoder.DUTPort("FIFO_LostSampleCount", ... 109 | "Direction", "OUT", ... 110 | "DataType", numerictype(0,32,0), ... 111 | "Dimension", [1 1], ... 112 | "IOInterface", "AXI4", ... 113 | "IOInterfaceMapping", "0x128"); 114 | 115 | hPort_debugRead_FIFO_BackPressureAppliedOnMM2S = hdlcoder.DUTPort("FIFO_BackPressureAppliedOnMM2S", ... 116 | "Direction", "OUT", ... 117 | "DataType", numerictype(0,32,0), ... 118 | "Dimension", [1 1], ... 119 | "IOInterface", "AXI4", ... 120 | "IOInterfaceMapping", "0x12C"); 121 | 122 | hPort_debugRead_FIFO_ValidWriteCount = hdlcoder.DUTPort("FIFO_ValidWriteCount", ... 123 | "Direction", "OUT", ... 124 | "DataType", numerictype(0,32,0), ... 125 | "Dimension", [1 1], ... 126 | "IOInterface", "AXI4", ... 127 | "IOInterfaceMapping", "0x134"); 128 | 129 | hPort_debugRead = hdlcoder.DUTPort("debugRead", ... 130 | "Direction", "OUT", ... 131 | "DataType", "Bus", ... 132 | "Dimension", [1 1], ... 133 | "IOInterface", "AXI4", ... 134 | "SubPorts", [hPort_debugRead_AXI4M_WrValidCnt, hPort_debugRead_BRAM_FSM_BankRdCompleteCnt, hPort_debugRead_BRAM_FSM_StoppingFIFO_Counter, hPort_debugRead_AXI4M_WriteCounter, hPort_debugRead_BRAM_FSM_Concat, hPort_debugRead_FIFO_FullEventCount, hPort_debugRead_FIFO_LostSampleCount, hPort_debugRead_FIFO_BackPressureAppliedOnMM2S, hPort_debugRead_FIFO_ValidWriteCount]); 135 | 136 | mapPort(hFPGA, [hPort_resetIPCore hPort_inputImageDDROffset, hPort_debugRegInput, hPort_ddrDoneCounter, hPort_fifo_full_event, hPort_debugRead]); 137 | 138 | %% AXI4-Stream DMA 139 | addAXI4StreamInterface(hFPGA, ... 140 | "InterfaceID", "AXI4-Stream DMA", ... 141 | "WriteEnable", true, ... 142 | "WriteDataWidth", 64, ... 143 | "WriteFrameLength", framesize_wr, ... 144 | "ReadEnable", true, ... 145 | "ReadDataWidth", 64, ... 146 | "ReadFrameLength", framesize_rd,... 147 | "WriteTimeout",0,... 148 | "ReadTimeout",0); 149 | 150 | hPort_axis_mm2s_tdata = hdlcoder.DUTPort("axis_mm2s_tdata", ... 151 | "Direction", "IN", ... 152 | "DataType", numerictype(1,64,0), ... 153 | "Dimension", [1 1], ... 154 | "IOInterface", "AXI4-Stream DMA"); 155 | 156 | hPort_axis_s2mm_tdata = hdlcoder.DUTPort("axis_s2mm_tdata", ... 157 | "Direction", "OUT", ... 158 | "DataType", numerictype(0,64,0), ... 159 | "Dimension", [1 1], ... 160 | "IOInterface", "AXI4-Stream DMA"); 161 | 162 | mapPort(hFPGA, [hPort_axis_mm2s_tdata, hPort_axis_s2mm_tdata]); 163 | 164 | end 165 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/simCheckOutput_rangeDoppler.m: -------------------------------------------------------------------------------- 1 | %% Run this after reading matrix value out 2 | Valid = out.rdValid(:); 3 | rdMat = out.rdMat(:); 4 | rdMat = rdMat(Valid); 5 | iter = floor(length(rdMat)/(N1*N2)); 6 | 7 | 8 | 9 | %% check range-doppler with fft-shift 10 | Valid = out.rdValid(:); 11 | rdMat = out.rdMat(:); 12 | rdMat = rdMat(Valid); 13 | % rdMat = rdMat((1:N1*N2)'); 14 | 15 | img = reshape(rdMat(1:N1*N2*iter),N2,N1,iter); 16 | 17 | for ii = 1:iter 18 | cubeOutput = fftshift(transpose(img(:,:,ii)),2); 19 | cubeOutput = 20*log10(abs(cubeOutput)); 20 | 21 | % nexttile([1,2]); 22 | imagesc([-VelMax VelMax],[RngMin RngMax],cubeOutput); 23 | title('Range-Doppler'); 24 | xlabel('Velocity'); 25 | ylabel('Range'); 26 | colorbar; 27 | end 28 | 29 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/socmemlib.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/socmemlib.slx -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/validateTranspose.m: -------------------------------------------------------------------------------- 1 | 2 | warning('only run this if you are comparing integer non-complex values for the 256x64 transpose'); 3 | 4 | dataOut = out.logsout.find('axi4mrd_dataOut').Values.Data; 5 | dataValid = out.logsout.find('axi4mrd_validOut').Values.Data; 6 | % validLength = sum(dataValid == 1) - mod(length(dataValid),N1*N2); 7 | % matrixExtract = dataOut(dataValid(1:validLength)); 8 | % numMatrices = length(matrixExtract)/(N1*N2); 9 | matrixExtract = dataOut(dataValid); 10 | trimLen = mod(length(matrixExtract),N1*N2); 11 | matrixExtract = matrixExtract(1:(length(matrixExtract) - trimLen)); 12 | c = reshape(matrixExtract,N2,N1,[]); %<--- note we swap N2 and N1 because this is transposed.. 13 | 14 | numMatrices = length(matrixExtract)/(N1*N2); 15 | for ii = 1:numMatrices 16 | diff = double(MatrixInput.') - double(c(:,:,ii)); 17 | if ~any(diff(:)~=0) 18 | fprintf('transpose good = %d \n',ii); 19 | else 20 | warning('bad transpose!') 21 | end 22 | end -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/part2_rangedoppler_hdl/writeDopplerInput_fpgaIO.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % Constant Design parameters 3 | % 4 | %-------------------------------------------------------------------------- 5 | 6 | N1 = 256; % row 7 | N2 = 64; % columns 8 | 9 | enableFullMatrixWrite = true; 10 | debugInputFrame = true; 11 | %-------------------------------------------------------------------------- 12 | % Adjustable Design parameters 13 | % 14 | %-------------------------------------------------------------------------- 15 | 16 | % init parameters 17 | range_doppler_system_param_init; 18 | 19 | % Number of coherent processing intervals (CPI) to run 20 | NumCPI = 1; 21 | 22 | % Create radar data cube 23 | radarDataCube = createRadarDataCubeMod(... 24 | txSignalFullPeriod,antennaElement,Fs,Fc, ... 25 | targetPos, targetVel, targetRCS, ... 26 | RngMax, RxActiveTime, RngGate, ... 27 | CPILength, NumCPI, CPILength*pulsePeriod); 28 | 29 | %% Create fpga object 30 | hFPGA = fpga("Xilinx"); 31 | 32 | 33 | 34 | %% Setup fpga object 35 | % This function configures the "fpga" object with the same interfaces as the generated IP core 36 | if enableFullMatrixWrite 37 | frameLenWrite = 256*64; 38 | frameLenRead = 256*64; 39 | else 40 | frameLenWrite = 256; 41 | frameLenRead = 256*64; 42 | end 43 | setup_fpgaIO(hFPGA,frameLenWrite,frameLenRead); 44 | writePort(hFPGA, "resetIP", true); 45 | 46 | if debugInputFrame 47 | debugRegInput.bypassFFT = true; 48 | debugRegInput.bypassMatchedFilter = true; 49 | writePort(hFPGA, "debugRegInput", debugRegInput); 50 | else 51 | debugRegInput.bypassFFT = false; 52 | debugRegInput.bypassMatchedFilter = false; 53 | writePort(hFPGA, "debugRegInput", debugRegInput); 54 | end 55 | 56 | %% Create frame 57 | radarDataCube_fi = packBits(radarDataCube); 58 | radarDataCube_fi_mat = reshape(radarDataCube_fi,256,64); 59 | radarDataCube_fi_mat = fi(radarDataCube_fi_mat,0,64,0); 60 | 61 | if debugInputFrame 62 | radarDataCube_fi = fi(1:(256*64),0,64,0); 63 | radarDataCube_fi_mat = reshape(radarDataCube_fi,256,64); 64 | end 65 | 66 | 67 | %% Write frame 68 | if ~enableFullMatrixWrite 69 | prevValidCount = 0; 70 | for ii = 1:64 71 | writePort(hFPGA, "axis_mm2s_tdata", radarDataCube_fi_mat(:,ii)); 72 | data_debugRead = readPort(hFPGA, "debugRead"); 73 | measuredValidCount = data_debugRead.FIFO_ValidWriteCount; 74 | fprintf('valid count diff = %d \n',double(measuredValidCount) - double(prevValidCount)); 75 | prevValidCount = measuredValidCount; 76 | end 77 | else 78 | writePort(hFPGA, "axis_mm2s_tdata", radarDataCube_fi(:)); 79 | data_debugRead = readPort(hFPGA, "debugRead"); 80 | measuredValidCount = data_debugRead.FIFO_ValidWriteCount; 81 | fprintf('valid count diff = %d \n',double(measuredValidCount) - 256*64); 82 | 83 | end 84 | %% read and Unpack 85 | rangeDopplerRead = readPort(hFPGA, "axis_s2mm_tdata"); 86 | 87 | data_ddrDoneCounter = readPort(hFPGA, "ddrDoneCounter"); 88 | fprintf('DDR4 write count = %d \n', uint32(data_ddrDoneCounter)); 89 | 90 | if ~debugInputFrame 91 | re = reinterpretcast(bitsliceget(rangeDopplerRead,32,1),numerictype(1,32,21)) ; 92 | imag = reinterpretcast(bitsliceget(rangeDopplerRead,64,33),numerictype(1,32,21)) ; 93 | rdMat = complex(re,imag); 94 | else 95 | output_data = reshape(rangeDopplerRead,64,256); 96 | expectedTranspose = double(radarDataCube_fi_mat.'); 97 | plot(output_data(:) - expectedTranspose(:)) 98 | xlabel('Samples') 99 | title('Error for Expected vs Actual BRAM Burst transpose'); 100 | 101 | end 102 | 103 | %% AXI4 debug register reads 104 | data_fifo_full_event = readPort(hFPGA, "fifo_full_event"); 105 | 106 | fprintf('Number of samples FIFO outputted = %d \n',data_debugRead.FIFO_ValidWriteCount); 107 | fprintf('Number of bursts completed for writes = %d \n',data_debugRead.AXI4M_WrValidCnt); 108 | fprintf('Number of times BRAM FSM paused input FIFO = %d \n',data_debugRead.BRAM_FSM_StoppingFIFO_Counter); 109 | fprintf('Number of lost samples = %d \n',data_debugRead.FIFO_LostSampleCount); 110 | fprintf('Number of times back-pressure applied on MM2s = %d \n',data_debugRead.FIFO_BackPressureAppliedOnMM2S); 111 | fprintf('Number of times FIFO was full = %d \n',data_debugRead.FIFO_FullEventCount); 112 | 113 | 114 | %% 115 | if ~debugInputFrame 116 | img = reshape(double(rdMat),64,256); 117 | cubeOutput = fftshift(transpose(img),2); 118 | cubeOutput = 20*log10(abs(cubeOutput)); 119 | 120 | nexttile([1,2]); 121 | imagesc([-VelMax VelMax],[RngMin RngMax],cubeOutput); 122 | title('Range-Doppler'); 123 | xlabel('Velocity'); 124 | ylabel('Range'); 125 | colorbar; 126 | end 127 | 128 | 129 | 130 | %% Release hardware resources 131 | release(hFPGA); 132 | 133 | 134 | %% Helper functions 135 | 136 | function output = packBits(waveformInput) 137 | 138 | waveformInput_fi = fi(waveformInput,1,20,18); 139 | % [real(waveformInput_fi) imag(waveformInput_fi)] 140 | output = bitconcat(real(waveformInput_fi(:)),imag(waveformInput_fi(:))); 141 | 142 | end 143 | 144 | 145 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/-LsZ8HXJj2Q_3Mm_5RR2W21dUukd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/-LsZ8HXJj2Q_3Mm_5RR2W21dUukp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/0avZ0B7B9QBO8c3kVcoPdfvh0a4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/0avZ0B7B9QBO8c3kVcoPdfvh0a4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/4SII37bbmPr-uDt2KwUOF17LD3Md.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/4SII37bbmPr-uDt2KwUOF17LD3Mp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/hVqQ-9HgOfR-miUHZ1Olro2oO1Ed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/hVqQ-9HgOfR-miUHZ1Olro2oO1Ep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/tKvNkHTpbT6GAm3k-7n7cooRcn0d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/tKvNkHTpbT6GAm3k-7n7cooRcn0p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/ySwxmLB6i3-U3ibpDX9G5VF_qIkd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/1AK6k8_2MMsrq1VagZS1umPpphk/ySwxmLB6i3-U3ibpDX9G5VF_qIkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/4SVYQZsILIuEyZXh7AZiBXaAzWId.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/4SVYQZsILIuEyZXh7AZiBXaAzWIp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/TDGNiicbXqPcaT25VpzQ4PfNaGEd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/TDGNiicbXqPcaT25VpzQ4PfNaGEp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/TnMVnPKCYgLFQp-huKXjIUP3g50d.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/TnMVnPKCYgLFQp-huKXjIUP3g50p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/XI63F3DpcFZVEmLxabCze_1yGYUd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/XI63F3DpcFZVEmLxabCze_1yGYUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/u09gIjf84mrcY04PvVsIqz_A2nId.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/u09gIjf84mrcY04PvVsIqz_A2nIp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/ytXa1Px-hQUhxMW6RexuadiW05Md.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/CAsOFWEXbRicMJSXkpnan34QAz4/ytXa1Px-hQUhxMW6RexuadiW05Mp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EP7gYHkiKJzsbwl1Kmg0OEWqO4od.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EP7gYHkiKJzsbwl1Kmg0OEWqO4op.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/fSmbuBCUit5i5wOBPuJA2g5w9NId.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/fSmbuBCUit5i5wOBPuJA2g5w9NIp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/lJnjawKd-WsGvgvgCWqsl0Tg_aUd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/lJnjawKd-WsGvgvgCWqsl0Tg_aUp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/pJPJd6FiWRygNl9o0EVnymaY7Ykd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/pJPJd6FiWRygNl9o0EVnymaY7Ykp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/NwDM1JfMyUKVVWcp71u8HzQ1GJc/ErjdZpt4SMkWn8v-1ahF4A3siMMd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/NwDM1JfMyUKVVWcp71u8HzQ1GJc/ErjdZpt4SMkWn8v-1ahF4A3siMMp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/NwDM1JfMyUKVVWcp71u8HzQ1GJc/MnQp2l-5jErytlj-zxMUdpGpr5cd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/NwDM1JfMyUKVVWcp71u8HzQ1GJc/MnQp2l-5jErytlj-zxMUdpGpr5cp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/WZRuNzqc-Db7NcQAZO8Y-R8U9cc/66WgGCcF5RIH9MCEgPmgjZK9k3Ud.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/WZRuNzqc-Db7NcQAZO8Y-R8U9cc/66WgGCcF5RIH9MCEgPmgjZK9k3Up.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/WZRuNzqc-Db7NcQAZO8Y-R8U9cc/AtMjXDrOSm8YDv3_4UFXiyrWqNEd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/WZRuNzqc-Db7NcQAZO8Y-R8U9cc/AtMjXDrOSm8YDv3_4UFXiyrWqNEp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/1AK6k8_2MMsrq1VagZS1umPpphkd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/1AK6k8_2MMsrq1VagZS1umPpphkp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CAsOFWEXbRicMJSXkpnan34QAz4d.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CAsOFWEXbRicMJSXkpnan34QAz4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NwDM1JfMyUKVVWcp71u8HzQ1GJcd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NwDM1JfMyUKVVWcp71u8HzQ1GJcp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/tczr9cMCNMOtxnSsL6yRolFxYBId.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/tczr9cMCNMOtxnSsL6yRolFxYBIp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/root/WZRuNzqc-Db7NcQAZO8Y-R8U9ccp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/EGS-wA3-Ks6urVqBkUEHtwtFE_Ed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/EGS-wA3-Ks6urVqBkUEHtwtFE_Ep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/KRklbgq8aG-kfYmOgOLRLkm3QDId.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/KRklbgq8aG-kfYmOgOLRLkm3QDIp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/Q6dDcsN2OKbQzgD58TRr8ONsFJMd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/Q6dDcsN2OKbQzgD58TRr8ONsFJMp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/WSzvG5f_5Cvt8a1ZYLPc6xfuSq4d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/WSzvG5f_5Cvt8a1ZYLPc6xfuSq4p.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/Xi_uJVws7Ulmwu5Gll1EDSreybMd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/Xi_uJVws7Ulmwu5Gll1EDSreybMp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/b9vcJ5kLPMvo3kZz_IJEYIN8Z6cd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/b9vcJ5kLPMvo3kZz_IJEYIN8Z6cp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/haKPcoVMP6OfLpW27bivJk-zciAd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/haKPcoVMP6OfLpW27bivJk-zciAp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/rKuGYAHY8-cXC9XRh5EcCRlNuEQd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/rKuGYAHY8-cXC9XRh5EcCRlNuEQp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/uPQ5MtfZJq79kMUTlWx4p0q_8hod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/resources/project/tczr9cMCNMOtxnSsL6yRolFxYBI/uPQ5MtfZJq79kMUTlWx4p0q_8hop.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/shared_files/AXIBusObjects.m: -------------------------------------------------------------------------------- 1 | function AXIBusObjects() 2 | % AXIBUSOBJECTS initializes a set of bus objects in the MATLAB base workspace 3 | 4 | % Bus object: BusAXIWriteCtrlM2S 5 | clear elems; 6 | elems(1) = Simulink.BusElement; 7 | elems(1).Name = 'wr_addr'; 8 | elems(1).Dimensions = 1; 9 | elems(1).DimensionsMode = 'Fixed'; 10 | elems(1).DataType = 'uint32'; 11 | elems(1).SampleTime = -1; 12 | elems(1).Complexity = 'real'; 13 | elems(1).Min = []; 14 | elems(1).Max = []; 15 | elems(1).DocUnits = ''; 16 | elems(1).Description = ''; 17 | 18 | elems(2) = Simulink.BusElement; 19 | elems(2).Name = 'wr_len'; 20 | elems(2).Dimensions = 1; 21 | elems(2).DimensionsMode = 'Fixed'; 22 | elems(2).DataType = 'uint32'; 23 | elems(2).SampleTime = -1; 24 | elems(2).Complexity = 'real'; 25 | elems(2).Min = []; 26 | elems(2).Max = []; 27 | elems(2).DocUnits = ''; 28 | elems(2).Description = ''; 29 | 30 | elems(3) = Simulink.BusElement; 31 | elems(3).Name = 'wr_valid'; 32 | elems(3).Dimensions = 1; 33 | elems(3).DimensionsMode = 'Fixed'; 34 | elems(3).DataType = 'boolean'; 35 | elems(3).SampleTime = -1; 36 | elems(3).Complexity = 'real'; 37 | elems(3).Min = []; 38 | elems(3).Max = []; 39 | elems(3).DocUnits = ''; 40 | elems(3).Description = ''; 41 | 42 | BusAXIWriteCtrlM2S = Simulink.Bus; 43 | BusAXIWriteCtrlM2S.HeaderFile = ''; 44 | BusAXIWriteCtrlM2S.Description = ''; 45 | BusAXIWriteCtrlM2S.DataScope = 'Auto'; 46 | BusAXIWriteCtrlM2S.Alignment = -1; 47 | BusAXIWriteCtrlM2S.Elements = elems; 48 | clear elems; 49 | assignin('base','BusAXIWriteCtrlM2S', BusAXIWriteCtrlM2S); 50 | 51 | % Bus object: BusAXIWriteCtrlS2M 52 | clear elems; 53 | elems(1) = Simulink.BusElement; 54 | elems(1).Name = 'wr_ready'; 55 | elems(1).Dimensions = 1; 56 | elems(1).DimensionsMode = 'Fixed'; 57 | elems(1).DataType = 'boolean'; 58 | elems(1).SampleTime = -1; 59 | elems(1).Complexity = 'real'; 60 | elems(1).Min = []; 61 | elems(1).Max = []; 62 | elems(1).DocUnits = ''; 63 | elems(1).Description = ''; 64 | 65 | elems(2) = Simulink.BusElement; 66 | elems(2).Name = 'wr_complete'; 67 | elems(2).Dimensions = 1; 68 | elems(2).DimensionsMode = 'Fixed'; 69 | elems(2).DataType = 'boolean'; 70 | elems(2).SampleTime = -1; 71 | elems(2).Complexity = 'real'; 72 | elems(2).Min = []; 73 | elems(2).Max = []; 74 | elems(2).DocUnits = ''; 75 | elems(2).Description = ''; 76 | 77 | BusAXIWriteCtrlS2M = Simulink.Bus; 78 | BusAXIWriteCtrlS2M.HeaderFile = ''; 79 | BusAXIWriteCtrlS2M.Description = ''; 80 | BusAXIWriteCtrlS2M.DataScope = 'Auto'; 81 | BusAXIWriteCtrlS2M.Alignment = -1; 82 | BusAXIWriteCtrlS2M.Elements = elems; 83 | clear elems; 84 | assignin('base','BusAXIWriteCtrlS2M', BusAXIWriteCtrlS2M); 85 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/shared_files/createRadarDataCubeMod.m: -------------------------------------------------------------------------------- 1 | function dataCube = createRadarDataCubeMod(TxWaveform,RxArray,Fs,Fc, ... 2 | TargetPos,TargetVel,TargetRCS,... 3 | RngMax,RngActiveTime,RngGateTime,... 4 | CPILength,NumCPI,CPIDelta) 5 | 6 | rng('default') 7 | 8 | tx = phased.Transmitter('PeakPower',3000,'Gain',50); 9 | 10 | freespaceTx = phased.FreeSpace('SampleRate',Fs,... 11 | 'MaximumDistanceSource','Property',... 12 | 'MaximumDistance',RngMax,... 13 | 'OperatingFrequency',Fc); 14 | 15 | radarTarget = phased.RadarTarget('MeanRCS',TargetRCS,'OperatingFrequency',Fc); 16 | 17 | targetPlatform = phased.Platform('InitialPosition',TargetPos,'Velocity',TargetVel); 18 | 19 | freespaceRx = phased.FreeSpace('SampleRate',Fs,... 20 | 'MaximumDistanceSource','Property',... 21 | 'MaximumDistance',RngMax,... 22 | 'OperatingFrequency',Fc); 23 | 24 | rxCollector = phased.Collector('Sensor',RxArray,'OperatingFrequency',Fc); 25 | 26 | rx = phased.ReceiverPreamp('Gain',80,'NoiseFigure',30,'SampleRate',Fs); 27 | 28 | TxPos = [0;0;0]; 29 | TxVel = [0;0;0]; 30 | RxPos = [0;0;0]; 31 | RxVel = [0;0;0]; 32 | 33 | RngActiveSamples = RngActiveTime*Fs; 34 | RngGateSamples = RngGateTime*Fs; 35 | PulsePeriod = length(TxWaveform)/Fs; 36 | 37 | dataCube = complex(zeros(RngActiveSamples,CPILength,NumCPI)); 38 | 39 | T = 0; 40 | for nn=1:NumCPI 41 | if nn > 1 42 | targetPlatform(T); 43 | end 44 | for ii=1:CPILength 45 | [TgtPos,TgtVel] = targetPlatform(PulsePeriod); 46 | temp = tx(TxWaveform); 47 | temp = horzcat(temp,temp); 48 | temp = freespaceTx(temp,TxPos,TgtPos,TxVel,TgtVel); 49 | temp = radarTarget(temp); 50 | temp = freespaceRx(temp,TgtPos,RxPos,TgtVel,RxVel); 51 | [~,ang] = rangeangle(TgtPos); 52 | temp = rxCollector(temp,ang); 53 | temp = rx(temp); 54 | dataCube(:,ii,nn) = temp(uint32(RngGateSamples+1):end,:); 55 | end 56 | T = T+CPIDelta; 57 | end 58 | 59 | end 60 | 61 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/shared_files/getLogged.m: -------------------------------------------------------------------------------- 1 | 2 | function signal_val = getLogged(logsout,signal_name) 3 | 4 | % logsout = simout_obj.logsout; 5 | if isempty(logsout) 6 | error('No logged signal found. Make sure ''%s'' is logged in the model',... 7 | signal_name); 8 | end 9 | 10 | sig = logsout.getElement(signal_name); 11 | if isempty(sig) 12 | error('Signal ''%s'' not found. Make sure it is logged and named correctly.',... 13 | signal_name); 14 | end 15 | 16 | signal_val = squeeze(sig.Values.Data); 17 | 18 | end 19 | -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/shared_files/range_doppler_system_param_init.m: -------------------------------------------------------------------------------- 1 | %% Radar parameters 2 | 3 | % Environment 4 | propSpeed = physconst('LightSpeed'); % Propagation speed 5 | Fc = 10e9; % Operating/carrier frequency 6 | lambda = propSpeed/Fc; 7 | 8 | % Inherit sample rate 9 | if ~exist('Fs','var') 10 | Fs = 250e6; 11 | end 12 | Ts = 1/Fs; 13 | 14 | 15 | 16 | 17 | % Application parameters 18 | pulseWidthSamples = 32; 19 | pulseBw = Fs/2; % Pulse bandwidth 20 | 21 | CPILength = 64; % Number of pulses in a Coherent Processing Interval 22 | 23 | % totalSamplesPulse = Fs/PRF; 24 | % = 4250; 25 | RxActiveSamples = 256; 26 | RngGateSamples = 8346 - RxActiveSamples; 27 | 28 | % Derived params 29 | pulsePeriodSamples = RngGateSamples+RxActiveSamples; 30 | pulseWidth = pulseWidthSamples*Ts; % Pulse width 31 | pulsePeriod = pulsePeriodSamples*Ts; % Pulse repetition period 32 | PRF = 1/pulsePeriod; % Pulse repetition frequency 33 | CPIPeriod = CPILength*pulsePeriod; 34 | RxActiveTime = RxActiveSamples*Ts; 35 | 36 | 37 | % 38 | 39 | 40 | RngGate = RngGateSamples*Ts; % Range gate start 41 | RngMin = propSpeed*RngGate/2; 42 | RngMax = propSpeed/(PRF*2); % Maximum unambiguous range 43 | VelMax = propSpeed*PRF/(Fc*4); % Maximum unambiguous velocity 44 | 45 | RngDimLen = RxActiveSamples; 46 | VelDimLen = CPILength; 47 | RngEstBins = linspace(RngMin,RngMax,RngDimLen); 48 | VelEstBins = linspace(-VelMax,VelMax,VelDimLen); 49 | 50 | % Matched filter parameters 51 | hwav = phased.LinearFMWaveform(... 52 | 'PulseWidth',pulseWidth,... 53 | 'PRF',PRF,... 54 | 'SweepBandwidth',pulseBw,... 55 | 'SampleRate',Fs); 56 | matchingCoeff = getMatchedFilter(hwav); 57 | txSignalFullPeriod = hwav(); 58 | txSignal = txSignalFullPeriod(1:pulseWidthSamples); 59 | 60 | %% Target parameters 61 | target1Az = -47; 62 | target1Dist = 4950; 63 | target1Speed = 100; 64 | target1RCS = 2.5; 65 | 66 | target2Az = 50; 67 | target2Dist = 4900; 68 | target2Speed = -150; 69 | target2RCS = 4; 70 | 71 | target1Pos = [target1Dist*cosd(target1Az); target1Dist*sind(target1Az); 0]; 72 | target1Vel = [target1Speed*cosd(target1Az); target1Speed*sind(target1Az); 0]; 73 | target2Pos = [target2Dist*cosd(target2Az); target2Dist*sind(target2Az); 0]; 74 | target2Vel = [target2Speed*cosd(target2Az); target2Speed*sind(target2Az); 0]; 75 | 76 | targetPos = [target1Pos target2Pos]; 77 | targetVel = [target1Vel target2Vel]; 78 | targetRCS = [target1RCS target2RCS]; 79 | 80 | %% Rx Array / Beamforming parameters 81 | 82 | numAntennaElements = 1; 83 | 84 | antennaElement = phased.IsotropicAntennaElement(... 85 | 'FrequencyRange',[Fc-1e8 Fc+1e8], 'BackBaffled', true); 86 | 87 | 88 | % Beamforming scan angle 89 | RxScanAngle = target2Az; 90 | 91 | 92 | %% CFAR detection 93 | CFARGuardVel = 1; 94 | CFARGuardRng = 1; 95 | CFARTrainVel = 8; 96 | CFARTrainRng = 4; 97 | CFARGuardRegion = [CFARGuardRng CFARGuardVel]; 98 | CFARTrainRegion = [CFARTrainRng CFARTrainVel]; 99 | CFARRngPad = CFARGuardRng+CFARTrainRng; 100 | CFARVelPad = CFARGuardVel+CFARTrainVel; 101 | CFARRngIdx = (1+CFARRngPad):(RngDimLen-CFARRngPad); 102 | CFARRngBins = RngEstBins(CFARRngIdx); 103 | CFARRngNumBins = numel(CFARRngIdx); 104 | CFARVelIdx = [(1+CFARVelPad):(VelDimLen/2 - 2) ... 105 | (VelDimLen/2 + 3):(VelDimLen-CFARVelPad)]; 106 | CFARVelBins = VelEstBins(CFARVelIdx); 107 | CFARVelNumBins = numel(CFARVelIdx); 108 | CFARProb = 1e-12; 109 | CFARIdx = zeros(2,CFARVelNumBins*CFARRngNumBins); 110 | nn = 1; 111 | for ii=CFARVelIdx 112 | for jj=CFARRngIdx 113 | CFARIdx(:,nn) = [jj;ii]; 114 | nn=nn+1; 115 | end 116 | end -------------------------------------------------------------------------------- /rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/shared_files/window_taper.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathworks/FPGA-Adaptive-Beamforming-and-Radar-Examples/fc4f485755b9486f0b891e46fbf67c1143c8e104/rangedoppler/hw_only/partB_MatchedFilterFFTTranspose/shared_files/window_taper.slx --------------------------------------------------------------------------------