<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Eren の 宇宙船</title>
  
  <subtitle>Of Course I Still Love You</subtitle>
  <link href="https://erenship.com/atom.xml" rel="self"/>
  
  <link href="https://erenship.com/"/>
  <updated>2023-05-20T14:38:07.842Z</updated>
  <id>https://erenship.com/</id>
  
  <author>
    <name>Eren</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>ARM_DS 工程创建教程</title>
    <link href="https://erenship.com/posts/4ssaf4.html"/>
    <id>https://erenship.com/posts/4ssaf4.html</id>
    <published>2023-05-20T13:53:07.000Z</published>
    <updated>2023-05-20T14:38:07.842Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p><em>注：本文主要内容参考了 “Arm® Development Studio Getting Started Guide” chapter 9，如有疏漏欢迎指正。</em></p>          </div><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>首先来看官方手册对 ARM_DS 是定义：</p><blockquote><p>Arm® Development Studio是一种专业的软件开发解决方案，适用于裸机嵌入式系统和基于Linux的系统。它涵盖了从引导代码和内核移植到应用程序和裸机调试的所有开发阶段，包括性能分析。</p></blockquote><p>它包括以下内容：</p><ul><li><p>Arm Compiler for Embedded 6 工具链。</p><p>构建嵌入式和裸机嵌入式应用程序。</p></li><li><p>Arm Debugger</p><p>一款支持Arm处理器和Fixed Virtual Platform (FVP)目标上的软件开发的图形化调试器。</p></li><li><p>Fixed Virtual Platform (FVP)目标</p><p>针对Armv6-M、Armv7-A&#x2F;R&#x2F;M和Armv8-A&#x2F;R&#x2F;M架构的单核和多核模拟模型。这些模型使您能够在没有任何硬件的情况下开发软件。</p></li><li><p>Arm Streamline</p><p>一款图形化性能分析工具，可以将抽样数据和系统跟踪转换为报告，以可视化和统计的形式呈现数据。</p></li><li><p>Graphics Analyzer</p><p>Graphics Analyzer允许图形开发人员跟踪其应用程序中的OpenGL ES、Vulkan和OpenCL API调用。</p></li></ul><p>简单来说 ARM_DS 就是 ARM 自己推出的 IDE 工具，和 CCS &#x2F; IAR 类似，同样也是基于 Eclipse 所开发。</p><h1 id="工程创建"><a href="#工程创建" class="headerlink" title="工程创建"></a>工程创建</h1><p>环境： Windows 版本：ADS IDE 2022.1</p><p>以创建 C&#x2F;C++ 工程为例，建议工程先在 Visual Studio 中测试代码是否能正常运行。</p><h2 id="导入源码"><a href="#导入源码" class="headerlink" title="导入源码"></a>导入源码</h2><ol><li><p>File &gt; Import &gt; Project from Folder or Archive</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202204662.png"></p></li><li><p>Directory &gt; select your C project archived file</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202204691.png"></p></li><li><p>导入 VS 源码之后，便可以在左侧边框栏看到你刚刚导入的 VS 工程文件</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202204703.png"></p></li></ol><h2 id="工程配置"><a href="#工程配置" class="headerlink" title="工程配置"></a>工程配置</h2><p>导入代码之后，我们需要对项目进行相关设置，将 VS 工程设置为 ADS 工程，这样才能使工程跑起来。</p><p>右键创建的工程 &gt; <strong>Properties</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202204578.png"></p><p>里面的所有设置根据你的需求设置即可。</p><p>如果设置完成之后，最后编译不通过，那可能是你没有对头文件进行设置（如果你的 VS 工程使用的是绝对路径）。那么这时你需要在 “Includes” 中修改相应的头文件路径，注意“Arm C Compiler 6” 和 “ARM Assembler 6”  都需进行修改。</p><h2 id="Debug-session-配置"><a href="#Debug-session-配置" class="headerlink" title="Debug session 配置"></a>Debug session 配置</h2><blockquote><p><em>In Arm® Development Studio, you confifigure a debug session with the <strong>New Debug Connection</strong> wizard. This wizard enables you to connect to your target.</em></p></blockquote><p>在编译通过之后，我们还需配置链接模型（Model Connection）。这一步是最关键的一部， Fixed Virtual Platform (FVP）</p><p>下文将引导配置一个裸机模型连接，连接到一个 Cortex®-A35 固定虚拟平台 (FVP)，前面创建的项目。这一步的目的是在 Arm Development Studio 中配置连接到 FVP 的调试会话，以便进行裸机应用程序调试。</p><ol><li>创建一个 .ds 脚本文件，让 Fixed Virtual Platform (FVP) 处理半主机（semihosting），而不是让 Arm Debugger 处理。在 Arm Development Studio 中，可以使用以下步骤创建这样一个脚本文件：<ul><li>从主菜单中选择 “File &gt; New &gt; Other…”；</li><li>在 “New” 对话框中，选择 “Arm Debugger &gt; Arm Debugger Script”，然后点击 “Next”；</li><li>点击 “Workspace…”，选择 “HelloWorld” 项目作为这个脚本文件的位置，然后点击 “OK”；</li><li>在 “File Name” 字段中，命名这个脚本文件为 “use_model_semihosting”，然后点击 “Finish” 按钮。这将打开一个空的编辑器窗口。</li><li>在编辑器窗口中添加以下代码，并按 “Ctrl + S” 保存：</li></ul></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-built_in">set</span> semihosting enabled off<br></code></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212806.png"></p><ol start="2"><li><p>从主菜单，select <strong>File</strong> &gt; <strong>New</strong> &gt; <strong>Model Connection</strong></p></li><li><p>在 “Model Connection” 对话框中，指定连接的详细信息：</p><ul><li><p>为调试连接输入一个名称，例如 “HelloWorld_FVP”；</p></li><li><p>选择 “Associate debug connection with an existing project”，并选择在上一节 “Build your project” 中创建和构建的项目。</p></li><li><p>点击 “Next” 按钮。</p></li></ul></li><li><p>在 “Target Selection” 对话窗口中，指定 tagert</p><ul><li><p>选择 <strong>Arm FVP (Installed with Arm DS)</strong> &gt; <strong>Base_A53x1；</strong></p></li><li><p>点击 <strong>“Finish”</strong></p></li></ul></li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212884.png"></p><ol start="5"><li>在 “Edit Configuration” 对话框中，确保选择了正确的目标设备，指定了适当的应用程序文件，并且调试器知道从哪里开始进行调试：<ul><li>在 “Connection” 选项卡下，确保选择了 “Arm FVP (Installed with Arm DS) &gt; Base_A53x1 &gt; Bare Metal Debug &gt; Cortex-A53”；</li><li>在 “Bare Metal Debug” 中，在 “Model parameters” 字段中添加以下参数：</li></ul></li></ol><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs routeros">-C bp.<span class="hljs-attribute">secure_memory</span>=<span class="hljs-literal">false</span><br></code></pre></td></tr></table></figure><aside> 🪲 注：不同内核需要配置不同的参数<p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212897.png"></p></aside><p>这个参数的作用是禁用安全内存保护，以便在调试过程中能够访问内存。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212910.png"></p><p>​选择“Target Configuration &gt; Application on host to download &gt; Workspace”;    </p><p>​点击并展开“HelloWorld”项目，在“Debug”文件夹中选择“HelloWorld.axf”，然后点击“OK”按钮;</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212922.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212934.png"></p><p>​选择 “Debug from symbol”;</p><p>​启用 “Run target initialization debugger script (.ds&#x2F;.py)” 选项，并点击 “Workspace…”按钮。;</p><p>​选择 “use_model_semihosting.ds” 脚本文件，然后点击“OK”按钮。</p><p>这些操作将指定在开始调试会话时运行的脚本文件，并确保 FVP 处理半主机操作。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212947.png"></p><ol start="6"><li>点击“Debug”按钮，将应用程序加载到目标设备上，并将调试信息加载到调试器中。这将启动调试会话，并将您带入调试器的界面中。在调试器中，可以通过设置断点、单步执行和查看变量等操作来调试应用程序。</li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212960.png"><aside> 🪲 至此，我们所 ADS 工程的目前已经能正常运行。</p></aside><p>以下是调试器的相关说明：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202212971.png"></p><h2 id="Trace-调式工具"><a href="#Trace-调式工具" class="headerlink" title="Trace 调式工具"></a>Trace 调式工具</h2><p>在 ADS 中，同样有相当丰富的调试工具供我们使用。在 debug session 中可以通过 Trace 查看所有被执行的指令情况。</p><p>在使用 Trace 跟踪程序之前，我们需要先进行相关配置以开启 Trace。</p><p>开启过程如下图：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202220419.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202220493.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202220505.png"></p><p>至此，我们边成功开启了 Trace，愉快地 debug 吧。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202220517.png"></p><h1 id="套壳创建工程"><a href="#套壳创建工程" class="headerlink" title="套壳创建工程"></a>套壳创建工程</h1><p>在 ADS 工程配置过程中，稍有不慎都会导致整个工程无法正常编译运行。如果在排除所有配置之后工程仍然无法正常运行，那么我们可以采取套壳的方法进行工程创建。</p><p>所谓套壳，这里的壳就是 ADS 中的例程工程。例程毋庸置疑是能够正常运行，所有我们需要做的就是将壳内的程序替换为我们的代码即可。</p><p>套壳的原则：选择我们需要的内核例程，不要例程中的删除启动文件。</p><p>以下是一个套壳的流程：</p><ol><li>Import 例程；</li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202223028.png"></p><ol start="2"><li><p>导入例程之后，删除例程中不需要的应用层源码（也可以不删除，注释掉程序入口函数就行）；</p></li><li><p>导入我们的工程源码；</p></li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202223050.png"></p><ol start="4"><li>上述操作完毕后，请进行编译测试。</li></ol><h3 id="建立工程间的代码连接"><a href="#建立工程间的代码连接" class="headerlink" title="建立工程间的代码连接"></a>建立工程间的代码连接</h3><p>对于一份源码，我们常常需要建立 VS 工程（验证程序正确性），IAR工程（看 Profile）和 ADS（对 arm有更好的支持）工程。在这种情况下，如果对于工程源码很大的情况下，拷贝相同的代码来创建工程这就会变得十分冗余，且各工程间的修改并不同步。</p><p>所以在 ADS 中，我们就需要使用下面的方法来避免上述情况。</p><p>这一步是发生在导入文件的过程中，在导入源码文件时我们需要点击下方的 “Create links in workspace”，以此来建立 ADS 工程对源码的链接。如此之后，ADS 共在其 workspace 中创建与源码相同的源码文件目录，但其中并无文件。因为 “Create links in workspace” 已将代码连接到我们原始代码文件夹中。</p><p>这样我们既减小了由于创建多个工程造成的代码冗余，又避免了多个工程中的代码不同步的情况。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202223065.png"></p><p>可以看到下图中的目录为，源码工程文件夹下的目录文件。同时其中包含了 IAR、VS、ADS 等工程文件。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202305202223079.png"></p>]]></content>
    
    
    <summary type="html">本文将简要介绍如何在 ARM_DS 创建并成功运行一个工程。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="ARM_DS" scheme="https://erenship.com/tags/ARM-DS/"/>
    
    <category term="IDE" scheme="https://erenship.com/tags/IDE/"/>
    
  </entry>
  
  <entry>
    <title>音视频笔记｜运动估计 ME 源码简要分析（上）</title>
    <link href="https://erenship.com/posts/49d0.html"/>
    <id>https://erenship.com/posts/49d0.html</id>
    <published>2023-04-16T05:26:42.000Z</published>
    <updated>2023-04-30T02:52:09.309Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><blockquote><p>运动估计在分别会在 lookahead 阶段和后续编码阶段被使用，但两者使用的方法并不相同。本文将介绍编码阶段的 ME 进行讨论，下文将对 lookahead 阶段的 ME 进行介绍。</p></blockquote><p>运动估计是帧间预测阶段的核心部分，它通过比较当前帧与先前帧之间的相似性，来确定宏块（Macroblock）或子宏块（Sub-macroblock）之间的运动矢量。运动估计可以有效地消除时间冗余，从而降低编码后的比特率，提高编码效率。x264中的运动估计算法有很多种，包括钻石搜索（Diamond Search），六边形搜索（Hexagon Search）和不对称交叉多六边形搜索（Uneven Multi-Hexagon Search）等。</p><h2 id="ME-相关知识"><a href="#ME-相关知识" class="headerlink" title="ME 相关知识"></a>ME 相关知识</h2><h3 id="宏块的运动补偿"><a href="#宏块的运动补偿" class="headerlink" title="宏块的运动补偿"></a>宏块的运动补偿</h3><p>宏块（Macroblock）是帧中 16x16 大小的区域，它是包括 MPEG-1、MPEG-2、MPEG-4 Visual、H.261、H.262、H,264 在内的很多视频编码标准的运动补偿预测的基本单元。</p><p>在常见的 YUV 4:2:0 图像编码格式中，一个宏块由：</p><ol><li><p>64 个红色色差采样构成，这些采样组成 1 个 8x8 的采样块；</p></li><li><p>64 个红色色差采样构成，这些采样组成 1 个 8x8 的采样块；</p></li><li><p>64 个蓝色色差采样构成，这些采样组成 1 个 8x8 的采样块；</p></li></ol><p>即一共 6 个采样块，示意图如下：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092038902.png"></p><p>宏块的运动估计，主要是寻找参考帧中和当前宏块匹配的 16x16 采样区域。参考帧是先前就编码好的一个帧，在时间维上，参考帧可以在过去或者未来。参考帧中以当前宏块为中心的区域被搜索，寻找最佳匹配。</p><p>最佳匹配的照度、色差采样，被从当前宏块中减去，这样就产生了一个残余宏块。残余宏块与标示了最佳匹配区域和当前宏块的相对位移的 <strong>移动向量</strong> 一起编码并传输。</p><p>在上述基本的运动估计、运动补偿的基础上，有很多变体的算法：</p><ol><li>如果使用了未来的帧作为参考帧，则未来的帧必须在当前帧之前编码，也就是帧的编码必须是乱序的；</li><li>当参考帧和当前帧的差异非常大时，不使用运动补偿可能更加高效，编码器可能选择使用帧内预测；</li><li>视频中的移动物体很少能恰恰匹配16x16的边缘，因此使用可变大小的块往往更加高效；</li><li>物体移动的距离可能不是整像素，例如物体可能在水平方向移动3.83像素的距离。因此一个好的预测算法会在搜索最佳匹配之前在参考帧中，在次像素级别进行插值。</li></ol><h2 id="Preset-与-ME"><a href="#Preset-与-ME" class="headerlink" title="Preset 与 ME"></a>Preset 与 ME</h2><p>笔者本以为在 ultrafast 等较快的 Preset 模式下 ME 是不会开启的，但后来翻看源码发现：在所有 Preset 模式下都会启用，同时会根据 Preset 档次来选择对应的 ME 算法（diamon，haxgon，umh 等）</p><p>AQ（Adopt Quatinazation, 自适应量化） 在除 ultrafast （禁用 AQ 降低复杂度） 以外的所有 Preset 下都会开启。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092039639.png"></p><h2 id="源码中调用位置"><a href="#源码中调用位置" class="headerlink" title="源码中调用位置"></a>源码中调用位置</h2><aside> 💡 ME 在源码中代码调用顺序（真正的编码阶段） encode_frame() → x264_encoder_encode() → slices_write() → slice_write() → x264_macroblock_analyse() → mb_analyse_inter_p16x16() → x264_me_search_ref()</aside><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092041548.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092041568.png"></p><ul><li><strong>slices_write()</strong></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092042242.png"></p><ul><li>**slice_write()**（主要是slice，不是复数）</li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092042266.png"></p><ul><li><strong>x264_macroblock_analyse() - 【slice_write() &#x2F; analyse.c】</strong></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092042280.png"></p><ul><li><strong>mb_analyse_inter_p16x16()【P 帧为例】</strong></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092042294.png"></p><ul><li><strong>x264_me_search_ref【mb_analyse_inter_b16x16】</strong></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202304092042306.png"></p><p>以上便是ME在源码中的函数调用位置。</p><p>由于笔者在此阶段也只是简略进行分析，如有疏漏请欢迎指正！</p>]]></content>
    
    
    <summary type="html">本文将简要分析 x264 中运动估计 ME 模块。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="H264" scheme="https://erenship.com/tags/H264/"/>
    
    <category term="x264" scheme="https://erenship.com/tags/x264/"/>
    
  </entry>
  
  <entry>
    <title>音视频笔记｜H264 基础原理介绍</title>
    <link href="https://erenship.com/posts/1db7.html"/>
    <id>https://erenship.com/posts/1db7.html</id>
    <published>2022-11-11T08:26:30.000Z</published>
    <updated>2023-04-29T14:37:41.091Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一、视频压缩基础"><a href="#一、视频压缩基础" class="headerlink" title="一、视频压缩基础"></a>一、视频压缩基础</h2><h3 id="1-1-压缩基本概念"><a href="#1-1-压缩基本概念" class="headerlink" title="1.1 压缩基本概念"></a>1.1 压缩基本概念</h3><ul><li><p>编码的目的是为了压缩，编码是一种压缩技术方法；</p></li><li><p>编码的作用就是压缩数据和统一格式；</p></li><li><p>视频压缩原理——数据冗余</p><ul><li>空间冗余：图像相邻像素之间有较强的相关性</li><li>时间冗余：相邻前后帧图像内容相似</li><li>视觉冗余：人眼对某些细节不敏感，对图像中高频信息的敏感度小于低频信息，故可以适当剔除高频信息</li><li>编码冗余（信息熵冗余）：一幅图像中不同像素出现的概率不同，对出现次数较多的像素用少的位数编码以此来减小编码大小（哈夫曼编码）</li></ul></li></ul><h3 id="1-2-封装格式"><a href="#1-2-封装格式" class="headerlink" title="1.2 封装格式"></a>1.2 封装格式</h3><ul><li>封装格式也叫容器，就是将已经编码压缩好的视频轨和音频轨按照一定的格式放到一个文件中；</li><li>他是一个外壳容器，常见的格式（后缀名）有 mp4、mov、avi、mkv 等；</li></ul><h3 id="1-3-常见视频压缩算法"><a href="#1-3-常见视频压缩算法" class="headerlink" title="1.3 常见视频压缩算法"></a>1.3 常见视频压缩算法</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111600783.png"></p><h2 id="二、H264-编码概述"><a href="#二、H264-编码概述" class="headerlink" title="二、H264 编码概述"></a>二、H264 编码概述</h2><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111605703.png"></p><h3 id="2-1-YUV-图像"><a href="#2-1-YUV-图像" class="headerlink" title="2.1 YUV 图像"></a>2.1 <strong>YUV 图像</strong></h3><p>YUV 是一种色彩编码模型，也叫做 YCbCr，其中 “Y” 表示明亮度（Luminance），“U” 和 “V” 分别表示色度（Chrominance）和浓度（Chroma）</p><p>其实亮度 Y 也可以理解成 RGB 图像中的灰度值。YUV 颜色空间主要在多媒体流中使用较多。YUV 空间最大的特点就是图像的亮度 Y 和色度 UV 是分离的。通常人对色度 UV 的敏感性要小于对亮度 Y 的敏感性。所以通常都会对 UV 进行压缩，甚至没有UV分量一样可以显示完整的图像。当只有 Y 分量的时候，图像表示为灰度图。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111600892.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111605779.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111605795.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111600780.png"></p><h3 id="2-2-I-帧-P-帧-B-帧"><a href="#2-2-I-帧-P-帧-B-帧" class="headerlink" title="2.2 I 帧 P 帧 B 帧"></a>2.2 I 帧 P 帧 B 帧</h3><p>在 H264 协议中定义了三类帧</p><p>I 帧：关键帧（包含完整的画面数据），仅由帧内预测的宏块组成，采用 <strong>帧内压缩</strong> 技术。<br>P 帧：预测帧，向前参考帧，在压缩时，只参考前面已经处理的帧。<br>B 帧：双向参考帧，在压缩时，它即参考前而的帧，又参考它后面的帧。采用帧间压缩技术。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111607020.png"></p><h3 id="2-3-GOP-图像组"><a href="#2-3-GOP-图像组" class="headerlink" title="2.3 GOP 图像组"></a>2.3 GOP 图像组</h3><p>GOP（Group of picture）是指两个 IDR 帧之间的一组画面组。</p><p>两个 I 帧之间是一个图像序列，在一个图像序列中只有一个I帧。如下图所示：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111607297.png"></p><h3 id="2-4-IDR-立即刷新图像"><a href="#2-4-IDR-立即刷新图像" class="headerlink" title="2.4 IDR 立即刷新图像"></a>2.4 IDR 立即刷新图像</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111608950.png"></p><p>在 H.264 中，图像以序列为单位进行组织。<strong>一个序列的第一个图像叫做 IDR 图像（立即刷新图像），IDR 图像都是 I 帧图像。H.264 引入 IDR 图像是为了解码的重同步，当解码器解码到 IDR 图像时，立即将参考帧队列清空，将已解码的数据全部输出或抛弃，重新查找参数集，开始一个新的序列。</strong>这样，如果前一个序列出现重大错误，在这里可以获得重新同步的机会。IDR 图像之后的图像永远不会使用IDR之前的图像的数据来解码。<strong>IDR 图像一定是 I 图像，但 I 图像不一定是 IDR 图像</strong>。I 帧之后的图像有可能会使用I帧之前的图像做运动参考。</p><p>IDR 帧的性质是，比如第 1000 帧是 IDR 帧，那么这一帧相当于一个分水岭，从 1001 帧开始，所有的帧都不能再参照1000帧之前的帧。</p><p>视频开头的 I 帧一定是 IDR 帧</p><p>GOP 越大，编码的 I 帧就越少，相对而言 P、B 帧的压缩效率就越高。</p><h3 id="2-5-H264-画质级别"><a href="#2-5-H264-画质级别" class="headerlink" title="2.5 H264 画质级别"></a>2.5 H264 画质级别</h3><p>H.264有四种画质级别,分别是baseline, extended, main, high：<br>　　1、Baseline Profile：基本画质。支持I&#x2F;P 帧，只支持无交错（Progressive）和CAVLC；<br>　　2、Extended profile：进阶画质。支持I&#x2F;P&#x2F;B&#x2F;SP&#x2F;SI 帧，只支持无交错（Progressive）和CAVLC；(用的少)<br>　　3、Main profile：主流画质。提供I&#x2F;P&#x2F;B 帧，支持无交错（Progressive）和交错（Interlaced），<br>　　　 也支持CAVLC 和CABAC 的支持；<br>　　4、High profile：高级画质。在main Profile 的基础上增加了8x8内部预测、自定义量化、 无损视频编码和更多的YUV 格式；<br>H.264 Baseline profile、Extended profile和Main profile都是针对8位样本数据、4:2:0格式(YUV)的视频序列。在相同配置情况下，High profile（HP）可以比Main profile（MP）降低10%的码率。<br>根据应用领域的不同，Baseline profile多应用于实时通信领域，Main profile多应用于流媒体领域，High profile则多应用于广电和存储领域。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111608540.png"></p><h2 id="三、H264-编码流程"><a href="#三、H264-编码流程" class="headerlink" title="三、H264 编码流程"></a>三、H264 编码流程</h2><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111608684.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111608406.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111609032.png"></p><h3 id="3-1-宏块划分-x2F-扫描"><a href="#3-1-宏块划分-x2F-扫描" class="headerlink" title="3.1 宏块划分&#x2F; 扫描"></a>3.1 宏块划分&#x2F; 扫描</h3><ul><li>视频以宏块为单元，宏块越大视频文件越小；</li><li>视频的本质是宏块的运动；</li><li>在H.264 中，句法元素共被组织成 序列、图像、片、宏块、子宏块五个层次</li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111609781.png"></p><p>对一个 YUV 图像来说，可以划分为一个个 16x16 的宏块。</p><p>H264 默认是使用 16X16 大小的区域作为一个宏块，也可以划分成 8X8 大小。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111609744.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111609472.png"></p><p><strong>划分好宏块后，计算宏块的象素值</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111610619.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111610376.png"></p><p><strong>划分子块</strong></p><p>H264对比较平坦的图像使用 16X16 大小的宏块。但为了更高的压缩率，还可以在 16X16 的宏块上更划分出更小的子块。子块的大小可以是 8X16､ 16X8､ 8X8､ 4X8､ 8X4､ 4X4非常的灵活。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111611117.png"></p><h3 id="3-2-帧分组"><a href="#3-2-帧分组" class="headerlink" title="3.2 帧分组"></a>3.2 帧分组</h3><p>1、分组：把几帧图像分为一组（GOP，也就是一个序列），为防止运动变化，帧数不宜取多<br>2、定义帧：将每组内各帧图像定义为三种类型，即 I 帧、B帧和P帧<br>3、预测帧：以帧作为基础帧，以帧预测P帧，再由 I 帧和P帧预测B帧<br>4、数据传输：最后将 I 帧数据与预测的差值信息进行存储和传输</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111611732.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111611794.png"></p><p>通过宏块扫描与宏块搜索可以发现这两个帧的关联度是非常高的。进而发现这一组帧的关联度都是非常高的。因此，上面这几帧就可以划分为一组。其算法是：<strong>在相邻几幅图像画面中，一般有差别的像素只有10%以内的点,亮度差值变化不超过2%，而色度差值的变化只有1%以内，我们认为这样的图可以分到一组。</strong></p><p>在这样一组帧中，经过编码后，<strong>我们只保留第一帖的完整数据</strong>，其它帧都通过参考上一帧计算出来。我们称第一帧为<strong>IDR／I帧</strong>，其它帧我们称为<strong>P／B帧</strong>，这样编码后的数据帧组我们称为 <strong>GOP</strong>。</p><h3 id="3-3-帧间压缩（运动估计与补偿）"><a href="#3-3-帧间压缩（运动估计与补偿）" class="headerlink" title="3.3 帧间压缩（运动估计与补偿）"></a>3.3 帧间压缩（运动估计与补偿）</h3><p>帧间压缩(Interframe compression)也称为时间压缩(Temporal_compression)，是基于许多视频或动画的连续前后两帧具有很大的相关性(即连续的视频其相邻帧之间具有冗余信息)的特点来实现的；通过比较时间轴上不同帧之间的数据实施压缩，进一步提高压缩比。</p><p>在视频中，帧内压缩就是压缩 GOP 图像组中的 B 帧与 P 帧。</p><p>H264 编码器首先按顺序从缓冲区头部取出两帧视频数据，然后进行宏块扫描。当发现其中一幅图片中有物体时，就在另一幅图的邻近位置（搜索窗口中）进行搜索。如果此时在另一幅图中找到该物体，那么就可以计算出物体的运动矢量了。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111612969.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111612601.png"></p><p>运动矢量计算出来后，将相同部分（也就是绿色部分）减去，就得到了补偿数据。我们最终只需要将补偿数据进行压缩保存，以后在解码时就可以恢复原图了。压缩补偿后的数据只需要记录很少的一点数据。</p><p>我们把运动矢量与补偿称为<strong>帧间压缩技术</strong>，它解决的是视频帧在时间上的数据冗余。除了帧间压缩，帧内也要进行数据压缩，帧内数据压缩解决的是空间上的数据冗余。</p><p>帧间压缩的主要过程先进行宏块查找，寻找出残差值，进行运动矢量计算，最后通过残差值和运动矢量推算出下一帧的数据。</p><p>残差值是指帧之间有差别的部分；</p><p>帧间压缩 (Interframe compression) 也称为时间压缩 (Temporal_compression)，是基于许多视频或动画的连续前后两帧具有很大的相关性(即连续的视频其相邻帧之间具有冗余信息)的特点来实现的；通过比较时间轴上不同帧之间的数据实施压缩，进一步提高压缩比。</p><h3 id="3-4-帧内预测"><a href="#3-4-帧内预测" class="headerlink" title="3.4 帧内预测"></a>3.4 帧内预测</h3><p>人眼对图象都有一个识别度，对低频的亮度很敏感，对高频的亮度不太敏感。所以基于一些研究，可以将一幅图像中人眼不敏感的数据去除掉。这样就提出了帧内预测技术。</p><p>H264的帧内压缩与JPEG很相似。一幅图像被划分好宏块后，对每个宏块可以进行 9 种模式的预测。找出与原图最接近的一种预测模式。</p><p>帧内（Intraframe）压缩也称为空间压缩（Spatial compression）。当压缩一帧图像时，仅考虑本帧的数据而不考虑相邻帧之间的冗余信息，这实际上与静态图像压缩类似。帧内一般采用有损压缩算法，达不到很高的压缩比。</p><p>在视频中，帧内压缩就是压缩 GOP 图像组中的 I 帧&#x2F; IDR帧(属于I帧)。</p><p>帧内压缩是空域， 在空间XY轴进行压缩，进行压缩参考本帧数据，压缩率较小。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111612830.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111612901.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111612511.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111613081.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111613600.png"></p><p>帧内预测后的图像与原始图像的对比如下：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111613674.png"></p><p>然后，将原始图像与帧内预测后的图像相减得残差值。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111613101.png"></p><p>再将我们之前得到的预测模式信息一起保存起来，这样我们就可以在解码时恢复原图了。效果如下：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111613601.png"></p><p>经过帧内与帧间的压缩后，虽然数据有大幅减少，但还有优化的空间。</p><blockquote><p>帧内压缩与帧间压缩都属于有损压缩。</p><p>视频花屏的产生原因：一组 GOP 中有帧丢失，主要是 P 帧和 B 帧的丢失，这样残差值和运动矢量也会丢失，造成了当前帧解码失败，就会出现花屏。</p><p>视频卡顿的原因：当有帧丢失，就丢弃 GOP 内所有帧，直到下一个 I 帧出现，重新刷新图像。I 帧是 GOP 的第一帧，时间周期可能长，等待下一个 I 帧来之前的这段时间，就会出现卡顿。</p><p>这两者是不能同时兼顾的，比如微信视频通话没有花屏，但是会出现卡顿。一般视频录制的时候一般会有花屏，但不会出现卡顿。</p></blockquote><h3 id="3-5-DCT-和量化"><a href="#3-5-DCT-和量化" class="headerlink" title="3.5 DCT 和量化"></a>3.5 DCT 和量化</h3><p>对残差数据做 DCT</p><p>可以将残差数据做整数离散余弦变换，去掉数据的相关性，进一步压缩数据</p><p>将残差数据宏块进行 DCT 转换。</p><p>变换是视频、图像编码的核心部分。目前所采用的变换算法都是从傅里叶变换演变而来。</p><p>单纯的变换并不会导致视频（图像）的码率变小，反而会增大。</p><p>但是非常巧妙的一点是：变换把图像从空域转换成的时域，把由色块组成的图像变为由基准色调与图像细节组成；低频代表图片的基准色调，高频代表图像细节，类比电路中的基频与谐波。变换会使得图像的低频系数集中于某一点（左上角），频率向右下角递增。</p><p>一般来说，4x4大小的图像大多只是颜色平缓的色块，不会有太多的细节，因此低频系数会较大，而高频系数较小。另外，人的眼睛对于高频系数，即图像细节，并不会特别敏感。因此，通过量化可以去掉很大一部分小的高频系数。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111614106.png"></p><p>量化是使数据比特率下降的有效工具。量化过程的输入值动态范围很大，需要较多的比特才能表示一个数值，量化后的输出则只需要较小比特表示。<br>量化是不可逆过程，处理过程中有信息丢失，存在量化误差。</p><p>H.264采用标量量化技术，它将每个图像样点编码映射成较小的数值。一般标量量化器的原理为：<br>F Q &#x3D; r o u n d ( y &#x2F; Q P ) FQ&#x3D;round(y&#x2F;QP)FQ&#x3D;round(y&#x2F;QP)<br>其中，y 为输入样本点编码，QP 为量化步长，FQ 为 y 的量化值，round()为取整函数（其输出为与输入实数最近的整数）</p><p>在量化和反量化过程中，量化步长 QP 决定量化器的编码压缩率及图像精度。如果 QP 比较大，则量化值 FQ 动态范围较小，其相应的编码长度较小，数据压缩率高但会损失较多的图像细节信息；如果QP 比较小，则 FQ 动态范围较大，相应的编码长度也较大，但图像细节信息损失较少。编码器根据图像值实际动态范围自动改变 QP 值，在编码码率和图像精度之间折衷，达到整体最佳效果。</p><h3 id="3-6-熵编码"><a href="#3-6-熵编码" class="headerlink" title="3.6 熵编码"></a>3.6 熵编码</h3><p>经过 ZigZag 扫描后，一连串的数字的最后大部分为 0，以及一些 +1,-1。针对这一系列的数字，从概率的角度，再进行一次编码，这个过程称之为熵编码。</p><p>熵编码主要分为 CAVLC，和 CABAC，分别代表基于上下文的自适应可变长编码和基于上下文的自适应二进制算术编码。</p><h4 id="3-6-1-CAVLC"><a href="#3-6-1-CAVLC" class="headerlink" title="3.6.1 CAVLC"></a>3.6.1 CAVLC</h4><p>请参考下述文章</p><blockquote><p><a href="https://cloud.tencent.com/developer/article/1612331?from=article.detail.1612330">编码原理（五）–熵编码–CAVLC</a></p></blockquote><ul><li>非零系数的数目（TotalCoeffs）: 代表 ZigZag 扫描后序列中非 0 值的个数；         </li><li>拖尾系数的数目（TrailingOnes）:指 Z 扫描后，末尾高频信号中出现连续1或-1的个数（中间可以隔任意多个0），拖尾系数最多有5个。当连续1或-1的个数超过3个，只有最后3个1或-1是拖尾系数，其他的当作普通的非零系数。</li><li>TotalZeros: 最后一个非零系数前零的数目；        </li><li>nC：用来决策 coeff 如何编码的变量；        </li><li>ZerosLeft: 当前系数之前所有的 0 的个数；        </li><li>RunBefore: 紧邻当前系数的0的个数；</li></ul><hr><p>利用相邻已编码符号所提供的相关性，为索要编码的符号选择合适的上下文模型。</p><p>利用合适的上下文模型，就可以大大降低符号间的冗余度。</p><p>TotalCoeffs 和 TrailingOnes 通过查表方式进行编码，H.264 针对 TotalCoeffs 和 TrailingOnes，提供了 4 张变长表和 1 张定长表（部分见附表9-5）。</p><p>编码表的选择是由NC确定的，NC的值是由上下文信息确定的。对于色度直流信号，NC&#x3D;-1；对于其他的NC，根据当前块左边4x4块和上面4x4块的非零系数的个数A和B决定。如表一：其中X表示该块与当前块属于同一slice且可用。根据NC选择编码表的策略如表二：</p><blockquote><p>非零系数主要集中在低频部分，高频系数大部分为零，量化后经过 zig-zag 编码。</p><p>非零系数的幅值通常在靠近DC（即直流分量）部分较大，而在高频部分较小；</p><p>上下文模型主要体现在：非零系数编码所需表格和拖尾系数后缀长度的更新。</p><p>CAVLC 以 zig-zag 顺序用于对变换后的残差块进行编码。</p><p>CAVLC 是 CABAC 的替代品，虽然其压缩效率不如 CABAC，但 CAVLC 实现简单，并且在所有的 H.264 profile 中都支持。</p><p>通过 根据已编码句法元素的情况动态调整编码中使用的码表，取得了极高的压缩比。</p></blockquote><h4 id="3-6-2-CABAC"><a href="#3-6-2-CABAC" class="headerlink" title="3.6.2 CABAC"></a>3.6.2 CABAC</h4><ul><li><a href="http://lazybing.github.io/blog/2017/09/12/video-coding/">http://lazybing.github.io/blog/2017/09/12/video-coding/</a></li></ul><h2 id="四、H-264-码流分层"><a href="#四、H-264-码流分层" class="headerlink" title="四、H.264 码流分层"></a>四、H.264 码流分层</h2><h3 id="4-1-VCL-amp-NAL"><a href="#4-1-VCL-amp-NAL" class="headerlink" title="4.1 VCL &amp; NAL"></a>4.1 VCL &amp; NAL</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111614098.png"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111614769.png"></p><ul><li><p>H.264 的功能分为两层，即视频编码层（VCL）和网络提取层（NAL，Network Abstraction </p><p>Layer）。</p></li><li><p>VCL Layer 將 vidoe image 分割為許多的 slices，這此slice在分成許多的NALU傳送出去</p></li><li><p>VCL 数据即编码处理的输出，它表示被压缩编码后的视频数据序列。在 VCL 数据传输或存</p><p>储之前，这些编码的 VCL 数据，先被映射或封装进 NAL 单元中。</p><p>每个 NAL 单元包括一个原始字节序列负荷（RBSP）、一组对应于视频编码数据的 NAL 头信息。</p><p>NAL 单元序列的结构见图 6.6 </p></li><li><p><strong>切片头</strong>：包含了一组片的信息，比如片的数量，顺序等等</p></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111615356.png"></p><p>H.264从层次来看分为两层：视频编码层（VCL， Video Coding Layer）和网络提取层（NAL，Network Abstraction Layer）。VCL输出的是原始数据比特流（SODB，String of data bits），表示H.264的语法元素编码完成后的实际的原始二进制码流。</p><p>SODB通常不能保证字节对齐,故需要补齐为原始字节序列负荷（RBSP，Raw Byte Sequence Payload）。NAL层实际上就是最终输出的H.264码流，它是由一个个NALU组成的，每个NALU包括一组对应于视频编码数据的NAL头信息和一个原始字节序列负荷（RBSP，Raw Byte Sequence Payload）。以上名词之间的关系如下：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs ini"><span class="hljs-attr">RBSP</span> = SODB + RBSP trailing bits<br><span class="hljs-attr">NALU</span> = NAL header(<span class="hljs-number">1</span> byte) + RBSP<br><span class="hljs-attr">H.264</span> = Start Code Prefix(<span class="hljs-number">3</span> bytes) + NALU + Start Code Prefix(<span class="hljs-number">3</span> bytes) + NALU +…<br></code></pre></td></tr></table></figure><p>所以H.264码流的结构如下：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111615200.png"></p><p>NALU (Nal Unit) &#x3D; NALU头 + RBSP 在 VCL</p><p>数据传输或存储之前，这些编码的 VCL 数据，先被映射或封装进 NAL 单元(以下简称 NALU，Nal Unit) 中。每个 NALU 包括一个原始字节序列负荷(RBSP, Raw Byte Sequence Payload)、一组 对应于视频编码的 NALU 头部信息。RBSP 的基本结构是:在原始编码数据的后面填加了结尾 比特。一个 bit“1”若干比特“0”，以便字节对齐。</p><p>一个原始的 H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111615327.png"></p><ul><li>StartCode : Start Code 用于标示这是一个NALU 单元的开始，必须是”00 00 00 01” 或”00 00 01”（Annex B码流格式才必须是”00 00 00 01” 或”00 00 01”）</li></ul><p><strong>下表为 NAL Header Type</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211111615707.png"></p><h3 id="4-2-码流格式"><a href="#4-2-码流格式" class="headerlink" title="4.2 码流格式"></a>4.2 码流格式</h3><p>H.264 标准中指定了视频如何编码成独立的包，但如何存储和传输这些包却未作规范，虽然标准中包含了一个 Annex 附件，里面描述了一种可能的格式 Annex B，但这并不是一个必须要求的格式。<br>为了针对不同的存储传输需求，出现了两种打包方法。一种即 Annex B 格式，另一种称为 AVCC 格式。</p><ul><li>Annex B<br>从上文可知，一个 NALU 中的数据并未包含他的大小（长度）信息，因此我们并不能简单的将一个个 NALU 连接起来生成一个流，因为数据流的接收端并不知道一个 NALU 从哪里结束，另一个 NALU 从哪里开始。<br>Annex B格式用起始码（Start Code）来解决这个问题，它在每个 NALU 的开始处添加三字节或四字节的起始码 0x000001 或 0x00000001。通过定位起始码，解码器就可以很容易的识别NALU的边界。<br>当然，用起始码定位NALU边界存在一个问题，即NALU中可能存在与起始码相同的数据。为了防止这个问题，在构建 NALU时，需要将数据中的0x000000，0x000001,0x000002,0x000003 中插入防竞争字节（Emulation Prevention Bytes) 0x03，使其变为：<br>0x000000 &#x3D; 0x0000 03 00<br>0x000001 &#x3D; 0x0000 03 01<br>0x000002 &#x3D; 0x0000 03 02<br>0x000003 &#x3D; 0x0000 03 03<br>解码器在检测到 0x000003 时，将 0x03 抛弃，恢复原始数据。</li></ul><p>由于 Annex B 格式每个 NALU 都包含起始码，所以解码器可以从视频流随机点开始进行解码，常用于实时的流格式。在这种格式中通常会周期性的重复 SPS 和PPS，并且经常时在每一个关键帧之前。</p><h3 id="4-3-H264的传输"><a href="#4-3-H264的传输" class="headerlink" title="4.3 H264的传输"></a>4.3 H264的传输</h3><p> <strong>H264是一种码流</strong> 类似与一种不见头，也不见尾的一条<strong>河流</strong>。如何从和流中取到自己想要的<strong>数据</strong>呢，</p><p>在H264的标砖中有这样的一个封装格式叫做”Annex-B”的字节流格式。 它是H264编码的主要字节流格式。</p><p>几乎市面上的编码器是以这种格式进行输出的。<strong>起始码 0x 00 00 00 01 或者 0x 00 00 01</strong> 作为<strong>分隔符</strong>。</p><p>两个 0x 00 00 00 01之间的字节数据 是表示一个NAL Unit</p><p>宏快作为压缩视频的最小的一部分，需要被组织，然后在网络之间做相互传输。</p><p> 如果单纯的用 <strong>宏快</strong> 来发送数据是 <strong>杂乱无章</strong> 的，就好像在没有 <strong>集装箱</strong> 出现之前，货物总是随意被堆放到船上。</p><p>上货（编码），下货是非常痛苦的。 当集装箱出现之后，一切都发生了改变，传输效率大大增高。</p><p> 集装箱可以理解成 <strong>H264编码标准</strong>，他制定了相互传输的格式，将宏快 有组织，有结构，有顺序的形成一系列的码流。这种码流既可 通过 InputStream 网络流的数据进行传输，也可以封装成一个文件进行保存。</p><h2 id="参考引用"><a href="#参考引用" class="headerlink" title="参考引用"></a>参考引用</h2><p>[1] <a href="https://blog.csdn.net/LuohenYJ/article/details/84957101">YUV图像处理入门1</a></p><p>[2] <a href="https://blog.51cto.com/u_15375308/4010325">H264编码(帧内预测)</a></p><p>[3] <a href="https://www.cnblogs.com/Lxk0825/p/9927757.html">H.264编码profile &amp; level控制</a></p><p>[4] <a href="https://blog.csdn.net/wuqingsen1/article/details/118030223">帧内压缩与帧间压缩</a></p><p>[5] <a href="https://www.cnblogs.com/Lxk0825/p/9925064.html">H.264分层结构与码流结构</a></p><p>[6] <a href="https://blog.csdn.net/Liu1314you/article/details/77185215">H.264中普通I帧和IDR帧究竟有什么区别</a></p><p>[7] <a href="https://www.cnblogs.com/AndyJee/p/3724917.html">运动补偿与运动估计</a></p><p>[8] <a href="http://www.elkpi.com/topics/2016/04/color-formats-equasys-gmbh.html">Color Formats – equasys GmbH</a></p><p>[9] <a href="http://blog.gitdns.org/2017/03/14/h264/">h264</a></p><p>[10] <a href="https://yumichan.net/video-processing/video-compression/introduction-to-h264-2-sodb-vs-rbsp-vs-ebsp/">Introduction to H.264: (2) SODB vs RBSP vs EBSP</a></p><p>[11] <a href="https://www.cnblogs.com/Lxk0825/p/9925041.html">H.264基本原理与编码流程</a></p><p>[12] <a href="https://blog.51cto.com/u_15077549/3366546">【知识点】H264, H265硬件编解码基础及码流分析</a></p><p>[13] <a href="https://pjchender.dev/webdev/webrtc-media-basic/#%E4%BB%80%E9%BA%BC%E6%98%AF%E7%B7%A8%E8%A7%A3%E7%A2%BC%E5%99%A8">[Media] 影音傳輸-基礎知識_GOP&#x2F;视频基础</a></p><p>[14] <a href="https://blog.51cto.com/u_15375308/5073333">深入讲解音视频编码原理，H264码流详解——手写H264编码器</a></p><p>[15] <a href="https://cloud.tencent.com/developer/article/1612330">编码原理（四）—ZIGZAG扫描</a></p><p>[16] <a href="https://blog.csdn.net/qq_42139383/article/details/118334630">一文搞懂H264量化原理以及计算过程</a></p>]]></content>
    
    
    <summary type="html">本文将简述 H.264 的基本原理过程，如有疏漏欢迎指正交流。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="H264" scheme="https://erenship.com/tags/H264/"/>
    
    <category term="x264" scheme="https://erenship.com/tags/x264/"/>
    
  </entry>
  
  <entry>
    <title>DSP 学习笔记｜（七）HiFi 汇编说明</title>
    <link href="https://erenship.com/posts/ekff.html"/>
    <id>https://erenship.com/posts/ekff.html</id>
    <published>2022-11-06T12:17:38.000Z</published>
    <updated>2023-04-30T03:00:46.525Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一、储备知识"><a href="#一、储备知识" class="headerlink" title="一、储备知识"></a>一、储备知识</h2><h3 id="汇编构成"><a href="#汇编构成" class="headerlink" title="汇编构成"></a>汇编构成</h3><p>基本上 assembly source 由以下三个部分組成，</p><ul><li>instruction set</li><li>assembler syntax</li><li>directive</li></ul><p>Instruction set 基本上对于相同的 CPU 来说是固定的，比较不会随着 assembler 不同。</p><p>每個 CPU 可能會有不同 version 的 <a href="http://en.wikipedia.org/wiki/List_of_instruction_sets">instruction set architecture (ISA) </a>如，</p><ul><li>ARMv6</li><li>ARMv7-A</li><li>ARMv7-M</li><li>MIPS32r2 等等，及每一個 version 可能有不同的 extension 如，</li><li>Thumb2</li><li>Neon</li></ul><p>Assembler syntax 每個不同的 assembler 會有一些自訂的語法，如 symbol 的標記方式、 include header 、如何宣告資料、 註解格式等，請參閱各自的 toolchain 的說明文件。</p><h3 id="调用约定"><a href="#调用约定" class="headerlink" title="调用约定"></a>调用约定</h3><p>理解汇编首先且最重要的事就是明白汇编代码与代码之间是如何交互的。函数如何调用其他函数。包括参数是如何传递给函数，及函数返回值是如何返回的。</p><p>这些事情执行的过程与实现被称为调用约定（Calling Conventions）。编译器必须遵循它预定义的标准，这样才能让编译后的代码能和其他不同编译器编译出的代码能够交互。没有标准，编译器能编译出不相配的代码。</p><p>如上讨论，寄存器是和 CPU 联系非常紧密的一小块内存，经常用于存储一些正在使用的数据。</p><blockquote><p>函数的调用过程中有两个参与者，一个是调用方 caller，另一个是被调用方 callee。</p><p>调用约定规定了 caller 和 callee 之间如何相互配合来实现函数调用，具体包括的内容如下：</p><p>函数的参数存放在哪的问题。是放在寄存器中？还是放在栈中？放在哪个寄存器中？放在栈中的哪个位置？<br>函数的参数按何种顺序传递的问题。是从左到右将参数入栈，还是从右到左将参数入栈？<br>返回值如何传递给 caller 的问题。是放在寄存器里面，还是放在其他地方？</p></blockquote><p>ARM处理器有16个寄存器，从r0到r15，每一个都是32位比特。调用约定指定他们其中的一些寄存器有特殊的用途，例如：</p><ul><li>r0-r3：用于存放传递给函数的参数；</li><li>r4-r11：用于存放函数的本地参数；</li><li>r12：是内部程序调用暂时寄存器。这个寄存器很特别是因为可以通过函数调用来改变它；</li><li>r13：栈指针sp(stack pointer)。在计算机科学内栈是非常重要的术语。寄存器存放了一个指向栈顶的指针。看这里了解更多关于栈的信息；</li><li>r14：是链接寄存器lr(link register)。它保存了当目前函数返回时下一个函数的地址；</li><li>r15：是程序计数器pc(program counter)。它存放了当前执行指令的地址。在每个指令执行完成后会自动增加；</li></ul><p>你可以在 ARM 文档里了解更多关于 ARM 调用约定的信息。苹果也在文档【iOS开发调用约定】内有做过详细描述。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062022892.png" alt="image-20220818201922094"></p><h2 id="二、汇编指示（assembly-directive）"><a href="#二、汇编指示（assembly-directive）" class="headerlink" title="二、汇编指示（assembly directive）"></a>二、汇编指示（assembly directive）</h2><ul><li>类似 <code>_main:</code> 或<code>Ltmp0: </code> 的形式被称之为标签（label）, 用于辅助定位代码或者资源地址, 便于开发者理解和记忆；</li><li>类似 <code>pushq </code>或 <code>movq</code>的形式被称之为汇编指令, 它们会被汇编器编译为机器代码, 最终被 CPU 所执行；</li><li>类似 <code>.section</code> 或 <code>.globl </code> 等以 <code>.</code> 开头的形式被称之为编译器指令（assembly directive）, 用于告知编译器相关的信息或者进行特定操作。他们不是汇编指令而是作用于汇编器的，可以忽略所有这样的代码；</li><li>关于 directive 和 instruction 这两个词的区别，前者翻译为指示，后者翻译成指令。因为一般 directive 并不会产生代码而是指示编译器的一些行为，而 instruction 则会产生实际的代码；</li></ul><h3 id="loc-5-76-49"><a href="#loc-5-76-49" class="headerlink" title=".loc 5 76 49"></a>.loc 5 76 49</h3><p>**eg. **</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062024593.png" alt="image-20221106202447549"></p><p><strong>说明：</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062025851.png" alt="image-20221106202535805"></p><ul><li>fileno : 文件描述符</li><li>lineno : 行号</li><li>colum：列数（操作符的位置）</li></ul><h3 id="literal-position"><a href="#literal-position" class="headerlink" title=".literal_position"></a>.literal_position</h3><p><strong>eg.</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062026045.png" alt="image-20221106202654001"></p><p><strong>说明：</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062027133.png" alt="image-20221106202729103"></p><h3 id="p2align"><a href="#p2align" class="headerlink" title=".p2align"></a>.p2align</h3><p><strong>eg.</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062027550.png" alt="image-20221106202759522"></p><p><strong>说明：</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062028692.png" alt="image-20221106202825671"></p><p>p2align 3 表示 2 的 3 次幂 &#x3D; 8</p><p>p2align 2 表示 2 的  2 次幂 &#x3D; 4</p><h3 id="函数名"><a href="#函数名" class="headerlink" title="函数名_"></a><em>函数名</em>_</h3><p><strong>eg.</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062028708.png" alt="image-20221106202846674"></p><p>编译器通常在函数名的前面添加一个下划线。</p><h3 id="cfi-startproc"><a href="#cfi-startproc" class="headerlink" title=".cfi_startproc"></a>.cfi_startproc</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062029324.png" alt="image-20221106202911293"></p><p><strong>eh_frame：</strong>GCC Exception <a href="https://so.csdn.net/so/search?q=Frame&spm=1001.2101.3001.7020">Frame</a>，也就是eh_frame。这里提到 eh_frame 是 dwarf 调试信息的变体（variant）。eh_frame 段中存储着跟函数入栈相关的关键数据。当函数执行入栈指令后，在该段会保存跟入栈指令一一对应的编码数据，根据这些编码数据，就能计算出当前函数栈大小和cpu的哪些寄存器入栈了，在栈中什么位置。</p><h3 id="cfi-def-cfa"><a href="#cfi-def-cfa" class="headerlink" title=".cfi_def_cfa"></a>.cfi_def_cfa</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062029324.png"></p><h3 id="cfi-def-cfa-offset"><a href="#cfi-def-cfa-offset" class="headerlink" title=".cfi_def_cfa_offset"></a>.cfi_def_cfa_offset</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062029935.png" alt="image-20221106202947900"></p><h3 id="prologue-end"><a href="#prologue-end" class="headerlink" title="prologue_end"></a>prologue_end</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062030883.png" alt="image-20221106203003854"></p><h3 id="type"><a href="#type" class="headerlink" title=".type"></a>.type</h3><p><strong>eg.</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062030101.png" alt="image-20221106203029065"></p><p>汇编里面所有以 <code>:</code> 结尾的都会视为标签 ( <code>label</code> )，在这里我们定义一个叫做 <code>main</code> 的标签，并且使用 <code>.type</code> 伪指令定义这个标签的类型是一个函数(<code>function</code>)，到此我们就定义了我们的 <code>main</code> 函数。</p><p><strong>说明：</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062030010.png" alt="image-20221106203044974"></p><h3 id="Ltmp："><a href="#Ltmp：" class="headerlink" title=".Ltmp："></a>.Ltmp：</h3><p>标签，不是指令。是这部分的汇编代码名字。</p><h3 id="is-stmt"><a href="#is-stmt" class="headerlink" title="is_stmt"></a>is_stmt</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062031682.png" alt="image-20221106203108647"></p><p>此选项会将 .debug_line 状态机中的 is_stmt 寄存器设置为 value，该值必须为 0 或 1。</p><h3 id="L32R"><a href="#L32R" class="headerlink" title="L32R"></a>L32R</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062031375.png" alt="image-20221106203139344"></p><p>L32R 指令从指定地址加载 32 位值。因此，“l32r a2，2ec8” 将地址 0x2ec8 处的 32 位值加载到寄存器 a2 中。</p><h3 id="L-本地标签"><a href="#L-本地标签" class="headerlink" title="L. 本地标签"></a>L. 本地标签</h3><p><strong>eg.</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062032854.png" alt="image-20221106203207817"></p><p>所有以 <code>L.</code> 开头的都为本地标签，这些标签只能用于函数内部。</p><h3 id="Ⅱ-1-0"><a href="#Ⅱ-1-0" class="headerlink" title="[Ⅱ *1+0]"></a>[Ⅱ *1+0]</h3><p><strong>eg.</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062033476.png" alt="image-20221106203305432"></p><p>[Ⅱ * 1 + 0]</p><p><strong>Ⅱ</strong>：数字乘以 II 符号表示正在执行的迭代；</p><p><strong>1</strong>：乘 1 代表在第二次迭代中的运算，乘 0 就代表在第一次迭代中的运算；</p><p><strong>0</strong>：最后的数字代表该指令处于第几个 cycle 中。</p><h3 id="指示参考表（节选）"><a href="#指示参考表（节选）" class="headerlink" title="指示参考表（节选）"></a>指示参考表（节选）</h3><table><thead><tr><th>GNU Assembler Directive</th><th align="center">Note</th></tr></thead><tbody><tr><td>.text</td><td align="center">Tells <code>as</code> to assemble the following statements onto the end of the text subsection numbered subsection, which is an absolute expression. If subsection is omitted, subsection number zero is used.</td></tr><tr><td>.file</td><td align="center"><code>.file</code> (which may also be spelled <code>.app-file&#39;) tells </code>as<code>that we are about to start a new logical file. string is the new file name. In general, the filename is recognized whether or not it is surrounded by quotes</code>“‘;</td></tr><tr><td>.globl</td><td align="center"><code>.global</code> makes the symbol visible to <code>ld</code>. If you define symbol in your partial program, its value is made available to other partial programs that are linked with it. Otherwise, symbol takes its attributes from a symbol of the same name from another file linked into the same program.</td></tr><tr><td>.p2align</td><td align="center">Pad the location counter (in the current subsection) to a particular storage boundary. The first expression (which must be absolute) is the number of low-order zero bits the location counter must have after advancement. For example &#96;.p2align 3’ advances the location counter until it a multiple of 8. If the location counter is already a multiple of 8, no change is needed.</td></tr><tr><td>.section</td><td align="center">Use the <code>.section</code> directive to assemble the following code into a section named name.</td></tr><tr><td>.asciz</td><td align="center"><code>.asciz</code> is just like <code>.ascii</code>, but each string is followed by a zero byte. The “z” in &#96;.asciz’ stands for “zero”.</td></tr></tbody></table><h2 id="三、调用约定"><a href="#三、调用约定" class="headerlink" title="三、调用约定"></a>三、调用约定</h2><blockquote><p>调用约定，即调用 Call0 ABI 和窗口 ABI，在 <em>Xtensa Instruction Set Architecture (ISA) Reference Manual</em> 中进行了更广泛的描述。</p></blockquote><ul><li><p>Application Binary Interface (ABI) 应用程序二进制接口；</p></li><li><p>对于窗口 ABI，入口点上的第一个指令是一个入口指令，它被一个 CALL<em>N</em> 或 CALLX<em>N</em> 指令调用（其中 N 是 4、8 或 12）；</p></li><li><p>第二个入口点总是实现调用 call0 ABI，入口点将用 CALL0 指令调用，并将使用 RET 指令返回。</p></li></ul><p><strong>eg.</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062033682.png" alt="image-20221106203349642"></p><p><strong>👇 call4，call8，call12 列对应窗口 ABI</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202211062034087.png" alt="image-20221106203416052"></p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p>[1] Optimizing Code for HiFi Audio Engines</p><p>[2] Using as（The GNU Assembler）</p><p>[3] Xtensa® System Software Reference Manual</p><p>[4] <a href="https://blog.csdn.net/weixin_39822728/article/details/111197567?utm_term=%E6%B1%87%E7%BC%96%E4%BB%A3%E7%A0%81Ltmp%E6%A0%87%E7%AD%BE&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-0-111197567-null-null&spm=3001.4430">arm汇编指令_iOS汇编ARM教程</a></p><p>[5] <a href="https://blog.csdn.net/W15242345526/article/details/126127334?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166080560516781685398459%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=166080560516781685398459&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-126127334-null-null.142%5Ev41%5Econtrol,185%5Ev2%5Econtrol&utm_term=%E6%B1%87%E7%BC%96%E4%BB%A3%E7%A0%81Ltmp%E6%A0%87%E7%AD%BE&spm=1018.2226.3001.4187">C程序设计语言的汇编解释（第一章节，一些实例）</a></p><p>[6] <a href="https://zhuanlan.zhihu.com/p/388683540">ARM汇编入门指南</a></p><p>[7] <a href="https://www.quora.com/What-is-the-difference-between-an-instruction-and-a-directive-in-assembly-language">What is the difference between an instruction and a directive in assembly language?</a></p><p>[8] <a href="https://www.cntofu.com/book/46/assembly/yue_du_assembly_code.md">Reading assembly code</a></p><p>[9] <a href="https://blog.csdn.net/qq_29328443/article/details/107232025">x86_64汇编之四：函数调用、调用约定</a></p><p>[10] <a href="https://mp.weixin.qq.com/s?__biz=Mzg5ODUxNDMxMA==&mid=2247488571&idx=1&sn=452d68c7a3ea182666e1f913e2f3e62d&chksm=c06038d2f717b1c4b078784ca0d911ac97cc0b75539755c00a4ccc7c74e1b6d5336289ae9989&token=570592262&lang=zh_CN#rd">函数调用时栈是如何变化的？</a></p>]]></content>
    
    
    <summary type="html">笔者将学习 HiFi 4 汇编的过程记录于本文。文中内容主要参考 Cadence 官方文档。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="DSP" scheme="https://erenship.com/tags/DSP/"/>
    
    <category term="HiFi" scheme="https://erenship.com/tags/HiFi/"/>
    
  </entry>
  
  <entry>
    <title>DSP 学习笔记｜（六）DSP 中的定点 &amp; 浮点</title>
    <link href="https://erenship.com/posts/awfs.html"/>
    <id>https://erenship.com/posts/awfs.html</id>
    <published>2022-11-06T09:09:54.000Z</published>
    <updated>2023-04-30T03:00:26.988Z</updated>
    
    <content type="html"><![CDATA[<h2 id="DSP-中的定点与浮点转换"><a href="#DSP-中的定点与浮点转换" class="headerlink" title="DSP 中的定点与浮点转换"></a>DSP 中的定点与浮点转换</h2><p>​许多 DSP 都是定点 DSP，处理定点数据会相当快，但是处理浮点数据就会非常慢。可以利用 Q 格式进行浮点数据到定点的转化，节约 CPU 时间。实际应用中，浮点运算大都时候都是既有整数部分，也有小数部分的。所以要选择一个适当的定标格式才能更好的处理运算。</p><p>​Q 格式表示为：Qm.n，表示数据用 m 比特表示整数部分，n 比特表示小数部分，共需要 m+n+1 位来表示这个数据，多余的一位用作符合位。假设小数点在 n位的左边（从右向左数），从而确定小数的精度</p><p>​例如 Q15 表示小数部分有 15 位，一个 short 型数据，占 2 个字节，最高位是符号位，后面 15 位是小数位，就假设小数点在第 15 位左边，表示的范围是：-1 &lt; X &lt; 0.9999695 。</p><p>​浮点数据转化为 Q15，将数据乘以 2^15；Q15 数据转化为浮点数据，将数据除以 2^15。</p><p>​例如：假设数据存储空间为 2 个字节，0.333×2^15&#x3D;10911&#x3D;0x2A9F，0.333 的所有运算就可以用 0x2A9F 表示，同理 10911×2^(-15)&#x3D;0.332977294921875，可以看出浮点数据通过 Q 格式转化后是有误差的。</p><p>​例：两个小数相乘，0.333*0.414&#x3D;0.137862</p><p>　　0.333 * 2^15&#x3D;10911&#x3D;0x2A9F，0.414 * 2^15&#x3D;13565&#x3D;0x34FD</p><p>　　short a &#x3D; 0x2A9F;</p><p>　　short b &#x3D; 0x34FD;</p><p>　　short c &#x3D; a * b &gt;&gt; 15;　　&#x2F;&#x2F; 两个 Q15 格式的数据相乘后为 Q30 格式数据，因此为了得到 Q15 的数据结果需要右移 15 位</p><p>​这样 c 的结果是 0x11A4 &#x3D; 0001000110100100，这个数据同样是 Q15 格式的，它的小数点假设在第 15 位左边，即 0.001000110100100 &#x3D; 0.1378173828125… 和实际结果 0.137862 差距不大。或者 0x11A4 &#x2F; 2^15 &#x3D; 0.1378173828125</p><h2 id="Q-格式的运算"><a href="#Q-格式的运算" class="headerlink" title="Q 格式的运算"></a>Q 格式的运算</h2><ul><li>定点加减法：须转换成相同的 Q 格式才能加减 </li><li>定点乘法：不同 Q 格式的数据相乘，相当于 Q 值相加，即 Q15 数据乘以 Q10 数据后的结果是 Q25 格式的数据</li><li>定点除法：不同 Q 格式的数据相除，相当于 Q 值相减</li><li>定点左移：左移相当于 Q 值增加</li><li>定点右移：右移相当于 Q 减少</li></ul><h2 id="Q-格式的应用格式"><a href="#Q-格式的应用格式" class="headerlink" title="Q 格式的应用格式"></a>Q 格式的应用格式</h2><p>​实际应用中，浮点运算大都时候都是既有整数部分，也有小数部分的。所以要选择一个适当的定标格式才能更好的处理运算。一般用如下两种方法：</p><ol><li>使用时使用适中的定标，既可以表示一定的整数复位也可以表示小数复位，如对于 2812 的 32 位系统，使用 Q15 格式，可表示－65536.0～65535.999969482 区间内的数据。</li><li>全部采用小数，这样因为小数之间相乘永远是小数，永远不会溢出。取一个极限最大值（最好使用 2 的 n 次幂），转换成 x&#x2F;Max 的小数（如果 Max 是取的 2 的 n 次幂，就可以使用移位代替除法）。</li></ol><h2 id="其他资料"><a href="#其他资料" class="headerlink" title="其他资料"></a>其他资料</h2><p>​支持浮点运算的DSP就是浮点DSP芯片，在这种片子上可以自由进行小数运算。而在定点DSP上是不能直接进行小数运算的，需要先给数值定标，且这个小数点不可移动。</p><p>​因此，定点DSP完成小数运算时，编程稍微复杂一点。速度肯定就不如浮点的片子了。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><p><a href="https://blog.csdn.net/messi_cyc/article/details/77934566">Q格式（Q15）DSP上浮点数据定点化处理</a></p></li><li><p><a href="https://blog.csdn.net/cuiweitju/article/details/39395715">定点DSP与浮点DSP的比较（定点DSP和浮点DSP的定义）</a></p></li><li><p><a href="https://cloud.tencent.com/developer/article/1670449">一文教你搞懂C语言的Q格式</a></p></li><li><p><a href="https://www.796t.com/content/1549700470.html">DSP中的定點運算</a></p></li><li><p><a href="https://www.daimajiaoliu.com/daima/479b6a503900409">DSP学习笔记（二）——DSP中浮点数与定点数格式与运算处理</a></p></li></ul>]]></content>
    
    
    <summary type="html">在 DSP 中定点与浮点之间的计算差异往往是大相径庭的，本文将简述他们之间的差异。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="DSP" scheme="https://erenship.com/tags/DSP/"/>
    
  </entry>
  
  <entry>
    <title>关于 valine 评论插件失效记录</title>
    <link href="https://erenship.com/posts/f86f.html"/>
    <id>https://erenship.com/posts/f86f.html</id>
    <published>2022-07-30T00:48:14.000Z</published>
    <updated>2023-04-30T03:01:11.968Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>博客底部的 valine 评论插件无法正常显示。</p><h2 id="问题分析"><a href="#问题分析" class="headerlink" title="问题分析"></a>问题分析</h2><p>在使用 <code>F11</code> 打开网页控制窗口，可以看到 valine 相关的连接出错。</p><p>ERR_CONNECTION_REFUSED 问题</p><div class="note note-success">            <p>判断是否为 DNS 劫持的方法</p><ul><li>ping 自己的 REST API 服务器地址（xxxxx 为 自己 AppID 的前 8 位字符）<br>（如果 ping xxxxxxxx.api.lncldglobal.com 域名指向 127.0.0.1 可能是 DNS 劫持）</li></ul>          </div><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/Snipaste_2022-07-23_11-24-09.png" alt="Snipaste_2022-07-23_11-24-09"></p><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><ul><li>修改 DNS</li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/Snipaste_2022-07-23_11-22-25.png" alt="Snipaste_2022-07-23_11-22-25"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/Snipaste_2022-07-23_11-23-18.png" alt="Snipaste_2022-07-23_11-23-18"></p><h2 id="参考引用"><a href="#参考引用" class="headerlink" title="参考引用"></a>参考引用</h2><p>[1] <a href="https://iyichen.xyz/2022/01/hexo-leancloud-valine-access-fail/">Hexo使用国际版LeanCloud Valine评论连接失败</a></p><p>[2] <a href="https://github.com/xCss/Valine/issues/340">国际版域名问题 #340</a></p><p>[3] <a href="https://github.com/DesertsP/Valine-Admin/issues/63">关于时区的一个问题 #63</a></p><p>[4] <a href="https://inktea.xyz/2022/bed6.html">LeanCloud-Valine出现ERR_CONNECTION_REFUSED问题</a></p>]]></content>
    
    
    <summary type="html">针对评论插件 Valine 出现 ERR_CONNECTION_REFUSED 问题进行解决。</summary>
    
    
    
    <category term="DIY Pie" scheme="https://erenship.com/categories/DIY-Pie/"/>
    
    
    <category term="Hexo" scheme="https://erenship.com/tags/Hexo/"/>
    
  </entry>
  
  <entry>
    <title>DSP 学习笔记 |（五）HiFi 4 User&#39;s Guide 笔记</title>
    <link href="https://erenship.com/posts/9860.html"/>
    <id>https://erenship.com/posts/9860.html</id>
    <published>2022-07-24T01:49:09.000Z</published>
    <updated>2023-04-30T03:00:08.642Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>本文笔记整理摘自《HiFi4 DSP User’s Guide》。</p>          </div><blockquote><p><strong>先导阅读手册</strong>：</p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095009245.png" alt="image-20220724095009245" style="zoom:80%;" /></blockquote><h2 id="一、-HiFi-4-概述"><a href="#一、-HiFi-4-概述" class="headerlink" title="一、 HiFi 4 概述"></a>一、 HiFi 4 概述</h2><div class="note note-warning">            <ul><li>Cadence HiFi ：Cadence Tensilica HiFi DSP 架构，用于音频解码</li><li>Tensilica：嵌入式处理器公司，已被芯片 EDA 巨头 Cadence 收购</li><li>Xtensa：DSP 处理器核心，也是该系列的型号名称，也是该处理器中指令集架构的名称</li><li>HiFi：特指 32 位音频&#x2F;语音处理数字信号处理 (DSP) 核，基于 Xtensa® 架构</li></ul>          </div><h3 id="1-1-HiFi-4-特点"><a href="#1-1-HiFi-4-特点" class="headerlink" title="1.1 HiFi 4 特点"></a>1.1 HiFi 4 特点</h3><p>HiFi 4 DSP 是一个高性能的嵌入式数字信号处理器，专门为音频和语音处理进行了优化。</p><p>HiFi 4 DSP 由三个主要部件组成：</p><ol><li>一个 DSP 子系统；</li><li>一个可选的单精度浮点单元；</li><li>一个协助比特流访问和变长（Huffman）编解码的子系统。</li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095035434.png" alt="image-20220724095035434"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095047136.png" alt="image-20220724095047136"></p><ul><li>HiFi 4 DSP 是一个 VLIW 架构，支持并行执行四个操作。</li><li>DSP 的读取、比特流和 Huffman 操作以及核心操作都可以在 VLIW 指令的 0 槽和 1 中，存储仅在槽 0 中可用。DSP MAC、ALU 和可选的浮点操作通常在槽 2 和槽 3 中进行。</li><li>HiFi 4 DSP 是建立在 Xtensa RISC 架构的基础上，它实现了丰富的通用标量指令集，为高效的嵌入式处理进行了优化。</li><li>由 Cadence 提供的音频包不使用 DMA。因此，大多数客户要么使用缓存，要么使本地存储器足够大以覆盖所需的应用。</li></ul><h3 id="1-2-寄存器"><a href="#1-2-寄存器" class="headerlink" title="1.2 寄存器"></a>1.2 寄存器</h3><p><strong>AE_DR 寄存器</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095058671.png" alt="image-20220724095058671"></p><ul><li><p>HiFi 4 DSP 包含一个 16 进制 64 位寄存器 AE _ DR。</p></li><li><p>当寄存器被存储到内存中时，寄存器的较高一半总是存储在较低的内存地址中，并从较低的内存地址加载。寄存器的单独的一半或四分之一始终是单独的数据项。 例如，如果将 32 位元素向左移动，则 L 元素不会溢出到高位元素中</p></li></ul><p><strong>AE_EP 寄存器</strong></p><ul><li>HiFi 4 DSP 支持一个 4 进制、8 位的额外精度寄存器 AE_EP。</li><li>该寄存器的访问时间比 AE_D R寄存器晚一个周期。</li></ul><p><strong>AE_VALIGN 寄存器</strong></p><ul><li>HiFi 4 DSP 支持一个 4 进制、64 位的对齐寄存器 AE_VALIGN。</li><li>使用这个寄存器允许硬件以每周期 64 位的速度加载或存储非 64 位对齐的 SIMD 流位&#x2F;周期。</li><li>对齐的加载和存储只存在于槽0中，所以不可能同时发出这些指令。</li></ul><h3 id="1-3-操作助记符"><a href="#1-3-操作助记符" class="headerlink" title="1.3 操作助记符"></a>1.3 操作助记符</h3><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220720152135269.png" alt="image-20220724095113577" style="zoom:150%;" /><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095120543.png" alt="image-20220724095120543" style="zoom:150%;" /><h3 id="1-4-定点数及其运算"><a href="#1-4-定点数及其运算" class="headerlink" title="1.4 定点数及其运算"></a>1.4 定点数及其运算</h3><p>一个定点数的数据类型 <em>m.n</em> 包含一个符号位，在小数点的左边有m-1位，在小数点的右边有n位。</p><p>当表示为一个二进制的时候，最不重要的 n 位是小数部分，最重要的 m 位是整数部分。</p><h3 id="1-5-VLIW-槽及格式"><a href="#1-5-VLIW-槽及格式" class="headerlink" title="1.5 VLIW 槽及格式"></a>1.5 VLIW 槽及格式</h3><p>HiFi 4 DSP 可以在一个 88 位的指令束中发出 4 个操作，或在一个 48 位的指令束中发出 2 个操作。使用 Xtensa LX FLIX (VLIW) 技术，HiFi 4 DSP 支持几种不同的格式，有不同的插槽限制。每条指令都属于一种格式，但不同的格式可以在一条指令中打包不同数量的操作。</p><ul><li>第一个插槽支持标量与矢量的 <strong>读取与写入</strong>，以及 <strong>标量 Xtensa 操作</strong>；</li><li>第二个插槽支持标量与矢量的 <strong>读取与写入</strong>，以及 <strong>矢量 Xtensa 操作</strong>；</li><li>最后两个插槽主要支持 <strong>矢量逻辑运算</strong> 与 <strong>矢量乘法运算</strong>。</li></ul><p>对于可选择的浮点单元来说，大多数浮点操作都可在 slot 3 和 slot 4 中进行。</p><p><strong>在优化 HiFi 4 DSP 代码中理解开槽的概念是十分重要的。</strong>循环通常受到只能进入一个或另一个槽的操作的限制。例如，每个周期不可能发出一个以上的（可能的SIMD）存储。如果一个循环被一个槽中的操作所限制，那么试图优化另一个槽中的操作就没有意义了。 </p><h2 id="二、DSP-编程"><a href="#二、DSP-编程" class="headerlink" title="二、DSP 编程"></a>二、DSP 编程</h2><div class="note note-info">            <ul><li>HiFi 4 DSP 每个周期提供四个 MAC。 它提供对整数和小数运算的等效支持。</li><li>不利用 SIMD 的应用程序的运行速度将比利用 SIMD 的应用程序慢 4 倍。</li><li>对于 24 位和 32x16 位的应用程序，编译器不会自动矢量化。应用程序编写器必须使用显示矢量数据类型或内部函数来编写代码。</li></ul>          </div><h3 id="2-1-数据类型"><a href="#2-1-数据类型" class="headerlink" title="2.1 数据类型"></a>2.1 数据类型</h3><ul><li>HiFi 4 DSP 支持 16、24、32 以及 64 位的数据类型。所有类型都包含整数与分数版本。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095144861.png" alt="image-20220724095144861"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095156736.png" alt="image-20220724095156736"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095206371.png" alt="image-20220724095206371"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095217319.png" alt="image-20220724095217319"></p><h3 id="2-2-编码与解码"><a href="#2-2-编码与解码" class="headerlink" title="2.2 编码与解码"></a>2.2 编码与解码</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095229654.png" alt="image-20220724095229654"></p><h3 id="2-3-基于内嵌函数编程"><a href="#2-3-基于内嵌函数编程" class="headerlink" title="2.3 基于内嵌函数编程"></a>2.3 基于内嵌函数编程</h3><p>每条 HiFi 4 DSP 指令都可以通过一个相同名称的内部函数直接访问，除了 “.” 需要全部变成 “_”。</p><h2 id="三、HiFi-4-指令集"><a href="#三、HiFi-4-指令集" class="headerlink" title="三、HiFi 4 指令集"></a>三、HiFi 4 指令集</h2><ul><li><p>对于矢量读取和写入，<strong>内存中的高位地址总是存储在寄存器中的最小有效位</strong>。</p></li><li><p>HiFi 4 DSP 还支持两个圆形缓冲区，可用于对齐或不对齐的数据。</p></li><li><p>虽然向量变量不需要被对齐到 64位，但它们仍然必须根据每个标量元素的要求进行对齐，例如32位的向量的 ints。</p></li><li><p>AE_LA64.PP 是一个特殊的初始化指令，这条指令将数据从数据流的起点加载到对齐寄存器中。对齐指令工作的具体细节与程序员无关。只要调用 AE_LA64_PP 引导内在的第一个要加载的地址（不管是否对齐），然后用适当的对齐加载继续加载。</p></li><li><p>大多数读取和写入操作的助记符包含一个尺寸，表示操作符的大小；</p></li><li><p>大多数加载和存储操作的助记符包含一个后缀，<strong>表示如何计算有效地址以及是否更新基址寄存器</strong>。</p></li><li><p>定点数 1.31, 是指令里面操作的数据类型，int 之后，还有按照指令规范的类型来转换。</p><p>int &#x3D; 2, 在经过 1.31 后，二进制，000….10（32位）。如果是负数，第一位是符号位，补码形式。</p></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095242956.png" alt="image-20220724095242956"></p><h3 id="3-1-读取与写入操作"><a href="#3-1-读取与写入操作" class="headerlink" title="3.1 读取与写入操作"></a>3.1 读取与写入操作</h3><ul><li><p>load 是将内存里面的值读取到寄存器（CPU 内部的存储单元）。如果都是放在寄存器的，寄存器哪有那么多地方给你存东西？</p></li><li><p>store 是将寄存器里面的值写入到内存。</p></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095252488.png" alt="image-20220724095252488"></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">//将数组a的值赋值给数字b，分别使用load和store指令</span><br><br><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> ** argv)</span><br>&#123;<br><span class="hljs-comment">// 初始化数据</span><br><span class="hljs-type">short</span> a[<span class="hljs-number">4</span>] = &#123;<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>&#125;;<br><span class="hljs-type">short</span> b[<span class="hljs-number">4</span>];<br>ae_int16x4 *ap = (ae_int16x4 *) &amp;a[<span class="hljs-number">0</span>];<br>ae_int16x4 *bp = (ae_int16x4 *) &amp;b[<span class="hljs-number">0</span>];<br>ae_int16x4 src;<br><span class="hljs-comment">// load：先读取内存中的值到寄存器</span><br>AE_L16X4_IP(src, ap, <span class="hljs-number">8</span>);<br><span class="hljs-comment">// store: 将数组a中的值存到数组b中</span><br><span class="hljs-comment">//AE_SA16x4_IP (src, ae_valign u, *ap);</span><br>AE_S16X4_IP(src, bp, <span class="hljs-number">8</span>);<br><br><span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">4</span>; i++)<br>&#123;<br><span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%d\n&quot;</span>, a[i]);<br><span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%d\n&quot;</span>, b[i]);<br>&#125;<br><span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>&#125;<br></code></pre></td></tr></table></figure><h3 id="3-2-乘积累加操作"><a href="#3-2-乘积累加操作" class="headerlink" title="3.2 乘积累加操作"></a>3.2 乘积累加操作</h3><p>乘积累加运算 （ 英语：Multiply Accumulate, MAC,）。</p><p>乘法 multiplication、加法 adder、周期 cycle 就是 mac，乘加器，表示一个周期完成一次乘法和加法运算。DSP 的重要性能指标。DSP 的主要工作就是大量的乘加器运算。</p><p>DSP 一个机器指令周期能实现乘加运算，这是 DSP 的精髓。 实现这个运算的内核就是 MAC。 </p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095327286.png" alt="image-20220724095327286"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095339843.png" alt="image-20220724095339843"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095352754.png" alt="image-20220724095352754"></p><p><strong>MAC:</strong></p><p>两个和四个 MAC 操作有两种形式——双 MAC 取两个 MAC 的结果，并将它们加或减，如下示例所示。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">acc = acc – d0.L*d1.L + d0.H*d1.H<br></code></pre></td></tr></table></figure><p><strong>MACs:</strong><br>SIMD MACs 不结合不同乘数的结果。相反，它们对数据的不同部分执行示例乘法操作，如下示例所示。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c++">acc.h = acc.h – d0.h*d1.h<br>acc.l = acc.l – d0.l*d1.l<br></code></pre></td></tr></table></figure><p>高位和低位各算各的，SIMD MACs 将其结果打包为 32 位或 16 位，因此在其名称中使用 P。通过同时添加或减去两个乘法结果，双 MAC 指令能够保持它们的累积精度，而不需要写入多个输出寄存器。</p><ul><li>在单乘法和 SIMD 乘法运算中，每个乘法&#x2F;累加操作系列都有一个仅乘法变体，即乘法&#x2F;加法变体和乘法&#x2F;减法变体，通过将 accum_type 设置为空、A 或 S 来表示分别。 </li><li>使用 MUL 变体，累加器内容会被以下结果覆盖乘法。 使用 MULA 变体，乘法的结果被添加到累加器内容并写回累加器。 使用 MULS 变体，结果从累加器的内容中减去乘法的值并写回累加器。</li><li>accum_type 以 Z 开头的双 MAC 操作是对零进行累加的。换句话说，累积器的初始内容被丢弃。那些没有 Z的操作则是针对累加器的初始内容进行累加。在可选的 Z 后面，有两个字母表示加法或减法，两个乘法结果各一个。</li><li>小数乘法指令在 accum_type 后面有一个 F。</li></ul><p><strong>对称 &amp; 非对称四舍五入</strong></p><ul><li>整数 SIMD 乘法指令扔掉了其结果的高位，就像标准的 C&#x2F;C++乘法。小数 SIMD 乘法指令使用对称或不对称的四舍五入方法，将低位舍去。</li><li>在非对称四舍五入的情况下，两半被向上舍入，即 0.5 倍的最小有效结果位被舍入为 1.0，-0.5 倍的最小有效结果位被舍入为 1.0。即 0.5 倍的最小有效结果位被向上舍入为 1.0，-0.5 倍的最小有效结果位被向上舍入为 0。</li><li>在对称四舍五入的情况下，两个半数从零开始四舍五入，即 -0.5 倍的最小有效结果位四舍五入到 -1.0。</li><li>在指令描述中，对称舍入被称为 round，而非对称舍入被称为 round+∞。</li></ul><p><strong>饱和 &amp; 非饱和乘法</strong></p><p>​执行操作时，某个中间变量的值的范围大于了最终结果的值的类型范围。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs c">eg. <br>（中间变量值）int32 <span class="hljs-type">int</span> <span class="hljs-number">129</span><br>（最终值）int8 <span class="hljs-title function_">char</span> <span class="hljs-params">(范围：<span class="hljs-number">-128</span> - <span class="hljs-number">127</span>)</span><br> 此时最终值就会溢出，变成 -127，此时与实际值相差很远了。<br> <br>饱和：先做一个判断<br> <span class="hljs-title function_">if</span><span class="hljs-params">(<span class="hljs-type">int</span> &gt; <span class="hljs-number">128</span>)</span><br>     <span class="hljs-type">int</span> = <span class="hljs-number">128</span>;<br> 这样就避免了最后结果会相差很大。<br>    <br></code></pre></td></tr></table></figure><ul><li>没有保护位的小数 MAC 运算，1.31x1.31 到 1.63 或 1.31，1.31x1.15 到 1.31 和 1.15x1.15 到 1.15 或 1.31，使它们的结果饱和。 所有其他 MAC 操作都是完整的或具有保护位且不会饱和。</li><li>饱和乘法有一个 S 跟在大小或四舍五入的名称后面。</li><li>一些 16x16 位乘法器被设计为与 ITU-T&#x2F;ETSI 内在函数，因此串联进行多次饱和。 这些指令的名称中有 SS。</li></ul><p><strong>其他</strong></p><ul><li>无符号乘以无符号的乘法，在其前面有一个 U。无符号乘以有符号 的乘法，在指定符前有一个 US。利用 AE_EP 寄存器文件产生 72 位累加器的乘法运算，在指令前有一个 EP。</li><li><strong>所有 MAC 操作都出现在第三个或第四个插槽中</strong>。 出现在第三个插槽中的任何乘法运算都将具有后缀  _S2。 C&#x2F;C++ 程序员可以忽略后缀。 编译器会在需要时自动将普通乘法转换为 _S2 乘法。</li></ul><h3 id="3-3-加、减与比较操作"><a href="#3-3-加、减与比较操作" class="headerlink" title="3.3 加、减与比较操作"></a>3.3 加、减与比较操作</h3><p>Add, Subtract and Compare Operations</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095415682.png" alt="image-20220724095415682"></p><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095438397.png" alt="image-20220724095438397"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095454559.png" alt="image-20220724095454559"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095517115.png" alt="image-20220724095517115"></div></div><div class="group-image-row"></div></div><h3 id="3-4-移位操作"><a href="#3-4-移位操作" class="headerlink" title="3.4 移位操作"></a>3.4 移位操作</h3><p>Shift Operations 移位操作</p><p><strong>所有移位操作都以前缀 AE_S 开始。</strong>下面的字母是 L 或 R，表示主要移位方向是左还是右。下一个字母是 L或 A，表示是逻辑移位（在右移时填入0）还是算术移位（在右移时符号扩展）。下一个字母 I 表示立即移位，A 表示 AR 移位，S 表示 AE_SAR 移位。后面是一个数字，表示被移位的元素的大小，还有一个可选的R表示右移位而不是截断的右移，以及一个可选的 S 表示饱和的左移。</p><h3 id="3-5-归一化操作"><a href="#3-5-归一化操作" class="headerlink" title="3.5 归一化操作"></a>3.5 归一化操作</h3><h3 id="3-6-Divide-Step-操作"><a href="#3-6-Divide-Step-操作" class="headerlink" title="3.6 Divide Step 操作"></a>3.6 Divide Step 操作</h3><h3 id="3-7-截断操作"><a href="#3-7-截断操作" class="headerlink" title="3.7 截断操作"></a>3.7 截断操作</h3><p>Truncate Operations</p><p>AE_TRUNC16X4F32 Operation</p><h3 id="3-8-移动操作"><a href="#3-8-移动操作" class="headerlink" title="3.8 移动操作"></a>3.8 移动操作</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724095531219.png" alt="image-20220724095531219"></p><h2 id="四、-HiFi-4-备忘录"><a href="#四、-HiFi-4-备忘录" class="headerlink" title="四、 HiFi 4 备忘录"></a>四、 HiFi 4 备忘录</h2><h3 id="4-1-HiFi-4-的头文件"><a href="#4-1-HiFi-4-的头文件" class="headerlink" title="4.1 HiFi 4 的头文件"></a>4.1 <strong>HiFi 4 的头文件</strong></h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;xtensa/tie/xt_hifi4.h&gt;</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;xtensa/hal.h&gt;</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;xtensa/xtruntime.h&gt;</span></span><br></code></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">本文笔记整理摘自《HiFi4 DSP User&#39;s Guide》。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="DSP" scheme="https://erenship.com/tags/DSP/"/>
    
    <category term="HiFi" scheme="https://erenship.com/tags/HiFi/"/>
    
  </entry>
  
  <entry>
    <title>DSP 学习笔记 |（四）Xtensa ISA 笔记</title>
    <link href="https://erenship.com/posts/6ba9.html"/>
    <id>https://erenship.com/posts/6ba9.html</id>
    <published>2022-07-24T01:40:18.000Z</published>
    <updated>2023-05-20T14:37:16.859Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>本文笔记主要整理摘自《Xtensa® Instruction Set Architecture (ISA)》。</p>          </div><h2 id="一、-XCC-编译器"><a href="#一、-XCC-编译器" class="headerlink" title="一、 XCC 编译器"></a>一、 XCC 编译器</h2><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724094306520.png" alt="image-20220724094306520"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093233735.png" alt="image-20220724093233735"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093243706.png" alt="image-20220724093243706"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093252702.png" alt="image-20220724093252702"></p><h2 id="二、-Candence-处理器"><a href="#二、-Candence-处理器" class="headerlink" title="二、 Candence 处理器"></a>二、 Candence 处理器</h2><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093310661.png" alt="image-20220724093310661"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093416020.png" alt="image-20220724093416020"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093322357.png" alt="image-20220724093322357"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093348993.png" alt="image-20220724093348993"></p><h2 id="三、-语法"><a href="#三、-语法" class="headerlink" title="三、 语法"></a>三、 语法</h2><h3 id="3-1-数据类型"><a href="#3-1-数据类型" class="headerlink" title="3.1 数据类型"></a>3.1 数据类型</h3><ol><li><p><code>ae_int32x2</code><br>由两个 32 位的数据类型组成一个 64 位的数据，8 字节对齐。如果使用 int 类型强制转换，那么在内存分布上，将是两个相同的 32 位数据，举例如下：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">test</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>&#123;<br>    <span class="hljs-type">int</span> mem1 = <span class="hljs-number">0x1234</span>;<br>    <span class="hljs-type">int</span> mem2 = <span class="hljs-number">0x5678</span>;<br>    ae_int32x2 p = mem1;<br><br>    <span class="hljs-type">int</span> *p1 = (<span class="hljs-type">int</span> *)&amp;p;<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;(int)p = 0x%0x\n&quot;</span>,(<span class="hljs-type">int</span>)p);<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;*(p1) = 0x%0x\n&quot;</span>,*(p1));<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;*(p1+1) = 0x%0x\n&quot;</span>,*(p1+<span class="hljs-number">1</span>));<br><br>    ae_int32x2 p2 = <span class="hljs-built_in">AE_MOVDA32X2</span>(mem1, mem2);<br>    <span class="hljs-type">int</span> *p3 = (<span class="hljs-type">int</span> *)&amp;p2;<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;p3=0x%0x,*(p3) = 0x%0x\n&quot;</span>,p3,*(p3));<br>    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;p3+1=0x%0x,*(p3+1) = 0x%0x\n&quot;</span>,p3+<span class="hljs-number">1</span>,*(p3+<span class="hljs-number">1</span>));<br>&#125;<br><br>输出：<br>    <br>(<span class="hljs-type">int</span>)p = <span class="hljs-number">0x1234</span><br>*(p1) = <span class="hljs-number">0x1234</span><br>*(p1+<span class="hljs-number">1</span>) = <span class="hljs-number">0x1234</span><br>p3=<span class="hljs-number">0x2ffffeb8</span>,*(p3) = <span class="hljs-number">0x1234</span><br>p3+<span class="hljs-number">1</span>=<span class="hljs-number">0x2ffffebc</span>,*(p3+<span class="hljs-number">1</span>) = <span class="hljs-number">0x5678</span><br>    <br>分析：AE_MOVDA32X2作用是将两个<span class="hljs-number">32</span>位数拼成一个<span class="hljs-number">64</span>位数。<br></code></pre></td></tr></table></figure></li></ol><h2 id="四、-基础的-SIMD-编程"><a href="#四、-基础的-SIMD-编程" class="headerlink" title="四、 基础的 SIMD 编程"></a>四、 基础的 SIMD 编程</h2><p><strong>SIMD</strong> ：Single Instruction Multiple Data，<strong>单指令流多数据流</strong>，是一种采用一个控制器来控制多个处理器，<strong>同时对一组数据（又称“数据向量”）中的每一个分别执行相同的操作从而实现空间上的并行性的技术。</strong>在 <a href="https://zh.wikipedia.org/wiki/%E5%BE%AE%E5%A4%84%E7%90%86%E5%99%A8">微处理器</a> 中，单指令流多数据流技术则是一个 <a href="https://zh.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E5%99%A8">控制器 </a>控制多个平行的 <a href="https://zh.wikipedia.org/w/index.php?title=%E5%A4%84%E7%90%86%E5%BE%AE%E5%85%83&action=edit&redlink=1">处理微元</a>.</p><p>由于单指令流多数据流处理效率高的原因，常被用于在多媒体应用中的 3D 图像和音视频处理。</p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093442891.png" alt="image-20220724093442891" style="zoom:200%;" /><p>基本的 SIMD 操作概念：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093451811.png" alt="image-20220724093451811"></p><p>SIMD 操纵不能以不同的形式处理多数据，如下图所示。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093500823.png" alt="image-20220724093500823"></p><h3 id="4-1-矢量类型"><a href="#4-1-矢量类型" class="headerlink" title="4.1 矢量类型"></a>4.1 矢量类型</h3><p>C 语言常用的数据类型例如 <code>char</code> 、<code>float</code> 被称为标量类型。在 SIMD 运算中的数据类型被称作矢量类型。每个矢量类型都有其相应的标量类型。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220711144041063.png" alt="image-20220724093512219"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093522749.png" alt="image-20220724093522749"></p><p>在 SIMD 编程中，经常需要将特定的向量元素称为标量或将标量块称为单个向量。本节介绍了满足这一需求的引用方法，例如，只输出向量的第三个元素或将标量数组输入数据捆绑成适合 SIMD 处理的向量成为可能。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093533040.png" alt="image-20220724093533040"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093550883.png" alt="image-20220724093550883"></p><h3 id="4-2-基础的-SIMD-运算"><a href="#4-2-基础的-SIMD-运算" class="headerlink" title="4.2 基础的 SIMD 运算"></a>4.2 基础的 SIMD 运算</h3><ol><li><p><strong>以加法为例，介绍标量运算与 SIMD 运算</strong></p><p>a. <strong>标量运算</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093601622.png" alt="image-20220724093601622"></p><p>b. <strong>SIMD 运算</strong></p></li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093628087.png" alt="image-20220724093628087"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093639289.png" alt="image-20220724093639289"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093702759.png" alt="image-20220724093702759"></p><p>​c. 完整的加法例程<img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093714182.png" alt="image-20220724093714182"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093727381.png" alt="image-20220724093727381"></p><div class="note note-info">            <p>运算几乎都是以标量矩阵作为输入数据。</p>          </div><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093743600.png" alt="image-20220724093743600"></p><ol start="2"><li><strong>条件运算</strong></li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093752699.png" alt="image-20220724093752699"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093802584.png" alt="image-20220724093802584"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093810499.png" alt="image-20220724093810499"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093821334.png" alt="image-20220724093821334"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093828937.png" alt="image-20220724093828937"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093836377.png" alt="image-20220724093836377"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093847048.png" alt="image-20220724093847048"></p><h2 id="五、寄存器"><a href="#五、寄存器" class="headerlink" title="五、寄存器"></a>五、寄存器</h2><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220724093859234.png" alt="image-20220724093859234"></p><h3 id="5-1-通用（AR）-寄存器"><a href="#5-1-通用（AR）-寄存器" class="headerlink" title="5.1 通用（AR） 寄存器"></a>5.1 通用（AR） 寄存器</h3><p>地址寄存器（Address Registers, AR）。每条指令最多包含三个 4 位的通用寄存器（AR）指令，每个指令可以选择 16 个 32 位寄存器中的一个。这些通用寄存器被命名为地址寄存器，以区别于协处理器寄存器，后者在许多系统中可能作为 “数据 “寄存器使用。然而，AR 寄存器并不限于保存地址，它们也可以保存数据。</p><p>如果配置了窗口寄存器选项，地址寄存器文件将被扩展，并使用从虚拟到物理寄存器的映射。</p><p>地址寄存器文件的内容在复位后是未定义的。</p><h3 id="5-2-移位和移位量寄存器（SAR）寄存器"><a href="#5-2-移位和移位量寄存器（SAR）寄存器" class="headerlink" title="5.2 移位和移位量寄存器（SAR）寄存器"></a>5.2 移位和移位量寄存器（SAR）寄存器</h3><p>移位和移位量寄存器（Shifts and the Shift Amount Register，SAR)。ISA 提供了传统的即时移位（逻辑左移、逻辑右移和算术右移），但是它没有提供单指令移位，其中移位量是一个寄存器操作数。从一个普通的寄存器中获取移位量会产生一个关键的时序路径。另外，简单的移位不能有效地扩展到更大的宽度。漏斗式移位（两个数据值在输入移位器的时候被 catenated）解决了这个问题，但是需要太多的操作数。ISA 通过提供一个漏斗移位来解决这两个问题，其中移位量是从 SAR 寄存器中获取的。可变移位由编译器合成，使用指令从一般寄存器中的移位量计算 SAR，然后再进行漏斗移位。</p>]]></content>
    
    
    <summary type="html">本文笔记主要整理摘自《Xtensa® Instruction Set Architecture (ISA)》。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="DSP" scheme="https://erenship.com/tags/DSP/"/>
    
    <category term="HiFi" scheme="https://erenship.com/tags/HiFi/"/>
    
  </entry>
  
  <entry>
    <title>DSP 学习笔记 |（三）C &amp; DSP 基础概念</title>
    <link href="https://erenship.com/posts/af34.html"/>
    <id>https://erenship.com/posts/af34.html</id>
    <published>2022-07-23T16:00:38.000Z</published>
    <updated>2023-04-30T03:00:16.460Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>记录在学习过程中所需的 C 语言与 DSP 相关基础知识补充。</p>          </div><h2 id="一、C-语言基础"><a href="#一、C-语言基础" class="headerlink" title="一、C 语言基础"></a>一、C 语言基础</h2><h3 id="1-1-零碎"><a href="#1-1-零碎" class="headerlink" title="1.1 零碎"></a>1.1 零碎</h3><ol><li><p><strong>const</strong> 修饰：用 const 修饰过的指针变量 p 不能修改 a 中的内容，而没有用 const 修饰过的指针变量 q 照样可以修改 a 中的内容，而且 a 自己也可以重新给自己赋值。它用来 <strong>告诉编译器， 被修饰的这些东西，具有“只读”的特点</strong> 。</p></li><li><p>C 语言中 “ ! ” 是对<strong>立面的意思</strong>。例如 ！ &#x3D; 就是不等于的意思，常用在循环条件判断中，或者逻辑运算中，例如 x&#x3D;! (1&#x3D;&#x3D;1),（1&#x3D;&#x3D;1）的结果为1，但有！ X的结果从1变为0。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220706163451150.png" alt="image-20220706163451150"></p></li><li><p><strong>字节对齐</strong>：计算机中内存大小的基本单位是字节（byte），理论上来讲，可以从任意地址访问某种基本数据类型，但是实际上，计算机并非逐字节大小读写内存，而是以 2,4,或 8 的 倍数的字节块来读写内存，如此一来就会对基本数据类型的合法地址作出一些限制，即它的地址必须是 2，4 或 8 的倍数。那么就要求各种数据类型按照一定的规则在空间上排列，这就是对齐。</p><p><strong>对齐原因</strong>：根本在于 CPU 访问数据的效率问题。</p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220708153912242.png" alt="image-20220708153912242" style="zoom:80%;" /><p><strong>对齐准则</strong>：总的来说，字节对齐有以下准则：</p><ul><li><strong>结构体变量的首地址能够被其对齐字节数大小所整除</strong>。</li><li><strong>结构体每个成员相对结构体首地址的偏移都是成员大小的整数倍</strong>，如不满足，对前一个成员填充字节以满足。</li><li><strong>结构体的总大小为结构体对最大成员大小的整数倍</strong>，如不满足，最后填充字节以满足。</li></ul></li><li><p><strong>寄存器</strong>：CPU 内部的存储单元，寄存器是 CPU 内部用来创建和储存 CPU 运算结果和其它运算结果的地方。</p></li><li><p><strong>计算机字长（机器字长）</strong>：计算机字长（机器字长）取决于数据总线的宽度，通常就是CPU一次能处理的数据的位数（CPU位数）。</p></li><li><p><strong>argc &amp; argv</strong>:</p><p>argc 是 argument count 的缩写，表示传入 main 函数中的参数个数，包括这个程序本身；</p><p>argv 是 argument vector 的缩写，表示传入 main 函数中的参数列表，其中 argv[0] 表示这个程序的名字。</p></li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220708165617659.png" alt="image-20220708165617659"></p><ol start="7"><li><ul><li>二进制的【或】运算：遇1得1<br>参加运算的两个对象，按二进制位进行“或”运算。<br>运算规则：0|0&#x3D;0； 0|1&#x3D;1； 1|0&#x3D;1； 1|1&#x3D;1；<br>参加运算的两个对象只要有一个为1，其值为1。</li><li>二进制的【与】运算：遇0得0<br>运算规则：0&amp;0&#x3D;0; 0&amp;1&#x3D;0; 1&amp;0&#x3D;0; 1&amp;1&#x3D;1;<br>即：两位同时为“1”，结果才为“1”，否则为0</li><li>二进制的【非】运算：各位取反<br>运算规则：~1&#x3D;0； ~0&#x3D;1；<br>对一个二进制数按位取反，即将0变1，1变0。</li><li>二进制的【异或】运算符 “^”：相同为0 ，不同为1”<br>参加运算的两个数据，按二进制位进行“异或”运算。<br>运算规则：0^0&#x3D;0；   0^1&#x3D;1；   1^0&#x3D;1；   1^1&#x3D;0；<br>参加运算的两个对象，如果两个相应位为“异”（值不同），则该位结果为1，否则为0。</li></ul></li><li><p><strong>有符号位 &amp; 无符号位</strong><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220712164201496.png" alt="image-20220712164201496"></p></li><li><p><strong>浮点数标准</strong></p></li></ol><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220712172111112.png" alt="image-20220712172111112"></p><p>​<img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-f7561bf6717325ea710620df172ff528_r.jpg" alt="v2-f7561bf6717325ea710620df172ff528_r"></p><p>​<img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220712175656905-16586252982787.png" alt="image-20220712175656905"></p><ol start="10"><li><p><strong>小数的二进制计算</strong></p><p>采用 “乘 2 取整，顺序排列” 法，用 2 乘十进制小数，可以得出积，将积的整数部分取出，再用 2 乘余下的小数部分，又得到一个积，再将积的整数部分取出，如此进行，直到积中的小数部分为零，或者达到所要求的<a href="https://so.csdn.net/so/search?q=%E7%B2%BE%E5%BA%A6&spm=1001.2101.3001.7020">精度</a>为止。然后把取出的整数部分按顺序排列起来。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20190601082719128.png" alt="20190601082719128"></p></li><li><p>内联函数能提高程序运行效率（inline)</p></li><li><p>正数的补码是其本身，负数是除最高位（符号位）保留外，其余取反，末位加一。</p></li><li><p><strong>宏函数</strong>：宏函数是在 <strong>程序编译时进行简单的字符替换</strong>，而函数是在程序生成后才进行调用，这时会占用开销时间（主程序函数保留现场，在子函数体中需要进行参数的传递 – 实参传递给形参以及调用完后形参的销毁等步骤 ），因此宏函数占用的编译时的时间，而函数占用的是执行时的时间。</p><p>注意宏函数在调用时只是对函数中的变量做简单的 <strong>替换</strong>，注意这里的替换真的是替换，非常死板的那种！！！所以在宏函数中经常看到（）</p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220721114507999.png" alt="image-20220721114507999" style="zoom:80%;" /><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220721114522687.png" alt="image-20220721114522687" style="zoom:80%;" /></li></ol><h3 id="1-2-汇编-amp-反汇编"><a href="#1-2-汇编-amp-反汇编" class="headerlink" title="1.2 汇编 &amp; 反汇编"></a>1.2 汇编 &amp; 反汇编</h3><div class="note note-primary">            <p>汇编语言是高级语言转换成机器码的桥梁，通过汇编语言的编译转换成机器码，计算机就可以执行程序。</p><p>因为在计算机中，所有的程序都是按照机器码执行的，所以对汇编语言的理解，能够增加对底层执行的认识。</p>          </div><p>下图为一个 c 程序变成一个可执行程序的过程：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20161106180515946.png" alt="20161106180515946"></p><p><strong>汇编</strong>：</p><ol><li>动词，指的是把 <a href="https://so.csdn.net/so/search?q=%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80&spm=1001.2101.3001.7020">汇编语言 </a>翻译成机器语言的过程。<br>就是图中 hello.s 文件经过汇编器变成二进制 hello.o 文件的过程。</li><li>名词，指的便是汇编语言<br>就是 hello.c 经过预处理器，再经过编译器生成的 hello.s 文件。这个文件里的东西就叫汇编程序（汇编语言）。</li></ol><p>汇编指令一般都是由操作符和操作数组成，操作符也被称为指令助记符，它是指令中的关键字，表示本条指令操作类型，不能省略。操作数可以省略，也可以有很多，但各操作数之间要用 “，”分开。指令助记符与操作符之间要用空格分开。</p><p><strong>反汇编：</strong></p><ol><li>动词，指的是由已生成的机器语言（二进制语言）转化为汇编语言的过程，也可以说是汇编的逆向过程。</li><li>名词，指的是有机器语言经过反汇编过程生成的汇编语言。</li><li>反汇编生成的汇编代码，每一行前面都有一串16进制的数字。这些数字就是每一行汇编代码对应的机器代码。</li><li><strong>反汇编就是我们把一系列的机器码转换成改程序的助记符</strong>。如果我们拿到一份机器码程序，而我们想要知道他的功能和工作方式，可以对机器码进行反汇编。</li></ol><h2 id="二、DSP-基础"><a href="#二、DSP-基础" class="headerlink" title="二、DSP 基础"></a>二、DSP 基础</h2><h3 id="2-1-定点数与浮点数"><a href="#2-1-定点数与浮点数" class="headerlink" title="2.1 定点数与浮点数"></a>2.1 定点数与浮点数</h3><p>首先我们要认清一个概念，定点数不一定是整数，浮点数不一定是小数。</p><p>为了轻松指定使用多少位来表示数字的整数和小数部分，我们使用称为Q格式的表示法。例如，<strong>要指定我们对整数部分使用三位，对小数部分使用四位，我们可以说数字采用 Q3.4 格式。</strong></p><p>如其名，浮点数和定点数的区别就在于浮点和定点上，点就是指小数点。浮点数就是小数点是浮动的，定点数就是小数点是固定不动的。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220712174207897.png" alt="image-20220712174207897"></p><p>数字信号处理可以分为两类：定点和浮点。 区分依据是用于存储和操纵数据数字表示的格式。 定点 DSP 设计用于表示和操控整数，包括正整数和负整数，最低为 16 位，因而可能的位模式有 65,536 种 (2^16 浮点 DSP 用于表示和操控有理数，最低为 32 位，与科学计数法相似，数值用尾数和指数表示（例如 A x 2B， A 为尾数，B 为指数)，因而可能的位模式有 4,294,967,296种 (2^32).</p><p><strong>对定点数而言，数值范围与精度是一对矛盾，一个变量要想能够表示比较大的数值范围，必须以牺牲精度为代价；而想提高精度，则数的表示范围就相应地减小。</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220712173606593.png" alt="image-20220712173606593"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220712170135724.png" alt="image-20220712170135724"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220712165740026.png" alt="image-20220712165740026"></p><h3 id="2-2-饱和运算"><a href="#2-2-饱和运算" class="headerlink" title="2.2 饱和运算"></a>2.2 饱和运算</h3><p>所谓饱和运算，就是当运算结果大于一个上限或小于一个下限时，结果就等于上限或是下限。例如：BYTE 运算，最大值是 255，0xF1+0x35 应该是等于 0x26，但由于结果大于 255，那么饱和运算的结果就是 0xFF。在图像处理里经常有（比如说增加亮度）两种灰度值运算后要判断值是否大于 255 或小于 0，根据结果再取 255 或 0。</p>]]></content>
    
    
    <summary type="html">记录在学习过程中所需的 C 语言与 DSP 相关基础知识补充。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="C language" scheme="https://erenship.com/tags/C-language/"/>
    
    <category term="DSP" scheme="https://erenship.com/tags/DSP/"/>
    
  </entry>
  
  <entry>
    <title>DSP 学习笔记 |（二） 指令集架构</title>
    <link href="https://erenship.com/posts/847f.html"/>
    <id>https://erenship.com/posts/847f.html</id>
    <published>2022-07-23T15:38:42.000Z</published>
    <updated>2023-04-30T02:59:20.374Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>本文将介绍指令集（ISA）概念，以便在后续的学习中建立其理论基础。</p>          </div><h2 id="一、什么是指令集？"><a href="#一、什么是指令集？" class="headerlink" title="一、什么是指令集？"></a>一、什么是指令集？</h2><p><img src="https://pic2.zhimg.com/80/v2-a5f2cf435cc3d0ff055aca0f7437e639_720w.jpg" alt="img"></p><p>这张图描述了整个计算机系统从上到下的抽象层。首先最顶层的是应用程序（Application），那么应用程序在计算机里是由什么构成的呢？是由它的下一层级，算法（Algorithm）构成的。算法也依赖于所实现它的编程语言（Programming Language），然而编程语言也需要操作系统（Operating System）的支持才能正确工作。那什么东西支持操作系统呢？再往下一层就是我们今天的主角：指令集架构（Instruction Set Architecture, 以下简称 ISA）。</p><p>从 ISA 开始往下，都是和硬件电路相关的内容了，所以我们可以得出一个基本的定义：<strong>指令集架构是一个能为电路硬件翻译应用程序的一层抽象层</strong>。它能够为操作系统制定很多规则和约束，也能让编程者不用操心具体的电路结构，转而在这一抽象的、高级的、定义很多规则的层面编写程序，比如：</p><ul><li>这个计算机架构里有多少个寄存器（Register）？</li><li>我能进行哪些运算操作？（有哪些指令？ADD，SUB，MUL等等）</li><li>如果遇到异常或者中断该怎么办？</li><li>数据可以有哪些类型？最多有几个字节？</li><li>等…</li></ul><p>ISA 在编译器编写者（CPU软件）和处理器设计人员（CPU硬件）之间提供了一个抽象层：</p><ul><li>处理器设计者：依据 ISA 来设计处理器；<br>处理器使用者（如：写编译器的牛*程序员）：依据 ISA 就知道 CPU 选用的指令集，就知道自己可以使用哪些指令以及遵循哪些规范。</li><li>定义处理器上的软件如何构建，这是 ISA 的最重要内涵，现代处理器都是支持高级语言编程、操作系统等等特性，ISA 要定义出指令集内的指令是如何支撑起 C 语言里堆栈、过程调用，操作系统里异常、中断，多媒体平台里数字图像处理、3D 加速等等。</li></ul><blockquote><p>x86 ISA 现在是 Intel 和 AMD 共同拥有，也就是说如果你要开新的 x86 cpu 公司你必须向这两者付版权费用，而且必须两者都同意你才能获得完整的 ISA，如果你只获得一部分不完整的 ISA，那就和完全没拿到 ISA 一样。ISA 在 cpu 里面，就像是字典，用厨房的比喻就是菜谱，菜谱定义了你这个厨房会做什么菜，这个菜做出来是什么样什么味道，那么顾客在这家连锁店的任何一间都能叫到相同的菜，吃到相同的味道。</p><p>ARM ISA 当然是 ARM 公司所有的，当时 ARM 公司是定菜单的，并且给出试菜的人，说你们每家店都要做出这个味才算 ARM。而做店的则是不同的公司，像qualcomn 啦，他们中间喜欢怎么做菜是他们的自由，但是必须会那几道菜，必须做出这个味。</p></blockquote><div class="note note-warning">            <p><strong>提示</strong></p><ol><li>常见的一个误解的答案：<strong>指令集并不存储于CPU中</strong>，应该这样说：CPU本身是指令集 (结构) 的一个实现&#x2F;实例；</li><li>一个 ISA 可能包含多个指令集；</li></ol>          </div><h2 id="二、指令集架构-vs-微架构"><a href="#二、指令集架构-vs-微架构" class="headerlink" title="二、指令集架构 vs 微架构"></a>二、指令集架构 vs 微架构</h2><p>指令集架构（ISA）和微架构（Microarchitecture）很多时候会被人们混淆。<strong>其实微架构就是对 ISA 的一种实现。</strong></p><p>综合而言，微架构是指令集架构的一种实现方式，不同的处理器有着不一样的微架构。如果你是 RTL 设计工程师或者验证工程师，你就会拿到处理器的指令集架构的手册，然后根据这个手册来设计或者验证芯片的微架构。</p><p>提高 CPU 性能的一个关键方向是如何提高指令级的细粒度并行。目前指令级细粒度并行性的一些方法有:</p><ul><li>流水线：流水线已经普遍应用于处理器中，通过改进单个流水线的实现，几乎无法再获得更多的收益。</li><li>多处理器：使用多个处理器仅对有限的应用程序能够起到提高性能的效果。</li><li>超标量体系结构：超标量架构可以提高所有类型程序的性能。超标量体系结构意味着一次能够完成多个指令的执行</li><li>每条指令完成多个独立操作：即超长指令字架构（Very Long Instruction Word – VLIW）。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220718192033581.png" alt="image-20220718192033581"></p><ul><li><p><strong>VLIW</strong></p><ul><li><p>市面上多数的 DSP 都是采取 <strong>VLIW</strong> 指令集(超长指令字)，一次发一个指令包，<strong>指令包包含多个 slot（指令槽），相当于一次发射多条指令</strong>，实现指令级的并行 ILP；DSP 在微架构上的一个优化，就是通过增加指令包的 slot 数量，比如从 4 个增加到 5 个，提高 IPC；</p></li><li><p>与多发射CPU不一样的是，所有的指令打包都是由编译器完成，因此指令吞吐量很依赖于编译器的优化；</p></li><li><p>如果遇到前后指令相关依赖的情况，就不能把这些指令放到一个指令包中，<strong>这种情况下指令包的指令不是满载的</strong>；</p></li><li><p>许多厂商为了提高 IPC，会对这种情况做相应的优化。</p></li></ul></li></ul><p><strong>VLIW 指令架构优缺点</strong></p><p>优点：</p><ul><li>不需要动态调度硬件，简化硬件电路</li><li>不需要在 VLIW 指令中进行依赖项检查，简单的指令多发射硬件</li><li>取指后分发到不同能单元，不需要进行指令对齐&#x2F;分配 简化硬件电路</li></ul><p>缺点：</p><ul><li>编译器需要找到 N 个独立的操作</li><li>如果无法找到，需要在一个 VLIW 指令中插入 NOP，降低并行性，增加代码大小</li><li>当执行宽度 (N)、指令延迟、功能单元改变时需要重新编译（超标量架构不需要重新编译）</li><li>同步执行会导致独立操作停止</li><li>在延迟时间最长的指令完成之前，任何指令都不能执行</li></ul><h2 id="三、-指令集分类"><a href="#三、-指令集分类" class="headerlink" title="三、 指令集分类"></a>三、 指令集分类</h2><p>指令集架构中最重要的就是所包含的指令（Instructions），一个架构中可能包含成百上千的指令，但它们大致可以被分为一下几类：</p><ul><li>数据流转移：Load</li><li>算术逻辑（利用到算术逻辑单元 ALU，arithmetic and logic unit 指令）：ADD、SUB、MUL</li><li>控制流转移：JR（JUMP）、JAL（Jump and Link）、BEQ（Branch if Equal）</li><li>浮点运算：ADD.D、SUB.S、MUL.D</li><li>多媒体运算：ADD.PS、SUB.PS</li><li>字符串运算：REP MOVSB（in x86）</li></ul><div class="note note-info">            <p>精简指令集RISC【educed instruction set computer】</p><p>复杂指令集CISC【complex instruction set computer】</p>          </div><h2 id="四、-寻址模式"><a href="#四、-寻址模式" class="headerlink" title="四、 寻址模式"></a>四、 寻址模式</h2><blockquote><p>寻址方式就是处理器根据指令中给出的地址信息来寻找有效地址的方式，是确定本条指令的数据地址以及下一条要执行的指令地址的方法。</p><p>寻址模式（Addressing Mode）定义了一个指令按照那种方式去寻找想要的数据，其中定义了寄存器和相应的内存位置。</p></blockquote><p>指令寻址的方式包括两部分：</p><ul><li><p><strong>指令的寻址</strong><br>这里的指令寻址指的是具体的操作码上发出的指令。是 <strong>狭义上的指令寻址</strong>。</p></li><li><p><strong>数据的寻址</strong></p><p>可以理解为地址码上操作数的地址寻址</p></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-1450a904d1852b165216c95753fbfda9_r.jpg" alt="v2-1450a904d1852b165216c95753fbfda9_r"></p><h3 id="4-1-指令寻址"><a href="#4-1-指令寻址" class="headerlink" title="4.1 指令寻址"></a>4.1 指令寻址</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-40b03665473d340e41c8cf8408a72884_720w.jpg" alt="v2-40b03665473d340e41c8cf8408a72884_720w"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-4c620fdfcd35f8517e3786715d6e8f38_720w.jpg" alt="v2-4c620fdfcd35f8517e3786715d6e8f38_720w"></p><p>上述即为指令寻址的两种方式：</p><ul><li>顺序寻址</li><li>跳转寻址</li></ul><h3 id="4-2-数据寻址"><a href="#4-2-数据寻址" class="headerlink" title="4.2 数据寻址"></a>4.2 数据寻址</h3><p>通过 <strong>顺序寻址或者跳转寻址</strong> 取到操作码知道要做什么操作后，我们要拿着地址码去找处理对象了。这里地址码寻址操作对象的寻址方式也是很丰富的简单看个图感受一下：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220719105514473.png" alt="image-20220719105514473"></p><p>地址码其实分为两部分 —— 寻址特征 + 形式地址：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-e9d2e66898dff67075b272076151c6ac_720w.jpg" alt="v2-e9d2e66898dff67075b272076151c6ac_720w"></p><ul><li>寻址特征存的就是每个寻址方式上的蓝色小标，表示一种方式。</li><li>形式地址不是直接对应到存储器中的地址，而是需要根据 <strong>寻址特征的要求</strong> 转换为对应到存储器的地址 。<br>所以我们把通过 <strong>寻址特征和形式地址求出来的真正对应到存储器的地址称之为有效地址。</strong></li></ul><p><strong>1. 立即寻址</strong></p><p>方式：把我们实际要操作的数，直接存放在形式地址中。<strong>立即寻址是获取操作数最快的方式</strong></p><p>eg：假如我们要直接操作的数为 3，那么我们可以用一条一地址指令这么设置：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-9e705f0134f0f4d5c73388641941c8e9_720w.jpg" alt="v2-9e705f0134f0f4d5c73388641941c8e9_720w"></p><p>直接把 3 的补码写在形式地址中</p><ul><li>寻址特征为#，代表立即寻址的意思。</li><li>形式地址 <strong>写的是操作数 3 的补码（011）。</strong></li></ul><p>立即寻址主要执行取指令访存1次，不需要执行指令访存，一共访存1次。</p><p><strong>立即数</strong>：立即寻址方式的目的就是将操作数紧跟在操作码后面，与操作码一起放在指令代码段中，在程序运行时，程序直接调用该操作数，而不需要到其他地址单元中去取相应的操作数，上述的写在指令中的操作数也称作立即数。</p><p><strong>2. 直接寻址</strong></p><p>直接寻址指令中的地址码字段给的是 <strong>操作数的有效位置</strong>，我们可以根据这个有效位置直接去内存中寻找操作数。指令中在操作码字段后面的部分是操作数的地址</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-aa9aa62ad61a4a3fb5a1679f220f4e10_720w.jpg" alt="v2-aa9aa62ad61a4a3fb5a1679f220f4e10_720w"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/v2-5888816bbc50ab0983a356da892d010f_720w.jpg" alt="v2-5888816bbc50ab0983a356da892d010f_720w"></p><p>与立即寻址相比：直接寻址主要执行取指令访存1次，还有执行指令访存1次，一共访存2次。</p><p><strong>直接寻址和立即寻址的区别</strong></p><p>立即寻址：是把一个“常数”送到指定位置。<br>直接寻址：是把一个“变量”送到指定位置。</p><p><strong>3. 间接寻址</strong></p><p>指令中给出的地址是操作数地址的地址。</p><p><strong>4. 寄存器寻址</strong></p><p>指定的寄存器中存放着操作数本身。</p><p><strong>5. 寄存器间接寻址</strong></p><p>指定的寄存器中存放的不是操作数，而是操作数的地址。</p><h2 id="五、-指令编码"><a href="#五、-指令编码" class="headerlink" title="五、 指令编码"></a>五、 指令编码</h2><p>对于指令编码（Instruction Encoding），或者说是指令的组成，每个架构的不尽相同。从长度上，可以分为三类：</p><ol><li><p><strong>固定长度指令（Fixed-Length Instruction）</strong></p><p>每个指令的长度都一样，好处是解码非常的方便简易。一些 精简指令集（RISC） 的架构，比如 MIPS、ARM、RISC-V、PowerPC就在使用这种模式。</p></li><li><p><strong>可变化长度指令（Variable-Length Instruction）</strong> </p><p>每个指令都有自己特定的长度，这样设计的好处是可以压缩缓存器和内存的空间，因为很早之前存储器的容量都很小，很珍贵，所以 可变化长度指令 是最先发展起来的。复杂指令集就是这一阵营的代表：x86（最短 1B，最长可达 17B）、IBM 360、Motorola 68k 等。</p></li><li><p><strong>压缩型指令（Compressed Instructions）</strong></p><p>一般这种指令的长度都非常短（16-Bit），目的都是减少编译后的代码量。代表有 MIPS16、ARM THUMB 等。</p></li></ol><p>还有一种特殊的架构：<strong>超长指令集（Very Long Instruction Word，VLIW）</strong>是由英特尔和惠普共同在21世纪初提出的一种用于改善工作站性能的新型架构，里面的每条 <strong>指令束（Instruction Bundle）</strong>是由四条或者更多的普通指令集合在一起而形成的。由于技术和时代原因，最后悄然退场。代表作：IA-64 &#x2F; Intel Itanium (英特尔安腾处理器)。</p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><p>[1] <a href="https://zhuanlan.zhihu.com/p/370204019">关于寻址方式一篇就够了</a></p><p>[2] <a href="https://panda-tang.blog.csdn.net/article/details/104361017?spm=1001.2014.3001.5502">如何快速判断立即数</a> </p><p>[3] <a href="https://zhuanlan.zhihu.com/p/449069647">Computer Architecture —— ISA 指令集架构介绍 （一）：为什么需要 ISA</a></p><p>[4] <a href="https://zhuanlan.zhihu.com/p/346757887">Computer Architecture —— ISA 指令集架构介绍 （二）：四大特性（完结）</a></p><p>[5] <a href="https://www.arm.com/glossary/isa">What Is an Instruction Set Architecture?</a></p><p>[6] <a href="https://zhuanlan.zhihu.com/p/20731557">科普向 ISA,cpu架构原理</a></p><p>[7] <a href="https://blog.csdn.net/whatday/article/details/87268727?spm=1001.2101.3001.6650.9&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-9-87268727-blog-103138156.pc_relevant_multi_platform_whitelistv1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-9-87268727-blog-103138156.pc_relevant_multi_platform_whitelistv1&utm_relevant_index=10">XTENSA处理器介绍</a></p><p>[8] <a href="https://suda-morris.github.io/blog/cs/xtensa.html#xtensa-%E5%A4%84%E7%90%86%E5%99%A8%E7%9A%84%E7%A1%AC%E4%BB%B6%E6%8A%BD%E8%B1%A1%E5%B1%82-hal">𝙓𝙩𝙚𝙣𝙨𝙖 基础</a></p><p>[9] <a href="https://www.jianshu.com/p/66e205efbba9">HIFI3 DSP芯片技术摘要</a></p><p>[10] <a href="https://blog.csdn.net/qq582880551/article/details/122467496">Cadence Tensilica Xtensa HiFi 音频解码器相关介绍</a></p>]]></content>
    
    
    <summary type="html">本文将介绍指令集（ISA）概念，以便在后续的学习中建立其理论基础。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="DSP" scheme="https://erenship.com/tags/DSP/"/>
    
    <category term="ISA" scheme="https://erenship.com/tags/ISA/"/>
    
  </entry>
  
  <entry>
    <title>DSP 学习笔记 |（一） 初识 DSP</title>
    <link href="https://erenship.com/posts/65e8.html"/>
    <id>https://erenship.com/posts/65e8.html</id>
    <published>2022-07-16T09:26:24.000Z</published>
    <updated>2023-04-30T02:57:39.059Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>由于工作需要，在此开设 DSP 学习笔记系列。如有错误，欢迎交流指正！</p>          </div><h2 id="一、DSP-概念"><a href="#一、DSP-概念" class="headerlink" title="一、DSP 概念"></a>一、DSP 概念</h2><p>数字信号处理器（DSP，Digital Signal Processor）接收经数字化处理的语音、音频、视频、温度、压力或位置等现实世界信号，然后以数学方式进行操作处理。 可以非常迅速地执行”加”、”减”、”乘”、”除”之类数学运算功能。</p><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/DSP_block_diagram.svg.png" alt="DSP_block_diagram.svg" style="zoom: 30%;" /></center><br/><p>通过下图可以清楚了解 MP3 播放器中 DSP 的工作原理。 在录制阶段，模拟音频通过接收器或其他来源输入。 模拟信号接着通过一个模数转换器转换为数字信号，再传至 DSP。 DSP 进行 MP3 编码，然后将文件保存至内存。 在回放阶段，文件从内存中取出，由DSP解码，再经数模转换器转回模拟信号。这样模拟信号就可以通过音响系统输出。 在更复杂的例子中，DSP 将执行其他功能，如音量控制、均衡和用户界面。</p><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/mp3demo_light_blue.gif" style="zoom: 100%" /></center><br/><p><strong>DSP 与其它处理器的差别</strong></p><p>数字信号处理器（DSP）、通用微处理器（MPU）、微控制器（MCU）三者的区别在于：DSP 面向高性能、 重复性、数值运算密集型的实时处理；MPU 大量应用于计算机；MCU 则适用于以控制为主的处理过程。</p><h2 id="二、DSP-结构特点"><a href="#二、DSP-结构特点" class="headerlink" title="二、DSP 结构特点"></a>二、DSP 结构特点</h2><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220716173129183.png" alt="image-20220716173129183" style="zoom:50%;" /></center><br/><ol><li><strong>哈佛结构</strong>：一种将 <u>程序指令存储</u> 和 <u>数据指令存储</u> 分开的存储器结构。可以减轻程序运行时的总线瓶颈。(程序和数据不在同一个地方)</li></ol><br/><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220716173403540.png" alt="image-20220716173403540" style="zoom:40%;" /></center><br/><ol start="2"><li><p><strong>专业的硬件乘法器</strong></p><p>经典的 FFT、IIR 和 FIR 等数字信号处理算法中，乘法的 DSP 运算的重要组成部分；</p><ul><li><p><strong>时钟周期</strong>：晶振频率的倒数；</p></li><li><p><strong>机器周期</strong>：把一条指令分割成若干个阶段，每个阶段就称为机器周期；</p></li><li><p><strong>指令周期</strong>：取指令、译码、操作，完成一条指令所需要的时间。</p></li></ul></li><li><p><strong>流水线操作</strong></p><p>执行指令的几个阶段在程序执行过程中是重叠的，即几条不同的指令同时处于激活状态，每天指令处于不同的阶段。</p><p>取指和取操作数都需要对 CPU 和内存来进行对数据的和指令的交换。由于 DSP 是哈佛结构，CPU 和存储器不在同一位置，所有可以同时进行。在冯诺依曼结构中，数据和指令都在同一存储器中，不能重叠进行。</p><br/><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220716173832518.png" alt="image-20220716173832518" style="zoom:50%;" /></center><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220716173857726.png" alt="image-20220716173857726" style="zoom:50%;" /></center><br/></li><li><p><strong>特殊的 DSP 指令</strong></p><p>DSP 采用特殊的指令。</p></li><li><p><strong>快速的指令周期</strong></p><p>快速的指令周期、哈佛结构、流水线操作、专用的硬件乘法器、特殊的 DSP 指令，再加上集成电路的优化设计可使 DSP 芯片的指令周期在 200ns 以下。</p></li></ol><h2 id="三、DSP-芯片分类"><a href="#三、DSP-芯片分类" class="headerlink" title="三、DSP 芯片分类"></a>三、DSP 芯片分类</h2><ol><li>根据基础特性分类：静态 DSP 芯片、一致性 DSP 芯片</li><li>根据数据格式分类：定点 DSP 芯片、浮点 DSP 芯片</li><li>根据用途分类：通用型 DSP  芯片、专业型 DSP 芯片</li></ol><h2 id="四、DSP-内部结构"><a href="#四、DSP-内部结构" class="headerlink" title="四、DSP 内部结构"></a>四、DSP 内部结构</h2><p>DSP 包含以下这些重要元件：</p><ul><li><strong>程序存储器：</strong>储存 DSP 将用来处理数据的程序</li><li><strong>数据存储器：</strong>储存将要处理的信息</li><li><strong>计算引擎：</strong>进行数学处理、访问程序存储器中的程序及数据存储器中的数据。</li><li><strong>输入&#x2F;输出：</strong>提供一系列功能，与外部连接</li></ul><h3 id="4-1-内存总线"><a href="#4-1-内存总线" class="headerlink" title="4.1 内存总线"></a>4.1 内存总线</h3><p><strong>内存总线（Memory Bus）</strong>：包含数据总线和地址总线，总线是为了数据交换的。</p><p>以 TI DSP  ‘28x 为例，CPU 内部总线：</p><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220716175339210.png" alt="image-20220716175339210" style="zoom:50%;" /></center><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220716175437558.png" alt="image-20220716175437558" style="zoom:80%;" /></center><center><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220714204045145.png" alt="image-20220714204045145" style="zoom:40%;" /></center><h3 id="4-2-CMD-文件"><a href="#4-2-CMD-文件" class="headerlink" title="4.2 CMD 文件"></a>4.2 CMD 文件</h3><ul><li>命令文件即 CMD （Command）是 DSP 运行程序必不可少的文件，用于 <u>指定 DSP 存储器分配</u>；</li><li>CMD 文件主要由两个伪指令构成，即 MEMORY 和 SECTIONS；</li><li>MEMORY 指令定义目标存储器的配置，SECTIONS 指令规定程序中各个段及其在存储器中的位置。</li></ul><h2 id="五、DSP-相关名词"><a href="#五、DSP-相关名词" class="headerlink" title="五、DSP 相关名词"></a>五、DSP 相关名词</h2><ul><li><p><strong>模拟信号处理 vs 数字信号处理</strong></p><p>前者可以处理包括微波毫米波乃至光波信号（分辨率很高）。后者按照奈氏准则的要求，受 S&#x2F;H 、A&#x2F;D 和处理速度的限制，对高频信号处理没有优势。</p></li><li><p>在 DSP 开发中就是通过对 DSP 的寄存器进行配置或者赋值，来控制 DSP 使其按照我们预定的功能运行。</p></li><li><p><strong>align &#x3D; 16</strong>，地址对齐，起始地址必须是 16 的倍数。</p></li><li><p><strong>位:</strong> 数字字可细分的最小单位。 位数反映字宽。 字的位数越多，该字代表的数越大。</p></li><li><p><strong>DMA（直接存储器访问）：</strong>DSP的I&#x2F;O处理器通过外部、主机、串行、SPI 和 UART 端口支持在 DSP 存储器和外部存储器、主机或外设之间的数据 DMA。 每次 DMA 操作可以传输整块数据。</p></li><li><p><strong>定点：</strong>DSP 操控和表示最适合数字的一种方法，其中该数字不大于单个内部寄存器中的最大数字。 寄存器的大小由其包含的位数确定。 例如，32 位数可能大于 16 位数。</p></li><li><p><strong>浮点：</strong>数字由尾数和指数表示的系统。 例如，a×2b，其中”a”为尾数，b为指数。 利用该方法，DSP 可操纵非常小的数字或非常大的数字。 浮点处理器表示IEEE确定的标准格式数字。 它是由 32 位表示的科学计数法。</p></li><li><p><strong>Von Neumann architecture 架构</strong>： 这是大多数（非 DSP）微处理器所用的架构。 该架构采用单一地址和数据总线进行存储器访问</p></li><li><p><strong>Harvard 架构：</strong>DSP 使用具有独立总线的内存架构以便编程和存储数据。 两个总线使 DSP 同时获得数据字和指令。</p></li><li><p><strong>I&#x2F;O 处理器：</strong> DSP 具有分布式 DMA 架构，其中每个支持 DMA 的外设均配有 DMA 控制器。 此外，大多数端口可直接（非 DMA）访问内部存储器和 I&#x2F;O 存储器。 I&#x2F;O 处理器这一术语在全球范围内指 DMA 控制器、DMA 通道仲裁和外设至总线连接。</p></li><li><p><strong>MIPS:</strong> 百万条指令&#x2F;秒，其中每个指令可执行多个操作。</p></li><li><p><strong>MACS:</strong>  乘加&#x2F;秒</p></li><li><p><strong>MOPS:</strong>  百万次操作&#x2F;秒</p></li><li><p><strong>MFLOPS:</strong>  百万次浮点操作&#x2F;秒</p></li><li><p><strong>字:</strong> 表示数据值的位串。 DSP 中的字长通常为16位、24位、32位和48位。</p></li></ul><h2 id="参考引用"><a href="#参考引用" class="headerlink" title="参考引用"></a>参考引用</h2><p>[1] <a href="https://www.bilibili.com/video/BV1j7411j7eJ?p=25&spm_id_from=pageDriver&vd_source=d9ea89354387124c55d399a79c8a00ba">DSP数字信号处理</a></p><p>[2] <a href="https://www.analog.com/en/education/education-library/lets-talk-dsp.html">Let’s Talk DSP</a></p><p>[3] <a href="https://www.analog.com/cn/design-center/landing-pages/001/beginners-guide-to-dsp.html">数字信号处理入门指南</a></p><p>[4] <a href="https://en.wikipedia.org/wiki/Digital_signal_processor">Digital signal processor</a></p>]]></content>
    
    
    <summary type="html">什么是 DSP？为什么需要 DSP？ DSP 和其他 MCU 的区别？本文将给出答案。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="DSP" scheme="https://erenship.com/tags/DSP/"/>
    
  </entry>
  
  <entry>
    <title>Origin 备忘录</title>
    <link href="https://erenship.com/posts/e1b4.html"/>
    <id>https://erenship.com/posts/e1b4.html</id>
    <published>2022-04-12T02:27:08.000Z</published>
    <updated>2023-04-30T02:58:28.877Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>在此记录笔者在使用 Origin 进行数据绘图过程中遇到的问题及笔记。</p>          </div><blockquote><p><strong>Origin</strong> 是由 <a href="https://zh.wikipedia.org/w/index.php?title=OriginLab&action=edit&redlink=1">OriginLab</a> 公司开发的一个科学绘图、数据分析软件，支持在 Microsoft Windows 下运行。Origin 支持各种各样的2D&#x2F;3D 图形。Origin 中的数据分析功能包括统计，信号处理，曲线拟合以及峰值分析。Origin 中的 <a href="https://zh.wikipedia.org/wiki/%E6%9B%B2%E7%B7%9A%E6%93%AC%E5%90%88">曲线拟合</a>是采用基于 <a href="https://zh.wikipedia.org/w/index.php?title=Levernberg-Marquardt%E7%AE%97%E6%B3%95&action=edit&redlink=1">Levernberg-Marquardt算法</a>（LMA）的非线性 <a href="https://zh.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95">最小二乘法 </a>拟合。Origin 强大的数据导入功能，支持多种格式的数据，包括 <a href="https://zh.wikipedia.org/wiki/ASCII">ASCII</a>、<a href="https://zh.wikipedia.org/wiki/Excel">Excel</a>、NI TDM、DIADem、<a href="https://zh.wikipedia.org/wiki/NetCDF">NetCDF</a>、SPC 等等。图形输出格式多样，例如 JPEG，GIF，EPS，TIFF 等。内置的查询工具可通过ADO 访问数据库数据。 ——Wikipedia</p></blockquote><h2 id="常见设置"><a href="#常见设置" class="headerlink" title="常见设置"></a>常见设置</h2><ol><li><strong>坐标轴遮挡数据点标志</strong></li></ol><p>​<img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202204121039961.png" alt="img"></p><ol start="2"><li><p><strong>增加上面和右边边框</strong></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202204121039582.png" alt="img"></p></li><li><p><strong>修改页面大小</strong></p></li></ol><blockquote><p>a. 在 plot details-graph-print&#x2F;dimensions 中修改页面尺寸，这是你最终得到的图像大小的物理尺寸，按期刊投稿要求；</p><p>b. 在 plot details-graph-Layer-size&#x2F;speed 中修改每层图层的物理尺寸，确定图像的长宽比，取消 unit % of page，将 unit设为确定的物理单位（cm，mm等）</p><p>c. 关键的一点，所有图层都要按步骤 2 修改</p><p>d. 修改坐标轴、曲线的粗线等。</p></blockquote><ol start="4"><li><strong>设置坐标轴单位长度相等</strong></li></ol><p>​<img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202204121039177.png" alt="img"></p><h2 id="三维图绘制"><a href="#三维图绘制" class="headerlink" title="三维图绘制"></a>三维图绘制</h2><p><strong><a href="https://blog.csdn.net/qqin0110/article/details/87900490">使用Origin画三维图和等高图、以及函数图</a></strong></p>]]></content>
    
    
    <summary type="html">在此记录笔者在使用 Origin 进行数据绘图过程中遇到的问题及笔记。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="Tools" scheme="https://erenship.com/tags/Tools/"/>
    
    <category term="Origin" scheme="https://erenship.com/tags/Origin/"/>
    
  </entry>
  
  <entry>
    <title>MATLAB 备忘录</title>
    <link href="https://erenship.com/posts/73eb.html"/>
    <id>https://erenship.com/posts/73eb.html</id>
    <published>2022-04-10T11:41:11.000Z</published>
    <updated>2023-04-30T02:59:51.068Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>在此记录笔者在使用 MATLAB 过程中遇到的问题及笔记。</p>          </div><blockquote><p>MATLAB（Matrix Laboratory，矩阵实验室）是由美国 The MathWorks 公司出品的商业数学软件。MATLAB 是一种用于算法开发、数据可视化、数据分析以及数值计算的高级技术计算语言和交互式环境。除矩阵运算、绘制函数&#x2F;数据图像等常用功能外，MATLAB 还可用来创建用户界面，以及调用其它语言（包括 C、C++、Java、Python、FORTRAN）编写的程序。 ——Wikipedia</p></blockquote><h2 id="常用知识"><a href="#常用知识" class="headerlink" title="常用知识"></a>常用知识</h2><ol><li><p><strong>分号的作用</strong></p><p>两个作用：1. 数组行分隔符；2. 取消运行显示</p></li></ol><h2 id="常用操作"><a href="#常用操作" class="headerlink" title="常用操作"></a>常用操作</h2><ol><li><p><strong>批量添加&#x2F;取消注释</strong></p><figure class="highlight erlang-repl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs erlang-repl">ctrl + r  <span class="hljs-comment">% 添加注释</span><br>ctrl + t  <span class="hljs-comment">% 取消注释</span><br></code></pre></td></tr></table></figure></li><li><p><strong>中断正在执行的操作</strong></p><figure class="highlight llvm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs llvm">ctrl + <span class="hljs-keyword">c</span>  <br>% 很多程序操作都是使用 ctrl+<span class="hljs-keyword">c</span> 进行操作中断<br></code></pre></td></tr></table></figure></li><li><p><strong>清屏</strong><br>清除命令窗口中的所有输入和输出信息，不影响命令的历史记录。</p><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs abnf">clc<span class="hljs-comment">;</span><br></code></pre></td></tr></table></figure></li><li><p><strong>清除变量名</strong></p><p>清除 workspace 中的无用的变量，尤其是一些特别大的矩阵，不用时及时清理，可以减少内存占用。</p><figure class="highlight mel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs mel"><span class="hljs-keyword">clear</span>;  % 清除 <span class="hljs-keyword">workspace</span> 中的无用的变量<br><span class="hljs-keyword">clear</span> all;  % 清除 <span class="hljs-keyword">workspace</span> 中的所有变量<br></code></pre></td></tr></table></figure></li><li><p><strong>关闭绘图窗口</strong></p><figure class="highlight mercury"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs mercury">close <span class="hljs-built_in">all</span>;  <span class="hljs-comment">% 关闭所有绘图窗口 </span><br><span class="hljs-comment">%% 一般主函数都是三件套</span><br>clc;<br>clear <span class="hljs-built_in">all</span>;<br>close <span class="hljs-built_in">all</span>;<br></code></pre></td></tr></table></figure></li><li><p><strong>取实部虚部</strong></p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs ini"><span class="hljs-attr">a</span> = <span class="hljs-number">1</span> + <span class="hljs-number">2</span>i<span class="hljs-comment">;</span><br><span class="hljs-attr">shibu</span> = real(a)<span class="hljs-comment">;</span><br><span class="hljs-attr">xubu</span> = imag(a)<span class="hljs-comment">;</span><br></code></pre></td></tr></table></figure></li><li><p><strong>查看.mat文件中的数据</strong></p><figure class="highlight autohotkey"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs autohotkey"><span class="hljs-built_in">whos  %</span> 命令行输入<br></code></pre></td></tr></table></figure></li></ol><h2 id="绘图"><a href="#绘图" class="headerlink" title="绘图"></a>绘图</h2><ol><li><p><strong>二维线条</strong></p><figure class="highlight matlab"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs matlab"><span class="hljs-built_in">plot</span>(t, r1, <span class="hljs-string">&#x27;linewidth&#x27;</span>,<span class="hljs-number">1.2</span>)<br><span class="hljs-comment">% Linewidth 是修改线宽，Markersize 是修改离散点标记的大小（比如x或＋）</span><br></code></pre></td></tr></table></figure></li><li><p><strong>显示网格</strong></p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs nginx"><span class="hljs-attribute">grid</span> <span class="hljs-literal">on</span>;<br></code></pre></td></tr></table></figure></li><li><p><strong>图片标题</strong></p><figure class="highlight hsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs hsp"><span class="hljs-keyword">title</span>(<span class="hljs-string">&#x27;图片标题&#x27;</span>)<span class="hljs-comment">;</span><br></code></pre></td></tr></table></figure></li><li><p><strong>坐标轴设置</strong></p></li></ol>   <figure class="highlight matlab"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs matlab">xlabel(<span class="hljs-string">&#x27;x 轴的标题&#x27;</span>)，ylabel(<span class="hljs-string">&#x27;y 轴的标题&#x27;</span>);  <span class="hljs-comment">%坐标轴标题</span><br>axis([<span class="hljs-number">0</span> <span class="hljs-number">100</span> <span class="hljs-number">0</span> <span class="hljs-number">90</span>]);  <span class="hljs-comment">% 设置坐标轴范围</span><br><br>set(gca, <span class="hljs-string">&#x27;YTick&#x27;</span>, (<span class="hljs-number">0</span>: <span class="hljs-number">5</span>: <span class="hljs-number">100</span>))  <span class="hljs-comment">% 设置 Y 坐标的刻度</span><br>set(gca, <span class="hljs-string">&#x27;FontSize&#x27;</span>, <span class="hljs-number">8</span>)  <span class="hljs-comment">% 设置坐标轴字体为 8</span><br><br><span class="hljs-built_in">legend</span>(<span class="hljs-string">&#x27;KF&#x27;</span>,<span class="hljs-string">&#x27;EKF&#x27;</span>,<span class="hljs-string">&#x27;UKF&#x27;</span>)：在坐标区上添加图例 KF,EKF,UKF<br></code></pre></td></tr></table></figure><h3 id="线型、符号及颜色汇总"><a href="#线型、符号及颜色汇总" class="headerlink" title="线型、符号及颜色汇总"></a>线型、符号及颜色汇总</h3><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/image-20220416171408067.png" alt="image-20220416171408067"></p><h2 id="其他问题"><a href="#其他问题" class="headerlink" title="其他问题"></a>其他问题</h2><ol><li><strong>串口通讯中出现 “COMXX is not available.” 错误</strong></li></ol>   <figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs pgsql">打开串口时出现错误：MATLAB:<span class="hljs-type">serial</span>:fopen:opfailed<br>打开失败: Port: COM1 <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> available. <span class="hljs-keyword">No</span> ports are available.<br>Use INSTRFIND <span class="hljs-keyword">to</span> determine <span class="hljs-keyword">if</span> other instrument objects are connected <span class="hljs-keyword">to</span> the requested devic<br></code></pre></td></tr></table></figure><p>   <strong>解决方法</strong>：错误提示中已经说明了使用  <code>instrfind  </code> 去检查串口对象是否在运行（被占用）。</p><p>   在命令行输入 <code>instrfind </code> 可以看到：</p><p>   Instrument Object Array</p><p>   Index:    Type:     Status:   Name: 1   serial    closed    Serial-COM3</p><p>   index 为 1 那行中 COM3 已经被打开了。在代码中打开串口前加一行代码：<code>fclose(instrfind)</code>;   </p><p>   用意是把已经打开的串口关闭，此时再运行代码，就可以成功打开串口了。</p><ol start="2"><li><p><strong>1e2&#x3D;100</strong></p><p>表示一个数。这是科学计数法表示，e 前面指的是基数，e 后面指的是 10 的幂数，如 2.2e3&#x3D;2.2×1000&#x3D;2200。</p></li><li><p><strong>workspace 不显示变量信息</strong></p><p>使用 <code>function</code> 后就会这样。自动清掉在 <code>function</code> 内部建立的变量。 解决方法：去掉头部的 <code>function main</code> 和最后一个 <code>end</code>。</p></li><li><p><strong>“警告: 矩阵为奇异工作精度”</strong></p><p><strong>解决方法</strong>：把 <code>inv</code> 改成 <code>pinv</code> 即可。因为 <code>inv</code> 是对矩阵求逆，而对于不是可逆矩阵的矩阵求逆就会出错，<code>pinv</code> 就是对不是可逆矩阵的矩阵求伪逆。</p></li><li><p><strong>matlab 中 @(x)的含义</strong></p><p>表示 f 为函数句柄，@是定义句柄的运算符。f&#x3D;@(x)acos(x) 相当于建立了一个函数文件：</p><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs abnf">% f.m<br>function<br><span class="hljs-attribute">y</span><span class="hljs-operator">=</span>f(x)<br><span class="hljs-attribute">y</span><span class="hljs-operator">=</span>acos(x)<span class="hljs-comment">;</span><br></code></pre></td></tr></table></figure></li><li><p><strong><strong>NaN: not a number</strong></strong></p></li></ol>]]></content>
    
    
    <summary type="html">在此记录笔者在使用 MATLAB 过程中遇到的问题及笔记。</summary>
    
    
    
    <category term="Study Pie" scheme="https://erenship.com/categories/Study-Pie/"/>
    
    
    <category term="MATLAB" scheme="https://erenship.com/tags/MATLAB/"/>
    
    <category term="Tools" scheme="https://erenship.com/tags/Tools/"/>
    
  </entry>
  
  <entry>
    <title>「游记」坡坡坎坎去重庆</title>
    <link href="https://erenship.com/posts/3187.html"/>
    <id>https://erenship.com/posts/3187.html</id>
    <published>2021-01-19T13:42:56.000Z</published>
    <updated>2023-04-30T03:02:16.500Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-primary">            <p>每日 3w 的步数体验，混到私人小区 33 楼去拍立交桥，迷路在错综复杂的古楼，四字弟弟拍戏地重游…都在这冬日的山城雾都重庆之旅里了。</p>          </div><p>虽然身为四川人，上一次去重庆是陪姐姐艺考，但并没有好好的去玩过重庆。这次趁着放假早，就又约着土豆到重庆扫街去。</p><p>和土豆出行就是放心，一溜烟就把车票、酒店、行程给规划好了。（不禁感叹：土豆随行，天下任我行！）</p><p>不得不说成渝双经济圈的国家战略起来后，成都到重庆乘坐复兴号只需要一个小时，完全属于还没睡舒坦就到站的乘车体验。</p><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://i.loli.net/2021/01/20/QRiEgASZs1cwCX9.jpg"  /></div><div class="group-image-wrap"><img src="https://i.loli.net/2021/01/20/S3mNjW5dkzl7Kxy.jpg" alt="微信图片编辑_20210120132141"  /></div></div><div class="group-image-row"></div></div><p>如下是我们计划要去的拍照机位，主要是土豆在小红书上找到的一些我们比较喜欢的拍照点。</p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210120202019.jpeg" alt="微信图片编辑_20210120191438" style="zoom: 50%;" /><div class="note note-info">            <p>由于本身就是奔着拍照去的，那么话不多说直接上图。下文图片均出自土豆及笔者之手。</p><p>笔者设备：富士 X-T200（15-45mm）</p><p>土豆设备：富士 X100F（23mm f&#x2F;2.0）、佳能 80D（50mm f&#x2F;1.8）</p>          </div><h2 id="山上城-·-「雾都」"><a href="#山上城-·-「雾都」" class="headerlink" title="山上城 · 「雾都」"></a>山上城 · 「雾都」</h2><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210120211652.jpg" alt="微信图片_20210120210817 (1)"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/2021012ss0133412.jpg" alt="DSCF0966"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/2021012015330ll6.jpg" alt="微信图片_20210120144808"></p><h2 id="霓虹城-·-「雾都」"><a href="#霓虹城-·-「雾都」" class="headerlink" title="霓虹城 · 「雾都」"></a>霓虹城 · 「雾都」</h2><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210120133352.jpg" alt="微信图片_20210120132018"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202101201ll35735.jpg" alt="微信图片_20210120132018"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210135518.jpg" alt="微信图片_20210120133616"></p><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202101201357.jpg" alt="微信图片_20210120132220"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202100535.jpg" alt="微信图片_20210120150839"></div></div><div class="group-image-row"></div></div><h2 id="轻轨城-·-「雾都」"><a href="#轻轨城-·-「雾都」" class="headerlink" title="轻轨城 · 「雾都」"></a>轻轨城 · 「雾都」</h2><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202101275709.jpg" alt="微信图片_20210120154713"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210120ll152834.jpg" alt="微信图片_20210120145105"></div></div><div class="group-image-row"></div></div><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210120153940.jpg" alt="微信图片_20210120145513"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210120152l243.jpg" alt="微信图片_20210120145108"></div></div><div class="group-image-row"></div></div><h2 id="旧楼城-·-「雾都」"><a href="#旧楼城-·-「雾都」" class="headerlink" title="旧楼城 · 「雾都」"></a>旧楼城 · 「雾都」</h2><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/20210120155035.jpg" alt="微信图片_20210120153155"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202103953.jpg" alt="微信图片_20210119214414"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/2021012017kk5257.jpg" alt="微信图片_20210120153155"></div></div><div class="group-image-row"></div></div><p><img src="https://cdn.jsdelivr.net/gh/erenlu/picgo/img/202101235.jpg" alt="微信图片_20210120153207"></p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>本次重庆行并不是典型的打卡式旅游 <del>（机位打卡不算打卡？双标怪）</del>，反倒是去了许多小众偏门的景点。这样体验最大的好处就是能探索到未知，也许下一个路口处就是你想要的惊喜，又也许是竹篮打水一场空。总之，面对不确定性也是很让人着迷的体验。</p><p>在旅途中我常挂在嘴边的便是：满重庆都是坡坡坎坎的噢。“你以为你在地下，其实你在地上” 。在坐车的时候我打趣道：重庆出租车师傅脑壳里的地图都跟我们的不一样，他们的是 3D 的立体地图。</p><p>重庆的确是座旅游城市，许多地方的设计都对游客非常友好，在一些后记被人挖掘出来的打卡机位还会专门设置打卡位。</p><p>雾都城，雾都人，雾都魂… 还有雾都的火锅儿都很让人感到亲切。</p><p>ps：本次雾都之行最大的遗憾就是没有拍到我们最期待的赛博朋克风街道。</p>]]></content>
    
    
    <summary type="html">每日 3w 的步数体验，混到私人小区 33 楼去拍立交桥，迷路在错综复杂的古楼，四字弟弟拍戏地重游...都在这冬日的山城雾都重庆之旅里了。</summary>
    
    
    
    <category term="Life Pie" scheme="https://erenship.com/categories/Life-Pie/"/>
    
    
    <category term="Photography" scheme="https://erenship.com/tags/Photography/"/>
    
    <category term="Travel" scheme="https://erenship.com/tags/Travel/"/>
    
  </entry>
  
  <entry>
    <title>Eren 的 2020 年终总结</title>
    <link href="https://erenship.com/posts/2407.html"/>
    <id>https://erenship.com/posts/2407.html</id>
    <published>2021-01-04T15:20:47.000Z</published>
    <updated>2023-04-30T02:59:00.881Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>2020 年外部世界的关键字大概就是【变】，从新冠疫情、股市熔断、美国大选… 外部世界的风云变幻给以独立而弱小的个体不安全感，作为个体我今年的关键词大概就是【观察】，对自我的不断观察与自我接纳。</p>          </div><h2 id="自我"><a href="#自我" class="headerlink" title="自我"></a>自我</h2><p>在 2020 年，我做的最重要的一件事就是对自己进行持续不断的观察，从自我跳脱出来进行自我意识的察觉。在情绪的表达上能够更加的通透，只少现在我能在开心的环境下表达出内心的喜悦，在让我感到不悦的场景下正常地表达出我 的愤怒。而不是像过去，觉得什么事情都是可以忍受的，即使是那些令我不快的，通俗意义上来讲就是老好人的形象，性格的菱角也不在掩饰。</p><p>这一年我逐渐在学会如何对情感的正确感受与表达。</p><div>            <input type="checkbox" disabled checked="checked">每月进行自我复盘          </div><div>            <input type="checkbox" disabled checked="checked">持续进行自我察觉          </div><div>            <input type="checkbox" disabled checked="checked">多和比自己优秀的人接触          </div><div>            <input type="checkbox" disabled >践行极简主义（上半年疫情在家各种断舍离，下半年就被消费主义狂潮席卷了）          </div><h2 id="学习"><a href="#学习" class="headerlink" title="学习"></a>学习</h2><p>今年上半年疫情在家，学习效率极低，现在回想那荒废的大半年，只好小猪叹气了。研二开学，阴差阳错进到导师公司的一个项目中，开始了由硬件转软件的过程。也算是确定了以后专心搞软件的决心，老实说一直对太底层的电路板、PCB 板着实感兴趣不起来。自入学以来对嵌入式的态度就是暧昧不清，<del>现在确定转软件之后算是把今后的路给走窄了吧。</del></p><p>毕设的题目也定了下来，关于毕设本想只是搭建整个项目系统，毕竟 BLE + AOA 在商用上还算个新定位模式。没想到开题还是被批说是本科生的毕设水平，“研究生要做的是 research”… 好吧，还是得老老实实研究算法。</p><div>            <input type="checkbox" disabled checked="checked">发表了一篇 EI 论文          </div><div>            <input type="checkbox" disabled checked="checked">完成了智能水表项目的交接          </div><div>            <input type="checkbox" disabled checked="checked">完成了开题答辩          </div><div>            <input type="checkbox" disabled >Java 程式的学习 （断断续续地学习，效率极低）          </div><div>            <input type="checkbox" disabled >智能水表服务器搭建（搭个服务器也打不好，太垃圾了）          </div><h2 id="生活"><a href="#生活" class="headerlink" title="生活"></a>生活</h2><p>2020 年，有身边的亲人离去，会很伤心，但最亲爱的爷爷身体还算健康，虽然由于年纪大的原因，难免会有一些身体上的磕磕碰碰，但好在都有惊无险。</p><p>这后半年身边人给我最大的感受就是大家都在不约而同的讨论起来房产。身边的朋友们也都是刚需，最开始我也是一股脑扎进房市进行研究，但现在冷静下来之后更多的是观察。不会抱有买到就是赚到的心态，加之我本身就没有对房子的执念，在哪儿都是住。房屋的本质是居住，我不愿意牺牲最青春的十年去背负沉重的房贷，牺牲现金流动性，被迫放弃机会成本，所以近五年对于购房的事情我不会再庸人自扰了。<del>（可如何说服母亲大人是个bug）</del></p><p>2020 年，对于金钱相较于以往有看淡，会更加注重生活的体验。当然，对于搞钱这件事是一如既往的感兴趣。只是说我会更倾向于花钱买体验，而不是将钱存起来享受存钱、拥有钱的快乐。（写到这里莫名想到之前一个导游的洗脑话术：挣钱都已经这么辛苦了，花钱还不快乐点呀！）</p><div>            <input type="checkbox" disabled checked="checked">基金年化总收益：45%（事实告诉我们正确的买鸡方式是：买了然后忘掉这笔钱的存在）          </div><div>            <input type="checkbox" disabled checked="checked">三亚旅游（去了沙滩🏖️ 看了大海🌊 赏了夕阳🌇 逛了森林🌲 民宿被拒❌ 进了警局👮🏻）          </div><div>            <input type="checkbox" disabled checked="checked">第一次去蹦迪（老嗨老嗨了，然后耳朵聋了一个星期，苦笑ing）          </div><div>            <input type="checkbox" disabled checked="checked">第一次吃海底捞也算吧（为了享受学生优惠，下午三点去吃也是够拼的）          </div><div>            <input type="checkbox" disabled >日本行🗾（因为疫情原因流产了）          </div><h2 id="感情"><a href="#感情" class="headerlink" title="感情"></a>感情</h2><p>今年结束了一段感情，其实本应该早就结束。但自己的逃避性格和自私，双方硬是硬撑了半年。如果要有一个总结，那就是过程很快乐，结局很无奈。感情是最不应该自学的课题，得不到就是学到。自此对于感情这件事，自己对此也是看通透了许多。现在的我早已对纯洁的校园恋爱失去了兴趣，莫名的被现实起来，不知道算不算是遗憾。</p><p>在此分享上周看复旦大学文学系梁永安教授关于爱情的 <a href="https://www.douban.com/people/1109956/status/3217177951/">论述</a>，希望自己能往这方面发展：</p><blockquote><p>希望爱情解决自己的人生问题，而爱情本来是个感情它不是问题。</p><p>真正拥有爱情或者有资格谈恋爱的是那种人，就是他有能力一个在这个世界上生活。</p><p>这样生活它本身是富有活力的，只有这样的人他才有能力辐射出去温暖，</p><p>才有能力给别人一种信心和快乐。</p><p>…</p><p>你首先把自己建设成一个不需要恋爱，不需要婚姻，我也能独立地在世界上丰富而自由的生活。</p><p>这样的话，你既可以谈恋爱，也可以不谈。</p><p>你不会变成别人的压力</p></blockquote><div class="note note-danger">            <p>难免落俗，但浪漫不死</p>          </div><h2 id="兴趣"><a href="#兴趣" class="headerlink" title="兴趣"></a>兴趣</h2><p>阅读是仍在持续做的事情，电影与动漫总是能超额完成观影任务<del>（苦笑）</del>。小惊喜便是今年开通了博客，并结识了有趣的小伙伴。用文字记录生活，是我一直在做的事情，无论以什么样的载体形式。今年双十一购入了一款微单，摄影小白也开始入坑了…</p><p>此外播客的表现形式让我很惊奇，这一年光是在小宇宙 app 上就陆陆续续听了大概 200h 的播客内容。其中《得意忘形》、《BYM》是我的最爱了。</p><p>2020 阅读的书籍也有好有坏，相较于去年少了虚构类文学，多了许多所谓的 “中信” 畅销书。这也让给我不可避免地尽可能理想地去思考问题，从而丧失了理想主义的幻想，这难免少了些浪漫主义色彩。</p><ul><li><p>年度书籍：《<a href="https://book.douban.com/subject/5346110/">穷查理宝典》</a>《<a href="https://book.douban.com/subject/10517238/">平凡的世界</a>》《<a href="https://book.douban.com/subject/27064488/">活着</a>》</p></li><li><p>年度电影：《<a href="https://www.douban.com/link2/?url=https://movie.douban.com/subject/1307697/&query=%E8%8A%9D%E5%8A%A0%E5%93%A5&cat_id=1002&type=search&pos=1">芝加哥</a>》《<a href="https://movie.douban.com/subject/24298954/">疯狂原始人 2</a>》《<a href="https://movie.douban.com/subject/24733428/">心灵奇旅</a>》</p></li><li><p>年度音乐：《<a href="https://music.douban.com/subject/34946085/">MELANCHOLY</a>》《u’re mine》《<a href="https://music.douban.com/subject/35142476/">Shall We Talk (Tre Lune MMXIX)</a>》</p></li><li><p>年度电视剧：《<a href="https://movie.douban.com/subject/27166039/">Rick and Morty 4</a>》《<a href="https://movie.douban.com/subject/27622782/">上载人生</a>》《<a href="https://movie.douban.com/subject/30312909/">外星也难民 1</a>》</p></li></ul><div>            <input type="checkbox" disabled checked="checked">阅读 19 本课外书籍          </div><div>            <input type="checkbox" disabled checked="checked">入坑摄影          </div><div>            <input type="checkbox" disabled checked="checked">开通博客          </div><div>            <input type="checkbox" disabled checked="checked">沉迷播客          </div><div>            <input type="checkbox" disabled checked="checked">去了几个有趣的展          </div><div class="note note-primary">            <p>理工科素养是成为创造者的要素，但是文科素养是一个人行事风格的基调。这种「基调」是会扩散到周围环境的。</p>          </div><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>2020，现如今需要复盘总结的地方仍也不少，但无论怎样已经平安度过了。</p><p>2021，向前（钱）看吧！也希望能多有机会出去旅游，2020 年去过的地方实在太少了。</p><p>共勉之。</p>]]></content>
    
    
    <summary type="html">2020 年外部世界的关键字大概就是【变】，从新冠疫情、股市熔断、美国大选… 外部世界的风云变幻给以独立而弱小的个体不安全感，作为个体我今年的关键词大概就是【观察】，是对自我的不断观察与自我接纳。</summary>
    
    
    
    <category term="Life Pie" scheme="https://erenship.com/categories/Life-Pie/"/>
    
    
  </entry>
  
  <entry>
    <title>我有时也想变作猫咖里的一只猫</title>
    <link href="https://erenship.com/posts/e31e.html"/>
    <id>https://erenship.com/posts/e31e.html</id>
    <published>2020-10-25T05:47:38.000Z</published>
    <updated>2023-04-30T02:57:57.780Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-primary">            <p>真正严肃的哲学问题只有一个，那便是自杀。  ——阿尔贝 · 加缪《西西弗神话》</p>          </div><h2 id="两位年轻人的自杀"><a href="#两位年轻人的自杀" class="headerlink" title="两位年轻人的自杀"></a>两位年轻人的自杀</h2><p>今晚刷 B 站看到自己很喜欢的曾在东京大学留学的 up 主 <u><a href="https://space.bilibili.com/60614881?spm_id_from=333.788.b_765f7570696e666f.2">无聊的 Do 君</a></u> 发布了一条《<a href="https://www.bilibili.com/video/BV1ry4y1r7yW">一个叫叶修的年轻人决定去死</a>》，视频中悼念了一位名叫叶修的朋友（于 2020 年 7 月自杀，时年 25 岁），纪念的内容很是真诚。</p><div style="position: relative; width: 100%; height: 0; padding-bottom: 75%;">    <iframe src="//player.bilibili.com/player.html?aid=797601310&bvid=BV1ry4y1r7yW&cid=248505512&page=1"  scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"></iframe></div><p>​                               </p><p>我出于好奇便搜索了一下 <u><a href="https://space.bilibili.com/917629?from=search&seid=16414891925240022834">@路边的叶修</a></u>。了解到他是 B 站上最早一批发布生活 vlog 的 up 主，主要记录其在东京的留学生活。视频风格以真实暖心为特色，也曾因拍摄的留学 vlog 接受过央视的采访。 在他生前发布的视频留言下有不少悼念的网友，并提到其视频在留学期间给予他们很大的帮助。</p><p>我翻看了他早期发布的视频，内容十分生活化，拍摄初期也显露出稚嫩。但在观看的过程中给我以舒缓和亲切感，在加上他聊天式的旁白，一个乐观的、爱生活的在东京留学的大男孩形象跃然于脑海中。</p><p>下面是他发布的第一个 vlog：</p><div style="position: relative; width: 100%; height: 0; padding-bottom: 75%;">    <iframe src="//player.bilibili.com/player.html?aid=7887482&bvid=BV1Us411877i&cid=12946886&page=1"  scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"></iframe></div><p>​                                     </p><p>2015-2016 期间他陆续发布了大概 100 期这样的视频。可在 2020 年 7 月，他选择自杀的方式结束了他 25 岁的生命。</p><p>我是在他去世后 4 个月的今天了解到他，所以当我在翻看他过往视频的时候，总是会不禁带入如此的思考：这样一位乐观、开朗、愿意分享生活并陆续影响了许多留学生的年轻人为什么会早早结束生命。在视频中越是看到他那样的记录生活、热爱生活，我越是陷入人脆弱的沉思。</p><p>我的心情也逐渐随着对叶修的了解所低落起来，我想这也许是共情的缘故吧。</p><hr><p>年轻人、死亡，这两个不着边际的词汇放在一起，进而让我想到前几周大连理工大学研究生自杀的事件。因为平时不刷新闻、微博的缘故，关于这件事情并没有去过多了解。大体印象就停留在：噢，又有一位抗压能力差的研究生自杀了罢了。借此，我翻看了那位同学的遗书。读罢，老实说我还挺喜欢他的文字。没什么华丽的辞藻，尽是些朴实的措辞，再加上一些略显幼稚的玩笑与自嘲，显得真诚无比。从文字中我明明感受到了，他是一个会用幽默的三棱镜滤去内心忧伤的人，是一个会在生活中进行自我消解的人。在文末他提到下辈子想作猫咖里的一只猫，没有对生活报以热爱的人是不会说出这样的话的。可他最终还是选择了离开。</p><p><img src="https://i.loli.net/2020/10/25/C69np2oSwd1Vteu.png" alt="image-20201025142943459"></p><p> 今晚似乎被上帝抛出一个「想热爱生活却选择死亡」的命题给我。在以往我以及身边大多数人的观点总是：那些会选择早早就选择结束生命的人一定是糟糕得一点儿打击都承受不了的废物。可现在我产生了困惑，因为他们并不是那样的啊，他们甚至是曾带给人力量的人啊。</p><p>就像蒲柏所说：</p><blockquote><p>人就想绿萝，他的生存靠别的东西支持，他拥抱别人，就从拥抱中得到力量。</p></blockquote><p>难道我们仍一棍子打死地评价道：他们就是内心脆弱得不堪一击的 loser 吗？也许是没勇气，没能力去面对，去承受当下、未来的期盼。也许会有一个声音说：那你大可丧下去啊！</p><p>可谁让我们都活在这滚烫的十年里，正如王小波在《黄金时代》里那样写到：</p><blockquote><p>那天我二十一岁，在我一生的黄金时代。</p></blockquote><p>我想如果我不能激荡起一丝浪花的话，我也打算早早地在下辈子变成某间猫咖里的一只猫，不过我大概没有那样的勇气吧。  </p><p class="note note-success">人的脆弱与坚强一样，都值得我们去珍惜。</p><hr><p>视频标题 《一个叫叶修的年轻人决定去死》，应该是参照名叫《<a href="https://www.douban.com/link2/?url=https://book.douban.com/subject/26672693/&query=%E4%B8%80%E4%B8%AA%E5%8F%AB%E6%AC%A7%E7%BB%B4%E7%9A%84%E7%94%B7%E4%BA%BA%E5%86%B3%E5%AE%9A%E6%AD%BB%E5%8E%BB&cat_id=1001&type=search&pos=0">一个叫欧维的男人决定死去</a>》的小说所起。在此我想分享书中最爱的这句话给看到这里的你：</p><blockquote><p>每个人的生命中都有一个故事。要是你不了解那个故事，就不了解那个人。</p></blockquote><p>我们不知道叶修在回国这几年发生了什么，也不知道那位大连研究生经历了怎样的压力。因为我们不了解他们的故事，也就不了解他们，就更没有资格去评判他们。</p><h2 id="最后恭喜我们还活着的这个事实"><a href="#最后恭喜我们还活着的这个事实" class="headerlink" title="最后恭喜我们还活着的这个事实"></a>最后恭喜我们还活着的这个事实</h2><p>思绪很多，但最后得出的结论似乎只是：人好像也不总是能一直乐观下去的对吧。就像我自己，每个几个月都会间歇性地低落，然后去思索一些宏大而荒谬的命题。这总会显得很傻，所以只好偷偷地写在日记本上。</p><p>不过最后恭喜我们还活着的这个事实，多去和能让自己觉得活着真好的事物接触吧！</p><iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=100% height=86 src="//music.163.com/outchain/player?type=2&id=34468324&auto=1&height=66"></iframe>]]></content>
    
    
    <summary type="html">这是一篇没有主旨的随笔。借由两位年轻人的自杀，进而让我开始思考死亡这个宏大而荒诞的命题。</summary>
    
    
    
    <category term="Life Pie" scheme="https://erenship.com/categories/Life-Pie/"/>
    
    
  </entry>
  
  <entry>
    <title>「您好，我们这边是蚂蚁金服客服...」</title>
    <link href="https://erenship.com/posts/faee.html"/>
    <id>https://erenship.com/posts/faee.html</id>
    <published>2020-10-03T12:50:31.000Z</published>
    <updated>2023-04-30T02:59:12.012Z</updated>
    
    <content type="html"><![CDATA[<h2 id="诈骗电话"><a href="#诈骗电话" class="headerlink" title="诈骗电话"></a>诈骗电话</h2><p>今日午后正在躺椅上休憩，突然接到一通来自「安徽」的私人手机号。</p><blockquote><p>「您好，我们这边是蚂蚁金服客服。请问您是不是 E 先生呢？您的手机尾号是不是 XXXX ? 」</p><p>「是的」</p><p>「我们这边后台有看到您开通的借呗有逾期未还金额。」</p><p>「挂断…」</p></blockquote><p>这本看似是个人信息泄露后平淡无奇的诈骗电话，但却着实让我有些紧张起来。</p><hr><p>事情要从一周前说起。 9 月 23 日开始，我的手机会陆续收到支付宝登陆的短信验证码，起初以为就是正常的误输操作。但接下来几天仍在收到登录的短信验证码，更甚在某一日的 1 个小时内连续收到 20+ 条相同的验证短信。</p><blockquote><p>【支付宝】你正在登录支付宝，验证码5287，泄露验证码会影响资金安全。唯一热线：95188</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201004122715.png" alt="IMG_7500"></p><p>这让我开始意识到，可能有人在试图登录我的支付宝账户。但由于支付宝有二次登录验证，所以只要我保护好短信验证码不会被泄露，那么我的账户仍是安全的。（支付宝的验证码位6位数，对方有 1 &#x2F; 1000000 &#x3D; 0.0001% 的概率成功，并且暴力破解的平均时间会超过验证码超时时间。所以 Duck 不必担心验证码被试对。）</p><p>三天之后突然收到「阿里巴巴」发来的短信，同样是陆续收到很多条。</p><blockquote><p>【阿里巴巴】您正在自助开通账户，验证码636175，请在15分钟内按页面提示提交验证码，切勿将验证码泄露于他人。</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201004122735.PNG" alt="IMG_7491"></p><p>不过我同样是并无理会。但一向注重隐私的我开始思考是哪个环节出现纰漏，我开始想到是否是最近在浏览他人博客时，留下的电子邮件。进而让有心之人通过邮箱账号进行支付宝登录。不过这种推测仍处在很初步的怀疑阶段。</p><p>直到接到那通电话，让我意识到「<strong>骗子可能开始主动出击了</strong>」。</p><h2 id="拨通-95188"><a href="#拨通-95188" class="headerlink" title="拨通 95188"></a>拨通 95188</h2><p>在挂掉安徽那通电话后，我随即拨通了支付宝客服电话「95188」。</p><p>拨打 95188 ，我主要想了解清楚以下几点情况：</p><ol><li>在诈骗电话已经打上门的情况下，我的支付宝账户是否仍然安全？</li><li>对方是使用手机号还是电子邮箱进行登录？</li><li>我的借呗是否被开通？借呗的开通流程和借款流程是什么？</li><li>在个人信息已确认泄露无疑的情况下，我个人能做哪些措施去加强账户安全系数（是否需要更换邮箱账号、手机号等）？</li></ol><p>由于我需要咨询业务的权限不同，先后有三名客服接待了我，我也获得了相应的答案。</p><ol><li>在不泄露验证码的情况下，账户仍是安全的。</li><li>通过支付宝后台查看到，在 9 月 23 日 至今的短信验证码申请是通过手机号登录发送的，并不是邮箱账号。所以之前所推测的由于四处胡乱留邮箱所引起的信息泄露就可以排除掉了（其实通过邮箱去反推姓名、手机号的社工难度也很大）。</li><li>我的借呗没有被开通。借呗开通和借款均需要支付密码。</li><li>在确认个人信息已泄露的情况下，可以更换手机或邮箱。但最重要的是保管好短信验证码，最好使用完之后立马删除短信。<strong>定期在 &lt;支付宝安全中心&gt; 使用安全检测功能</strong>。</li><li>建议：<strong>不要信任何私人号码，挂断后主动咨询官方电话</strong>，逆向询问。</li></ol><p>了解到并无大碍之后，又继续酣睡了 😴。</p><h2 id="复盘"><a href="#复盘" class="headerlink" title="复盘"></a>复盘</h2><p>虽然这是一次低级的电信诈骗，可是作为半个信息技术行业从业者，遇到个人信息被泄露得如此彻底，这也是非常值得我去复盘反思的。</p><p>此外，在 9 月 23 日发现异常的两天内，我做了以下三件事情来将损失减到最小。</p><ol><li>将支付宝中余额宝的大部分金额转到银行卡。（不争气的基金实在不忍心因为这件事情割肉卖掉，时常安慰自己是价值投资者…）</li><li>更换全新的支付宝登录密码，检查登录邮箱账户的安全性。</li><li>确认是否购买支付宝账户险。</li></ol><p>在工作、学校中难免会要求填写各种个人信息。这是我们无法回避的，如果信息从这样的渠道泄露我们实在是无能为力，但这不能成为我们彻底放弃个人信息保护的借口。关于此次信息泄露我怀疑是之前同某个培训机构合作所导致的，因为财务往来是通过支付宝，并且个人信息也会填写。并且因为培训机构泄露我的个人信息的情况遇到不止一两次。</p><div class="note note-success">            <p>在这里吐槽一下经常说「信息泄露很正常，没必要在意，反正都已经泄露了，无所谓」的人，每每听到这样的说辞我都会内心 OS :「以后你的个人信息满天飞，在黑市全套信息就值个 2 RMB。而由于我有意在保护个人信息，那么在黑市上全套信息也许能值 500 RMB？」</p>          </div><p>关于信息保护的措施，分享几点我个人在使用的 tips（虽然还是被泄露了…）。</p><ul><li><p>使用两个手机号</p><blockquote><p>一个用于银行卡、亲人联系等会一直用下去的情况。</p><p>另一个用于购物和一些不得不填手机号的情况，此号码通常会每个一两年更换一次。</p></blockquote></li><li><p>网站注册名</p><p>各种网站如需填写姓名，则以网站名为后缀。今后若收到骚扰短信，自然会知道从哪里泄露的。（如：赵B站，赵知乎，赵XX）</p></li><li><p>不贪小便宜去填写商家促销打折等信息</p><p>永远记住你的信息是值钱的。（除了某宝的店铺会员，不过也是使用小号去登记）</p></li><li><p>遇事不决先百度</p><p>在遇到某些自己都不清楚是不是诈骗行为的情况下，先百度（不用 google，因为这种偏家常范儿的问题百度里的内容更多，更接地气），去查询网上是否有相似情况再做判断。</p></li></ul><p>​                        </p><div class="note note-primary">            <p>It’s a proud thing to pay for security and privacy。</p>          </div>]]></content>
    
    
    <summary type="html">当接到这通诈骗电话后，我意识到事情应该引起警惕了。</summary>
    
    
    
    <category term="Life Pie" scheme="https://erenship.com/categories/Life-Pie/"/>
    
    
  </entry>
  
  <entry>
    <title>Hexo 博客站点加速不完全指南</title>
    <link href="https://erenship.com/posts/db37.html"/>
    <id>https://erenship.com/posts/db37.html</id>
    <published>2020-09-28T00:42:42.000Z</published>
    <updated>2023-04-30T02:57:11.962Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在我们使用 Hexo 作为框架搭建静态博客时，存在两个主要因素影响着网站访问速度。</p><ul><li><p>GitHub 在国内访问速度不稳定</p><p>由于我们搭建的博客是放在 GitHub 上面的，而国内用户直接访问 GitHub 网速不佳。这将是十分影响博客的用户体验。所以使用国内访问速度更快的托管服务商 Vercel （当然也可以用别的服务商，只是在国内来说 Vercel 效果较好）进行网站托管；</p></li><li><p>在使用本地图库引用的情况下，当博客图片资源过大时，网站图片加载会变得缓慢。</p></li></ul><p>所以，我们在此主要针对以上两个问题来进行优化。</p><h2 id="Vercel-托管"><a href="#Vercel-托管" class="headerlink" title="Vercel 托管"></a>Vercel 托管</h2><p><strong>Vercel</strong> 是一家提供 JamStack（静态网站）托管的平台，支持自动从 GitHub 等仓库拉取代码, 按自定义构建方式进行构建，最后把生成的静态网站进行发布; 在这基础上同时也支持自定义域名，自动申请 SSL 证书等功能。</p><p>由于国内访问 Vercel 的速度要比访问 GitHub pages快很多，所以我们只需要把站点交给 Vercel 进行托管就能大幅度提升博客的加载速度。</p><div class="note note-success">            <p>参考教程： <a href="https://vincentqin.tech/posts/speedup-gitpage/">使用 Vercel 加速 Hexo 静态博客访问</a> </p>          </div><p>在使用 Vercel 托管之后，访客在访问博客网站时相当于是在访问 Vercel 的服务器（因为此时已经在域名服务商处处新增了对应 Vercel 站点的域名解析），而不是去访问最开始的 GitHub pages 网址。</p><p>此外，按照上述教程进行操作之后，查看 Domain 一栏是否解析生效。此时可能会出现一会儿配置失败，一会儿配置成功的情况。若出现标红提示配置失败，点击查看错误提示。<strong>如果是提示更改为 Vercel 的 DNS 服务器，只需到你博客域名服务商，将 DNS 服务器地址更改为 Vercel 要求的地址即可。</strong>（例如我的域名服务商是阿里云，我到官网去把阿里云官方的 DNS 服务器地址改为 Vercel 的即可。DNS 服务器地址为两个，都需要进行更改）<img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo/img/20200812033929.png" alt="Snipaste_2020-08-12_02-35-18"></p><p><strong>效果图</strong></p><p>对比站点 github.io 的原始域名，访问延迟明显减小：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo/img/20200814001334.png" alt="对比"></p><p>使用百度站长对网站速度进行测试：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo/img/20200812040604.png" alt="网站速度诊断"></p><h2 id="jsDelivr-加速"><a href="#jsDelivr-加速" class="headerlink" title="jsDelivr 加速"></a>jsDelivr 加速</h2><p>在博客的撰写中，我们一般是直接引用本地图库资源（使用 hexo-asset-image 插件）对文章进行配图。之后再<code>hexo g -d</code> 将文章和图片资源一同部署到 GitHub 。而我们在访问这些图片资源时又需要再从 GitHub 上进行提取，而 GitHub 上的访问速度本身已经很慢，再去加载大量图片更加会拖慢网页速度。虽然我们前面已经对博客进行了 Vercel 托管，但是我们有一种更简单高效的方式对图片进行上传，那就是<strong>利用 GitHub 图库+ jsDelivr CDN 加速+ PicGo 客户端实现图库的高效使用</strong>。</p><p>简单说明以上三个工具的使用情形：</p><ul><li><p>GitHub 图库：用于存放我们需要使用的文章配图文件的仓库；</p></li><li><p>jsDelivr ：用于 CDN 加速，在 Markdown 文本编辑器中直接引用 jsDelivr 的图片外链，即可快速访问图片资源；</p></li><li><p>PicGo：用于 Markdown 写作端生成对应的 jsDelivr 图片外链，配合 Typora 编辑器时可直接拖拽图片自动生成外链使用。（<strong>故推荐 Typora 客户端 + PicGo 客户端搭配使用，食用效果更佳！</strong>）</p><p>​</p></li></ul><p><strong>什么是 jsDelivr ?</strong></p><blockquote><p>jsDelivr 是国外的一家优秀的公共CDN 服务提供商，也是首个「打通中国大陆（网宿公司运营）与海外的免费CDN 服务」。 jsDelivr 有一个十分好用的功能——它可以加速Github 仓库的文件。 我们可以借此搭建一个免费、全球访问速度超快的图床。</p></blockquote><p><strong>什么是 PicGo ?</strong>  </p><blockquote><p>一个用于快速上传图片并获取图片URL链接的工具。</p></blockquote><div class="note note-success">            <p>参考教程：</p><ul><li><a href="https://www.itrhx.com/2019/08/01/A27-image-hosting/">Github+jsDelivr+PicGo 打造稳定快速、高效免费图床</a></li><li><a href="https://www.cnblogs.com/hoxis/p/12470044.html">Typora原生集成PicGo图床工具！</a></li></ul>          </div><hr><p><strong>此方法会弃用本地图库，启用 GitHub + jsDelivr + PicGo 的方式对文章进行配图操作。</strong> </p><p>所以可以卸载 hexo-asset-image 插件，保持 Hexo 的清爽：</p><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs arduino">npm remove  hexo-asset-image<br></code></pre></td></tr></table></figure><p>并在配置文件_config.yml 中将此行由 true 改为 false：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">post_asset_folder:</span> <span class="hljs-literal">false</span><br></code></pre></td></tr></table></figure><p>此时，在你每次<code>hexo n &quot;title&quot;</code> 的时候就不会在 _posts下面生成同名的文件夹放图片文件了，大可将需要使用的图片放在除博客文件的其他位置（所以你甚至可以把已经生成外链的图片删掉），因为照片放在专门的图片仓库，利用 jsDelivr 外链就可以直接访问，你不需要再将这些图片上传到博客的 GitHub 仓库里面去。下图红色地址就是我们直接可以访问到图片的 jsDelivr 外链地址。你可以点来试下，看看是不是我们下面这张图。 <a href="https://cdn.jsdelivr.net/gh/erenlu/PicGo/img/20200812034534.png">https://cdn.jsdelivr.net/gh/erenlu/PicGo/img/20200812034534.png</a></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo/img/20200812034534.png" alt="Snipaste_2020-08-12_03-45-17"></p><blockquote><p>注：在使用 PicGo 客户端时会遇到一些问题，具体解决方法参考：<a href="https://www.cnblogs.com/hoxis/p/12470044.html">Typora原生集成PicGo图床工具！</a> </p></blockquote><p>在使用图床之后，我们所用的的图片就可以不放在本地。那么图片在每次编译部署也就不用上传到网上，这缩短了编译时间。</p><h2 id="Valine-评论系统-（邮件提醒）"><a href="#Valine-评论系统-（邮件提醒）" class="headerlink" title="Valine 评论系统 （邮件提醒）"></a>Valine 评论系统 （邮件提醒）</h2><div class="note note-success">            <p>参考教程：</p><ul><li><a href="https://lete114.now.sh/article/Valine-LeanCloud-Config.html#%E5%89%8D%E8%A8%80">LeanCloud-Valine 保姆及配置教程</a></li><li><a href="https://lete114.now.sh/article/da1d5c8b.html">LeanCloud 因控流原因的解决办法</a></li></ul>          </div><h2 id="其他优化教程"><a href="#其他优化教程" class="headerlink" title="其他优化教程"></a>其他优化教程</h2><div class="note note-success">            <p>参考教程：</p><ul><li><p><a href="https://indexmoon.com/articles/1153730074/">Hexo 基础教程(四)：功能添加与优化</a></p><p>包含：添加 RSS，代码压缩，文章链接唯一化，SEO（搜索引擎优化）等内容。</p></li></ul>          </div><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>完成上述操作之后，博客的打开速度不出意外就会快很多。不过做了这么多操作，我们最核心关注的点还是应该在<strong>博客内容质量</strong>，以及<strong>输出频率</strong>上。总结下来就是内容为王，同时兼顾用户体验。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://vincentqin.tech/posts/speedup-gitpage/">使用 Vercel 加速 Hexo 静态博客访问</a></li><li><a href="https://www.itrhx.com/2019/08/01/A27-image-hosting/">Github+jsDelivr+PicGo 打造稳定快速、高效免费图床</a></li><li><a href="https://www.cnblogs.com/hoxis/p/12470044.html">Typora原生集成PicGo图床工具！</a></li><li><a href="https://blog.juanertu.com/archives/adff04af.html">PicGo+GitHub快速实现markdown图床</a></li><li><a href="https://juejin.im/post/6844904137407086600">利用 GitHub + PicGo + Typora 搭建属于自己的图床</a></li><li><a href="https://blog.iljw.me/2019/05/jsdelivr-cdn-github.html">使用 jsDelivr CDN 加速 Github 仓库的图片，以作为博客的图床</a></li></ul>]]></content>
    
    
    <summary type="html">从 Vercel 托管到 jsDelivr CDN 加速，以及添加 Valine 评论系统...这里是加速 Hexo 博客站点不完全指南。</summary>
    
    
    
    
    <category term="Hexo" scheme="https://erenship.com/tags/Hexo/"/>
    
    <category term="Blog" scheme="https://erenship.com/tags/Blog/"/>
    
  </entry>
  
  <entry>
    <title>嘿，青年艺术家们</title>
    <link href="https://erenship.com/posts/441c.html"/>
    <id>https://erenship.com/posts/441c.html</id>
    <published>2020-09-26T11:00:51.000Z</published>
    <updated>2023-04-30T02:56:47.596Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-success">            <p>展名：CHABF 2020 成都艺术书展</p><p>地点：麓湖生态城 A5 麓坊 · A4国际驻留艺术中</p><p>时间：2020.09.18 - 09.20</p>          </div><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>当时年纪小，喜欢装文艺，便留下了爱看展的习惯  <del>（现在好了，只爱钱 🐶）</del>。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926191712.JPG" alt="IMG_7310(20200926-003520)"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926204938.JPG" alt="IMG_7309(20200922-233444)"></p><h2 id="分享会"><a href="#分享会" class="headerlink" title="分享会"></a>分享会</h2><p>下午一点匆匆赶到会场，选择了一场名叫《美国连环画》的分享会。</p><p>分享者是一位来自东北的艺术家，绘画风格很像美国漫画《马男波杰克》以及《吉普森一家》。分享者讲述了自己在美求学中所经历的创作痛苦和挣扎，最终在体验生活的过程中逐渐找到属于自己的绘画风格。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926195238.JPG" alt="IMG_7132(20200920-095350)"></p><p>分享者在展会中的作品：</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926200019.JPG" alt="IMG_7150"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926200425.JPG" alt="IMG_7149"></p><h2 id="盆栽"><a href="#盆栽" class="headerlink" title="盆栽"></a>盆栽</h2><p>这组盆栽的配文实在是有打动到我，所以干脆全拍下来啦。</p><div class="note note-success">            <p>今天有个孩子说：我只能等到十八岁才能过生日，等我过生日的时候要去天上吃云朵，这是我生日最想做的事。</p>          </div><div class="note note-warning">            <p>我：一个人看店就很难出去参加活动什么的。</p><p>客人：可以让男朋友来替一下呀。</p><p>我：唉，异地恋没办法呀。</p><p>客人：那他在哪里呀？</p><p>我：他在多远的未来。</p>          </div><div class="note note-danger">            <p>为了不迟到，每天按部就班的生活，放学就直接回家。今天突然想，这么生活太无聊了吧，怎么能光上学不跟自然接触呢？</p>          </div><div class="note note-secondary">            <p>数字媒体的飞速进步反而让我越发觉得我们的文明是非常脆弱的。100年以后，如果人类灭绝了，最可能留下的还是刻在石头上，最原始的东西。</p>          </div><div class="note note-info">            <p>我的勇气，基本都被拿去跟肯德基里做冰淇淋的人说 “做个大的给我行吗？” 和 “多来点酱吧”。</p>          </div><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926201259.JPG" alt="IMG_7135"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926201633.JPG" alt="IMG_7145"></div></div><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926201540.JPG" alt="IMG_7140"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003204l321.JPG" alt="IMG_7135"></div></div></div><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003204339.JPG" alt="IMG_7138"></p><p>当逛完这几座盆栽时，不禁让我思考：在平日疯狂敲击代码的日子里，我是否真的有在生活着？</p><h2 id="集市"><a href="#集市" class="headerlink" title="集市"></a>集市</h2><p>说是集市，因为这个会场真的就是青年艺术家们摆摊设点的集市场。不同的是，这里没有讨价还价，有的只是关乎于作品和理念的交流。他们与络绎不绝的人们沟通着，阐述着创作理念。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926203509.JPG" alt="IMG_7247"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926204523.JPG" alt="IMG_7253"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926204627.JPG" alt="IMG_7263"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003202506.JPG" alt="IMG_7222"></p><p>👇  这位小姐姐十分热情地讲解着自己的作品。从她的介绍中了解到这是一本从细胞层面结合女性视角讲述女性的作品。背后墙上挂在作者收集的不同女性在卸妆过程中使用过的卸妆布（or 卸妆巾？），旨在展现每个女性作为独立个体存在的美。（一圈逛下来后，这位青年艺术家告诉我们她已经卖完了今天的大部分作品！）</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926210000.JPG" alt="IMG_7231"></p><p>他们在此努力售卖着梦想，这是值得尊重的。</p><h2 id="趣图"><a href="#趣图" class="headerlink" title="趣图"></a>趣图</h2><p>👇 这是一对双胞胎姐妹的作品展，里面展现了他们在成长过程中的喜乐悲欢。对于为什么要选用红配绿，最开始以为是她们一人喜欢红色一人喜欢绿色。在同创作者交流后，她们说到是以为姐妹俩一人性格更活泼些，一人性格更安静些，所以在创作时便分别选择了红色和绿色。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003202748.JPG" alt="IMG_7156"></p><p>  👇  人们可以自行在白纸上进行创作，于是我熟练地拿起画笔在纸上写道 “四六级包过，加 Q:xxxxx”。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003202806.JPG" alt="IMG_7154"></p><p>👇 一本来自废弃房屋里的手账。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003202821.JPG" alt="IMG_7168"></p><p>👇 创作的含义没看懂，不过就觉得这张拍得很有氛围~</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926213309.JPG" alt="IMG_7153">             </p><p>👇 大黑！<del>（大白的兄弟）</del>，艺术家在此进行了行为艺术表演。着实没看懂，领悟能力还是不 dei 行啊。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926215254.JPG" alt="IMG_7165">              </p><p>👇 「十五分钟的交换」创作者提前三天来到成都，与路人进行十五分钟的交谈，同时进行肖像画创作。每幅画里面都包含着作者对对象的理解。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003203001.JPG" alt="IMG_7142"></p><p>有些画里眼睛里有星星，有笑脸。这就是相由心生吼。</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/2020094954.JPG" alt="IMG_7210"></p><p>👇 interesting</p><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003203029.JPG" alt="IMG_7246"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003204554.jpeg" alt="20200926223016 (2)"></div></div><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20200926220546.JPG" alt="IMG_7285(20200921-233710)"></div></div></div>             <p>👇 这…</p><div class="group-image-container"><div class="group-image-row"><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003203405.JPG" alt="20200926215730"></div><div class="group-image-wrap"><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003203436.jpeg" alt="20200926220317"></div></div></div><p>👇 「里外美学实验室」这是一个很有意思的小展厅，里面摆放了格式的画作。每幅画作都配有相应制作的音乐，作者希望观赏者结合着音乐来观赏画作，用听觉和视觉共同体验作品来带的魅力。</p><p>其中一个作品是作者将交通事故合集配上清脆悦耳的节奏音，视频初始的压迫感和紧张瞬间就被缓解了。有点可惜没有用视频记录下来，感兴趣的朋友可以关注他们的公众号，并且可以进行声音投稿，来参加他们的新创作「ECHO 回音计划」。（公众号：里外美学实验室）</p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003203453.jpg" alt="20200926222005"></p><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003203508.jpg" alt="20200926221131"></p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>展会中许多内容都是匆匆晃过，许多想去了解的细节还没有同创作者们去交流。虽说都是一些青年艺术家们，有些人可能会觉得许多作品是在故作深沉，或者颇 “有少年不识愁滋味，为赋新词强说愁” 的味道，但个人认为先抛开艺术价值不谈，只要是有过思索过的作品都是值得肯定的。</p><p>看展是一定要看的，这辈子都不可能不看展的。年轻时爱装文艺留下的后遗症，莫得办法…</p>]]></content>
    
    
    <summary type="html">记录一次参观艺术书展（2020 成都）的经历。艺术书籍和传统书籍最大的不同就是在于艺术书籍的排版和制作会更加的用心，艺术书籍的主要作用并不是在于阅读，而是在于欣赏。</summary>
    
    
    
    <category term="literature Pie" scheme="https://erenship.com/categories/literature-Pie/"/>
    
    
  </entry>
  
  <entry>
    <title>把你的名字送上火星</title>
    <link href="https://erenship.com/posts/13b8.html"/>
    <id>https://erenship.com/posts/13b8.html</id>
    <published>2020-09-13T07:35:47.000Z</published>
    <updated>2023-04-30T03:01:40.703Z</updated>
    
    <content type="html"><![CDATA[<div class="note note-primary">            <p>「我们是获得了生命的星尘，然后被宇宙赋予了发现自我的使命。」  ——《写给忙碌者的天体物理学》</p>          </div><p>「<a href="https://www.nasa.gov/press-release/nasa-invites-public-to-submit-names-to-fly-aboard-next-mars-rover">Send Your Name To Mars</a>」是一项 NASA 发起的项目：让公众都有机会将自己的名字通过火星探测器送到火星上去。</p><blockquote><p>位于加利福尼亚州帕萨迪纳市的美国宇航局喷气推进实验室（JPL）的微器件实验室将使用电子束将提交的名字用模板印在硅芯片上，并在芯片上印上小于人类头发宽度千分之一（75纳米）的文字行。以这种大小，在一个一丁点大小的芯片上可以写下一百万个以上的名字。芯片将装在玻璃罩下的漫游车上。</p></blockquote><p>「<a href="https://www.space.com/21900-nasa-mars-rover-2020-images.html">火星 2020</a>」探测器已在 2020 年 7 月被发射，于 2021 年 2 月降落在火星上。所以目前我们已经无法参与「<a href="https://www.space.com/21900-nasa-mars-rover-2020-images.html">火星 2020</a>」探测器的活动。</p><p>但我们可以参与后续的火星探测计划，将自己的姓名送上火星。</p><ul><li><p>进入官网：<a href="https://mars.nasa.gov/participate/send-your-name/future">https://mars.nasa.gov/participate/send-your-name/future</a></p></li><li><p>填入个人信息：（姓名可以输入中文）</p></li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/202009131kk719.png" alt="Snipaste_2020-09-13_17-29-23"></p><ul><li>至此，就获得了前往火星的纪念品登机证：</li></ul><p><img src="https://cdn.jsdelivr.net/gh/erenlu/PicGo//img/20201003212717.jpeg" alt="BoardingPass_MyNameOnFutureMission"></p><p>让你的名字代替你先去火星旅行吧！</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><section class="footnotes"><div class="footnote-list"><ol><li><span id="fn:1" class="footnote-text"><span><a href="https://www.nasa.gov/press-release/nasa-invites-public-to-submit-names-to-fly-aboard-next-mars-rover">NASA Invites Public to Submit Names to Fly Aboard Next Mars Rover</a><a href="#fnref:1" rev="footnote" class="footnote-backref"> ↩</a></span></span></li><li><span id="fn:2" class="footnote-text"><span><a href="https://www.ifanr.com/1216268">现在，NASA 可以将你的名字送到火星上去</a><a href="#fnref:2" rev="footnote" class="footnote-backref"> ↩</a></span></span></li></ol></div></section>]]></content>
    
    
    <summary type="html">NASA 的浪漫。</summary>
    
    
    
    <category term="literature Pie" scheme="https://erenship.com/categories/literature-Pie/"/>
    
    
  </entry>
  
</feed>
