精华内容
下载资源
问答
  • HTTP 304状态码的详细讲解

    万次阅读 多人点赞 2017-04-12 10:33:55
    HTTP 304错误状态码的详细讲解 304缓存策略及实现 网页web常见状态码:200,301,302,304,400,401,404,500

     

    HTTP 304状态码的详细讲解


    304状态码或许不应该认为是一种错误,而是对客户端有缓存情况下服务端的一种响应。

     

    整个请求响应过程如下:


    客户端在请求一个文件的时候,发现自己缓存的文件有 Last Modified ,那么在请求中会包含 If Modified Since ,这个时间就是缓存文件的 Last Modified 。因此,如果请求中包含 If Modified Since,就说明已经有缓存在客户端。服务端只要判断这个时间和当前请求的文件的修改时间就可以确定是返回 304 还是 200 。
    对于静态文件,例如:CSS、图片,服务器会自动完成 Last Modified 和 If Modified Since 的比较,完成缓存或者更新。但是对于动态页面,就是动态产生的页面,往往没有包含 Last Modified 信息,这样浏览器、网关等都不会做缓存,也就是在每次请求的时候都完成一个 200 的请求。
    因此,对于动态页面做缓存加速,首先要在 Response 的 HTTP Header 中增加 Last Modified 定义,其次根据 Request 中的 If Modified Since 和被请求内容的更新时间来返回 200 或者 304 。虽然在返回 304 的时候已经做了一次数据库查询,但是可以避免接下来更多的数据库查询,并且没有返回页面内容而只是一个 HTTP Header,从而大大的降低带宽的消耗,对于用户的感觉也是提高。当这些缓存有效的时候,通过 Fiddler 或HttpWatch 查看一个请求会得到这样的结果:

     

     


    第一次访问 200
    按F5刷新(第二次访问) 304
    按Ctrl+F5强制刷新 200

    下面用Fiddler来查看上面的访问请求过程

    第一次(首次)访问 200

     

     

    第二次F5刷新访问 304


    请求的头信息里多了 “If-Modified-Since","If-None-Match" 

     

     

     


    第三次 按Ctrl+F5强制刷新 200

    同第一次,不贴图了

     

     

     

    为什么要使用条件请求

    当用户访问一个网页时,条件请求可以加速网页的打开时间(因为可以省去传输整个响应体的时间),但仍然会有网络延迟,因为浏览器还是得为每个资源生成一条条件请求,并且等到服务器返回HTTP/304响应,才能读取缓存来显示网页.更理想的情况是,服务器在响应上指定Cache-Control或Expires指令,这样客户端就能知道该资源的可用时间为多长,也就能跳过条件请求的步骤,直接使用缓存中的资源了.可是,即使服务器提供了这些信息,在下列情况下仍然需要使用条件请求:

    在超过服务器指定的过期时间之后
    如果用户执行了刷新操作的话
    在上节给出的图片中,请求头中包含了一个Pragma: no-cache.这是由于用户使用F5刷新了网页.如果用户按下了CTRL-F5 (有时称之为“强刷-hard refresh”),你会发现浏览器省略了If-Modified-Since和If-None-Match请求头,也就是无条件的请求页面中的每个资源.

    避免条件请求
    通常来说,缓存是个好东西.如果你想提高自己网站的访问速度,缓存是必须要考虑的.可是在调试的时候,有时候需要阻止缓存,这样才能确保你所访问到的资源是最新的.

    你也许会有个疑问:“如果不改变网站内容,我怎么才能让Fiddler不返回304而返回一个包含响应体的HTTP/200响应呢?”

    你可以在Fiddler中的网络会话(Web Sessions)列表中选择一条响应为HTTP/304的会话,然后按下U键.Fiddler将会无条件重发(Unconditionally reissue)这个请求.然后使用命compare命令对比一下两个请求有什么不同,对比结果如下,从中可以得知,Fiddler是通过省略条件请求头来实现无缓存请求的:

    Screenshot of Windiff of conditional and unconditional requests

    如果你想全局阻止HTTP/304响应,可以这么做:首先清除浏览器的缓存,可以使用Fiddler工具栏上的Clear Cache按钮(仅能清除Internet Explorer缓存),或者在浏览器上按CTRL+SHIFT+DELETE(所有浏览器都支持).在清除浏览器的缓存之后,回到Fiddler中,在菜单中选择Rules > Performance > Disable Caching选项,然后Fiddler就会:删除所有请求中的条件请求相同的请求头以及所有响应中的缓存时间相关的响应头.此外,还会在每个请求中添加Pragma: no-cache请求头,在每个响应中添加Cache-Control: no-cache响应头,阻止浏览器缓存这些资源.

     

     

     

     

     

    动态网页如何设置304

    以aspx页面为例,代码如下:

     

    var request = context.Request;
                var response = context.Response;
                if (request.Headers["If-Modified-Since"].NotNullOrEmpty() || request.Headers["If-None-Match"].NotNullOrEmpty())
                {
                    response.StatusCode = 304;
                    return;
                }
    //非304情况下的操作 略
    //设置缓存选项
                response.Clear();
                response.ClearContent();
                response.Headers["Last-Modified"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                response.Headers["ETag"] = id;//这里假设的是根据不同的id
                response.CacheControl = "private";
                response.ExpiresAbsolute = DateTime.Now.AddMonths(6);
               

     

    ETag是什么意思?

    HTTP 协议规格说明定义ETag为“被请求变量的实体值” 。 另一种说法是,ETag是一个可以与Web资源关联的记号(token)。典型的Web资源可以一个Web页,但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端
     

    asp.net web api的实现代码如下:

     

    // GET /images/001.png 
    [HttpGet] 
    public HttpResponseMessage Get(string filename) 
    { 
    	HttpResponseMessage response = new HttpResponseMessage();  
    
    	.....
    	string etag = string.Format("\"{0}\"", fileInfo.MD5); 
    	var tag = Request.Headers.IfNoneMatch.FirstOrDefault(); 
    	if (Request.Headers.IfModifiedSince.HasValue && tag != null && tag.Tag == etag) 
    	{ 
    		response.StatusCode = HttpStatusCode.NotModified; 
    	} 
    	else 
    	{ 
    		//dealcode ......
    		responseStream.Position = 0; 
    		response.StatusCode = fullContent ? HttpStatusCode.OK : HttpStatusCode.PartialContent; 
    		response.Content = new StreamContent(responseStream); 
    		response.Content.Headers.ContentType = new MediaTypeHeaderValue(fileInfo.ContentType); 
    		response.Headers.ETag = new EntityTagHeaderValue(etag); 
    		response.Headers.CacheControl = new CacheControlHeaderValue(); 
    		response.Headers.CacheControl.Public = true; 
    		response.Headers.CacheControl.MaxAge = TimeSpan.FromHours(480); 
    		response.Content.Headers.Expires = DateTimeOffset.Now.AddDays(20); 
    		response.Content.Headers.LastModified = fileInfo.UploadDate; 
    	} 
    	return response;
    }

     

    常见状态码:

    一些常见的状态码为:

    • 200 – 服务器成功返回网页
    • 404 – 请求的网页不存在
    • 503 – 服务器超时

    下面提供 HTTP 状态码的完整列表。点击链接可了解详情。您也可以访问 HTTP 状态码上的 W3C 页获取更多信息

    1xx(临时响应)
    表示临时响应并需要请求者继续执行操作的状态码。

    100(继续) 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
    101(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。

    2xx (成功)

    表示成功处理了请求的状态码。

    200(成功) 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。如果是对您的 robots.txt 文件显示此状态码,则表示 Googlebot 已成功检索到该文件。
    201(已创建) 请求成功并且服务器创建了新的资源。
    202(已接受) 服务器已接受请求,但尚未处理。
    203(非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
    204(无内容) 服务器成功处理了请求,但没有返回任何内容。
    205(重置内容) 服务器成功处理了请求,但没有返回任何内容。与 204 响应不同,此响应要求请求者重置文档视图(例如,清除表单内容以输入新内容)。
    206(部分内容) 服务器成功处理了部分 GET 请求。

    3xx (重定向)
    要完成请求,需要进一步操作。通常,这些状态码用来重定向。Google 建议您在每次请求中使用重定向不要超过 5 次。您可以使用网站管理员工具查看一下 Googlebot 在抓取重定向网页时是否遇到问题。诊断下的网络抓取页列出了由于重定向错误导致 Googlebot 无法抓取的网址。

    300(多种选择) 针对请求,服务器可执行多种操作。服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
    301(永久移动) 请求的网页已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码告诉 Googlebot 某个网页或网站已永久移动到新位置。
    302(临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个网页或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。
    303(查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。对于除 HEAD 之外的所有请求,服务器会自动转到其他位置。
    304(未修改)

    自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。

    如果网页自请求者上次请求后再也没有更改过,您应将服务器配置为返回此响应(称为 If-Modified-Since HTTP 标头)。服务器可以告诉 Googlebot 自从上次抓取后网页没有变更,进而节省带宽和开销。

     

    305(使用代理) 请求者只能使用代理访问请求的网页。如果服务器返回此响应,还表示请求者应使用代理。
    307(临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 <a href=answer.py?answer=>301</a> 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个页面或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。

    4xx(请求错误)
    这些状态码表示请求可能出错,妨碍了服务器的处理。

    400(错误请求) 服务器不理解请求的语法。
    401(未授权) 请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应。
    403(禁止) 服务器拒绝请求。如果您在 Googlebot 尝试抓取您网站上的有效网页时看到此状态码(您可以在 Google 网站管理员工具诊断下的网络抓取页面上看到此信息),可能是您的服务器或主机拒绝了 Googlebot 访问。
    404(未找到)

    服务器找不到请求的网页。例如,对于服务器上不存在的网页经常会返回此代码。

    如果您的网站上没有 robots.txt 文件,而您在 Google 网站管理员工具“诊断”标签的 robots.txt 页上看到此状态码,则这是正确的状态码。但是,如果您有 robots.txt 文件而又看到此状态码,则说明您的 robots.txt 文件可能命名错误或位于错误的位置(该文件应当位于顶级域,名为 robots.txt)。

    如果对于 Googlebot 抓取的网址看到此状态码(在”诊断”标签的 HTTP 错误页面上),则表示 Googlebot 跟随的可能是另一个页面的无效链接(是旧链接或输入有误的链接)。

    405(方法禁用) 禁用请求中指定的方法。
    406(不接受) 无法使用请求的内容特性响应请求的网页。
    407(需要代理授权) 此状态码与 <a href=answer.py?answer=35128>401(未授权)</a>类似,但指定请求者应当授权使用代理。如果服务器返回此响应,还表示请求者应当使用代理。
    408(请求超时) 服务器等候请求时发生超时。
    409(冲突) 服务器在完成请求时发生冲突。服务器必须在响应中包含有关冲突的信息。服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码,以及两个请求的差异列表。
    410(已删除) 如果请求的资源已永久删除,服务器就会返回此响应。该代码与 404(未找到)代码类似,但在资源以前存在而现在不存在的情况下,有时会用来替代 404 代码。如果资源已永久移动,您应使用 301 指定资源的新位置。
    411(需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
    412(未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
    413(请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
    414(请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
    415(不支持的媒体类型) 请求的格式不受请求页面的支持。
    416(请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态码。
    417(未满足期望值) 服务器未满足”期望”请求标头字段的要求。

    5xx(服务器错误)
    这些状态码表示服务器在处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。

    500(服务器内部错误) 服务器遇到错误,无法完成请求。
    501(尚未实施) 服务器不具备完成请求的功能。例如,服务器无法识别请求方法时可能会返回此代码。
    502(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
    503(服务不可用) 服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。
    504(网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
    505(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

     

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,分享一下给大家点击跳转到教程

     

    引用内容源址:

    http://www.jb51.net/article/43143.htm

    http://blog.sina.com.cn/s/blog_4c98b9600100jd4z.html

    http://www.cnblogs.com/shanyou/archive/2012/05/01/2477500.html

    --- end ---

     

    展开全文
  • 本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希望本文对大家...

    本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希望本文对大家学习计算机基础有所帮助!

     

    一. 机器数和真值

    在学习原码, 反码和补码之前, 需要先了解机器数和真值的概念.

    1、机器数

    一个数在计算机中的二进制表示形式,  叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.

    比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。

    那么,这里的 00000011 和 10000011 就是机器数。

    2、真值

    因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。

    例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

     

    二. 原码, 反码, 补码的基础概念和计算方法.

    在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式.

    1. 原码

    原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

    [+1]原 = 0000 0001

    [-1]原 = 1000 0001

    第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:

    [1111 1111 , 0111 1111]

    [-127 , 127]

    原码是人脑最容易理解和计算的表示方式.

    2. 反码

    反码的表示方法是:

    正数的反码是其本身

    负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.

    [+1] = [00000001]原 = [00000001]反

    [-1] = [10000001]原 = [11111110]反

    可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.

    3. 补码

    补码的表示方法是:

    正数的补码就是其本身

    负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

    [+1] = [00000001]原 = [00000001]反 = [00000001]补

    [-1] = [10000001]原 = [11111110]反 = [11111111]补

    对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

     

    三. 为何要使用原码, 反码和补码

    在开始深入学习前, 我的学习建议是先"死记硬背"上面的原码, 反码和补码的表示方式以及计算方法.

    现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同:

    [+1] = [00000001]原 = [00000001]反 = [00000001]补

    所以不需要过多解释. 但是对于负数:

    [-1] = [10000001]原 = [11111110]反 = [11111111]补

    可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?

    首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的尽量简单. 计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.

    于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码:

    计算十进制的表达式: 1-1=0

    1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2

    如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.

    为了解决原码做减法的问题, 出现了反码:

    计算十进制的表达式: 1-1=0

    1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

    发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在"0"这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.

    于是补码的出现, 解决了0的符号以及两个编码的问题:

    1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

    这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:

    (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补

    -1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)

    使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].

    因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

     

    四 原码, 反码, 补码 再深入

    计算机巧妙地把符号位参与运算, 并且将减法变成了加法, 背后蕴含了怎样的数学原理呢?

    将钟表想象成是一个1位的12进制数. 如果当前时间是6点, 我希望将时间设置成4点, 需要怎么做呢?我们可以:

    1. 往回拨2个小时: 6 - 2 = 4

    2. 往前拨10个小时: (6 + 10) mod 12 = 4

    3. 往前拨10+12=22个小时: (6+22) mod 12 =4

    2,3方法中的mod是指取模操作, 16 mod 12 =4 即用16除以12后的余数是4.

    所以钟表往回拨(减法)的结果可以用往前拨(加法)替代!

    现在的焦点就落在了如何用一个正数, 来替代一个负数. 上面的例子我们能感觉出来一些端倪, 发现一些规律. 但是数学是严谨的. 不能靠感觉.

    首先介绍一个数学中相关的概念: 同余

     

    同余的概念

    两个整数a,b,若它们除以整数m所得的余数相等,则称a,b对于模m同余

    记作 a ≡ b (mod m)

    读作 a 与 b 关于模 m 同余。

    举例说明:

    4 mod 12 = 4

    16 mod 12 = 4

    28 mod 12 = 4

    所以4, 16, 28关于模 12 同余.

     

    负数取模

    正数进行mod运算是很简单的. 但是负数呢?

    下面是关于mod运算的数学定义:

    clip_image001

    上面是截图, "取下界"符号找不到如何输入(word中粘贴过来后乱码). 下面是使用"L"和"J"替换上图的"取下界"符号:

    x mod y = x - y L x / y J

    上面公式的意思是:

    x mod y等于 x 减去 y 乘上 x与y的商的下界.

    以 -3 mod 2 举例:

    -3 mod 2

    = -3 - 2xL -3/2 J

    = -3 - 2xL-1.5J

    = -3 - 2x(-2)

    = -3 + 4 = 1

    所以:

    (-2) mod 12 = 12-2=10

    (-4) mod 12 = 12-4 = 8

    (-5) mod 12 = 12 - 5 = 7

     

    开始证明

    再回到时钟的问题上:

    回拨2小时 = 前拨10小时

    回拨4小时 = 前拨8小时

    回拨5小时= 前拨7小时

    注意, 这里发现的规律!

    结合上面学到的同余的概念.实际上:

    (-2) mod 12 = 10

    10 mod 12 = 10

    -2与10是同余的.

    (-4) mod 12 = 8

    8 mod 12 = 8

    -4与8是同余的.

    距离成功越来越近了. 要实现用正数替代负数, 只需要运用同余数的两个定理:

    反身性:

    a ≡ a (mod m)

    这个定理是很显而易见的.

    线性运算定理:

    如果a ≡ b (mod m),c ≡ d (mod m) 那么:

    (1)a ± c ≡ b ± d (mod m)

    (2)a * c ≡ b * d (mod m)

    如果想看这个定理的证明, 请看:http://baike.baidu.com/view/79282.htm

    所以:

    7 ≡ 7 (mod 12)

    (-2) ≡ 10 (mod 12)

    7 -2 ≡ 7 + 10 (mod 12)

    现在我们为一个负数, 找到了它的正数同余数. 但是并不是7-2 = 7+10, 而是 7 -2 ≡ 7 + 10 (mod 12) , 即计算结果的余数相等.

    接下来回到二进制的问题上, 看一下: 2-1=1的问题.

    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原= [0000 0010]反 + [1111 1110]反

    先到这一步, -1的反码表示是1111 1110. 如果这里将[1111 1110]认为是原码, 则[1111 1110]原 = -126, 这里将符号位除去, 即认为是126.

    发现有如下规律:

    (-1) mod 127 = 126

    126 mod 127 = 126

    即:

    (-1) ≡ 126 (mod 127)

    2-1 ≡ 2+126 (mod 127)

    2-1 与 2+126的余数结果是相同的! 而这个余数, 正式我们的期望的计算结果: 2-1=1

    所以说一个数的反码, 实际上是这个数对于一个膜的同余数. 而这个膜并不是我们的二进制, 而是所能表示的最大值! 这就和钟表一样, 转了一圈后总能找到在可表示范围内的一个正确的数值!

    而2+126很显然相当于钟表转过了一轮, 而因为符号位是参与计算的, 正好和溢出的最高位形成正确的运算结果.

    既然反码可以将减法变成加法, 那么现在计算机使用的补码呢? 为什么在反码的基础上加1, 还能得到正确的结果?

    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原 = [0000 0010]补 + [1111 1111]补

    如果把[1111 1111]当成原码, 去除符号位, 则:

    [0111 1111]原 = 127

    其实, 在反码的基础上+1, 只是相当于增加了膜的值:

    (-1) mod 128 = 127

    127 mod 128 = 127

    2-1 ≡ 2+127 (mod 128)

    此时, 表盘相当于每128个刻度转一轮. 所以用补码表示的运算结果最小值和最大值应该是[-128, 128].

    但是由于0的特殊情况, 没有办法表示128, 所以补码的取值范围是[-128, 127]

    本人一直不善于数学, 所以如果文中有不对的地方请大家多多包含, 多多指点!

    作者:张子秋
    出处:http://www.cnblogs.com/zhangziqiu/ 
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    展开全文
  • AutoSAR系列讲解 - 总目录

    万次阅读 多人点赞 2019-07-04 14:40:23
    下面蓝字都是传送门,点击进入即可: 学前必读 AutoSAR系列讲解 - 总目录 AutoSAR系列讲解 - 前言 AutoSAR系列讲解 - 资料下载 AutoSAR系列讲解 - 交流专区 AutoSAR系列讲解 - 思维导图计划 AutoSAR系列讲解 - 行业...

    总目录

    欢迎大家来到雪云飞星的《AutoSAR入门到精通系列讲解》,开始前博主先列出AutoSAR学习的大纲,同时这也可以作为大家学习AutoSAR的参考。下面蓝字都是传送门,点击进入即可:

    学前必读

    AutoSAR系列讲解 - 总目录
    AutoSAR系列讲解 - 前言
    AutoSAR系列讲解 - 资料下载
    AutoSAR系列讲解 - 交流专区
    AutoSAR系列讲解 - 思维导图计划
    AutoSAR系列讲解 - 行业统计

    一、AutoSAR入门篇

    1、AutoSAR的简介和目标(Overview)

    AutoSAR系列讲解(入门篇)1.1-AutoSAR发展
    AutoSAR系列讲解(入门篇)1.2-AutoSAR概述

    2、AutoSAR的应用层(AppL)

    AutoSAR系列讲解(入门篇)2.1-AppL概述
    AutoSAR系列讲解(入门篇)2.2-SWC的类型
    AutoSAR系列讲解(入门篇)2.3-Ports的类型
    AutoSAR系列讲解(入门篇)2.4-Runnables可运行实体

    3、AutoSAR的实时运行环境(RTE)

    AutoSAR系列讲解(入门篇)3.1-RTE概述
    AutoSAR系列讲解(入门篇)3.2-RTE对Runnables的运行支撑
    AutoSAR系列讲解(入门篇)3.3-RTE对Ports的支撑(上)
    AutoSAR系列讲解(入门篇)3.4-RTE对Ports的支撑(下)
    AutoSAR系列讲解(入门篇)3.5-RTE对数据一致性的管理
    AutoSAR系列讲解(入门篇)3.6-RTE与Interface接口

    4、AutoSAR的基础软件层(BSW)

    AutoSAR系列讲解(入门篇)4.1-BSW概述
    AutoSAR系列讲解(入门篇)4.2-BSW的I/O功能
    AutoSAR系列讲解(入门篇)4.3-BSW的Communication功能
    AutoSAR系列讲解(入门篇)4.4-BSW的Memory功能
    AutoSAR系列讲解(入门篇)4.5-BSW的Mode Management功能
    AutoSAR系列讲解(入门篇)4.6-BSW的Watchdog功能
    AutoSAR系列讲解(入门篇)4.7-BSW的Diagnostics功能
    AutoSAR系列讲解(入门篇)4.8-BSW的OS功能
    AutoSAR系列讲解(入门篇)4.9-BSW小结

    5、AutoSAR的方法论(Methodology)

    AutoSAR系列讲解(入门篇)5.1-方法论概述
    AutoSAR系列讲解(入门篇)5.2-描述文件
    AutoSAR系列讲解(入门篇)5.3-ECUEX文件
    AutoSAR系列讲解(入门篇)5.4-ECU的项目流程

    6、补充

    AutoSAR系列讲解(入门篇)6.1-Vector的工具链简介
    AutoSAR系列讲解(入门篇)6.2-Adaptive AUTOSAR简介

    二、AutoSAR实践篇

    7、软件组件(Software Compenonts)

    AutoSAR系列讲解(实践篇)7.1-DaVinci Developer使用初探
    AutoSAR系列讲解(实践篇)7.2-AppL在Dev中的配置(上)
    AutoSAR系列讲解(实践篇)7.3-AppL在Dev中的配置(下)
    AutoSAR系列讲解(实践篇)7.4-实验:配置SWC&RTE(上)
    AutoSAR系列讲解(实践篇)7.5-OS原理进阶(上)
    AutoSAR系列讲解(实践篇)7.6-OS原理进阶(下)
    AutoSAR系列讲解(实践篇)7.7-实验:配置SWC&RTE(下)

    8、I/O抽象(I/O Abstraction)

    AutoSAR系列讲解(实践篇)8.1-IO架构
    AutoSAR系列讲解(实践篇)8.2-IO相关驱动(上)
    AutoSAR系列讲解(实践篇)8.3-IO相关驱动(中)
    AutoSAR系列讲解(实践篇)8.4-IO相关驱动(下)
    AutoSAR系列讲解(实践篇)8.5-C/S原理进阶
    AutoSAR系列讲解(实践篇)8.6-实验:配置I/O

    9、通信(Communication)

    AutoSAR系列讲解(实践篇)9.1-协议数据单元PDU
    AutoSAR系列讲解(实践篇)9.2-信息发送的Filter机制
    AutoSAR系列讲解(实践篇)9.3-通信相关机制(上)
    AutoSAR系列讲解(实践篇)9.4-通信相关机制(下)
    AutoSAR系列讲解(实践篇)9.5-通信的数据映射
    AutoSAR系列讲解(实践篇)9.6-实验:配置通信

    10、模式管理(Mode Management)

    AutoSAR系列讲解(实践篇)10.1-模式管理概述
    AutoSAR系列讲解(实践篇)10.2-Ecu的上下电流程
    AutoSAR系列讲解(实践篇)10.3-BswM配置
    AutoSAR系列讲解(实践篇)10.4-网络管理
    AutoSAR系列讲解(实践篇)10.5-通信管理模块
    AutoSAR系列讲解(实践篇)10.6-模式管理进阶
    AutoSAR系列讲解(实践篇)10.7-服务映射
    AutoSAR系列讲解(实践篇)10.8-实验:模式管理

    11、存储抽象(Memory Abstraction)

    AutoSAR系列讲解(实践篇)11.1-BSW中的存储模块
    AutoSAR系列讲解(实践篇)11.2-存储处理与Block
    AutoSAR系列讲解(实践篇)11.3-NVRAM Block的配置
    AutoSAR系列讲解(实践篇)11.4-NvBlockSwComponents(上)
    AutoSAR系列讲解(实践篇)11.5-NvBlockSwComponents(下)
    AutoSAR系列讲解(实践篇)11.6-服务映射(自顶向下)
    AutoSAR系列讲解(实践篇)11.7-实验:配置存储

    12、诊断(Diagnostics)

    AutoSAR系列讲解(实践篇)12.1-Diagnostics简介
    AutoSAR系列讲解(实践篇)12.2-CanTP
    AutoSAR系列讲解(实践篇)12.3-Dcm
    AutoSAR系列讲解(实践篇)12.4-Fim
    AutoSAR系列讲解(实践篇)12.5-Dem
    AutoSAR系列讲解(实践篇)12.6-实验:配置诊断

    三、AutoSAR深入篇

    13、综合实验

    AutoSAR系列讲解(深入篇)13.1-闪烁一颗LED灯 1
    AutoSAR系列讲解(深入篇)13.2-闪烁一颗LED灯 2
    AutoSAR系列讲解(深入篇)13.3-闪烁一颗LED灯 3
    AutoSAR系列讲解(深入篇)13.4-闪烁一颗LED灯 4
    AutoSAR系列讲解(深入篇)13.5-闪烁一颗LED灯 5
    AutoSAR系列讲解(深入篇)13.6-闪烁一颗LED灯 6

    14、Tricore Mcal配置专题(EB)

    AutoSAR系列讲解(深入篇)14.1-EB Tresos使用初探
    AutoSAR系列讲解(深入篇)14.2-Mcal Port配置
    AutoSAR系列讲解(深入篇)14.3-Mcal Dio配置
    AutoSAR系列讲解(深入篇)14.4-Mcal Dio代码分析(上)
    AutoSAR系列讲解(深入篇)14.5-Mcal Dio代码分析(下)
    AutoSAR系列讲解(深入篇)14.6-Mcal Mcu时钟的配置
    AutoSAR系列讲解(深入篇)14.7-Mcal Adc配置(上)
    AutoSAR系列讲解(深入篇)14.8-Mcal Adc配置(下)
    AutoSAR系列讲解(深入篇)14.9-Mcal Gtm的Tom配置(上)
    AutoSAR系列讲解(深入篇)14.10-Mcal Gtm的Tom配置(下)

    15、补充杂记(不定期更新)

    AutoSAR系列讲解 - AutoSAR标准文档概览(上)
    AutoSAR系列讲解 - AutoSAR标准文档概览(下)
    AutoSAR系列讲解 - 有工具没有项目如何练习AutoSAR?
    AutoSAR系列讲解 - 基于Tasking工程的代码集成

    展开全文
  • 深入浅出的讲解傅里叶变换(真正的通俗易懂)

    万次阅读 多人点赞 2016-07-04 00:40:51
    我保证这篇文章和你以前看过的所有文章都不同,这是12年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者……  这篇文章的核心思想就是:  要让读者在不看任何数学公式的...
     
     
    原文出处: 韩昊   
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    作 者:韩 昊
    知 乎:Heinrich
    微 博:@花生油工人
    知乎专栏:与时间无关的故事
     
    谨以此文献给大连海事大学的吴楠老师,柳晓鸣老师,王新年老师以及张晶泊老师。
     
    转载的同学请保留上面这句话,谢谢。如果还能保留文章来源就更感激不尽了。

    我保证这篇文章和你以前看过的所有文章都不同,这是 2012 年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者……

    这篇文章的核心思想就是:

    要让读者在不看任何数学公式的情况下理解傅里叶分析。

    傅里叶分析不仅仅是一个数学工具,更是一种可以彻底颠覆一个人以前世界观的思维模式。但不幸的是,傅里叶分析的公式看起来太复杂了,所以很多大一新生上来就懵圈并从此对它深恶痛绝。老实说,这么有意思的东西居然成了大学里的杀手课程,不得不归咎于编教材的人实在是太严肃了。(您把教材写得好玩一点会死吗?会死吗?)所以我一直想写一个有意思的文章来解释傅里叶分析,有可能的话高中生都能看懂的那种。所以,不管读到这里的您从事何种工作,我保证您都能看懂,并且一定将体会到通过傅里叶分析看到世界另一个样子时的快感。至于对于已经有一定基础的朋友,也希望不要看到会的地方就急忙往后翻,仔细读一定会有新的发现。

    ————以上是定场诗————

    下面进入正题:

    抱歉,还是要啰嗦一句:其实学习本来就不是易事,我写这篇文章的初衷也是希望大家学习起来更加轻松,充满乐趣。但是千万!千万不要把这篇文章收藏起来,或是存下地址,心里想着:以后有时间再看。这样的例子太多了,也许几年后你都没有再打开这个页面。无论如何,耐下心,读下去。这篇文章要比读课本要轻松、开心得多……

    一、什么是频域

    从我们出生,我们看到的世界都以时间贯穿,股票的走势、人的身高、汽车的轨迹都会随着时间发生改变。这种以时间作为参照来观察动态世界的方法我们称其为时域分析。而我们也想当然的认为,世间万物都在随着时间不停的改变,并且永远不会静止下来。但如果我告诉你,用另一种方法来观察世界的话,你会发现世界是永恒不变的,你会不会觉得我疯了?我没有疯,这个静止的世界就叫做频域。

    先举一个公式上并非很恰当,但意义上再贴切不过的例子:

    在你的理解中,一段音乐是什么呢?

    这是我们对音乐最普遍的理解,一个随着时间变化的震动。但我相信对于乐器小能手们来说,音乐更直观的理解是这样的:


    好的!下课,同学们再见。

    是的,其实这一段写到这里已经可以结束了。上图是音乐在时域的样子,而下图则是音乐在频域的样子。所以频域这一概念对大家都从不陌生,只是从来没意识到而已。

    现在我们可以回过头来重新看看一开始那句痴人说梦般的话:世界是永恒的。

    将以上两图简化:

    时域:


    频域:

    在时域,我们观察到钢琴的琴弦一会上一会下的摆动,就如同一支股票的走势;而在频域,只有那一个永恒的音符。

    所以

    你眼中看似落叶纷飞变化无常的世界,实际只是躺在上帝怀中一份早已谱好的乐章。

    抱歉,这不是一句鸡汤文,而是黑板上确凿的公式:傅里叶同学告诉我们,任何周期函数,都可以看作是不同振幅,不同相位正弦波的叠加。在第一个例子里我们可以理解为,利用对不同琴键不同力度,不同时间点的敲击,可以组合出任何一首乐曲。

    而贯穿时域与频域的方法之一,就是传中说的傅里叶分析。傅里叶分析可分为傅里叶级数(Fourier Serie)和傅里叶变换(Fourier Transformation),我们从简单的开始谈起。

     

    二、傅里叶级数(Fourier Series)的频谱

    还是举个栗子并且有图有真相才好理解。

    如果我说我能用前面说的正弦曲线波叠加出一个带 90 度角的矩形波来,你会相信吗?你不会,就像当年的我一样。但是看看下图:

    第一幅图是一个郁闷的正弦波 cos(x)

    第二幅图是 2 个卖萌的正弦波的叠加 cos (x) +a.cos (3x)

    第三幅图是 4 个发春的正弦波的叠加

    第四幅图是 10 个便秘的正弦波的叠加

    随着正弦波数量逐渐的增长,他们最终会叠加成一个标准的矩形,大家从中体会到了什么道理?

    (只要努力,弯的都能掰直!)

    随着叠加的递增,所有正弦波中上升的部分逐渐让原本缓慢增加的曲线不断变陡,而所有正弦波中下降的部分又抵消了上升到最高处时继续上升的部分使其变为水平线。一个矩形就这么叠加而成了。但是要多少个正弦波叠加起来才能形成一个标准 90 度角的矩形波呢?不幸的告诉大家,答案是无穷多个。(上帝:我能让你们猜着我?)

    不仅仅是矩形,你能想到的任何波形都是可以如此方法用正弦波叠加起来的。这是没有接触过傅里叶分析的人在直觉上的第一个难点,但是一旦接受了这样的设定,游戏就开始有意思起来了。

    还是上图的正弦波累加成矩形波,我们换一个角度来看看:

    在这几幅图中,最前面黑色的线就是所有正弦波叠加而成的总和,也就是越来越接近矩形波的那个图形。而后面依不同颜色排列而成的正弦波就是组合为矩形波的各个分量。这些正弦波按照频率从低到高从前向后排列开来,而每一个波的振幅都是不同的。一定有细心的读者发现了,每两个正弦波之间都还有一条直线,那并不是分割线,而是振幅为 0 的正弦波!也就是说,为了组成特殊的曲线,有些正弦波成分是不需要的。

    这里,不同频率的正弦波我们成为频率分量。

    好了,关键的地方来了!!

    如果我们把第一个频率最低的频率分量看作“1”,我们就有了构建频域的最基本单元。

    对于我们最常见的有理数轴,数字“1”就是有理数轴的基本单元。

    (好吧,数学称法为——基。在那个年代,这个字还没有其他奇怪的解释,后面还有正交基这样的词汇我会说吗?)

    时域的基本单元就是“1 秒”,如果我们将一个角频率为\omega_{0}的正弦波 cos(\omega_{0}t)看作基础,那么频域的基本单元就是\omega_{0}

    有了“1”,还要有“0”才能构成世界,那么频域的“0”是什么呢?cos(0t)就是一个周期无限长的正弦波,也就是一条直线!所以在频域,0 频率也被称为直流分量,在傅里叶级数的叠加中,它仅仅影响全部波形相对于数轴整体向上或是向下而不改变波的形状。

    接下来,让我们回到初中,回忆一下已经死去的八戒,啊不,已经死去的老师是怎么定义正弦波的吧。

    正弦波就是一个圆周运动在一条直线上的投影。所以频域的基本单元也可以理解为一个始终在旋转的圆

    想看动图的同学请戳这里:

    File:Fourier series square wave circles animation.gif

    File:Fourier series sawtooth wave circles animation.gif

    以及这里:

    File:Fourier series sawtooth wave circles animation.gif

    点出去的朋友不要被 wiki 拐跑了,wiki 写的哪有这里的文章这么没节操是不是。

    介绍完了频域的基本组成单元,我们就可以看一看一个矩形波,在频域里的另一个模样了:


    这是什么奇怪的东西?

    这就是矩形波在频域的样子,是不是完全认不出来了?教科书一般就给到这里然后留给了读者无穷的遐想,以及无穷的吐槽,其实教科书只要补一张图就足够了:频域图像,也就是俗称的频谱,就是——

    再清楚一点:

    可以发现,在频谱中,偶数项的振幅都是0,也就对应了图中的彩色直线。振幅为 0 的正弦波。

    File:Fourier series and transform.gif

    动图请戳:

    File:Fourier series and transform.gif

    老实说,在我学傅里叶变换时,维基的这个图还没有出现,那时我就想到了这种表达方法,而且,后面还会加入维基没有表示出来的另一个谱——相位谱。

    但是在讲相位谱之前,我们先回顾一下刚刚的这个例子究竟意味着什么。记得前面说过的那句“世界是静止的”吗?估计好多人对这句话都已经吐槽半天了。想象一下,世界上每一个看似混乱的表象,实际都是一条时间轴上不规则的曲线,但实际这些曲线都是由这些无穷无尽的正弦波组成。我们看似不规律的事情反而是规律的正弦波在时域上的投影,而正弦波又是一个旋转的圆在直线上的投影。那么你的脑海中会产生一个什么画面呢?

    我们眼中的世界就像皮影戏的大幕布,幕布的后面有无数的齿轮,大齿轮带动小齿轮,小齿轮再带动更小的。在最外面的小齿轮上有一个小人——那就是我们自己。我们只看到这个小人毫无规律的在幕布前表演,却无法预测他下一步会去哪。而幕布后面的齿轮却永远一直那样不停的旋转,永不停歇。这样说来有些宿命论的感觉。说实话,这种对人生的描绘是我一个朋友在我们都是高中生的时候感叹的,当时想想似懂非懂,直到有一天我学到了傅里叶级数……

    三、傅里叶级数(Fourier Series)的相位谱

    上一章的关键词是:从侧面看。这一章的关键词是:从下面看。

    在这一章最开始,我想先回答很多人的一个问题:傅里叶分析究竟是干什么用的?这段相对比较枯燥,已经知道了的同学可以直接跳到下一个分割线。

    先说一个最直接的用途。无论听广播还是看电视,我们一定对一个词不陌生——频道。频道频道,就是频率的通道,不同的频道就是将不同的频率作为一个通道来进行信息传输。下面大家尝试一件事:

    先在纸上画一个sin(x),不一定标准,意思差不多就行。不是很难吧。

    好,接下去画一个sin(3x)+sin(5x)的图形。

    别说标准不标准了,曲线什么时候上升什么时候下降你都不一定画的对吧?

    好,画不出来不要紧,我把sin(3x)+sin(5x)的曲线给你,但是前提是你不知道这个曲线的方程式,现在需要你把sin(5x)给我从图里拿出去,看看剩下的是什么。这基本是不可能做到的。

    但是在频域呢?则简单的很,无非就是几条竖线而已。

    所以很多在时域看似不可能做到的数学操作,在频域相反很容易。这就是需要傅里叶变换的地方。尤其是从某条曲线中去除一些特定的频率成分,这在工程上称为滤波,是信号处理最重要的概念之一,只有在频域才能轻松的做到。

    再说一个更重要,但是稍微复杂一点的用途——求解微分方程。(这段有点难度,看不懂的可以直接跳过这段)微分方程的重要性不用我过多介绍了。各行各业都用的到。但是求解微分方程却是一件相当麻烦的事情。因为除了要计算加减乘除,还要计算微分积分。而傅里叶变换则可以让微分和积分在频域中变为乘法和除法,大学数学瞬间变小学算术有没有。

    傅里叶分析当然还有其他更重要的用途,我们随着讲随着提。

    ————————————————————————————————————

    下面我们继续说相位谱:

    通过时域到频域的变换,我们得到了一个从侧面看的频谱,但是这个频谱并没有包含时域中全部的信息。因为频谱只代表每一个对应的正弦波的振幅是多少,而没有提到相位。基础的正弦波A.sin(wt+θ)中,振幅,频率,相位缺一不可,不同相位决定了波的位置,所以对于频域分析,仅仅有频谱(振幅谱)是不够的,我们还需要一个相位谱。那么这个相位谱在哪呢?我们看下图,这次为了避免图片太混论,我们用7个波叠加的图。

    鉴于正弦波是周期的,我们需要设定一个用来标记正弦波位置的东西。在图中就是那些小红点。小红点是距离频率轴最近的波峰,而这个波峰所处的位置离频率轴有多远呢?为了看的更清楚,我们将红色的点投影到下平面,投影点我们用粉色点来表示。当然,这些粉色的点只标注了波峰距离频率轴的距离,并不是相位。


    这里需要纠正一个概念:时间差并不是相位差。如果将全部周期看作2Pi或者360度的话,相位差则是时间差在一个周期中所占的比例。我们将时间差除周期再乘2Pi,就得到了相位差。

    在完整的立体图中,我们将投影得到的时间差依次除以所在频率的周期,就得到了最下面的相位谱。所以,频谱是从侧面看,相位谱是从下面看。下次偷看女生裙底被发现的话,可以告诉她:“对不起,我只是想看看你的相位谱。”

    注意到,相位谱中的相位除了0,就是Pi。因为cos(t+Pi)=-cos(t),所以实际上相位为Pi的波只是上下翻转了而已。对于周期方波的傅里叶级数,这样的相位谱已经是很简单的了。另外值得注意的是,由于cos(t+2Pi)=cos(t),所以相位差是周期的,pi和3pi,5pi,7pi都是相同的相位。人为定义相位谱的值域为(-pi,pi],所以图中的相位差均为Pi。

    最后来一张大集合:

    四、傅里叶变换(Fourier Tranformation)

    相信通过前面三章,大家对频域以及傅里叶级数都有了一个全新的认识。但是文章在一开始关于钢琴琴谱的例子我曾说过,这个栗子是一个公式错误,但是概念典型的例子。所谓的公式错误在哪里呢?

    傅里叶级数的本质是将一个周期的信号分解成无限多分开的(离散的)正弦波,但是宇宙似乎并不是周期的。曾经在学数字信号处理的时候写过一首打油诗:

    往昔连续非周期,

    回忆周期不连续,

    任你ZT、DFT,

    还原不回去。

    (请无视我渣一样的文学水平……)

    在这个世界上,有的事情一期一会,永不再来,并且时间始终不曾停息地将那些刻骨铭心的往昔连续的标记在时间点上。但是这些事情往往又成为了我们格外宝贵的回忆,在我们大脑里隔一段时间就会周期性的蹦出来一下,可惜这些回忆都是零散的片段,往往只有最幸福的回忆,而平淡的回忆则逐渐被我们忘却。因为,往昔是一个连续的非周期信号,而回忆是一个周期离散信号。

    是否有一种数学工具将连续非周期信号变换为周期离散信号呢?抱歉,真没有。

    比如傅里叶级数,在时域是一个周期且连续的函数,而在频域是一个非周期离散的函数。这句话比较绕嘴,实在看着费事可以干脆回忆第一章的图片。

    而在我们接下去要讲的傅里叶变换,则是将一个时域非周期的连续信号,转换为一个在频域非周期的连续信号。

    算了,还是上一张图方便大家理解吧:

    或者我们也可以换一个角度理解:傅里叶变换实际上是对一个周期无限大的函数进行傅里叶变换。

    所以说,钢琴谱其实并非一个连续的频谱,而是很多在时间上离散的频率,但是这样的一个贴切的比喻真的是很难找出第二个来了。

    因此在傅里叶变换在频域上就从离散谱变成了连续谱。那么连续谱是什么样子呢?

    你见过大海么?

    为了方便大家对比,我们这次从另一个角度来看频谱,还是傅里叶级数中用到最多的那幅图,我们从频率较高的方向看。

    以上是离散谱,那么连续谱是什么样子呢?

    尽情的发挥你的想象,想象这些离散的正弦波离得越来越近,逐渐变得连续……

    直到变得像波涛起伏的大海:

    很抱歉,为了能让这些波浪更清晰的看到,我没有选用正确的计算参数,而是选择了一些让图片更美观的参数,不然这图看起来就像屎一样了。

    不过通过这样两幅图去比较,大家应该可以理解如何从离散谱变成了连续谱的了吧?原来离散谱的叠加,变成了连续谱的累积。所以在计算上也从求和符号变成了积分符号。

    不过,这个故事还没有讲完,接下去,我保证让你看到一幅比上图更美丽壮观的图片,但是这里需要介绍到一个数学工具才能然故事继续,这个工具就是——

     

    五、宇宙耍帅第一公式:欧拉公式

    虚数i这个概念大家在高中就接触过,但那时我们只知道它是-1 的平方根,可是它真正的意义是什么呢?


    这里有一条数轴,在数轴上有一个红色的线段,它的长度是1。当它乘以 3 的时候,它的长度发生了变化,变成了蓝色的线段,而当它乘以-1 的时候,就变成了绿色的线段,或者说线段在数轴上围绕原点旋转了 180 度。

    我们知道乘-1 其实就是乘了两次 i 使线段旋转了 180 度,那么乘一次 i 呢——答案很简单——旋转了 90 度。

    同时,我们获得了一个垂直的虚数轴。实数轴与虚数轴共同构成了一个复数的平面,也称复平面。这样我们就了解到,乘虚数i的一个功能——旋转。

    现在,就有请宇宙第一耍帅公式欧拉公式隆重登场——


    这个公式在数学领域的意义要远大于傅里叶分析,但是乘它为宇宙第一耍帅公式是因为它的特殊形式——当x等于 Pi 的时候。


    经常有理工科的学生为了跟妹子表现自己的学术功底,用这个公式来给妹子解释数学之美:”石榴姐你看,这个公式里既有自然底数e,自然数 1 和0,虚数i还有圆周率 pi,它是这么简洁,这么美丽啊!“但是姑娘们心里往往只有一句话:”臭屌丝……“

    这个公式关键的作用,是将正弦波统一成了简单的指数形式。我们来看看图像上的涵义:

    欧拉公式所描绘的,是一个随着时间变化,在复平面上做圆周运动的点,随着时间的改变,在时间轴上就成了一条螺旋线。如果只看它的实数部分,也就是螺旋线在左侧的投影,就是一个最基础的余弦函数。而右侧的投影则是一个正弦函数。

    关于复数更深的理解,大家可以参考:

    复数的物理意义是什么?

    这里不需要讲的太复杂,足够让大家理解后面的内容就可以了。

     

    六、指数形式的傅里叶变换

    有了欧拉公式的帮助,我们便知道:正弦波的叠加,也可以理解为螺旋线的叠加在实数空间的投影。而螺旋线的叠加如果用一个形象的栗子来理解是什么呢?

      光波

    高中时我们就学过,自然光是由不同颜色的光叠加而成的,而最著名的实验就是牛顿师傅的三棱镜实验:

    所以其实我们在很早就接触到了光的频谱,只是并没有了解频谱更重要的意义。

    但不同的是,傅里叶变换出来的频谱不仅仅是可见光这样频率范围有限的叠加,而是频率从 0 到无穷所有频率的组合。

    这里,我们可以用两种方法来理解正弦波:

    第一种前面已经讲过了,就是螺旋线在实轴的投影。

    另一种需要借助欧拉公式的另一种形式去理解:

    e^{it}=cos (t) +i.sin (t)
    e^{-it}=cos (t)-i.sin (t)

    将以上两式相加再除2,得到:

    这个式子可以怎么理解呢?

    我们刚才讲过,e^(it)可以理解为一条逆时针旋转的螺旋线,那么e^(-it)则可以理解为一条顺时针旋转的螺旋线。而 cos (t)则是这两条旋转方向不同的螺旋线叠加的一半,因为这两条螺旋线的虚数部分相互抵消掉了!

    举个例子的话,就是极化方向不同的两束光波,磁场抵消,电场加倍。

    这里,逆时针旋转的我们称为正频率,而顺时针旋转的我们称为负频率(注意不是复频率)。

    好了,刚才我们已经看到了大海——连续的傅里叶变换频谱,现在想一想,连续的螺旋线会是什么样子:

    想象一下再往下翻:

    是不是很漂亮?

    你猜猜,这个图形在时域是什么样子?

    哈哈,是不是觉得被狠狠扇了一个耳光。数学就是这么一个把简单的问题搞得很复杂的东西。

    顺便说一句,那个像大海螺一样的图,为了方便观看,我仅仅展示了其中正频率的部分,负频率的部分没有显示出来。

    如果你认真去看,海螺图上的每一条螺旋线都是可以清楚的看到的,每一条螺旋线都有着不同的振幅(旋转半径),频率(旋转周期)以及相位。而将所有螺旋线连成平面,就是这幅海螺图了。

    好了,讲到这里,相信大家对傅里叶变换以及傅里叶级数都有了一个形象的理解了,我们最后用一张图来总结一下:

    好了,傅里叶的故事终于讲完了,下面来讲讲我的故事:

    这篇文章第一次被卸下来的地方你们绝对猜不到在哪,是在一张高数考试的卷子上。当时为了刷分,我重修了高数(上),但是后来时间紧压根没复习,所以我就抱着裸考的心态去了考场。但是到了考场我突然意识到,无论如何我都不会比上次考的更好了,所以干脆写一些自己对于数学的想法吧。于是用了一个小时左右的时间在试卷上洋洋洒洒写了本文的第一草稿。

    你们猜我的了多少分?

    6 分

    没错,就是这个数字。而这 6 分的成绩是因为最后我实在无聊,把选择题全部填上了C,应该是中了两道,得到了这宝贵的 6 分。说真的,我很希望那张卷子还在,但是应该不太可能了。

    那么你们猜猜我第一次信号与系统考了多少分呢?

    45 分

    没错,刚刚够参加补考的。但是我心一横没去考,决定重修。因为那个学期在忙其他事情,学习真的就抛在脑后了。但是我知道这是一门很重要的课,无论如何我要吃透它。说真的,信号与系统这门课几乎是大部分工科课程的基础,尤其是通信专业。

    在重修的过程中,我仔细分析了每一个公式,试图给这个公式以一个直观的理解。虽然我知道对于研究数学的人来说,这样的学习方法完全没有前途可言,因为随着概念愈加抽象,维度越来越高,这种图像或者模型理解法将完全丧失作用。但是对于一个工科生来说,足够了。

    后来来了德国,这边学校要求我重修信号与系统时,我彻底无语了。但是没办法,德国人有时对中国人就是有种藐视,觉得你的教育不靠谱。所以没办法,再来一遍吧。

    这次,我考了满分,而及格率只有一半。

    老实说,数学工具对于工科生和对于理科生来说,意义是完全不同的。工科生只要理解了,会用,会查,就足够了。但是很多高校却将这些重要的数学课程教给数学系的老师去教。这样就出现一个问题,数学老师讲得天花乱坠,又是推理又是证明,但是学生心里就只有一句话:学这货到底干嘛用的?

    缺少了目标的教育是彻底的失败。

    在开始学习一门数学工具的时候,学生完全不知道这个工具的作用,现实涵义。而教材上有只有晦涩难懂,定语就二十几个字的概念以及看了就眼晕的公式。能学出兴趣来就怪了!

    好在我很幸运,遇到了大连海事大学的吴楠老师。他的课全程来看是两条线索,一条从上而下,一条从下而上。先将本门课程的意义,然后指出这门课程中会遇到哪样的问题,让学生知道自己学习的某种知识在现实中扮演的角色。然后再从基础讲起,梳理知识树,直到延伸到另一条线索中提出的问题,完美的衔接在一起!

    这样的教学模式,我想才是大学里应该出现的。

    最后,写给所有给我点赞并留言的同学。真的谢谢大家的支持,也很抱歉不能一一回复。因为知乎专栏的留言要逐次加载,为了看到最后一条要点很多次加载。当然我都坚持看完了,只是没办法一一回复。

    本文只是介绍了一种对傅里叶分析新颖的理解方法,对于求学,还是要踏踏实实弄清楚公式和概念,学习,真的没有捷径。但至少通过本文,我希望可以让这条漫长的路变得有意思一些。

    最后,祝大家都能在学习中找到乐趣…

    展开全文
  • 动画:用动画给女朋友讲解 TCP 四次分手过程

    万次阅读 多人点赞 2019-10-21 07:57:56
    大家好,我们又见面了,做为一个业余的动画师,上次的用动画的形式讲解 TCP 三次握手过程再各大平台收到了广大读者的喜爱,说文章有趣、有货、有内容,也受到了很多读者的关注。很多读者留言说什么时候用动画讲一讲 ...
  • #!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Time : 2019/1/21 21:06 # @Author : Arrow and Bullet # @FileName: gradient_descent.py # @Software: PyCharm ... from numpy import * ...# 数据集大小 即20个数据...
  • Nacos教程_4 配置讲解

    万次阅读 2021-01-14 14:33:39
    配置讲解4.1 dataid 配置讲解4.2 实现自动装填 4. 配置讲解 4.1 dataid 配置讲解 在 Nacos Spring Cloud 中,dataId 的完整格式如下: ${prefix}-${spring.profiles.active}.${file-extension} prefix 默认为 ...
  • ServletConfig讲解

    万次阅读 多人点赞 2018-07-16 16:05:18
    一、ServletConfig讲解 1.1、配置Servlet初始化参数  在Servlet的配置文件web.xml中,可以使用一个或多个&lt;init-param&gt;标签为servlet配置一些初始化参数。 例如: 1 &lt;servlet&gt; ...
  • 动态规划之01背包问题(最易理解的讲解

    万次阅读 多人点赞 2012-07-06 17:09:37
    01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻。 01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi...
  • Nacos教程_2 讲解

    万次阅读 2021-01-14 14:31:28
    讲解2.1 入门流程发布配置添加依赖main 函数远程获取结果2.2 配置管理1) 命名空间2) 监听3) 登录管理 2. 讲解 2.1 入门流程 发布配置 添加依赖 版本的话,和nacos 页面版本,尽量一致。现在版本在2.0 <?xml ...
  • JAVAEE习题讲解

    千人学习 2019-07-23 00:05:02
    本课程从理论和实战两方面讲解了web前端、数据库和JAVA等方面的常见习题,大家既可以作为自己平日的复习使用,也可以作用面试前的参考题目。 本课程目前公开的是一部分课程,会随着课程的延申陆续公开其他试题的...
  • ThreadLocal详细讲解

    万次阅读 2021-01-06 17:51:20
    标题ThreadLocal详细讲解(小白都能看懂) 一、ThreadLocal的作用: 我初始化一个ThreadLocal变量target,初始值即为null; 在进程1里,我将它设为1; 在进程2里,我获取这个初始值,他还是null,同时我将它设成3; ...
  • 基础算法讲解

    千人学习 2019-03-11 16:09:18
    备战编程比赛,算法基础讲解
  • 五笔字根表口诀的通俗易懂讲解

    万次阅读 多人点赞 2018-12-13 09:54:50
    1 先来讲解独立字。 独立字就是不用字根就可以输出的汉字,独立字包含一级简码,按键字两种。 一级简码:按一个字母一次,就可以输出一个汉字,就叫做一级简码。 比如:L=国,K=中,J=是。 一级简码输出的规则...
  • 本篇主要以图文讲解 —— 如何导入系统外部项目。
  • c语言例题讲解

    千次阅读 多人点赞 2020-05-25 15:37:47
    这是基于我之前发的《c语言快速入门》的强化,适合对c语言感兴趣的、升本、接本、插本、考研等等人群。 干货全拿走,来学习吧~ 第1集 编程讲解第1集(一共15集) ...编程讲解第2集(一共15集...编程讲解第8集(一...
  • DOS常用命令详细讲解

    千次下载 热门讨论 2013-08-20 15:52:08
    DOS常用命令详细讲解。我觉得很好,对学习DOS命令有帮助。
  • 团队分区讲解|分区讲解技术对比

    千次阅读 2020-08-11 16:36:36
    近年来,分区讲解系统已经被大多数景区、博物馆、企业展厅普遍采用,分区讲解系统也在不断的的升级,那么历代的分区讲解技术又有哪些区别呢? 传统分区讲解主要采用 RFID,红外,蓝牙实现,通常采用入口感应器,...
  • Java经典算法讲解

    万人学习 2015-05-01 04:13:33
    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计...算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。
  • 第三个部分是 Spring Boot 商城项目功能的讲解,让大家实际操作并实践上手一个大型的线上商城项目,并学习到一定的开发经验以及其中的开发技巧。 商城项目所涉及的功能结构图整理如下:   课程特色   &...
  • Codis实战讲解

    千人学习 2017-01-01 20:26:22
    Codis是由豌豆荚推出的一款高性能的Redis集群架构设计方案,利用Codis可以有效的整合所有Redis可用资源,并且... 在本课程中将为读者讲解Codis的配置以及高可用架构实现(HAProxy、Keepalived)。官方QQ群:612148723。
  • 计算机网络——子网划分(内含习题讲解

    万次阅读 多人点赞 2019-07-01 10:32:56
    PS:(习题是由b站--计算机网络-谢希仁第7版-河南科技大学 视频中获得) 前情提要:我们在这之前已经学过了两级的IP地址: 但是两级的IP地址有很多弊端,所以我们将要学习三级IP地址,也就是两级IP地址的升级版 ...
  • 蓝桥杯历届真题讲解

    千人学习 2019-03-12 18:01:42
    应某大学邀请,为同学们做算法题目的讲解,蓝桥杯的题目很好,很适合学习编程的同学们,把这些算法掌握好,为将来的软件开发打下坚实的基础。
  • ASP入门知识点讲解

    千人学习 2018-08-17 15:36:43
    从零基础知识开始讲解ASP的各类基础语法和IIS服务器的搭建,ASP作为你的入门级的编程语言,是你最方便的选择;学完asp的基础,我 们就可以尝试是做公司的网站,一些小型的商城系统,小型的微信/小程序网站、商城的...
  • Modbus协议讲解及实现

    千人学习 2020-03-23 20:30:54
    本课程不同于以往市面课程只是协议讲解无实现代码,而是采用讲解与实践并重的方式,结合STM32F103ZET6开发板进行手把手编程实践,十分有利于初学者学习。 涵盖了学习者在Modbus协议方面会遇到的方方面面的问题,是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 498,309
精华内容 199,323
关键字:

讲解