{"id":514765,"date":"2017-12-14T03:30:04","date_gmt":"2017-12-14T02:30:04","guid":{"rendered":"http:\/\/antonpotocnik.com\/?p=514765"},"modified":"2017-12-14T03:45:11","modified_gmt":"2017-12-14T02:45:11","slug":"red-pitaya-fpga-project-4-averager","status":"publish","type":"post","link":"https:\/\/antonpotocnik.com\/?p=514765","title":{"rendered":"Red Pitaya FPGA Project 5 \u2013 High-Bandwidth Averager"},"content":{"rendered":"<h1>Introduction<\/h1>\n<p>Up to now we discussed simple projects that demonstrated basic ideas behind FPGA programming. In this post we will go a step further and create a data acquisition system. In particular, we will implement a High-Bandwidth Averager, which will acquire a sequence of measurements at the highest sampling rate (125 Msamples\/s) and on each trigger accumulate these measurements on the on-chip Block Random Access Memory (BRAM). Our approach can be extended and ultimately used for ultra-sensitive homodyne or heterodyne detection in <a href=\"http:\/\/pavel-demin.github.io\/red-pitaya-notes\/sdr-receiver-hpsdr\/\" target=\"_blank\">radio systems<\/a>, radars, <a href=\"http:\/\/pavel-demin.github.io\/red-pitaya-notes\/pulsed-nmr\/\" target=\"_blank\">nuclear magnetic resonance<\/a> (NMR) or even <a href=\"https:\/\/arxiv.org\/abs\/1709.01030\" target=\"_blank\">superconducting quantum circuits<\/a>.<\/p>\n<p><a href=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/GW-Instek-GRS-6052A-oscilloscope.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/GW-Instek-GRS-6052A-oscilloscope.jpg\" alt=\"\" width=\"400\" height=\"237\" class=\"aligncenter size-full wp-image-566547\" srcset=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/GW-Instek-GRS-6052A-oscilloscope.jpg 500w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/GW-Instek-GRS-6052A-oscilloscope-300x178.jpg 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>FPGA acquisition system will require more comprehensive post-processing options such as data analysis, visualization and storage. For this reason we will take <a href=\"http:\/\/pavel-demin.github.io\/red-pitaya-notes\/pulsed-nmr\/\">Pavel Demin<\/a>&#8216;s approach and create a client program, running on any computer in the network, and a server program, running on the Red Pitaya&#8217;s Linux. Client will set configuration, start measurements, and download data from the server via a TCP\/IP protocol.<\/p>\n<p>This guide is split into to two parts, in the first part we will describe FPGA logic behind the Averager and in the second part we will demonstrate how to setup server on Red Pitaya\u2019s Linux and a python client on a local computer. The purpose of this project is to learn how to store and read-out acquired data from the FPGA programmable logic. <\/p>\n<h1>Building the Project<\/h1>\n<p>To start off download the project from github as described in previous posts. Then build custom IP cores by navigating to \/redpitaya_guide base folder in Vivado\u2019s tcl console and execute<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsource make_cores.tcl\r\n<\/pre>\n<p>This will create the following IP cores in the folder <em>tmp\/cores<\/em> needed for Averager project: <em>axis_red_pitaya_adc_v1_0<\/em>, <em>axis_red_pitaya_dac_v1_0<\/em>, <em>bram_switch<\/em>, <em>axi_bram_reader <\/em>and <em>axis_averager_v1_0<\/em>. The first two are taken from Pavel Demin, as discussed in the <a href=\"https:\/\/antonpotocnik.com\/?p=519284\" target=\"_blank\">previous post,\u00a0<\/a> the last three are custom made for accumulation and read-out of measured data.<\/p>\n<p>When custom cores are successfully generated, build the project by appropriately modifying the <em>make_project.tcl <\/em>script and execute it in the Vivado\u2019s tcl console as described in <a href=\"https:\/\/antonpotocnik.com\/?p=487360\" target=\"_blank\">Project 1<\/a><\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsource make_project.tcl\r\n<\/pre>\n<h1>FPGA part<\/h1>\n<p>The general block design of the Averager is composed of five main parts: processing system, configuration, data acquisition, triggering and averaging as shown in the figure below. We have also added a signal generator part for testing the data acquisition system. The signal generator creates a sine tone on both Red Pitayas&#8217; DAC output ports with frequency 125 MHz\/32 = 3.90625 MHz. This design is based on block design from <a href=\"https:\/\/antonpotocnik.com\/?p=519284\" target=\"_blank\">Project 4<\/a>, where processing system, data acquisition and signal generator hierarchies are described in greater detail.<\/p>\n<div id=\"attachment_519676\" style=\"width: 1197px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/5_averager_ProjectOverview.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-519676\" class=\"wp-image-519676 size-full\" src=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/5_averager_ProjectOverview.png\" width=\"1187\" height=\"668\" srcset=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/5_averager_ProjectOverview.png 1187w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/5_averager_ProjectOverview-300x169.png 300w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/5_averager_ProjectOverview-768x432.png 768w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/5_averager_ProjectOverview-1024x576.png 1024w\" sizes=\"auto, (max-width: 1187px) 100vw, 1187px\" \/><\/a><p id=\"caption-attachment-519676\" class=\"wp-caption-text\">Block Design Overview<\/p><\/div>\n<h3>Averager Hierarchy<\/h3>\n<p>High-Bandwidth Averager collects a number of consecutive measurements from the ADC block, reads the same number of values stored in the BRAM memory and writes the sum of collected and read values back to the memory. This is repeated on every trigger signal. Each memory location, therefore, contains a sum of ADC values always measured at the specific time after the trigger.<\/p>\n<p>Acquisition begins with a release of a <em>reset<\/em> signal. At this points the Averager sets BRAM memory locations to zero and awaits for a trigger. On each trigger the Averager accumulates <em>NSAMPLES<\/em> number of ADC values, adds them to the previous measurements and writes the sums back to the memory. After <em>NAVERAGES<\/em> number of triggers the Averager stops and asserts the <em>finished<\/em> signal. <\/p>\n<p>The <em>finished<\/em> signal has two functions: first it lets the program running on Red Pitaya&#8217;s Linux know that acquisition is completed and results can be read. The second function is to re-route the BRAM PORTA line of the Block Memory Generator from Averager to AXI BRAM Reader block. This gives a program running on the processing system\/Linux access for reading BRAM memory.<\/p>\n<div id=\"attachment_514815\" style=\"width: 1453px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_Averager2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-514815\" class=\"size-full wp-image-514815\" src=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_Averager2.png\" alt=\"\" width=\"1443\" height=\"572\" srcset=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_Averager2.png 1443w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_Averager2-300x119.png 300w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_Averager2-768x304.png 768w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_Averager2-1024x406.png 1024w\" sizes=\"auto, (max-width: 1443px) 100vw, 1443px\" \/><\/a><p id=\"caption-attachment-514815\" class=\"wp-caption-text\">Averager Hierarchy<\/p><\/div>\n<p>The key feature of our averaging algorithm is its capability to read and write data to the BRAM in a single clock cycle. Averager is ready for the next trigger on the second clock cycle after the previous measurement sequence is finished. This reduces the dead time during averaging and with that the overall duration of data acquisition. The High-Bandwidth Averager can measure up to approx. 65k, 32-bit wide ADC values set by the <a href=\"https:\/\/www.xilinx.com\/support\/documentation\/data_sheets\/ds190-Zynq-7000-Overview.pdf\" target=\"_blank\">2.1 Mb<\/a> size of the on-chip BRAM memory. However, the FPGA implementation might suffer from timing issues when using all of the resources. If we need more measurement storage we can use Red Pitaya&#8217;s on-board 512 MB DDR memory. We will show how to do that in future projects. Reading and writing in a single clock cycle requires Averager to use both read (PORTB) and write (PORTA) ports of the True Dual-Port Block Memory Generator and a special BRAM Switch block to share the BRAM Generator&#8217;s reading port between the Averager and the AXI BRAM Reader. The later is connected to the Processing System via the AXI interface.<\/p>\n<p>[expand title=&#8221;Implementation details&#8221;]<br \/>\nThe BRAM generator has to be set to Standalone, True Dual Port core. We set the maximum number of entries to 1024 and width to 32 bit. Make sure that no reset input is used and Always Enable option is used for both ports. The Averager IP core has <em>nsamples<\/em>, <em>naverages<\/em>, <em>trig<\/em>, <em>user_reset<\/em> and <em>data_in<\/em> input ports. In addition it has two BRAM ports for reading and writing to the BRAM memory and the <em>finished<\/em> and <em>averages_out<\/em> output ports. The later contains a number of averages currently done and it is mainly used for debugging. <em>finished<\/em> signal is connected to the 1 LSB and <em>averages_out<\/em> is connected to the 7 MSBs of the <em>led_o<\/em> external port.<\/p>\n<p>To view the Averager&#8217;s Verilog code right-click on the block and select <em>Edit in IP Packager<\/em>. The averaging is coded as a state machine with 5 states. The 0<sup>th<\/sup> state clears the registers, the 1st state prepares registers for writing zeros to the BRAM memory, the 2nd state performs the zero writing, the 3rd state prepares addresses for reading and writing and the 4th state performs reading and writing to the BRAM generator. Once the number of averages is met the system goes and stops in the 5th state.<br \/>\n[\/expand]<\/p>\n<p>&nbsp;<\/p>\n<h3><\/h3>\n<h3>Configuration GPIO Hierarchy<\/h3>\n<p>In the previous project we learned how to read and set registers on the FPGA logic. We will use the same approach here for setting configuration values such as number of samples, number of averages and trigger rate. We will use the second GPIO port as an input to indicate the completion of the averaging. 32 bits of the output port contain four 8-bit configuration values: <em>log2NAVERAGES, log2NSAMPLES, trigger_select<\/em> and <em>control<\/em>:<\/p>\n<p>gpio_out1[31:0] = <sub>31<\/sub>[{<em>log2NAVERAGES<\/em>} {<em>log2NSAMPLES<\/em>} {<em>trigger_select<\/em>} {<em>control<\/em>}]<sub>0<\/sub><\/p>\n<p>gpio_in2[31:0] = <sub>31<\/sub>[{31-bit empty} {1-bit finished}]<sub>0<\/sub><\/p>\n<p>For now only the LSB of <em>control<\/em> value is used as a <em>user_reset<\/em> bit. When this bit becomes asserted averaging resets and when it is disserted averaging starts with the next trigger signal.<\/p>\n<p>If you ever need more configuration output bits you can use Pavel Demin\u2019s <em>axi_configuration_v1_0<\/em> IP core with a custom number of bits in a single output port. <em>axi_configuration_v1_0<\/em> can be found in <em>redpitaya_guide\/core<\/em> folder and is automatically created when running <em>make_cores.tcl<\/em> script.<\/p>\n<div id=\"attachment_514768\" style=\"width: 510px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_GPIO.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-514768\" class=\"wp-image-514768\" src=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_GPIO-300x131.png\" alt=\"GPIO Hierarchy\" width=\"500\" height=\"218\" srcset=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_GPIO-300x131.png 300w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_GPIO-768x335.png 768w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/4_averager_GPIO.png 962w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><p id=\"caption-attachment-514768\" class=\"wp-caption-text\">GPIO Hierarchy<\/p><\/div>\n<h3><\/h3>\n<h3>Trigger Hierarchy<\/h3>\n<p>Trigger hierarchy creates a low frequency clock, which is used as a trigger for the Averager. The principle is very similar to the one in the LED blink project where we used an input clock to trigger a binary counter and select a specific bit of the counter\u2019s 32-bit output. Here we implement this principle in a custom RTL module. The selected bit is specified by the  <em>trigger_select<\/em> configuration value, which we extract from <em>gpio1_io_o<\/em>[15:8] port using Slice core.<\/p>\n<div id=\"attachment_519293\" style=\"width: 384px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2017\/01\/4_averager_Trigger.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-519293\" class=\"wp-image-519293 size-full\" src=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2017\/01\/4_averager_Trigger.png\" width=\"374\" height=\"162\" srcset=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2017\/01\/4_averager_Trigger.png 374w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2017\/01\/4_averager_Trigger-300x130.png 300w\" sizes=\"auto, (max-width: 374px) 100vw, 374px\" \/><\/a><p id=\"caption-attachment-519293\" class=\"wp-caption-text\">Trigger Hierarchy<\/p><\/div>\n<p>Trigger rate after the <a href=\"https:\/\/github.com\/apotocnik\/redpitaya_guide\/blob\/master\/projects\/4_frequency_counter\/selector.v\" target=\"_blank\">selector module<\/a> is calculated as<\/p>\n<p><code class=\"cpp plain\"><em>trigger_rate = f0 \/ 2<\/em><em>^(26 - trigger_select + 1)<\/em>,<\/code><\/p>\n<p>where <em>f0<\/em> = 125 MHz is the ADC clock frequency, +26 is an offset set in the <em>selector module<\/em> and +1 comes from the fact that <em>binary counter<\/em> is increased by one on every clock cycle, which makes the frequency of its first LSB equal to <em>f0<\/em>\/2. This is a very simple trigger that might not yield the best performance, but is sufficient to demonstrate the basic idea behind the Averager. Since our trigger rate is commensurate with DAC signal frequency the Averager will always start a measurement at the same phase of the signal. This will result in full averaged signal even for millions of averages. If trigger rate would be incommensurate relative to <em>f0<\/em>, the average would converge to zero.<\/p>\n<p>A more realistic design would include an external trigger. This could be brought into the programmable logic using <em>exp_#<\/em> port.<\/p>\n<p>&nbsp;<\/p>\n<h1>Software part<\/h1>\n<h3>Server<\/h3>\n<p>To setup a server on Red Pitaya&#8217; Linux, copy <em>server.c<\/em> file from the project folder <em>5_averager\/server<\/em> to the folder on the Linux, using for example WinSCP. With Putty compile and run the server by typing<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ngcc -o server server.c\r\n.\/server\r\n<\/pre>\n<p>Server is listening on port 1001 for incoming connections. After a connection is established client can send parameters, <em>nsamples<\/em>, <em>naverages<\/em> and <em>trigger_select<\/em>, and at the end request a measurement start. Parameters are sent as 32-bit values, where 4 MSB represent parameter identification number and 28 LSB the parameter value.<br \/>\nAfter <em>start_measurement<\/em> is received server releases the <em>user_restart<\/em> bit and waits for the <em>finished<\/em> signal from FPGA. When the measurement is finished server reads the data from BRAM memory and sends it to the client.    <\/p>\n<h3>Client<\/h3>\n<p>Client program is written in Python 2.7 and uses Qt Graphical User Interface (GUI). If you don&#8217;t already have python on your computer, I recommend installing <a href=\"http:\/\/python-xy.github.io\/\" rel=\"noopener\" target=\"_blank\">Python(X,Y)<\/a> for windows users. This collection includes all the required packages including Qt Designer and Spyder (IDE). <\/p>\n<p><em>averager.py<\/em> and <em>averager.ui<\/em> files can be found in the project directory <em>5_averager\/client<\/em>. I would suggest looking into the GUI file <em>averager.ui<\/em> by opening it with the <em>Qt Editor<\/em> and checking the element&#8217;s properties. Also reading python code <em>averager.py<\/em> using <em>Spyder<\/em> or any other text editor might be interesting. <\/p>\n<p>My preferred way of running the client is by executing the following line in IPython (Qt) enhanced console<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nrun averager.py\r\n<\/pre>\n<p>Averager&#8217;s GUI should be intuitive. Enter Red Pitaya&#8217;s IP address and press <em>Start<\/em> button. If you didn&#8217;t connect Red Pitaya&#8217;s OUT1 port to the IN1 port you will see a noisy signal. After connecting the two ports and pressing the start button a sinusoidal signal will appear in the graph section of the GUI as shown in the left screenshot below.<br \/>\n<div id=\"attachment_514818\" style=\"width: 912px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/Client.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-514818\" src=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/Client-1024x375.png\" alt=\"\" width=\"1024\" height=\"375\" class=\"aligncenter size-large wp-image-566544\" srcset=\"https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/Client-1024x375.png 1024w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/Client-300x110.png 300w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/Client-768x281.png 768w, https:\/\/antonpotocnik.com\/wp-content\/uploads\/2016\/12\/Client.png 1840w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><p id=\"caption-attachment-514818\" class=\"wp-caption-text\">Python Client Program<br \/><\/p><\/div><\/p>\n<p>You can play with different parameters. I recommend setting <em>trigger rate<\/em> to <em>f0\/<\/em>1024, <em>nsamples<\/em> to 1024 and <em>naverages<\/em> to 262114. The measurement should take approximately 4 s. It will be hard to detect differences between highly averaged measurements in a time domain. To see how noise reduces when increasing <em>naverages<\/em> plot FFT in log scale by checking <em>FFT<\/em> and <em>Log Scale<\/em> boxes and choose <em>Abs<\/em> value.<\/p>\n<p><em>Scale<\/em> check box re-scales the 14-bit ADC values into an appropriate voltage range. The scaling values depend on your jumper setting on the Red Pitaya board and slowly change with time. Since my scaling parameters might differ from yours, you can calibrate your Red Pitaya with known voltage sources and modify the scaling coefficients hard-coded in the <em>averager.py<\/em> file.<\/p>\n<h1>Conclusions<\/h1>\n<p>In this guide we have demonstrated how to efficiently write to the BRAM memory and read-out values at the end of the measurement. One could use Averager as an oscilloscope with a single average. However, to exploit all its capabilities one might need to extend it with an external trigger option or add a module that would detect signal transitions and issue automatic triggers to the Averager. In any case, I hope this project gives you enough material to further pursue your own FPGA ideas. <\/p>\n<p>&nbsp;<\/p>\n<table width=\"100%\">\n<tbody>\n<tr>\n<td><a href=\"https:\/\/antonpotocnik.com\/?p=519284\">&lt;&lt; Red Pitaya Project 4 &#8211; Frequency Counter<\/a><\/td>\n<td align=\"right\"><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<h1>References<\/h1>\n<ul>\n<li>Reference on RTL module interface <a href=\"https:\/\/www.xilinx.com\/support\/documentation\/sw_manuals\/xilinx2016_2\/ug994-vivado-ip-subsystems.pdf\">Xilinx User Guide &#8211; Designing IP Subsystems Using IP Integrator.<\/a><\/li>\n<li><a href=\"https:\/\/www.xilinx.com\/support\/documentation\/data_sheets\/ds190-Zynq-7000-Overview.pdf\">Zynq7000 <\/a>datasheet (Part number on Red Pitaya: XC7Z010).<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Up to now we discussed simple projects that demonstrated basic ideas behind FPGA programming. In this post we will go a step further and create a data acquisition system. In particular, we will implement a High-Bandwidth Averager, which will acquire a sequence of measurements at the highest sampling rate (125 Msamples\/s) and on each&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[29],"tags":[],"class_list":["post-514765","post","type-post","status-publish","format-standard","hentry","category-fpga"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p3Hjcy-29UF","_links":{"self":[{"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=\/wp\/v2\/posts\/514765","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=514765"}],"version-history":[{"count":30,"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=\/wp\/v2\/posts\/514765\/revisions"}],"predecessor-version":[{"id":566552,"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=\/wp\/v2\/posts\/514765\/revisions\/566552"}],"wp:attachment":[{"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=514765"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=514765"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/antonpotocnik.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=514765"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}