{"id":2370,"date":"2026-08-18T13:44:00","date_gmt":"2026-08-18T13:44:00","guid":{"rendered":"https:\/\/smartdata.ece.ufl.edu\/?p=2370"},"modified":"2026-08-18T16:01:35","modified_gmt":"2026-08-18T16:01:35","slug":"discrete-time-convolution-demo","status":"publish","type":"post","link":"https:\/\/smartdata.ece.ufl.edu\/index.php\/2026\/08\/18\/discrete-time-convolution-demo\/","title":{"rendered":"Discrete-Time Convolution Demo"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Disclaimer:<\/strong> This was built with the help of ClaudeAI as an educational tool for Foundations of Digital Signal Processing<\/p>\n\n\n\n<div id=\"dtc-root\" style=\"font-family:Georgia,serif;max-width:860px;margin:0 auto;padding:20px;background:#f4f7fa;border:2px solid #8aabcc;border-radius:10px;color:#1a1a2e;\">\n\n  <h2 style=\"text-align:center;margin:0 0 4px 0;font-size:1.4em;color:#0d2a4a;letter-spacing:1px;\">Discrete-Time Convolution Demo<\/h2>\n  <p style=\"text-align:center;margin:0 0 18px 0;font-size:0.93em;color:#555;\">(f \u2605 g)[n] = \u03a3<sub>k<\/sub> f[k] \u00b7 g[n \u2212 k]\n\n  <!-- Signal selectors -->\n  <div style=\"display:flex;gap:16px;justify-content:center;flex-wrap:wrap;margin-bottom:16px;\">\n    <div style=\"background:#fff;border:1px solid #8aabcc;border-radius:8px;padding:12px 18px;\">\n      <label style=\"font-size:0.88em;font-weight:bold;color:#0d2a4a;display:block;margin-bottom:6px;\">f[k] shape<\/label>\n      <select id=\"dtc-fShape\" style=\"font-size:0.9em;padding:4px 8px;border:1px solid #aaa;border-radius:5px;background:#fff;\">\n        <option value=\"rect\">Rectangle (box)<\/option>\n        <option value=\"tri\">Triangle<\/option>\n        <option value=\"exp\">Decaying Exp<\/option>\n        <option value=\"impulse\">Unit Impulse<\/option>\n        <option value=\"step\">Unit Step<\/option>\n      <\/select>\n    <\/div>\n    <div style=\"background:#fff;border:1px solid #8aabcc;border-radius:8px;padding:12px 18px;\">\n      <label style=\"font-size:0.88em;font-weight:bold;color:#0d4a1a;display:block;margin-bottom:6px;\">g[k] shape<\/label>\n      <select id=\"dtc-gShape\" style=\"font-size:0.9em;padding:4px 8px;border:1px solid #aaa;border-radius:5px;background:#fff;\">\n        <option value=\"rect\">Rectangle (box)<\/option>\n        <option value=\"tri\">Triangle<\/option>\n        <option value=\"exp\">Decaying Exp<\/option>\n        <option value=\"impulse\">Unit Impulse<\/option>\n        <option value=\"step\">Unit Step<\/option>\n      <\/select>\n    <\/div>\n  <\/div>\n\n  <!-- Slider -->\n  <div style=\"background:#fff;border:1px solid #8aabcc;border-radius:8px;padding:14px 20px;margin-bottom:18px;\">\n    <label style=\"font-size:0.92em;font-weight:bold;color:#1a1a2e;display:block;margin-bottom:8px;\">\n      Shift: <span id=\"dtc-nLabel\" style=\"color:#b03a00;font-family:monospace;\">n = 0<\/span>\n    <\/label>\n    <input id=\"dtc-nSlider\" type=\"range\" min=\"-10\" max=\"10\" step=\"1\" value=\"0\"\n      style=\"width:100%;accent-color:#b03a00;cursor:pointer;\">\n    <div style=\"display:flex;justify-content:space-between;font-size:0.75em;color:#999;margin-top:2px;\">\n      <span>\u221210<\/span><span>\u22125<\/span><span>0<\/span><span>+5<\/span><span>+10<\/span>\n    <\/div>\n  <\/div>\n\n  <!-- Top two panels -->\n  <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:14px;\">\n    <div style=\"background:#fff;border:1px solid #c0d4e8;border-radius:8px;padding:10px;\">\n      <div style=\"font-size:0.82em;font-weight:bold;color:#7a1010;margin-bottom:4px;text-align:center;\">f[k]<\/div>\n      <canvas id=\"dtc-cvF\" width=\"380\" height=\"150\" style=\"width:100%;display:block;border-radius:4px;background:#fafafa;\"><\/canvas>\n    <\/div>\n    <div style=\"background:#fff;border:1px solid #c0d4e8;border-radius:8px;padding:10px;\">\n      <div style=\"font-size:0.82em;font-weight:bold;color:#0a5a1a;margin-bottom:4px;text-align:center;\">g[n \u2212 k]  (flipped &amp; shifted)<\/div>\n      <canvas id=\"dtc-cvG\" width=\"380\" height=\"150\" style=\"width:100%;display:block;border-radius:4px;background:#fafafa;\"><\/canvas>\n    <\/div>\n  <\/div>\n\n  <!-- Overlap panel -->\n  <div style=\"background:#fff;border:1px solid #c0d4e8;border-radius:8px;padding:10px;margin-bottom:14px;\">\n    <div style=\"font-size:0.82em;font-weight:bold;color:#5a1a7a;margin-bottom:4px;text-align:center;\">\n      f[k] &amp; g[n\u2212k] overlaid \u2014 highlighted samples contribute to (f\u2605g)[n]\n    <\/div>\n    <canvas id=\"dtc-cvOverlap\" width=\"780\" height=\"160\" style=\"width:100%;display:block;border-radius:4px;background:#fafafa;\"><\/canvas>\n  <\/div>\n\n  <!-- Output panel -->\n  <div style=\"background:#fff;border:1px solid #c0d4e8;border-radius:8px;padding:10px;margin-bottom:14px;\">\n    <div style=\"font-size:0.82em;font-weight:bold;color:#1a3a7a;margin-bottom:4px;text-align:center;\">\n      (f \u2605 g)[n] \u2014 output so far (current n marked)\n    <\/div>\n    <canvas id=\"dtc-cvOutput\" width=\"780\" height=\"160\" style=\"width:100%;display:block;border-radius:4px;background:#fafafa;\"><\/canvas>\n  <\/div>\n\n  <!-- Running sum display -->\n  <div style=\"background:#fff3e0;border:1px solid #e0a060;border-radius:8px;padding:10px 18px;margin-bottom:14px;text-align:center;font-size:0.88em;\">\n    <span style=\"color:#555;\">Sum of products at current n: <\/span>\n    <span id=\"dtc-sumLabel\" style=\"font-family:monospace;font-size:1.1em;font-weight:bold;color:#b03a00;\">0<\/span>\n    <span style=\"color:#555;margin-left:18px;\">\u2192 (f\u2605g)[n] = <\/span>\n    <span id=\"dtc-outLabel\" style=\"font-family:monospace;font-size:1.1em;font-weight:bold;color:#1a3a7a;\">0<\/span>\n  <\/div>\n\n  <!-- Legend -->\n  <div style=\"display:flex;flex-wrap:wrap;gap:16px;justify-content:center;font-size:0.8em;\">\n    <span><span style=\"display:inline-block;width:14px;height:14px;background:#c0392b;border-radius:50%;vertical-align:middle;margin-right:5px;\"><\/span>f[k]<\/span>\n    <span><span style=\"display:inline-block;width:14px;height:14px;background:#27ae60;border-radius:50%;vertical-align:middle;margin-right:5px;\"><\/span>g[n\u2212k]<\/span>\n    <span><span style=\"display:inline-block;width:14px;height:14px;background:#f39c12;border-radius:50%;vertical-align:middle;margin-right:5px;\"><\/span>contributing products<\/span>\n    <span><span style=\"display:inline-block;width:14px;height:14px;background:#2471a3;border-radius:50%;vertical-align:middle;margin-right:5px;\"><\/span>(f\u2605g)[n]<\/span>\n    <span><span style=\"display:inline-block;width:14px;height:14px;background:#b03a00;border-radius:50%;vertical-align:middle;margin-right:5px;\"><\/span>current n<\/span>\n  <\/div>\n\n  <p style=\"font-size:0.77em;color:#888;text-align:center;margin-top:14px;\">\n    Drag the slider to change n. g[n\u2212k] is the time-reversed, shifted version of g[k]. Orange stems show where both signals are nonzero \u2014 their products sum to give (f\u2605g)[n].\n  <\/p>\n\n<\/div>\n\n<script>\n(function(){\n\n  \/\/ \u2500\u2500 Index ranges \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  var K_MIN = -10, K_MAX = 10;\n  var N_MIN = -10, N_MAX = 10;\n\n  function range(a,b){ var arr=[]; for(var i=a;i<=b;i++) arr.push(i); return arr; }\n  var kArr = range(K_MIN, K_MAX);\n  var nArr = range(N_MIN, N_MAX);\n\n  \/\/ \u2500\u2500 Signal definitions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function evalSignal(shape, k){\n    switch(shape){\n      case 'rect':    return (k>=0 && k<=4)  ? 1 : 0;\n      case 'tri':     return (k>=-3 && k<=3) ? (1-Math.abs(k)\/3) : 0;\n      case 'exp':     return (k>=0 && k<=8)  ? Math.pow(0.7,k) : 0;\n      case 'impulse': return (k===0) ? 1 : 0;\n      case 'step':    return (k>=0 && k<=6)  ? 1 : 0;\n    }\n    return 0;\n  }\n\n  function getArr(shape, indices){\n    return indices.map(function(k){ return evalSignal(shape,k); });\n  }\n\n  \/\/ \u2500\u2500 Convolution \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function computeFullConv(fShape, gShape){\n    return nArr.map(function(n){\n      var s=0;\n      kArr.forEach(function(k){ s += evalSignal(fShape,k)*evalSignal(gShape,n-k); });\n      return s;\n    });\n  }\n\n  \/\/ \u2500\u2500 Canvas helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  \/\/ Always read w\/h from the element's attribute integers, not layout pixels.\n  \/\/ This is the key fix: canvas.width is the backing-store size set by the\n  \/\/ attribute and is always valid, even inside hidden iframes.\n  function getWH(cv){\n    return { w: cv.width || parseInt(cv.getAttribute('width'),10),\n             h: cv.height || parseInt(cv.getAttribute('height'),10) };\n  }\n\n  function makeAx(w,h){ return {ml:42,mt:12,mb:24,mr:8,w:w,h:h}; }\n\n  function kToX(ax,k,kMin,kMax){\n    return ax.ml+(k-kMin)\/(kMax-kMin)*(ax.w-ax.ml-ax.mr);\n  }\n  function valToY(ax,v,yMin,yMax){\n    return ax.mt+(yMax-v)\/(yMax-yMin)*(ax.h-ax.mt-ax.mb);\n  }\n\n  function clearCv(ctx,w,h){\n    ctx.clearRect(0,0,w,h);\n    ctx.fillStyle='#fafafa';\n    ctx.fillRect(0,0,w,h);\n  }\n\n  function drawGrid(ctx,ax,kMin,kMax,yMin,yMax){\n    var y0=valToY(ax,0,yMin,yMax);\n    y0=Math.max(ax.mt,Math.min(ax.h-ax.mb,y0));\n    ctx.save();\n    ctx.strokeStyle='#ddd'; ctx.lineWidth=1; ctx.setLineDash([2,3]);\n    for(var k=kMin;k<=kMax;k++){\n      var x=kToX(ax,k,kMin,kMax);\n      ctx.beginPath(); ctx.moveTo(x,ax.mt); ctx.lineTo(x,ax.h-ax.mb); ctx.stroke();\n    }\n    ctx.setLineDash([]);\n    ctx.strokeStyle='#888'; ctx.lineWidth=1.5;\n    ctx.beginPath(); ctx.moveTo(ax.ml,y0); ctx.lineTo(ax.w-ax.mr,y0); ctx.stroke();\n    var x0=kToX(ax,0,kMin,kMax);\n    ctx.beginPath(); ctx.moveTo(x0,ax.mt); ctx.lineTo(x0,ax.h-ax.mb); ctx.stroke();\n    ctx.fillStyle='#999'; ctx.font='9px monospace'; ctx.textAlign='center';\n    for(var k=kMin;k<=kMax;k+=2){\n      ctx.fillText(k, kToX(ax,k,kMin,kMax), ax.h-6);\n    }\n    ctx.restore();\n    return y0;\n  }\n\n  function drawStems(ctx,ax,stems,kMin,kMax,yMin,yMax,y0){\n    stems.forEach(function(s){\n      if(s.val===0) return;\n      var x  = kToX(ax,s.k,kMin,kMax);\n      var y  = valToY(ax,s.val,yMin,yMax);\n      var yb = Math.max(ax.mt,Math.min(ax.h-ax.mb,y0));\n      ctx.save();\n      ctx.strokeStyle=s.color; ctx.lineWidth=s.lw||2;\n      ctx.beginPath(); ctx.moveTo(x,yb); ctx.lineTo(x,y); ctx.stroke();\n      ctx.beginPath(); ctx.arc(x,y,s.r||4,0,2*Math.PI);\n      ctx.fillStyle=s.color; ctx.fill();\n      ctx.strokeStyle='#fff'; ctx.lineWidth=1.2; ctx.stroke();\n      ctx.restore();\n    });\n  }\n\n  \/\/ \u2500\u2500 Canvases &#038; contexts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  var cvF   = document.getElementById('dtc-cvF');\n  var cvG   = document.getElementById('dtc-cvG');\n  var cvOv  = document.getElementById('dtc-cvOverlap');\n  var cvOut = document.getElementById('dtc-cvOutput');\n  var ctxF  = cvF.getContext('2d');\n  var ctxG  = cvG.getContext('2d');\n  var ctxOv = cvOv.getContext('2d');\n  var ctxOut= cvOut.getContext('2d');\n\n  \/\/ \u2500\u2500 Main draw \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function draw(n){\n    var fShape = document.getElementById('dtc-fShape').value;\n    var gShape = document.getElementById('dtc-gShape').value;\n\n    var fArr    = getArr(fShape, kArr);\n    var gArr    = kArr.map(function(k){ return evalSignal(gShape,n-k); });\n    var prods   = kArr.map(function(k,i){ return fArr[i]*gArr[i]; });\n    var convOut = computeFullConv(fShape,gShape);\n\n    var yMaxSig=1.4, yMinSig=-0.2;\n    var dim, ax, y0, W, H;\n\n    \/\/ --- f[k] ---\n    dim=getWH(cvF); W=dim.w; H=dim.h;\n    clearCv(ctxF,W,H);\n    ax=makeAx(W,H); y0=drawGrid(ctxF,ax,K_MIN,K_MAX,yMinSig,yMaxSig);\n    drawStems(ctxF,ax,\n      kArr.map(function(k,i){ return {k:k,val:fArr[i],color:'#c0392b'}; }),\n      K_MIN,K_MAX,yMinSig,yMaxSig,y0);\n\n    \/\/ --- g[n-k] ---\n    dim=getWH(cvG); W=dim.w; H=dim.h;\n    clearCv(ctxG,W,H);\n    ax=makeAx(W,H); y0=drawGrid(ctxG,ax,K_MIN,K_MAX,yMinSig,yMaxSig);\n    drawStems(ctxG,ax,\n      kArr.map(function(k,i){ return {k:k,val:gArr[i],color:'#27ae60'}; }),\n      K_MIN,K_MAX,yMinSig,yMaxSig,y0);\n\n    \/\/ --- Overlap ---\n    dim=getWH(cvOv); W=dim.w; H=dim.h;\n    clearCv(ctxOv,W,H);\n    ax=makeAx(W,H); y0=drawGrid(ctxOv,ax,K_MIN,K_MAX,yMinSig,yMaxSig);\n    drawStems(ctxOv,ax,\n      kArr.map(function(k,i){ return {k:k,val:fArr[i],color:'rgba(192,57,43,0.5)'}; }),\n      K_MIN,K_MAX,yMinSig,yMaxSig,y0);\n    drawStems(ctxOv,ax,\n      kArr.map(function(k,i){ return {k:k,val:gArr[i],color:'rgba(39,174,96,0.5)'}; }),\n      K_MIN,K_MAX,yMinSig,yMaxSig,y0);\n    \/\/ orange product stems\n    kArr.forEach(function(k,i){\n      if(prods[i]===0) return;\n      var x  = kToX(ax,k,K_MIN,K_MAX);\n      var y  = valToY(ax,prods[i],yMinSig,yMaxSig);\n      var yb = Math.max(ax.mt,Math.min(H-ax.mb,y0));\n      ctxOv.save();\n      ctxOv.strokeStyle='#e67e22'; ctxOv.lineWidth=3;\n      ctxOv.beginPath(); ctxOv.moveTo(x,yb); ctxOv.lineTo(x,y); ctxOv.stroke();\n      ctxOv.beginPath(); ctxOv.arc(x,y,6,0,2*Math.PI);\n      ctxOv.fillStyle='#f39c12'; ctxOv.fill();\n      ctxOv.strokeStyle='#fff'; ctxOv.lineWidth=1.5; ctxOv.stroke();\n      ctxOv.restore();\n    });\n\n    \/\/ --- Output ---\n    dim=getWH(cvOut); W=dim.w; H=dim.h;\n    clearCv(ctxOut,W,H);\n    var oMax=Math.max.apply(null,convOut.map(Math.abs));\n    var oScale=oMax>0.01?oMax:1;\n    ax=makeAx(W,H);\n    y0=drawGrid(ctxOut,ax,N_MIN,N_MAX,-oScale*0.2,oScale*1.3);\n    drawStems(ctxOut,ax,\n      nArr.map(function(ni,i){\n        if(ni>n) return {k:ni,val:0,color:'#2471a3'};\n        return {k:ni, val:convOut[i], color:(ni===n?'#b03a00':'#2471a3'), lw:(ni===n?3:2), r:(ni===n?6:4)};\n      }),\n      N_MIN,N_MAX,-oScale*0.2,oScale*1.3,y0);\n    \/\/ dashed marker\n    var mx=kToX(ax,n,N_MIN,N_MAX);\n    ctxOut.save();\n    ctxOut.strokeStyle='#b03a00'; ctxOut.lineWidth=1.5; ctxOut.setLineDash([4,3]);\n    ctxOut.beginPath(); ctxOut.moveTo(mx,ax.mt); ctxOut.lineTo(mx,H-ax.mb); ctxOut.stroke();\n    ctxOut.restore();\n\n    \/\/ --- Labels ---\n    var sumVal=prods.reduce(function(a,b){return a+b;},0);\n    var nIdx=n-N_MIN;\n    var outVal=(nIdx>=0&&nIdx<convOut.length)?convOut[nIdx]:0;\n    function fmt(v){ var s=v.toFixed(4).replace(\/\\.?0+$\/,''); return s||'0'; }\n    document.getElementById('dtc-sumLabel').textContent=fmt(sumVal);\n    document.getElementById('dtc-outLabel').textContent=fmt(outVal);\n  }\n\n  \/\/ \u2500\u2500 Event wiring \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  var slider = document.getElementById('dtc-nSlider');\n  var nLabel = document.getElementById('dtc-nLabel');\n\n  function onInput(){\n    var n=parseInt(slider.value,10);\n    nLabel.textContent='n = '+(n>=0?'+':'')+n;\n    draw(n);\n  }\n\n  slider.addEventListener('input', onInput);\n  document.getElementById('dtc-fShape').addEventListener('change', onInput);\n  document.getElementById('dtc-gShape').addEventListener('change', onInput);\n\n  \/\/ \u2500\u2500 Deferred first draw \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  \/\/ Use requestAnimationFrame so the browser has finished layout\n  \/\/ before we paint. A nested rAF gives a second frame of buffer\n  \/\/ for slower \/ iframe-based environments like Canvas LMS.\n  function deferredStart(){\n    requestAnimationFrame(function(){\n      requestAnimationFrame(function(){\n        onInput();\n      });\n    });\n  }\n\n  \/\/ Belt-and-suspenders: also fire on window load in case the\n  \/\/ script runs before the rest of the page is parsed.\n  if(document.readyState==='complete'){\n    deferredStart();\n  } else {\n    window.addEventListener('load', deferredStart);\n  }\n\n})();\n<\/script>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Disclaimer: This was built with the help of ClaudeAI as an educational tool for Foundations of Digital Signal Processing Discrete-Time Convolution Demo [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"post-templates\/post_noheader_nofooter2.php","format":"standard","meta":{"footnotes":""},"categories":[76,108],"tags":[],"class_list":["post-2370","post","type-post","status-publish","format-standard","hentry","category-education","category-foundations-of-digital-signal-processing"],"_links":{"self":[{"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/posts\/2370","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/comments?post=2370"}],"version-history":[{"count":3,"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/posts\/2370\/revisions"}],"predecessor-version":[{"id":2374,"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/posts\/2370\/revisions\/2374"}],"wp:attachment":[{"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/media?parent=2370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/categories?post=2370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smartdata.ece.ufl.edu\/index.php\/wp-json\/wp\/v2\/tags?post=2370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}