diff --git a/content/about.md b/content/about.md index 4c78698..b0c15f0 100644 --- a/content/about.md +++ b/content/about.md @@ -4,13 +4,13 @@ My name is Nir Galon, I'm a geek who always want to learn new things. I work as ![Nir Galon](/images/publishers/nir-galon.webp "Nir Galon") -To learn more about me you can visit my resume website at [nir.galon.io](https://nir.galon.io) or just follow me on [twitter](https://twitter.com/nirgn975), [github](https://github.com/nirgn975) or one of the other social networks I am on. If you wish to contact me just send me an email to nirgn[at]protonmail[dot]com. +To learn more about me you can visit my resume website at [nir.galon.io](https://nir.galon.io) or just follow me on [twitter](https://twitter.com/nirgn975), [github](https://github.com/nirgn975) or one of the other social networks I am on. If you wish to contact me just send me an email from the _"Contact"_ section at [nir.galon.io](https://nir.galon.io).   -This blog is in it's fifth iteration. I stared back in 2012 on blogger, the blog was in Hebrew and it was the beginning of my journey in tech, I moved on from there, now the blog is in English (sorry if you spot any typos and grammar mistakes, it's obviously not my native language) and it's on a lot more subjects (mainly computers, software development, hacking, and related stuff that are interested me). +This blog is in it's fifth iteration. I started back in 2012 on blogger, the blog was in Hebrew and it was the beginning of my journey in tech, I moved on from there, now the blog is in English (sorry if you spot any typos and grammar mistakes, it's obviously not my native language) and it's on a lot more subjects (mainly computers, software development, hacking, and related stuff that are interested me). -I also evolve from the technical side of it, the source code of the blog is on [GitHub](https://github.com/nirgn975/stories-of-a-lifelong-student) (open sourced) and I write the posts in [markdown](https://en.wikipedia.org/wiki/Markdown) and use [Hugo](https://gohugo.io/) to build and generate the website. +I also evolve from the technical side of it, the source code of the blog is on [GitHub](https://github.com/nirgn975/stories-of-a-lifelong-student) (open sourced), I write the posts in [markdown](https://en.wikipedia.org/wiki/Markdown), use [Hugo](https://gohugo.io) to build and generate the website, and host it on [Firebase](https://firebase.google.com).   diff --git a/content/posts/2014/learn-git-part-1-introduction.md b/content/posts/2014/learn-git-part-1-introduction.md new file mode 100644 index 0000000..86d375f --- /dev/null +++ b/content/posts/2014/learn-git-part-1-introduction.md @@ -0,0 +1,252 @@ +--- +title: "Learn Git - Part 1: introduction" +subtitle: "" +date: 2014-06-15T09:00:00+03:00 +lastmod: 2014-06-15T09:00:00+03:00 +draft: false +author: "Nir Galon" +authorLink: "https://nir.galon.io" +description: "" + +tags: ["git", "learn", "github", "cli", "command line", "workflow", "linus torvalds"] +categories: ["tools"] + +hiddenFromHomePage: false +hiddenFromSearch: false + +featuredImage: "/posts/2014/learn-git-part-1-introduction/cover.webp" +featuredImagePreview: "/posts/2014/learn-git-part-1-introduction/cover.webp" + +toc: + enable: true +math: + enable: false +lightgallery: true +license: "" +--- +I think everybody here at least heard about [GitHub](https://github.com) and maybe even about the file management system called [git](https://git-scm.com) which is everywhere in the development world those days. So, as a computer science student I choose to learn it, and what batter way to learn something then to write about it. + +So in this series of posts I'll document my journey to learn git (which is the base of GitHub as the only version control you can use on the platform). I hope more people can use it as a learning document or even to deepen their knowledge in the tool. + +  + +## 1. Some General Knowledge + +git is a distribute version control (basically a file management system with a db to save the changes that were made to those files over time) created by [Linus Torvalds](https://en.wikipedia.org/wiki/Linus_Torvalds) in 2005. Why he even created it you ask? He and some other Linux Kernel developers weren't happy with the source-control management (SCM) software they used at the time (BitKeeper). You can read in the [Wikipedia page of git](https://en.wikipedia.org/wiki/Git) about what exactly their issues was, but this is out of the scope of this post. + +**Why I even need a source control system?** + +This is a valid question. In the old days you were just edit your code, FTP it to your server, and that's it. Maybe you have one more fellow developer with you on the same project, he would have send you a piece of code, you paste it in the exact location in the file he told you too and that's it - FTP it to the server. + +You had problems? just shout him a question he probably down the hallway. But when software started to eat the world, getting bigger, more complex, with bigger teams, in different places in the world and different time zones it started to get messier. You need a version control to manage the code in different computers, try to merge pieces of code together, save the history (the changes that were made so we can go back in time in case we encounter some issue), and even want to know who made those changes. + +**How GitHub is related to all of this?** + +[GitHub](https://github.com) is a hosting company for `git` (repositories). The service was founded in 2008 and hosts public repos for free and private ones for a fee. But, from that simple idea, GitHub built a fully fledged software management system, it's now basically a way to manage the whole project with some social media capabilities and a way to share and contribute code. + +  + +## 2. Simple Commands + +Like most of CLI (command line) tools, `git` comes with a `help` command. So, if we ever got stuck we can always use it to find out about some command. + +```bash +$ git help # print all the commands with a simple explanation. +$ git help config # print all the config command options with a simple explanation. +``` + +![git help command in the terminal](/posts/2014/learn-git-part-1-introduction/cli-git-help.webp "git help command in the terminal") + +To install git I'll use `brew` (on Mac), but it's pretty easy to install on any OS, just use [this guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) for you OS. After we installed it, the first thing we want to do is to set our username and email, so every commit (we'll get to what is commit in the future) will be belong to you. + +``` +$ brew install git +$ git config --global user.name "" +$ git config --global user.email "" +``` + +We're ready to start working on our first repository (repo for short). Let's create a new one (just navigate to your wanted location in your file system with `cd`) and then initiate a new repo (you can do it with an empty directory or with a directory with some files in it already). This will create an invisible directory (directory that start with a dot (`.`)) with the name `git`. + +```bash +$ cd projects +$ mkdir newProject +$ git init +``` + +Now we have a local repository (not on any server, local to your computer). + +  + +## 3. Workflow + +Before we continue diving with the tool, I would like to take couple of minutes to go over the workflow with `git`. For convince I would borrow some names from the cryptography world: Alice and Bob. Let's suppose Alice created a file `README.md` and when a new file is created, it's start his life as an untracked file (that's means that the `git` system doesn't know about it), to make `git` track this file we need to add it to the _staging area_, and finally we make a `commit` - that's a `git` command to take a snapshot of all the files in the _staging area_. + +Now let's assume Alice working some more on the `README.md` file, doing some changes and even add a new file `LICENSE`, when she done, she need to add both of those files to the _staging area_, again, and `commit` those changes. This is pretty much will be our workflow at the moment. We'll making some work -> add the work that we done to the _staging area_ -> and commit it (taking the snapshot). + +  + +## 4. More Commands + +Once we understand the workflow in theory, we need to practice it. + +Maybe the most important command in `git` (in my opinion) is `status` - it allow us to check the changes that were made from the last `commit` (snapshot). Let's see what the result of this command will be after we initiate (with `git init`) the repo, and created a `README.md` file (didn't nothing like adding it to the _staging area_ or `commit` it). + +```bash +$ git status +On branch master + +No commits yet + +Untracked files: + (use "git add ..." to include in what will be committed) + README.md + +nothing added to commit but untracked files present (use "git add" to track) +``` + +We can see we got couple of pieces of information back: +- We are on branch `master` (we'll take about branches later) +- There is no commits yet in this repo. +- We have a new file (file that `git` doesn't track) in the name of `README.md` +- Nothing was added to the _staging area_, and `git` knows that there're files that it doesn't track yet (so we have something to give him, to adding to the _staging area_). + +So let's give `git` what it wants, let's start tracking this `README.md` file (with the `add` command and right after it the file itself), and then do another `status` command to see the output now. + +```bash +$ git add README.md +$ git status +On branch master + +No commits yet + +Changes to be committed: + (use "git rm --cached ..." to unstage) + new file: README.md +``` + +We see almost the same pieces of information, but now `git` have a file in his _staging area_ (a file ready to be `commit`ed). So, it's time to do our first `commit`. To do this we'll use the `commit` command. A flag that the `commit` command have is `m` which means _"message"_, with this flag we can add a message to the `commit` to describe the changes this `commit` is do. + +When we do the `commit` we basically take a snapshot of our file system in this exact time. Even a space means a change. This commit is added to the repo (project) timeline (it's accepted to draw it and imagine it as a timeline, because every `commit` has a timestamp, so we can place them all on a big timeline from the start of the project until now). + +```bash +$ git commit -m "Created an empty README file" +[master (root-commit) de7c8db] Created an empty README file + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 README.md +``` + +if we write the `status` command again, we'll see there is no changes to be added to the _staging area_ or no changes in the _staging area_ to be `commit`ed. We also can see in the first line that we on branch `master`, for now everything you need to know on branches is that we have a timeline (branch) in the name of `master`, and we `commit` things to that branch (timeline). + +```bash +$ git status +On branch master +nothing to commit, working tree clean +``` + +Now let's make some changes in `README.md` and create a new file named `LICENSE` (like we said Alice did in the [workflow section](#3-workflow)), and run the `status` command again. + +```bash +$ echo "first change" > README.md +$ touch LICENSE +$ git status +On branch master +Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git restore ..." to discard changes in working directory) + modified: README.md + +Untracked files: + (use "git add ..." to include in what will be committed) + LICENSE + +no changes added to commit (use "git add" and/or "git commit -a") +``` + +`git` knows that the `README.md` file has changed! and those changes are not staged (not in the _staging area_, not ready to be `commit`ed). `git` also noticed we created a new file that it doesn't track (`LICENSE`). + +To commit those files we need to add them to the _staging area_ first, we can do it like we did it earlier with the `add` command and the two files (with a space between them), but we can do it more efficiently with the `all` flag - which will add all of the changes and untracked files to the _staging area_ (be careful with this flag because something you). + +After we add them, we can use the `status` command again to see what have changed. We can see we have two files in the _staging area_, ready to be `commit`ed, one (`LICENSE`) is a new file, and the other (`README.md`) is a tracked file that just changed (modified). + +```bash +$ git add --all +$ git status +On branch master +Changes to be committed: + (use "git restore --staged ..." to unstage) + new file: LICENSE + modified: README.md +``` + +Now let's do a new `commit` (take a second snapshot) and then explore it a little bit. + +```bash +$ git commit -m "Add a new LICENSE file and finish README" +[master 380c1e1] Add a new LICENSE file and finish README + 2 files changed, 1 insertion(+) + create mode 100644 LICENSE +``` + +To look at the history, the log, of the current timeline we can use the `log` command. We see there're two `commit`s in the branch (timeline) we're currently at. And also much more information: +- We're in the `master` branch (timeline). +- The `commit`s hash, which is a unique string of number and letters to represent that `commit`. It's basically the name of the `commit`, with it we can reference that `commit`. +- The author and the exact time and date of the `commit`. +- The message of the commit (this is why the message is important. It should be understandable, concise and describe exactly what the changes are. It also accepted to write in present time and not history or future). + +```bash +$ git log +commit 380c1e1346008245c8268ccb039538df3e314b87 (HEAD -> master) +Author: Nir Galon +Date: Sat Oct 3 12:51:23 2020 +0300 + + Add a new LICENSE file and finish README + +commit de7c8db1ce767a3a757d760cb7200abe9d847c65 +Author: Nir Galon +Date: Sat Oct 3 02:03:24 2020 +0300 + + Created an empty README file +``` + +Like the drawing below, we can imagine it as two dots, where each dot is a `commit` (snapshot), and a line (timeline, the `branch`) is connected them. Going from the first (oldest) one at the left, to the newest one at the right. Where the most newest `commit`, the dot to the most right, is our current `commit` (`HEAD`). + +{{< mermaid >}} +gitGraph: +options +{ "nodeSpacing": 150, "nodeRadius": 10 } +end + commit + commit +{{< /mermaid >}} + +  + +## 5. Q & A + +Let's practice a little bit by going over the things we learned. + +### **Questions** + +1. You want to initiate a new repo. You're already in a directory with a file, what command do you write to do it? +2. You created some files, made a few `commit`s, you updated some files and the day is over, you want to do your last `commit` for the day and go home. But you don't remember what files you have changed from the last `commit`, what command can help you see the changes from the last `commit`? +3. You found out with the last command that you have only one file changed (`index.html`), make him ready to be `commit`ed. +4. Make a `commit`. +5. You created a new directory (`css`), with couple of files, add the entire directory (with all of it's files) to the _staging area_. +6. A colleague goes by your desk and ask you what have you been `commit`ed today, what command do you write to show him? + +### **Answers** + +1. The `git init` command. +2. The `git status` command. +3. The `git add` command: `git add index.html`. +4. The `git commit` command: `git commit -m "Add index.html"`. +5. To add an entire directory we'll just write it: `git add css`. +6. The `git log` command. + +  + +## 6. Summary + +So, we learn a bit about the history of `git`, why do we need it and how [GitHub](https://github.com) is related. From there we move on the learn some basic commands, the git workflow, and then to some of the most used commands in `git`. + +I recommend to learn through your fingers - to write all the commands yourself and see the output in your terminal. This is the best way to learn! Don't copy and paste answers to your terminal, write them yourself, slowly it'll get through and you'll remember and understand it all in no time. diff --git a/content/posts/2014/learn-git-part-2-getting-our-hands-dirty.md b/content/posts/2014/learn-git-part-2-getting-our-hands-dirty.md new file mode 100644 index 0000000..8a9bc47 --- /dev/null +++ b/content/posts/2014/learn-git-part-2-getting-our-hands-dirty.md @@ -0,0 +1,433 @@ +--- +title: "Learn Git - Part 2: getting our hands dirty" +subtitle: "" +date: 2014-07-06T09:00:00+03:00 +lastmod: 2014-07-06T09:00:00+03:00 +draft: false +author: "Nir Galon" +authorLink: "https://nir.galon.io" +description: "" + +tags: ["git", "learn", "github", "cli", "command line", "undo", "revert", "repo", "merge", "collaboration"] +categories: ["tools"] + +hiddenFromHomePage: false +hiddenFromSearch: false + +featuredImage: "/posts/2014/learn-git-part-2-getting-our-hands-dirty/cover.webp" +featuredImagePreview: "/posts/2014/learn-git-part-2-getting-our-hands-dirty/cover.webp" + +toc: + enable: true +math: + enable: false +lightgallery: true +license: "" +--- +This part is a direct continuation of [Learn Git - Part 1: introduction](https://lifelongstudent.io/2014/06/learn-git-part-1-introduction/), so if you haven't read it, go and read it first. We based on the things we learned and do there, so make sure you don't delete the repo we created in the part 1. + +  + +## 1. Making a difference + +So, let's say Alice is just coming in and sat down in her work station, on the computer, she's on her local repo (a local copy of the repo of the project, in her own computer). Yesterday she made some changes to the `LICENSE` file, she wants to continue her work but don't remember the changes she made yesterday (so she don't remember where she's at). + +To see the changes from the last commit, we can use the `diff` command. The output of the command is the changes that aren't in the _staging area_ - changes to files the `git` system already track, but we yet to `add` them and include those new changes. + +The _"old"_ line will begin with a minus (`-`) at the start of the line, and the _"new"_ line of code (with the changes) will begin with a plus (`+`) at the start of it. In our case the `LICENSE` file was empty, so at we only see a plus line with the text we added to the file. + +```bash +diff --git a/LICENSE b/LICENSE +index e69de29..39604a4 100644 +--- a/LICENSE ++++ b/LICENSE +@@ -0,0 +1 @@ ++Copyright (c) 2014 nirgn +``` + +If we now `add` the `LICENSE` file to the _staging area_ and then run again the `diff` command, we'll see nothing (because all of the changes are added to the _staging area_), but if we ,nonetheless, want to see the changes even in the _staging area_ we can use the `staged` flag and we would get the same output as before. + +**Don't regret anything! Ok, some things are ok to regret about** + +Now, if we use the `status` command, we'll see there is a file changed, added to the _staging area_, and ready to be `commit`ed. But if we didn't mean to add it to the _staging area_ yet? What if Alice didn't finish with this file yet, and want add it to a different `commit` later on? + +To remove files from the _staging area_ we'll use the `reset HEAD ` command. The elephant in the room - the `HEAD` in the command means the last `commit` in the current `branch` (timeline), in our case for the time being is `master`. So we actually reset the file to undo the changes, from the _staging area_, that were made until the last `commit`. + +```bash +$ git reset HEAD LICENSE +Unstaged changes after reset: +M LICENSE +``` + +Now if we run the `status` command, we can see that changes were made to the `LICENSE` file, but are not staged. If we want to undo the changes completely and revert the file to his state in the last `commit` we can do it by using the `checkout `. + +```bash +$ git checkout LICENSE +Updated 1 path from the index +``` + +Now the `status` command will show us there is no changes at all and the `LICENSE` file is back to his last `commit` state. + +  + +## 2. Revert all the things + +Until now we regret adding files to the _staging area_, but what if we already `commit`ed the file? or maybe we forget to include something in the file and we want it to be in the same `commit`? + +For those type of cases we can use the `reset` command with a new flag, `soft HEAD^`. This will undo the last `commit`, and bring all of the changes that were made in this `commit` to the _staging area_. As we said before the `HEAD` is the last `commit` in the current branch (timeline), but the caret symbol (`^`) says the one before. So `HEAD^` means the `commit` before the last one, in the current branch. + +So let's do some change to the `README.md` file, `add` it and `commit` it in one command (with a new flag). This type of `add` and `commit` is only allowed if the files is already been tracked. After we do it, let's use the `reset soft` command to undo it. + +```bash +$ echo "This is a new line" > README.md +$ git commit -a -m "Modify README file" +[master 017a141] Modify README file + 1 file changed, 1 insertion(+), 1 deletion(-) +$ git status +On branch master +nothing to commit, working tree clean +$ git reset --soft HEAD^ +$ git status +On branch master +Changes to be committed: + (use "git restore --staged ..." to unstage) + modified: README.md +``` + +Now we can still edit the `README.md` file and then `commit` everything together. + +If you only want to add something to the last `commit`, and even change the last `commit` text, a simpler way is to use the `commit` command with the `amend` flag. It'll add everything in the _staging area_ to the last commit and you can change the text of the commit in the process. + +```bash +$ git commit --amend -m "Add a new LICENSE file and add text to README" +[master 5870e6f] Add a new LICENSE file and add text to README + Date: Sat Oct 3 12:51:23 2020 +0300 + 2 files changed, 1 insertion(+) + create mode 100644 LICENSE +``` + +Another flag to know it the `hard`, it'll undo the changes like `soft`, but instead of leave them in the _staging area_ it'll delete them entirely like they never existed. + +```bash +$ git reset --hard HEAD^ +HEAD is now at de7c8db Created an empty README file +``` + +The commit is just disappeared, our file revert to the commit before it, and the changes is not preset anywhere. + +  + +## 3. Can anybody hear me? + +Until now, we worked on our local repo (the repo on our local computer). But what if we want to collaborate with another developer on the project? To do this, we need to upload the code to some sort of a server, if it's our company server or a different company server that we rent - doesn't matter, Bob (for example) need a copy of the code. + +In the old times, like I wrote in the first post, we would probably transfer the code on a disk on key between computers back and forth. But now days, we'll sync our local repo with some server that'll host the project's code (another repository copy in another computer - a server, the cloud). In other VCS (**V**ersion **C**ontrol **M**anagement) systems (like SVN for example) there is a centralized server - a single source of truth. + +With `git`, every repo has it's own single source of truth. `git` makes it a bit difficult to create a single source of truth, but it's possible none the less. For most it'll be the server, and in particularly - GitHub. + +This is where the `push` and `pull` commands comes in. Let's learn how to use them by creating a new repo on [GitHub](https://github.com), and push our local repo to the remote repo on [GitHub](https://github.com) (that's why all of our commands will start with `remote`). First, if you don't have a [GitHub](https://github.com) account already, create one and verify it. + +Now let's open a new repository by clicking on the plus button at the top right corner and then _"New repository"_. + +![GitHub new repository button](/posts/2014/learn-git-part-2-getting-our-hands-dirty/new-repository.webp "GitHub new repository button") + +You'll be redirect to a new page where you can fill out all the details about the project, like the new of the project / repository, a description, make it public (free of charge, everybody can see the code and even fork it) or private and more stuff at the bottom - we'll not get in to it right now, some of it will be discussed in future posts. + +![GitHub repo details](/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-details.webp "GitHub repo details") + +In my case the name will be `test`, I'll leave the description empty, the repo will be public, and without `README` file, `.gitignore` or `LICENSE` files (we'll create the manually). + +After we create the repo we'll get a URL from GitHub. This URL is the URL for the repo, with it we can `push` and `pull` code, and even `clone` the repo from GitHub server to a new local computer. + +![GitHub repo URL](/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-url.webp "GitHub repo URL") + +To `push` our code to the new [GitHub](https://github.com) `remote` repo we first need to config the GitHub repo address (the URL we got from them) as `remote` address so we can later push to that `remote` address. We'll do it with the `remote add ` command. + +```bash +$ git remote add origin https://github.com/nirgn975/test.git +$ git remote -v +origin https://github.com/nirgn975/test.git (fetch) +origin https://github.com/nirgn975/test.git (push) +``` + +I bet the first thing that comes to your head is "why we call our remote alias `origin`?", You're right, it's a bit wired, we can all if whatever we want. But `origin` is just a standard convention, and we'll love conventions. And the second command is just a way to print all the `remote` addresses, so we just make sure everything was added successfully. + +Now, it's finally time to push our local branch (timeline) `master` to `origin` (the GitHub repo). You'll need to fill your username and password so GitHub will check if you have permissions to push to that repo. + +```bash +$ git push origin master +Enumerating objects: 3, done. +Counting objects: 100% (3/3), done. +Writing objects: 100% (3/3), 224 bytes | 224.00 KiB/s, done. +Total 3 (delta 0), reused 0 (delta 0) +To github.com:nirgn975/test.git + * [new branch] master -> master +``` + +If we refresh the GitHub repo page we'll see the `README` file there, and a new _"Network"_ button (at the right menu, next to the _"Settings"_) where we can see all the `branch`s and all the `commit`s, with their messages, who're their author, when they `commit`ed, and more (basically like writing the `log` command on our terminal). + +So, we `push`ed our repo to a `remote` source on GitHub (or any other `git` hosting), but how can Bob take this code to his local machine? Like we said before, with the `pull` command (we'll also use the `pull` command to sync our local repo with the `remote` one, so get changes other team members did and `push`). + +```bash +$ git pull origin master +From github.com:nirgn975/test + * branch master -> FETCH_HEAD +Already up to date. +``` + +In this case, our local repo is already up to date with the `remote` one (of course it is, we push the code a couple of minutes ago and we don't have any one who push new code to our repo in the mean time). + +  + +## 4. Rap collaboration + +A collaboration is an important thing, not just for open source projects where a lot of different people (maybe even from different countries with different time zones and languages) will work on the same project, but also at work, even if it's not a big company with a lot of teams, chances are you're not develop the software alone. + +So, let's say Bob is working with Alice on the same team. It's his first day, and they want him to work on a new feature of the product. He need a local copy of the repo, so he `clone` the repo to his local machine. If you're on [GitHub](https://github.com) just go to the project repo and choose the _"Code"_ tab, at the bottom (above the _"Download ZIP"_) there is a section with the text _"HTTP clone URL"_ - this is the URL of the repo, copy it, and then go to your terminal to `clone` the repo. + +![GitHub repo clone URL](/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-clone-url.webp "GitHub repo clone URL") + +```bash +$ git clone https://github.com/nirgn975/test.git +``` + +The repo will be cloned on your local machine, in the directory that you were at in the terminal, to a new directory with the name of the of the repo. When you `clone` the repo to your local machine, the `git` system does 3 things: + +1. Download the repo to your local machine in a directory with the name of the repo. +2. Add a `remote` with the `origin` name that alias to the repo URL. +3. `git` will configure a branch named `master` and point the `HEAD` to be the last `commit` from the `master` branch in the `origin`. + +  + +## 5. Merge the branches + +Bob is ready now to work on the new feature, but to do this it's better to create a new `branch` (timeline) and not to work on the same main `branch` of the project (`master`). This is because while he work on his own feature, other people working on theirs features or bugs too, and if everyone will work on the same branch and `commit` frequently, it'll create a mess, and everyone will _"resolve conflicts"_ all of the time instead of working. + +To create a new `branch` out (or splits if you want) of the main `master` branch (the current branch we're in right now) can be done using the `branch` command. + +```bash +$ git branch home-page +``` + +After we created the new branch, let's check on which branch we're in right now. + +```bash +$ git branch +home-page +* master +``` + +We're still on `master`. So to move to the `home-page` branch, we'll use the `checkout` command. + +```bash +$ git checkout home-page +Switched to branch 'home-page' +``` + +Now we're in a different timeline (`branch`), we can do whatever we want and it'll just do it just in the `home-page` branch, and nothing will infect our `master` branch. Any time we want to can go back to `master` branch, and see the repo from `master` branch point of view (timeline). + +In the meantime, while we work on our feature, if other members of the project finish their own work and merge it to `master`, we can always `checkout` back to `master`, and `pull` the new `commit`s in `master`, to see our coworkers job. + +Now that we're on a new branch (`home-page`), let's create a new file called `index.html`, inside of it we'll add the basic html code we need for a simple web page, `add` it to the _staging area_, and commit the file. + +```bash +$ touch index.html +$ echo "\n\t\n\t\twebsite title\n\t\n\t\n\t\tcontent of website ...\n\t\n" >> index.html +$ git add index.html +$ git commit -m "Add basic html code" +``` + +The `commit` we just did, will be added to the current (`home-page`) timeline (`branch`), and will not be seen in any other `branch`. If we write the `ls` command in the terminal (in the current directory) we'll see all of our project files (`README.md` and `index.html`), but if we'll `checkout` to the `master` branch we'll not see the `index.html` file, even if we write the `git log` command, we'll not see our latest `commit` in there. + +Let's just check we aren't crazy and `checkout` back to the `home-page` branch, and then with the `ls` command makes sure we see our `index.html` file. + +So, let's say we're done with this task, we did all of the things we had to do here and we're ready to `merge` this `home-page` branch to the `master` branch. To do this we're first need to go to the branch we want to `merge` things to (in our case `master`), and then use the `merge` command to actually merge the code from the other branch to the branch we are at right now. + +```bash +$ git checkout master +Switched to branch 'master' +$ git merge home-page +Updating de7c8db..bfb8f2b +Fast-forward + index.html | 8 ++++++++ + 1 file changed, 8 insertions(+) + create mode 100644 index.html +``` + +We can see that `git` tells us it's update the branch by _"Fast forward"_, but what is it means? it's when we try to merge one commit with a commit that can be reached by following the first commit’s history, `git` simplifies things by moving the pointer forward because there is no divergent work to merge together, so it's called _"fast-forward"_. + +When we finished `merge`ing the `branch`, we don't need it anymore, so we can just delete it. We'll use the `branch` command with the `d` flag to do it. + +```bash +$ git branch -d home-page +Deleted branch home-page (was bfb8f2b). +``` + +Now let's create a new `branch` to work on a new task, the branch will be called `basic-main` (because we'll add some basic code to the main website page - `index.html`). We can create the branch and then move to it in two separate commands like we did before, but there is a simpler way! We can use the `checkout` command with a flag (`b`) that tells to create the branch if doesn't exist yet, so this way, in one command we create the branch and then move (`checkout`) to it. + +```bash +$ git checkout -b basic-main +Switched to a new branch 'basic-main' +``` +Then we'll add the `Go to detailed page!` line right after `content of website ..`. + +```html + + + website title + + + content of website ... + Go to detailed page! + + +``` + +Now we can `commit` the change in `index.html` and create a new page, `detailed.html` that the link will redirect us to (when we click it). + +```bash +$ git commit -a -m "Add a link to detailed page" +[basic-main e979b01] Add a link to detailed page + 1 file changed, 7 insertions(+), 6 deletions(-) +$ touch detailed.html +$ echo "\n\t\n\t\twebsite title\n\t\n\t\n\t\t

This is the detailed page

\n\t\n" >> detailed.html +$ git add detailed.html +$ git commit -a -m "Finish detailed page" +[basic-main af3853e] Finish detailed page + 1 file changed, 8 insertions(+) + create mode 100644 detailed.html +``` + +Let's imagine how our repo branches (timelines) is looking right now. + +{{< mermaid >}} +gitGraph: +options +{ "nodeSpacing": 100, "nodeRadius": 10 } +end + commit + commit + branch basicmain + checkout basicmain + commit + commit +{{< /mermaid >}} + +Right in the middle of our work on the `basic-main` branch, we get an email from our boss that there are bugs in `master` and we need to take care of it immediately. So let's head over to `master` (you can run `git branch` after you `checkout` to `master` just to make sure you're on `master`). + +```bash +$ git checkout master +Switched to branch 'master' +``` + +We don't know if anyone of our team members done with their work and `merge` it to `master` while we worked on our feature branch, so let's make sure we have an updated `master` by `pull`ing any new `commit`s from `origin`. Let's fix what we need to fix, and `commit` and `push` it to `origin`. + +```bash +$ git pull origin master +From github.com:nirgn975/test + * branch master -> FETCH_HEAD +Already up to date. +$ echo "# Awesome Website\n\nThis is the repo for the awesome website" >> README.md +$ git commit -a -m "Add a description for the repo" +[master c247760] Add a description for the repo + 1 file changed, 3 insertions(+) +$ git push origin master +Enumerating objects: 7, done. +Counting objects: 100% (7/7), done. +Delta compression using up to 16 threads +Compressing objects: 100% (6/6), done. +Writing objects: 100% (6/6), 679 bytes | 679.00 KiB/s, done. +Total 6 (delta 0), reused 0 (delta 0) +To github.com:nirgn975/test.git + de7c8db..0baa97a master -> master +``` + +Now that we put out the fire, let's head over to our `basic-main` branch, finish the work, `commit` it, and head back to `master` to merge it. + +```bash +$ git checkout basic-main +Switched to branch 'basic-main' +$ sed -i '' "s/content of website .../Welcome to the new website/g" index.html +$ git commit -a -m "Change welcome message" +[basic-main a0ff187] Change welcome message + 1 file changed, 1 insertion(+), 1 deletion(-) +$ git checkout master +Switched to branch 'master' +$ git merge basic-main +Merge made by the 'recursive' strategy. + detailed.html | 8 ++++++++ + index.html | 13 +++++++------ + 2 files changed, 15 insertions(+), 6 deletions(-) + create mode 100644 detailed.html +``` + +After the `merge` command a VI editor will open up on you terminal. With this, `git` is basically telling us I made the merge `commit` for you, but if you'll need to be more specific with the `commit` message edit it (and there is a default `commit` message in the Vi editor). To exist the VI editor we'll `write` and `quit` (`:wq`). + +Because we merge two branches with changes in each of them, `git` is doing a _"recursive"_ merge - `git` create a new `commit` right where we `merge` them, we can see it with the `git log` command. + +Let's imagine how to whole process looks like visually. + +{{< mermaid >}} +gitGraph: +options +{ "nodeSpacing": 100, "nodeRadius": 10 } +end + commit + commit + branch basicmain + checkout basicmain + commit + commit + checkout master + commit + checkout basicmain + commit + checkout master + merge basicmain +{{< /mermaid >}} + +  + +## 6. Q & A + +It's time to practice. Remember that the best practice is through your fingertips. If you don't have a project you want to upload and share, just create an empty directory and put a simple text file in there. If you can't figure out something, it's okay to look at the answers, but don't just look at it, write it in the terminal (don't copy-paste, write it on your own). + +### **Questions** + +1. A new file was added to the project, write a command to show you the changes from the last `commit`. +2. Add the `index.html` file to the _staging area_. +3. Wait a second, a colleague walks by your desk and ask to see what is different from the last `commit`, show him. +4. The colleague updates you that this `index.html` is no longer relevant, delete it from the _staging area_. +5. Do some changes to the `README.md` file, and because `git` already tracks that file, `add` and `commit` in one command. +6. Oops! I forget to tell you to add another file to that `commit`, you need to create a new file named `map.index` and `commit` it with the `README.md` file from the last commit. +7. Wait I didn't tell you what content to add to the `map.index` file, return it to the _staging area_. +8. A colleague send you in an email the new repo URL, add it to your local repo configuration (it's: `https://github.com/example/importantProject.git`). +9. You're done for today, let's push everything to the remote repo. Use a special flag so you'll not need to write the `origin` alias next time. +10. The IT team has wipe out your hard disk by mistake, clone the repository to your local machine from the address https://github.com/nirgn975/test.git +11. We need to create a new branch (with the name `fix457`) to fix some code, create it a move to it in one command. +12. Merge the `fix457` branch to the current branch you're in right now. + +### **Answers** + +1. The `git diff` command. +2. `git add index.html`. +3. Use the `git diff --staged` command and flag to show the changes that were also added to the _staging area_. +4. The `git reset HEAD index.html` command. +5. Use the `-a` flag like so: `git commit -a -m "Modify README.md file"`. +6. Because `git` doesn't track the new page let's first add it `git add map.index`, no we can use the `-amend` flag to add it to the last commit: `git commit -amend -m "Modify README.md file and add map.index"`. +7. Use the `git reset -soft HEAD^` command. +8. Use the `remote add` command like so: `git remote add origin https://github.com/example/importantProject.git`. +9. You need the `push` command with the `-u` flag: `git push -u origin master`. +10. Use the `clone` command like so: `git clone https://github.com/nirgn975/test.git`. +11. Use the `checkout` command with the `b` flag, like so: `git checkout -b fix457`. +12. `git merge fix457`. + +  + +## 7. Summary + +We now know how to see the changes that were made from the last `commit`, how to go back if we regret something we did in a `commit` or the commit message, or even forget to add something to the `commit`. + +We upload the project to a remote repository (GitHub in this case), we created new branches, worked with other team members, and merge our code to the `master` branch (we go over a `merge` with no changes in `master` and with one **with** changes in `master`, but not in the same file - we'll talk about it in future chapter). + +We definitely learned a lot in this chapter! Don't forget to practice it through your fingers, it's the best way to learn something new. And don't hesitate to ask questions in the comments if something is not clear - I'll do my best to help. diff --git a/content/posts/2017/jekyll-starter-kit-generator-2.1.0-is-out.md b/content/posts/2017/jekyll-starter-kit-generator-2.1.0-is-out.md index 678bbe4..165cada 100644 --- a/content/posts/2017/jekyll-starter-kit-generator-2.1.0-is-out.md +++ b/content/posts/2017/jekyll-starter-kit-generator-2.1.0-is-out.md @@ -49,7 +49,6 @@ What more cool stuff? Here are couple of examples. ![The generator in action](/posts/2017/jekyll-starter-kit-generator-2.1.0-is-out/the-generator-in-action.webp "The generator in action") - If you can’t wait and already want to try it, all you need to do is `npm install -g generator-jekyll-starter-kit` and then just `yo jekyll-starter-kit`. And if you want to help improve this project, just head up to the [repo page on GitHub](https://github.com/nirgn975/generator-jekyll-starter-kit).   diff --git a/content/posts/2020/like-a-spy-with-hak5-toys.md b/content/posts/2020/like-a-spy-with-hak5-toys.md index 061712e..4776f7a 100644 --- a/content/posts/2020/like-a-spy-with-hak5-toys.md +++ b/content/posts/2020/like-a-spy-with-hak5-toys.md @@ -143,7 +143,7 @@ When we toggle the `streaming` button we'll get the screenshots in live and can ![Screen Carb configuration](/posts/2020/like-a-spy-with-hak5-toys/screen-crab-configuration.webp "Screen Carb configuration") {{< admonition type=bug title="Debugging" open=true >}} -If you encounter some problems, you can add `DEBUG_LOG ON` as a third line in the `config.txt` file and the Screen Crab will save the the logs to a `crab.log` file so you can see what going on. +If you encounter with some problems, you can add `DEBUG_LOG ON` as a third line in the `config.txt` file and the Screen Crab will save the the logs to a `crab.log` file so you can see what going on. Another way is to just reset everything by delete all of the files the Screen Crab will create on the SD card (except from the `config.txt` and the `device.config` that we add earlier). {{< /admonition >}} diff --git a/data/_oldPosts/2012-09-16-little-android-bit-grammar.md b/data/_oldPosts/2012-09-16-little-android-bit-grammar.md deleted file mode 100644 index d265670..0000000 --- a/data/_oldPosts/2012-09-16-little-android-bit-grammar.md +++ /dev/null @@ -1,244 +0,0 @@ ---- -title: A little bit of Android Grammar -author: nirgn -layout: post -summary: "בפוסט הזה נדבר על כמה מושגים מתקדמים יותר של מערכת ההפעלה Android, כמו על ה stack הטכנולוגי שלה, איך משתמשים ב adb, מהו rom, איך משיגים הרשאות root ולמה אנחנו צריכים בכלל הרשאות כאלה, מהו bootloader, וכ׳ו." -category: Android ---- -בפוסט הזה אסקר ואסביר כמה מהמושגים (או Grammar)  היותר מתקדמים של מערכת ההפעלה Android. - -> יש לציין כי רוב התמונות והמידע המתוארך נלקח מ Wikipedia. - - - -### Android כמערכת הפעלה - -**השכבה האדומה: Linux Kernel – (אנדרואיד היא לא לינוקס)** - -
- Red Layer -
- -ליבת לינוקס ([Linux kernel](http://en.wikipedia.org/wiki/Linux_kernel)) היא הליבה המשמשת במערכות הפעלה ממשפחת לינוקס. השם "לינוקס" מתייחס אל ליבת המערכת, הקרנל (ליבה = בסיס המערכת), ז"א אלפי שורות קוד המהוות את הבסיס של מערכת ההפעלה. -כיום מקובל להשתמש בשם לינוקס למשפחה שלמה של מערכת הפעלה תואמות יוניקס, המשלבות את ליבת לינוקס עם ספריות וכלים מפרויקט גנו ([GNU](http://en.wikipedia.org/wiki/GNU)). לפעמים גם מדובר על הפצות לינוקס שלמות (מערכות הפעלה שלמה הכוללות שרתי אינטרנט דוגמת [Apache](http://en.wikipedia.org/wiki/Apache_HTTP_Server), סביבות עבודה גרפיות דוגמת [Gnome](http://en.wikipedia.org/wiki/GNOME) וחבילות ישומיים משרדיים דוגמת [Libre Office](http://en.wikipedia.org/wiki/LibreOffice)). - -בגלל שה Linux Kernel נמצא תחת רישיון GPL, כש Google או יצרני OEM (כמו [HTC](http://en.wikipedia.org/wiki/HTC), [SAMSUNG](http://en.wikipedia.org/wiki/Motorola), [MOTOROLA](http://en.wikipedia.org/wiki/Samsung) וכ'ו) או יצרני המעבדים (כמו [Qualcomm](http://en.wikipedia.org/wiki/Qualcomm)וכ'ו) משלבים את הקוד שלהם ב Kernel (המיועד לשימוש תחת מערכת ה Android), הם חייבים לדחוף את הקוד גם חזרה למעלה. וזה אומר, שכל קוד ש Google וכד' רוצות לשלב ב Kernel הן תשלב אותו גם כן בפרויקט המקורי, ולכן לכלום תיהיה גישה לקטע הקוד החדש ב Kernel (במילים אחרות: גוגל לא יכולה לבצע שימוש ב Linux Kernel, לשפצ'ר אותו, ולשמור את השיפוצ'רים החדשים רק לעצמה - היא חייבת לשתף את השאר). - -  - -**למה לינוקס קרנל?** - - * המחיר, לינוקס קרנל הינה חינמית. - * המטרה הייתה ליצור פלטפורמת מובייל שתרוץ על כמה שיותר מכשירים, וההתאמה של לינוקס קרנל לרוץ על מעבדי [ARM](http://en.wikipedia.org/wiki/ARM_architecture) של Nvidia,TI, Qualcomm וכ'ו, הינה קלה יחסית (מכיוון שמודל הדרייברים בלינוקס מובן מאוד). - * הקרנל מספק ניהול תהליכים, ניהול זיכרון, קישוריות ועוד מוכנים מראש. - * לינוקס קרנל מאובטחת ברמה גבוהה יחסית ומספקת בסיס טוב. - -**גרסאות ה Android השונות מבוססות על גרסאות Kernel שונות:** -אנדרואיד 1.5 - מבוססת על ליבת לינוקס 2.6.27. -אנדרואיד 1.6 - מבוססת על ליבת לינוקס 2.6.29. -אנדרואיד 2.0/2.1 - מבוססת על ליבת לינוקס 2.6.29. -אנדרואיד 2.2 -; מבוססת על ליבת לינוקס 2.6.32. -אנדרואיד 2.3 - מבוססת על ליבת לינוקס 2.6.35. -אנדרואיד 3.0/3.1 - מבוססת על ליבת לינוקס 2.6.36. -אנדרואיד 4.0 - מבוססת על ליבת לינוקס 3.0.1. -אנדרואיד 4.1 - מבוססת על ליבת לינוקס 3.0.31. -אנדרואיד 4.2 - מבוססת על ליבת לינוקס 3.4.0. - -  - -## השכבה הירוקה, הרמה השנייה: (Libraries ( + Android Runtime - -
- Green Layer -
- -הרמה השנייה (הירוקה), מורכבת כולה מספריות קוד פתוח. הספריות האלו משמשות שירותים שונים של מערכת ההפעלה, ובנוסף גם את המפתחים. - - * **Media Framework –** זוהי ספריה המספקת פיצ'רים חיוניים בתקשורת כגון Codecs, פורמטי וידאו ותמונות שונים (AAC, MP3, H.264, MPEG4, JPG, PNG) וכד'. - * **SGL –** מנוע גרפי 2D בסיסי. - * **OpenGL / ES –** קבוצה של תוכנות ויישומים ([API](http://en.wikipedia.org/wiki/Application_programming_interface)) של ממשק 3D ומסוגלים לבצע האצת חומרה 3D. - * **WebKit –** ספריות הדפדפן webkit, דפדפן קוד פתוח התומך בין היתר בג'אווה סקריפט וב CSS. - * **SSL –** פרוטוקולי תקשורת המאפשרים תקשורת מאובטחת ומוצפנת בין שני יישומים. - * **Surface Manager -** ספריה המאפשרת גישה לספריית "הלפני מנהלי ההתקן" של התצוגה במכשיר. - * **SQLite –** המאפשרת קריאה וכתיבה ישירות ממסד הנתונים בדיסק (בלי שרת מתווך תהליכים). - * **Bionc -** זהוי ספריית libc שמותאמת לאנדרואיד (בגלל הרישיון שיש לספרייה libc). - -**Android Runtime** - - * **Core Libes -** ספרייה המכילה את הקוד המקורי הבסיסי של מערכת ההפעלה אנדרואיד (שנכתב בשפת Java). - * **Dalvik VM -** דלביק זהוי מכונה ווירטואלית הנכתבה מאפס במיוחד למערכת האנדרואיד, ומיועדת להרצה של קבצי Apk. - -  - -**למה ליצור מכונה ווירטואלית חדשה (Dalvik) ולא להשתמש ב Java VM?** - - 1. Java VM עולה כסף, היא בבעלות Oracle. אם כל יצרנית תידרש "לרוץ" ל [Oracle](http://en.wikipedia.org/wiki/Oracle_Corporation)כדי לנהל משא ומתן לגבי העלות לשימוש ב Java VM, פלטפורמת ה Android לא תשיג את המטרה שלה (להיות פלטפורמת מובייל חינמית שתרוץ על כמה שיותר מכשירים). - 2. Java VM עם השנים התפתחה סביב מעבדי אינטל, מכיוון שזה בעיקר מה שהיה במחשבים ובשרתים העסקיים, ולכן לא מתאימה לרוץ על מעבדי ARM (לפחות בתצורה הנוכחית). - 3. Java VM טוענת את התוכנה לזיכרון (מהדיסק הקשיח) ורק אז יוצרת את האובייקט, שזה הגיוני, מכיוון שהדיסק הקשיח הרבה יותר איטי מה [RAM](http://en.wikipedia.org/wiki/Random-access_memory). דלביק לא עושה זאת, מכיוון שבמכשירים ניידים אין דיסק קשיח, ישנו זיכרון RAM ואחסון פלאש (מהיר מאוד להבדיל מהדיסק הקשיח המכני, ולכן אין סיבה לעשות זאת). - -
- Java Bytecode to Dalvik Bytecode -
- -  - -### Dalvik - -**ננתח את המצבים כשאנו כותבים ל Dalvik ול Java VM:** -כשנכתוב ל Java VM אנו נכתוב בשפת Java, הקומפילר של Java יקמפל לנו את הקוד ל bytecode (שזה הכלאה של חצי שפת תכנות וחצי שפת מחשב) ונקבל קובץ class, והקובץ הזה ירוץ על ה Java VM. -כשנכתוב ל Dalvik אנו נכתוב בשפת Java, הקומפילר של Java יקמפל לנו את הקוד ל bytecode ונקבל קובץ class, לאחר מכן הקומפילר של Dalvik יקמפל לנו שוב את ה bytecode ונקבל קובץ dex, הקובץ הזה ירוץ על Dalvik VM. - -ב Java אנו אוספים את כל קבצי ה class לתוך קובץ Jar ואז אנו מקווצים אותו כקובץ zip. ב Android אנו לא עושים את זה, אבל גם כקוד לא מקווץ, קוד המתאים ל Dalvik יהיה קטן יותר מקוד Java, וזה בגלל שהקומפילר (מהדר) של Dalvik מבצע אופטימיזציה גבוהה מאוד (מזהה קוד כפול, יכול לשנות מבני נתונים וספריות במידת הצורך, משנה את סדר הבייטים וכד'). כתוצאה מכל זה Dalvik משתמשת בפחות זיכרון מאשר Java VM. - -למי שמעוניין להרחיב, להלן סירטון בן שעה מ Google I/O 2008 המסביר בהרחבה כיצד Dalvik עובד: - - - -  - -### השכבה הכחולה: Applications Framework - -
- Framework Layer -
- -הרמה השלישית נקראת Application Framework ובמילים אחרות ניתן גם לקרוא לה API Level. - -זהו בעצם שלד המערכת, ה Framework חושף לאפליקציות את יכולות המערכת. כשהמפתח קובע את ה API Level של האפליקציה הוא בעצם קובע מה יהיה אפשרי (או נגיש) בשכבה הזו, וכתוצאה מכך על איזה גרסאות Android האפליקציה תוכל להיות מותקנת. לדוגמה, ב API Level 10 (גרסת אנדרואיד 2.3.3) התאפשר לראשונה לעשות שימוש ברכיב ה [NFC](http://en.wikipedia.org/wiki/Near_field_communication), ורק אפליקציות עם תמיכה מינמלית ב-API Level 10 ומעלה יוכלו לבצע שימוש ברכיב זה. - -  - -### השכבה הכחולה: Applications - -
- Apploctions Layer -
- -בשכבה הרבעית והאחרונה נמצא את כל האפליקציות המובנות, הבסיסיות, של המערכת (לדוגמה: החייגן, אנשי הקשר, הודעות, דפדפן, הלאנצ'ר וכ'ו). - -קובץ APK (או אפליקציה) זהו בעצם אוסף של קבצי dex (קוד המתאים לרוץ על Dalvik VM), משאבים (קבצי תמונות, קבצי ווידיאו, קבצי אודיו, קבצי XML וכד'), ואולי גם כמה Native libs. - -כל השכבות יחדיו כפי שאנדרואיד מורכבת: - -
- Android Architecture -
- -  - -### ADB - -ADB(ראשי תיבות שלAndroid Debug Bridge) זוהי תוכנית הרצה משורת הפקודה (cmd / terminal) על המחשב ומתקשרת עם המכשיר או האמלוטר (ובמילים אחרות, תכניות adb פותחת שורת פקודה למכשיר). - -
- Android ADB -
- -ה adb משמש מפתחים לניהול מערכת ה Android הישר מהמחשב. הוא מהווה דרייבר בין המכשיר למחשב ומוסיף פקודות לטרמינל ( / cmd) שנותנות למפתחים את היכולת לבצע פעולות שונות, כמו לתת הוראה למכשיר להיכנס למצבים מסויימים, לתת הוראה להתקין אפליקציה מסוימת (שנמצאת על המחשב ולא על המכשיר) וכד'. - -כשאנו פותחים את ה ADB (ניתן לפתוח אותו מתיקיית sdk/platform-tools) הוא קודם כל בודק האם יש תהליך ADB פתוח כבר, במידה ואין הוא מתחיל את התהליך. כאשר ה ADB עולה הוא מתחבר לפורט TCP 5037 ומקשיב לפקודות מה ADB (שורת הפקודה). השרת מחפש ומקים חיבורים לכל אמולטור / מכשיר בטווחי הפורטים 5555 עד 5585. כל אמולטור / מכשיר "רוכש" זוג יציאות, לדוגמה:  - -```shell -Emulator 1, console: 5554 -Emulator 1, adb: 5555 -Emulator 2, console: 5556 -Emulator 2, adb: 5557 -``` - -בעת פתיחת ה ADB וחיבור למכשיר, מה שמתבצע ברקע במכשיר זהו פתיחת Linux Shell, ולכן ניתן לבצע מגוון פעולות ע"י כתיבת פקודות ישירות למכשיר, בדומה לטרמינל ב Linux. -[כאן](http://android-dls.com/wiki/index.php?title=ADB) ניתן למצוא מגוון פקודות הניתנות ליישום בADB (עם הסבר). - -  - -### Bootloader - -
- Bootloader -
- -ה [Bootloader](http://en.wikipedia.org/wiki/Booting) לא ממש קשור ישירות למערכת ההפעלה של Android , אלא זהו רכיב תוכנה מיוחד שרץ בזמן עליית המערכת (אחרי הדלקת המכשיר ולפני שמערכת האנדרואיד עולה). תפקידו הוא לבצע בדיקות לזיכרון ולהעלות את מערכת ההפעלה (OS) לזיכרון ה RAM ו"להעביר את המושכות" על המכשיר למערכת ההפעלה. - -* נוהגים להשוות את ה Bootloader לתוכנת ה Bios שאנחנו מכירים מעולם ה PC שם ה Bios הוא בעצם יחידה נפרדת לגמרי ממערכת ההפעלה שעולה בזמן ה boot לפני עליית המערכת הפעלה (OS). - - -
- Clockworkmod Recovery -
- -  - -### Recovery - -המילה Recovery מתייחסת למחיצה נפרדת בה מותקנת קונסלת הריקברי (שאליה ניתן להגיע ע"י קומבינציה של מספר לחצנים, הקומבינציה תלוית מכשיר). הריקברי הקיים במערכת ה Android, לצערנו, פשוט מאוד באפשרויות שלו, אך בקלות יחסית ניתן להשיג את קוד המקור שלו ולהוסיף (לפתח) אפשרויות נוספות. תודות למפתחים המוכשרים שמציפים את קהילת האנדרואיד ישנם כמה וכמה ריקברי המבצעים זאת. הנפוצים שבינהם הינם: [Clockwork Recovery](https://www.clockworkmod.com/), [OpenRecovery](http://www.teamw.in/). - -הריקברי המבונה במערכת האנדרואיד מוגבל בכוונה תחילה. הוא נועד לבצע פעולות ספציפיות ולכן מציע אך ורק את 2 האפשרויות הבאות: למחוק את כל קבצי המערכת והמשתמש, ולהתקין עדכוני מערכת. בעוד הריקברי שפותח ע"י המפתחים השונים לרוב מציע עוד מגוון אפשרויות כגון: - - * אופציית גיבוי ושחזור. - * מחיקת מחיצות ספציפיות. - * התקנת חבילות שלא חתומות ע"י גורמים רשמיים. - * היכולת לבצע mount למחיצות השונות. - -  - -### APK - -
- Apk -
- -[Apk](http://en.wikipedia.org/wiki/Android_application_package) זהוי סיומת הקובץ בו נשמרות אפליקציות של מערכת האנדרואיד. ניתן להשוות את הסיומת לסיומת bat, jar, exe וכד'. הקובץ עצמו הינו קובץ zip רגיל לחלוטין (ניתן לשנות לו את הסיומת מ app.apk ל app.zip ולפתוח אותו באופן רגיל). -במידה ונפתח אותו, נראה מספר תיקיות וקצבים, בואו ננסה להבין מה הולך כאן: - - * **META-INF:** הספרייה מכילה בתוכה את החתימה של קובץ ה zip. ללא חתימת הקובץ לא ניתן להתקין את ה apk (האפליקציה), משום שהחתימה מכילה את 'תעודת הזהות' של הקובץ. בזמן ההתקנה המערכת בודקת אם החתימה מתאימה ונותנת הודעת שגיאה במידה ואחד הקבצים שונה. יש לציין כי ניתן לחתום את הקובץ מחדש. - * **res:** התיקייה מכילה את המשאבים (קבצים) לשימוש האפליקציה, לדוגמה: תמונות, קבצי xml וכד'. - * **AndroidManifest.xml:** קובץ הכרחי בשביל הצלחת התקנת האפליקציה על המכשיר. הקובץ מכיל את הפרטים של האפליקציה (שם האפליקציה, גרסה, הרשאות וכד'). - * **classes.dex:** קובץ המכיל את הספריות (class) שבהן השתמש המתכנת על מנת לכתוב את האפליקציה. הקובץ הנל כתוב בשפת Java bytecode (ג'אווה מקומפלת) ומתורגם לגמרי ע"י Dalvik virtual machine. - * **resources.arsc:** קובץ דחוס (ומקומפל) המכיל את המשאבים. - -**אפשר להתקין את קובץ הapk בשתי דרכים:** - - 1. להעתיקו למכשיר (זיכרון פנימי / SD card) ולהיכנס לתיקייה (עם מנהל קבצים דוגמת [Astro](https://play.google.com/store/apps/details?id=com.metago.astro&hl=en) או [ES File Explorer](https://play.google.com/store/apps/details?id=com.estrongs.android.pop&hl=en)) ולהתקינו (יש לוודא כי "יישומים לא מוכרים" מסומן ב V תחת הגדרות -> יישומים). - 2. להתקינו דרך ה ADB (יש לוודא כי המכשיר מחובר למחשב באמצעות כבל usb ולוודא כי תחת הגדרות -> יישומים -> פיתוח -> usb debugging מסומן ב V). - -  - -### Root - -מושג: מתן הרשאות של מנהל מערכת במכשיר (SuperUser). כמו Administrator ב windows, על מנת שנוכל לגשת ולשחק עם דברים שאינם בהרשאה של משתמש רגיל (כמו תיקיית ה System במקרה שלנו), (המושג מגיע מעולם הלינוקס בו תקיית המערכת נקראת root – שורש, ומסומנת ב / ). תיקיית ה System מוגנת וכדי לשנות שם דברים אנו צריכים את אותה הרשאה. בדרך כלל למשתמשים מן השורה אין צורך ב root אך למפתחים, האקרים ושאר סקרנים המעוניינים לשנות דברים, חייבים את ההרשאה הזו. - -**דוגמאות ללמה צריך את אותה הרשאה (Root):** - - 1. עד גרסת אנדרואיד 2.2 (Froyo) לא היה באנדרואיד עברית, ובשביל להוסיף פונטים עבריים למכשיר היה נדרש לשנות קבצי מערכת ולכן היו צריכים הרשאות SuperUser ובשביל להשיג את אותן הרשאות היינו צריכים לפרוץ את המכשיר (Root). - 2. כמו כן, ישנן אפליקציות שדורשות Root כמו: צילום מסך (למעט חלק מהמכשירים), המהרת המעבד (over clock), חלוקת מחיצות הזיכרון מחדש, התקנת רום שונה ועוד. - 3. למרות שהזכרנו שהרשאות אלה לרוב לא דרושות למשתמשים מן השורה, התהליך כמעט תמיד קל מאוד, ורוב המשתמשים מבצעים אותו על מנת ל"זכות" בחופש מלא. - -  - -### Rom - -Rom = מערכת ההפעלה. (לא ווינדוס פון 7, אנדרואיד או IOS, אלא גרסאות / הפצות שונות של אנדרואיד), (בדומה להפצות השונות של לינוקס). - -הרום "מגיע" כקובץ img (הרבה פעמים מגיע עם תוספות כך שארוז בקובץ zip), את הקובץ מעלים לכרטיס הזיכרון ומתקינים אותו דרך ה recovery , (או דרך download mode במכשירי סמסונג). Android היא מערכת הפעלה פתוחה מה שאומר שכולם יכולים להשיג את קוד המקור ולבצע שינויים בהתאם לרצוננו. ובהמשך לכך, קיימות קבוצות מפתחים, שמוציאים את הרומים שלהם (מערכות הפעלה בגרסאות שלהם) אחרי שינויים שהם ביצעו כגון שיפור חיי הסוללה, שיפור הביצועים של המכשיר, הורדת אפליקציות מובנות שאינן בשימוש, החלפת אפליקציות לגרסאות 'קלות' יותר, שינויים גרפיים ועוד. - - * בעבר (ולצערנו עוד קורה היום) היו מקרים בהם היצרניות זנחו מכשירים והפסיקו להוציא להם עידכונים (לדוג' סמסונג עם מכשיר ה-i7500), קהילת המפתחים הרבה פעמים דואגת לאותם משתמשים ומוציאה רומים בהם גרסאות האנדרואיד חדשות יותר או ממשקים חדשים (כמו שקרה עם ממשק הסנס גרסה 3, אצל מכשיר ה Desire של HTC). - -  - -### Odexed & Deodexed - -כולנו נתקלנו במושג הזה, אבל מה זה באמת אומר? -אני מניח שאתם יודעים שלמערכת ה Android ישנם מחיצות שונות, כמו מחיצת ה system/ שמכילה את כל אפליקציות המערכת (שאינן ניתנות לשינוי ומחיקה), ומחיצת ה data/ המכילה את אפליקציות המשתמש (אלה שכן ניתנות לשינוי ומחיקה). -בעת הפעלת המכשיר, מחיצת ה system/ הינה הראשונה להיטען ובכך ניתנת העדפה להימצאות בזיכרון, לאפליקציות הנמצאות במחיצה זו. - -ישנם שני מסלולים לפיהם המערכת תעבוד: - - * **Odexed -** ה cache של כל אפליקציה מוחזק בקובץ נפרד בשם odex. ונטען למכונה הווירטואלית בזמן עליית המכשיר, וזה מקטין את הזמן הנדרש למכשיר לעלות. - * **Deodexed -** ה cache של כל אפליקציה מוחזק בתוך ה Apk עצמו, בקובץ בשם classes.dex ומעלה את זמן טעינת המכשיר. - -רוב היצרניות (OEM) בוחרות באופציה הראשונה, שכן היא משפרת את זמני עליית המכשיר, מכיוון שה cache נבנה כחלק מה VM עצמו, בעוד באופציה השניה ה cache יטען בעת פתיחת האפליקציה (ה apk). אך רומים Deodexed, מאפשרים לשנות את המראה ותחושת הפעולה של אפליקציות מובנות במערכת, ולכן זהו אופציה פופלריות מאוד למרות הכל. בנוסף, במציאות, רק זמן העליה של המכשיר בפעם הראשונה (לאחר שניקתם את ה Dalvik cache) הינו ארוך מהרגיל. - -  - -### לסיכום - -עברנו על ארכיטקטורת מערכת ה Android והספריות השונות שבשימוש בכל שכבה ושכבה, נתנו הסבר לבחירה בלינוקס קרנל, ובבנית VM יחודיי (Dalvik). משם המשכנו למושגים הבסיסיים של המערכת כמו ADB, Bootloader, Recovery, apk, Root ו Rom. ולבסוף אף נגענו במושג מתקדם יותר והוא ההבדל בין אפליקציות Odexed ו Deodexed. diff --git a/data/_oldPosts/2012-11-01-multitasking-task-killer.md b/data/_oldPosts/2012-11-01-multitasking-task-killer.md deleted file mode 100644 index 3c01db7..0000000 --- a/data/_oldPosts/2012-11-01-multitasking-task-killer.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: 'Multitasking & Task killer' -author: nirgn -layout: post -summary: "בפוסט זה נדבר על אחד הדברים המבלבלים ביותר ב Android וזה ה Multitask." -category: Android ---- -אני חושב שאחד הדברים שהכי מטעים באנדרואיד זה עניין הריבוי משימות (או Multitasking) והאפליקציות הפתוחות ברקע. הרוב המוחלט של הציבור נוטה לטעות בעניין ואני אוסיף להגיד שלא באשמתו, הייתה זו [Microsoft](http://en.wikipedia.org/wiki/Microsoft) שהרגילה אותנו לסגור כל דבר שזז כדי לפנות מקום בזיכרון. - -אבל מה אם התוכנה צריכה X זיכרון ולנו פנוי X+Y זיכרון? לצערנו זה כבר מוטמע בנו כאינסטינקט ואנחנו נסגור את כל מה שאין לנו בו שימוש למרות שכבר עכשיו פנוי לנו יותר זיכרון ממה שאנו באמת צריכים. - - - -  - -### אז מאיפה מגיע המרדף אחרי הזיכרון הפנוי? - -כמו שהזכרתי בכותרת, המרדף מגיע כי ככה הרגילו אותנו, אנחנו רגילים לראות במנהל המשימות של Windows כמות זיכרון פנוי וככל שיש יותר הרי זה משובח (בלי שום קשר לכלום). - -אכן, לפעמים אנחנו צריכים X זיכרון ופנוי לנו פחות ממה שאנחנו צריכים, אז לסגור תוכניות פתוחות ללא שימוש זה הדבר הנכון לעשות. אבל לפעמים (רוב הזמן (; ), אנחנו נוטים לסגור חלונות פתוחים ללא קשר לאם פנוי לנו מספיק זיכרון או לא, כך התרגלנו לחשוב - ככל שיש יותר זיכרון פנוי המחשב יעבוד יותר מהר (כמו שהצלחתם להבין זה כשלעצמו לא תמיד נכון ואתם יכולים כעת לפתוח את מנהל המשימות ולראות שהמערכת שלכם לרוב לא משתמשת בכל הזיכרון שרכשתם בשבילה). - -  - -### איך זה מתקשר לאנדרואיד? - -האמת שפה הכל נפסק, ונשארת איתנו רק המחשבה אותה התרגלנו לחשוב. באנדרואיד (להבדיל ממה שרוב האנשים יגידו לכם) לא צריך לסגור חלונות! - -רוב האנשים בעלי מכשיר אנדרואיד מורידים מהמרקט מנהל משימות בשביל לסגור אפליקציות שעובדות ברקע, הרי הדבר הנפלא שאנו מתפארים בו באנדרואיד הוא ריבוי משימות 'אמיתי' (לא כמו במתחרה הוותיק iOS עליו נדבר בהמשך), אבל אם כך הדבר זה אומר שככל שאנחנו פותחים יותר אפליקציות המכשיר יעבוד יותר לאט. אז זהו שלא, המערכת, אנדרואיד, יודעת לנהל בעצמה את הזיכרון של המכשיר ולא צריכה מכם עזרה (למעט מקרי קצה שבהם אפליקציה תסרב לעבוד או תקרוס ואז צריך לפעמים לסגור אותה בברוטליות, באופן ידני). - -אני אעיז להגיד שהורדה של מנהל משימות לא רק שלא נכונה אלא בין היתר, גם פוגעת בתפקוד הבסיסי של המכשיר. - -  - -### יורדים לשורש הדברים - -**למערכת הפעלה ניידת יש דרישות ומגבלות מיוחדות:** - - 1. זיכרון מוגבל שלא יכול להבטיח תמיד מספיק מקום לשמירת המידע הנדרש לצורך החלפת משימות. - 2. המשתמש לא נדרש לסגור אפליקציות (ההנחה הבסיסית היא שהוא מעדיף להשאיר חלק גדול מהאפליקציות בהן הוא משתמש פתוחות, ולדפדף בינהן לפי רצונו). - -**אז איך התזמורת מנגנת בפועל:** - -כל אפליקציה רצה על תהליך משלה, ברגע שמערכת ההפעלה זקוקה למשאבי זיכרון עבור משימה אותה היא מבצעת, היא פשוט תהרוג את התהליך של אפליקציה הנמצאת בהמתנה ותשתמש במשאבים שהתפנו (הפעולה הזו נעשית באופן ברוטלי, בלי שום תהליך שמירה לפניו, סינכרון או אזהרה מוקדמת!). - -**את מי מהפעילויות שנמצאות בהמתנה תבחר המערכת להרוג?** - -הבחירה תעשה על פי קריטריונים של חשיבות האפליקציה למשתמש (לפי נתונים מפעילות עבר) ולפי השוואת זמני ההמתנה (כשהעדיפות היא להרוג את מי שלא היה פעיל זמן רב יותר). כמובן שאם מערכת ההפעלה לא נמצאת במצוקת משאבים, היא תאפשר לתהליך לעבוד ברקע עד כמה שיצטרך. - -למרות הנאמר למעלה, האפליקציות שתהליכן נהרג יוכלו להמשיך לפעול ברגע שהמשתמש יחזיר אותן לפעולה (זה מתאפשר היות שהנתונים החיוניים לחזרה לפעולה מהנקודה בה המשתמש צפה באפליקציה לאחרונה, נשמרים ברגע שהאפליקציה יורדת מהתצוגה ועוברת לרוץ ברקע). - -**לא הכל מושלם, ישנם כמה בעיות** - - * החיסול הברוטלי של משימות הרצות ברקע על ידי המערכת מאוד בעייתי לפעמים. למשל: נגן MP3 שרץ ברקע, הרי לא הגיוני להרוג את התהליך שלו במקרה שיחסרו משאבים לאפליקציה אחרת. אז קיים מנגנון שיסמן למערכת ההפעלה לאפשר לתהליך לעבוד, למרות שהוא עובד ברקע ולכאורה בעדיפות לחיסול. - * ה Service רץ ברקע ללא ממשק, במקרה שמערכת ההפעלה נאלצת להרוג תהליך היא תדאג להפעילו מחדש ברגע שיתפנו משאבים מספיקים לכך. (ניתן להגדיר Service שיהיה חסין יותר מפני חיסול ע"י מערכת הפעלה אבל האפליקציה חייבת להכיל אייקון שיסמן למשתמש שהוא עובד ושניתן יהיה לסגור אותו). - -  - -### למה לא לחסוך את הפעולה למערכת? - -כמו שהבנתם לאנדרואיד יש מערכת לניהול זיכרון שיודעת לנהל את עצמה (והיא אפילו עושה את זה טוב), ברגע שאתם סוגרים את התהליך באופן ידני אתם יוצרים במילה אחת בלאגן! - -לשם הדוגמה, נניח שכרגע סגרתם תהליך הנמצא כעת בהקפאה, המערכת (באחת הסריקות) תגלה שהתהליך לא נמצא בהקפאה (למרות שהוא היה צריך להיות שם), אז היא תפעיל אותו מחדש ותכניס אותו למצב הקפאה. אני בטוח שעכשיו לכמה מכם נופלים אסימונים ללמה סגרתם אפליקציה, ואחרי 5 דק' ראיתם אותה שוב פתוחה. - -ועכשיו הגענו למסקנה הפשוטה שלא רק שלא "עזרתם" למערכת אלא גם גרמתם לה לעבוד שוב כדי לפתוח את האפליקציה מחדש, זאת אומרת המעבד עבד-> סוללה נגמרת מהר יותר (דרך אגב, המעבד עבד-> הוא עסוק בדברים אחרים במקום לגרום לפעולות שאתם עושים כרגע לרוץ חלק). - -  - -### Multi Task - -נושא הריבוי משימות הינו נושא כאוב אצל משתמשי האנדרואיד, בעוד תמיד שמכשיר האנדרואיד ניהיה טיפה לאגי ([lag](http://en.wikipedia.org/wiki/Lag)) אנחנו תמיד מתרצים זאת עם נושא ריבוי המשימות, משתמשי ה iOS יכולים לשמוע מוסיקה ולגלוש בלי שהמכשיר יתקל בלאגים ואין להם צורך לתרץ ולהסביר זאת. - -אז נדגים את דרך הפעולה של מערכת האנדרואיד ומערכת ה iOS בעזרת ניסוי קטן: ניקח מכשיר אנדרואיד ומכשיר iOS (אייפון) ונטען דף אינטרנט כבד (כדי שזמן הטעינה יהיה ארוך, ניקח לדוג' את [Facebook](http://en.wikipedia.org/wiki/Facebook)), כשהטעינה מגיעה לחצי ויש עם מה "לשחק" נשים את האצבע על המסך ונזיז אותו מעלה / מטה. התהליך שיקרה ב iOS הוא שהטעינה תעצור לגמרי! והמערכת תתן עדיפות לתהליך המגע שהתחלנו כעת, באנדרואיד הטעינה תמשיך והמערכת תנסה לשלב בין התהליכים. מה שראינו כרגע יהיה מאופיין באנדרואיד בלאגים (lags) מכיוון שכוח העיבוד מוגבל ואינו יכול לבצע את כל התהליכים בעת ובעונה אחת (ככל שמכשיר האנדרואיד יהיה בעל יותר משאבים, מעבד יותר מהיר, יותר ליבות, יותר זיכרון וכ'ו הסבירות שהתהליך יתאפיין בלאגים נמוכה). - -בגרסת אנדרואיד ICS (גרסה 4.0) המפתחים בגוגל לקחו רעיון מה PC, וגרמו ל [GPU](http://en.wikipedia.org/wiki/Graphics_processing_unit) (המעבד הגרפי) לעזור ל [CPU](http://en.wikipedia.org/wiki/Central_processing_unit) (המעבד המרכזי) בעיבוד התהליכים ובכך לגרום לריצה חלקה יותר של המערכת. בנוסף ICS תומכת באופן מלא במעבדים מרובי ליבות ויודעת לחלק בינהם את הנטל (כמו ב PC) כך שהמערכת, שוב, תרוץ בצורה חלקה יותר. - -מה שראינו באנדרואיד הוא מולטי טסקינג מלא, 2 התהליכים (המגע והטעינה של הדפדפן) נמצאים במצב 'נורמלי', והמעבד נותן עדיפות לשתיהם במידה שווה. בעוד מה שראינו ב iOS הוא שהמעבד נותן עדיפות להתליך שרץ בזמן אמת (במקרה הזה המגע) ומפסיק לגמרי את תהליך הטעינה בדפדפן. - -יש לציין כי אפל הגדירה תהליכים מסויימים אחרת ואיפשרה להם לרוץ ברקע (דוגמת הנגן), אך תהליכים אלה אינם מציינים כי ב iOS מתאפשרת פעולת הריבוי משימות אלא פשוט לתהליכים אלה יש שיטות אחרות. - -  - -### ICS - 4.0 - -אם עד היום (עד גרסה ICS) יכולתם לראות רק את 6 היישומים האחרונים שהפעלתם (ע"י לחיצה ממושכת על מקש הבית) ב ICS אתם גם יכולים "לסגור" אותם ע"י דחיפה שלהם לצד ימין. אבל הם לא נסגרים לגמרי, הם נשארים קפואים. - -המערכת מתנהגת בידיוק כמו שהייתה רגילה (באופן לא אבסורדי, בצורה יותר חכמה מאיתנו), אך כדי שאנחנו לא נפריע לה להתנהל החליטו בגוגל לספק לנו את יצר סגירת היישומים הפועלים ועתה אנחנו יכולים לא רק לצאת ממנו ע"י לחיצה על מקש החזור (מה שהיה עד היום) אלה גם לסגור אותו ע"י דחיפה ימינה (או יותר נכון לסגור את ה Activity). - -אם תרצו להרחיב קיים פוסט בנושא בבלוג המפתחים של אנדרואיד: [Multitasking the Android Way](http://android-developers.blogspot.co.il/2010/04/multitasking-android-way.html). diff --git a/data/_oldPosts/2013-02-17-array.md b/data/_oldPosts/2013-02-17-array.md deleted file mode 100644 index 82ebd7a..0000000 --- a/data/_oldPosts/2013-02-17-array.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: מערך (Array) -author: nirgn -layout: post -summary: "בפוסט זה אציג את מבנה הנתונים, מערך (Array), ואסביר על סימונים אסימפטוטים אותם נפגוש בהמשך, בפוסטי הבאים." -category: Data Structures ---- -פוסט זה הינו התחלה של קטגוריה חדשה בבלוג, בפוסט אציג את מבנה הנתונים מערך, ובנוסף אסביר על סימונים אסימפטוטים אותם נפגוש בפוסטים הבאים. -הפוסט אינו בא ללמד באופן מלא את כל הקשור למבנה הנתונים הנל, וניתן לראות בפוסט כתזכורת בלבד. - - - -  - -Array - מערך, הינו מבנה נתונים בסיסי במדעי המחשב לאיסוף ואחזקה של משתנים. כל משתנה נמצא בתא משלו, וניתן לגשת אליו באמצעות האינדקס של התא. -לשם המחשה, להלן ציור של מבנה הנתונים: - -
- One-dimensional Array -
- - * נהוג לצייר את המערך כשורה של תאים. - * אנו מתחילים לספור את האינדקסים כמו כל דבר במדעי המחשב ב 0 (ולא ב 1). - * שם המערך הוא A. - * כדי לפנות לתא במערך, אנו נרשום: [A[6. בכך נפנה לתא בעל האינדקס 6 (תא מספר 6) שבו נמצא הערך 101 (שימו לב כי זה האיבר השביעי במערך). - * מבנה זה של מערך נקרא מערך חד מימדי, שכן הינו בעל מימד אחד, שורה אחת. - -  - -### מערך דו מימדי - -מערך דו מימדי הינו מערך בעל כמה שורות (בניגוד למערך חד מימדי בו ישנה שורה אחת בלבד) ושקול למטריצה במתמטיקה. מערך דו מימדי של מספרים שלמים יראה כך: - -||0|1|2|3|4|5| -|:-:|:-:|:-:|:-:|:-:|:-:|:-:| -|0|45|23|92|82|34|0| -|1|34|76|83|10|60|92| -|2|72|37|93|94|18|65| -|3|15|98|32|6|95|27| -|4|92|3|45|96|48|9| - -כשנרצה לפנות לתא במערך, אנו נרשום [A[0,4 ובכך ניגש לשורה מס' 0 ולעמודה מס' 4, ובתא הזה מופיע הערך 34 (יש לציין כי לא בכל השפות ניגשים קודם למספר השורה ולאחר מכן לעמודה). - -  - -### תכונות המערך - -כמו שניתן לראות, מערך הינו אוסף של משתנים מסוג מסויים, במערך ניתן לשים מגוון סוגי משתנים, אך ברגע שהגדרנו את המערך להכיל סוג של משתנה כל המערך מכיל את אותו הסוג. ז"א שאם נגדיר את המערך A להכיל משתנה מסוג int (קיצור של integer - מספרים שלמים), כל התאים במערך יקבלו אך ורק int, ולא יתכן כי נכניס בתא אחד int (מספר שלם), ובשני צירוף של תווים (string - מחרוזת תווים או במילים פשוטות: מילים). - -גישה לתא במערך, תתבצע בזמן ריצה (O(1 מכיוון שאנו יודעים בדיוק לאיזה תא אנו רוצים לגשת, הפעולה תדרוש מאיתנו זמן ריצה קבוע ובסיסי: 1. בנוסף, המערך דורש בדיוק את כמות הזיכרון הנדרשת עבור הנתונים עצמם, ז"א שבמידה וישנם 9 נתונים הוא ידרוש בדיוק 9 תאים ולא יותר (להבדיל ממבני נתונים אחרים אותם נפגוש בהמשך). - -אחד החסרונות הגדולים במערך הוא פעולת מחיקת איברים, במידה ונרצה למחוק איבר מהמערך אנו נצטרך להעביר את שאר הערכים בתאים שאחריו, כל אחד, אחד אחורה. לדוגמה: אם נרצה למחוק את הערך בתא [A[6 אז לאחר המחיקה, נצטרך להעביר את הערך בתא [A[7 לתא [A[6, ולאחר מכן את הערך בתא [A[8 לתא [A[7. מכיוון שאנו לא יודעים איזה ערך נרצה למחוק כל פעם, ניקח את המקרה הגרוע ביותר, שהינו גודל המערך (למקרה ונרצה למחוק את הערך בתא הראשון - [A[0), נסמן את גודל המערך ב n ולכן זמן הריצה של פעולת המחיקה יהיה (O(n. - - -שימו לב שכשאנו ניגשים לתא, יש לנהוג במשנה זהירות, שכן במידה וננסה לגשת לתא שאינו קיים, נקבל שגיאה. לרוב, השגיאה לא תיהיה בזמן הקומפילציה אלא בזמן ריצת התוכנית - תוצאה שאינה רצויה כלל! בנוסף, שימו לב כי ברוב השפות לא ניתן לשנות את גודל המערך לאחר ההכרזה עליו. - -  - -### שימושי המערך - -בעזרת מערכים ניתן לייצג מבני נתונים מורכבים יותר, לדוגמה: תורים, מחסניות, ערימות, עצי חיפוש, טבלאות גיבוב, ועוד. בנוסף, מערכים משמשים כמבנה נתונים בהרבה אלגוריתמים שעל חלקם נעבור בהמשך. - -> שימו לב, למערך חד מימדי נהוג לקרוא פשוט "מערך", בעוד כשנרצה לציין מערך דו מימדי, נציין במפורש "מערך דו מימדי". - -  - -### סימונים אסימפטוטים - -נושא נפרד אותו רציתי להוסיף לפוסט (כהכנה לפוסטים הבאים), הינו סימונים אסימפטוטים. הסימונים האסימפטוטים השונים נועדו לעזור לנו לסמן ניתוח של זמני ריצה, זמני ריצה של מה? של אלגוריתמים. - -אלגוריתמים במדעי המחשב נכתבים כדי לרוץ על כל קלט שהוא, ולכן נהוג לסמן את גודל הקלט באות n, בדיוק כמו במתמטיקה, זהו משתנה לא ידוע. כשאנו נכתוב אלגוריתם לפתרון בעיה כלשהי, נרצה לבדוק אם הוא יעיל מבחינת זמני הריצה (ז"א פותר את הבעיה לשמה כתבנו אותו מהר יחסית או מהר מאלגוריתמים אחרים הפותרים את אותה הבעיה). - -אך לקלטים שונים יכולים להיות זמני ריצה שונים, לדוגמה אם נקבל כקלט מערך שכבר ממוין, יש אלגוריתם שיעבור על n התאים שבו, יראה כי כל התאים כבר נמצאים במקומם הנכון, וזהו. לעומת זאת אם נכניס כקלט מערך ממוין הפוך (ז"א מהגדול לקטן), אלגוריתם זה יעבור על n התאים n פעמים (n*n או n^2). - -מכיון שבשביל קלטים שונים נקבל זמני ריצה שונים, במדעי המחשב נהוג לחשב את זמני הריצה של אלגוריתמים במקרה הגרוע ביותר (ז"א לקלט שבו האלגוריתם יצטרך לעבוד הכי קשה כדי לפתור את הבעיה). ולכן ישנם סימונים מיוחדים שיעזרו לנו לתאר את זמני הריצה: - - * **(2^O(n** ה O (או גדולה) מקביל ל'מקסימום', ז"א שזמן הריצה יהיה מקסימום (במקרה הגרוע ביותר) n^2. - * **(Θ(n^2** (עיגול וקו בתוכו, באנגלית: [Theta](http://en.wikipedia.org/wiki/Theta)) מקביל ל'בדיוק', ז"א שלכל קלט זמן הריצה יהיה בדיוק n^2. - * **(Ω(n^2** (באנגלית: [Omega](http://en.wikipedia.org/wiki/Omega)) מקביל ל'מינימום', ז"א זמן הריצה יהיה מינימום n^2. - -> לפעמים באלגוריתמים מסובכים ומורכבים לא ניתן לחשב במדויק את זמני הריצה, ולכן משתמשים בסימונים אלו לתאר חסם עליון / תחתון של זמני הריצה. - -  - -### לסיכום - -הפוסט התמקד במבנה הנתונים הבסיסי מערך, ובהגדרות של סימונים אסימפטוטים שנועדו לתאר זמני ריצה של אלגוריתמים שונים. הפוסטים הבאים בנושא יתמקדו בכמה אלגוריתמים שונים למיון מערך, ולחיפוש ערך בתא במערך. אשמח לשמוע מכם אם יש אלגוריתם ספציפי עליו תרצו לקרוא (וכמובן, כמו תמיד, ביקורת כללית), בכל דרך תקשורת שבה תבחרו. diff --git a/data/_oldPosts/2013-04-14-stack.md b/data/_oldPosts/2013-04-14-stack.md deleted file mode 100644 index 0cb82bc..0000000 --- a/data/_oldPosts/2013-04-14-stack.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: מחסנית (Stack) -author: nirgn -layout: post -summary: "מחסנית (באנגלית: Stack), הינו מבנה נתונים מופשט הפועל ( מבנה לוגי, בניגוד למערך בו קיימת רציפות פיסית בזיכרון) בצורה דומה למחסנית של רובה. בנוסף, מבנה הנתונים עושה שימוש ברעיון של מבנה נתונים קיים, אך מייצג אותו באופן שונה (נהוג להגיד: מודל מתמטי שונה עבור מבנה נתונים בעל התנהגות דומה)." -category: Data Structures ---- -מחסנית (באנגלית: Stack), הינו מבנה נתונים מופשט הפועל בצורה דומה למחסנית של רובה. - -**למה הכוונה "מבנה נתונים מופשט"?** - -ז"א שמבנה הנתונים הינו מבנה לוגי (בניגוד למערך בו קיימת רציפות פיסית בזיכרון). בנוסף, מבנה הנתונים עושה שימוש ברעיון של מבנה נתונים קיים, אך מייצג אותו באופן שונה (נהוג להגיד: מודל מתמטי שונה עבור מבנה נתונים בעל התנהגות דומה). מבנה הנתונים הנ"ל הינו ייצוג שונה של מבנה הנתונים מערך, שאותו כבר הכרנו (ניתן לייצגו גם ע"י רשימה מקושרת). - - - -
- Stack -
- -  - -על מנת להבין כיצד עובד המבנה נהוג לייצר מחסנית (לאורך כמובן) כמו בציור מצד שמאל. -(ראשי תיבות: Last In First Out), ז"א שבדיוק כמו במחסנית, האיבר האחרון שנכנס הוא הראשון שיוצא (או הראשון שנכנס הוא האחרון לצאת). - -למבנה הנתונים מחסנית יש כמה פעולות בסיסיות שאיתן עובדים, את הפעולות הנ"ל יש לממש, ולכן כעת, נראה את הפעולות, מה הן אמורות לעשות, ואת המימוש שלהן ב[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode). - -  - -### הפעולות הבסיסיות: -**דחיפה -** הכנסת איבר חדש (לראש) המחסנית. -קוד: - -```c -PUSH (S, x) - top[S] <- top[S] + 1 - S[top[S]] <- x -``` - - * S הוא שם המחסנית. - * x הוא האיבר החדש שאותו אנו מכניסים למחסנית. - * top הוא מצביע, המצביע על האיבר האחרון במחסנית. - * נגדיל את top באחד (כדי שהמחסנית תכיל עוד תא). - * נכניס את x ל top החדש. - -  - -**שליפה -** הוצאת האיבר (מראש) המחסנית. -קוד: - -```c -POP (S) -if (EMPTY (S)) - then error "underflow" -else top[S] <- top[S] - 1 - return S[top[S] + 1] -``` - - * S הוא שם המחסנית. - * אם המחסנית ריקה, נחזיר הודעת שגיאה. - * אחרת (ז"א שאינה ריקה), נזיז את top אחד אחורה (ז"א ש top יצביע על הערך שלפני האחרון. וכך בעצם הקטנו את המחסנית). - * ונחזיר את top ועוד 1 (ז"א הערך שהוצאנו בסעיף למעלה מחוץ למחסנית). - -  - -**בנוסף,נדגים את פעולות השינוי Pop ו Push:** - -
- Push & Pop Example -
- -מימוש המחסנית S מתבצע באמצעות מערך. איברי המחסנית מופיעים רק במשבצות הבהירות. (i) המחסנית S מכילה 4 איברים; האיבר הנמצא בראשה הוא 9. (ii) המחסנית S אחרי הקריאות (PUSH(S,17 ו (PUSH(S,3. בשלב הבא, (iii), המחסנית S אחרי הקריאה (POP(S החזירה את האיבר 3, שהוא האיבר האחרון שהוכנס למחסנית. על אף שהאיבר 3 עדיין מופיע במערך, הוא אינו שייך עוד למחסנית; בראש המחסנית נמצא האיבר 17. (כל אחת מהפעולות האלו מתבצעת בזמן ריצה (O(1). - -  - -לפעמים (בעיקר בשביל הנוחות), מוגדרות על מחסנית פעולות נוספות: -**האם ריקה? -** הפעולה מחזירה true או false אם המחסנית ריקה או לא (בהתאמה). -קוד: - -```c -EMPTY (S) -if (top[S] = 0) - return True -else - return False -``` - - * S הוא שם המחסנית. - * אם [top[S ריק (ז"א שווה 0), אז אין איברים במחסנית, ולכן מחזירים true. - * אחרת נחזיר false. - -  - -**הצצה -** פעולה המחזירה את ערכו של האיבר בראש המחסנית (מבלי להוציאו מהמחסנית). [top[s משמש כאינדקס של האיבר האחרון שהוכנס. -קוד: - -```c -STACK-TOP (S) -if EMPTY(S) - then error "underflow" -return S[top[S]] -``` - - * S הוא שם המחסנית. - * נבדוק האם המחסנית ריקה, במידה וריקה נחזיר הודעת שגיאה. - * כל עוד המחסנית אינה ריקה, מחזירים את הערך במחסנית (/מערך) S במקום top. - -  - -### לסיכום - -אלה הן הפעולות הבסיסיות וקצת מעבר על מבנה הנתונים מחסנית. המחסנית ממומשת, לרוב, באמצעות מערך, אך גם ניתנת למימוש באמצעות רשימה מקושרת, ובשפות תוכנות מסויימות גם באמצעות רשימה. למחסנית יש המון שימושים ויישומים בפועל, ונחשבת למבנה נתונים בסיסי. - -בנוסף, יש לציין כי מצב בו מבוצעת פעולת שליפה על מחסנית ריקה מכונה חמיקה (Underflow) ונחזיר בו הודעת שגיאה, מנגד מצב בו [top[S גדול מ n מכונה גלישה (Overflow), ובפסאודו-קוד שלעיל לא טיפלנו במצבים אלה. diff --git a/data/_oldPosts/2013-05-19-selection-sort.md b/data/_oldPosts/2013-05-19-selection-sort.md deleted file mode 100644 index db3fc19..0000000 --- a/data/_oldPosts/2013-05-19-selection-sort.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: מיון בחירה (Selection Sort) -author: nirgn -layout: post -summary: "Selection Sort - מיון בחירה, הינו האלגוריתם האינטואיטיבי ביותר (לפחות לפי דעתי). אלגוריתמם זה משתמש במבנה הנתונים הבסיסי והידוע - מערך." -category: Algorithms ---- -Selection Sort - מיון בחירה, הינו האלגוריתם האינטואיטיבי ביותר (לפחות לפי דעתי). אלגוריתם זה משתמש במבנה הנתונים הבסיסי והידוע - [מערך]({% post_url 2013-02-17-array %}). - -### עקרון האלגוריתם - - * נמצא את האיבר בעל הערך הנמוך ביותר במערך. - * נחליף אותו עם האיבר הראשון במערך. - * ונמשיך באותה שיטה על שאר המערך (ללא האיבר הראשון). - - - -  - -### הקוד של האלגוריתם ב[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -```c -SELECTION-SORT(A) -for (i <- 1 to n-1) do - min <- i - for (j <- i+1 to n) do - if (A[min] > A[j]) - min <- j - exchange A[i] <-> A[min] -``` - -
- Selection Sort Animation -
- -להלן אנימציה (בצד שמאל) של האלגוריתם בפעולה על מערך, כשהמערך ההתחלתי הוא {7 ,8 ,4 ,1, 3, 9, 6, 2, 5, 8}, והמערך המתקבל בסוף הוא {9, 8 ,7, 6, 5, 4, 3, 2, 1, 0}. - -**הסבר מופשט:** - -ניתן לראות בקוד שישנה לולאה מקוננת (לולאה בתוך לולאה), על מנת לבדוק מהו האיבר הקטן ביותר במערך ולשים אותו במקום הראשון, ולאחר מכן (באיטצריה השניה של הלולאה החיצונית), שוב, נבדוק מהו האיבר הקטן ביותר במערך אך הפעם זהו יהיה תת מערך - מהאינקס השני ועד ל n (האינדקס האחרון במערך, או גודל המערך) וכך הלאה עד מערך בגודל תא אחד. - -בלולאה החיצונית אנו עוברים על המערך מהאיבר הראשון ועד לאיבר הלפני אחרון. אנו מכניסים את האינדקס (שעובדים עליו כעת) למשתנה בשם min, ומתחילים בלולאה הפנימית להשוות אותו לכל האיברים שאחריו ( i+1 ) ועד לאיבר האחרון במערך. אם אנו מוצאים איבר שקטן ממנו נכניס את האינדקס (מספר התא) למשתנה min. - -בסיום הריצה של האלגוריתם הפנימי נחליף את המשתנה שמצאנו (המשתנה הכי קטן מתוך סדרת הערכים שבה חיפשנו. שאינה בהכרח כל המערך, ובנוסף הסדרה תקטן בכל איטרציה) במשתנה באינדקס הראשון בתת המערך. - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים - -1. נקבל מערך: { 5, 7, 1, 3 }. -2. שורה 2: נתחיל לולאה מהתא הראשון עד לתא הלפני אחרון ונבצע: - * שורה 3: נכניס את מס' התא (i) למשתנה בשם min (ז"א min מכיל כרגע את המס' 1). - * שורה 4: ניכנס ללולאה חדשה מהתא ה i+1 (כרגע תא מס' 2) עד לתא האחרון במערך ונבצע: - * שורה 5: אם הערך בתא מס' min גדול מהערך בתא מס' j שהוא התא הנבדק כרגע). - * שורה 6: אז נכניס את j ל min (נחליף את מס' התא הקטן ביותר). - * במעבר הראשון, נראה כי 1 קטן מ 3, ולכן min יהיה שווה 2 (כי הערך 1 נמצא בתא מס' 2), במעבר הבא, 7 גדול מ 1 ולכן לא נבצע דבר, גם 5 גדול מ 1 ולכן לא נבצע דבר. - * שורה 7: נחליף את האיבר בתא מס' i (שבאיטרציה הזאת, הראשונה, הינו התא הראשון) באיבר שבתא מס' min (שזהו התא בעל האיבר עם הערך הקטן ביותר שמצאנו). -3. כרגע המערך יראה כך: { 5, 7, 3, 1 }. -4. נגיע שוב לשורה 2: הפעם i יעלה ל 2 ונבצע: - * שורה 3: נכניס את מס' התא (i) למשתנה בשם min (ז"א min מכיל כרגעאת המס' 2). - * שורה 4: ניכנס ללולאה חדשה מהתא ה i+1 (כרגע תא מס' 3) עד לתא האחרון במערך ונבצע: - * שורה 5: אם הערך בתא מס' min גדול מהערך בתא מס' j שהוא התא הנבדק כרגע). - * שורה 6: אז נכניס את j ל min (נחליף את מס' התא הקטן ביותר). - * מעבר ראשון: 7 לא קטן מ 3 ולכן לא נבצע דבר. מעבר שני: 5 לא קטן מ 3 ולכן לא נבצע דבר. - * שורה 7: נחליף את האיבר בתא מס' i (שבאיטרציה הזאת, הראשונה, הינו התא הראשון) באיבר שבתא מס' min (שזהו התא בעל האיבר עם הערך הקטן ביותר שמצאנו), ז"א שנחליף את האיבר בתא מס' 3 עם האיבר בתא מס' 3 (נחליף אותו בעצמו). -5. כרגע המערך יראה כך: { 5, 7, 3, 1 }. -6. נגיע שוב לשורה 2: הפעם i יעלה ל 3 ונבצע: - * שורה 3: נכניס את מס' התא (i) למשתנה בשם min (ז"א min מכיל כרגע את המס' 3). - * שורה 4: ניכנס ללולאה חדשה מהתא ה i+1 (כרגע תא מס' 4) עד לתא האחרון במערך ונבצע: - * שורה 5: אם הערך בתא מס' min גדול מהערך בתא מס' j שהוא התא הנבדק כרגע). - * שורה 6: אז נכניס את j ל min (נחליף את מס' התא הקטן ביותר). - * מעבר ראשון 5 קטן מ 7 ולכן min יהיה שווה 4 (כי הערך 5 נמצא בתא מס' 4). - * שורה 7: נחליף את האיבר בתא מס' i (שבאיטרציה הזאת, הראשונה, הינו התא הראשון) באיבר שבתא מס' min (שזהו התא בעל האיבר עם הערך הקטן ביותר שמצאנו). -7. כרגע המערך יראה כך: { 7, 5, 3, 1 }. -8. נגיע שוב לשורה 1: הפעם i יעלה ל 4, אך לא ניכנס שוב ללולאה, מכיוון ש n (מס' התאים במערך) הוא 4, ולפי תנאי הלולאה אנו נכנסים אליה רק כאשר i קטן שווה ל n-1 (שבמקרה שלנו, זה בעצם 3). - -**סיבוכיות זמן ריצה: (O(n^2**. -**סיבוכיות מקום: (O(1**. diff --git a/data/_oldPosts/2013-06-09-insertion-sort.md b/data/_oldPosts/2013-06-09-insertion-sort.md deleted file mode 100644 index cfa380e..0000000 --- a/data/_oldPosts/2013-06-09-insertion-sort.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: מיון הכנסה (Insertion Sort) -author: nirgn -layout: post -summary: "Insertion Sort - מיון הכנסה. האלגוריתם אינטואיטיבי למדי, ודרך הפעולה שלו דומה לדרך שבה ממיינים אנשים יד של קלפי משחק. גם באלגוריתמם זה נשתמש במבנה הנתונים מערך (Array)." -category: Algorithms ---- -Insertion Sort - מיון הכנסה, גם הוא אינטואיטיבי למדי, ודרך הפעולה שלו דומה לדרך שבה ממיינים אנשים יד של קלפי משחק. גם באלגוריתמם זה נשתמש במבנה הנתונים - [מערך]({% post_url 2013-02-17-array %}). - -### עקרון האלגוריתם - - * ניקח איבר ממערך הקלט, נכניסו למקומו הנכון בתוך המערך הממוין (שנבנה בחלק השמאלי של המערך). - * נחזור על שיטה זאת על כל המערך הלא ממוין הנותר (בחלק הימיני של המערך). - * שימו לב כי בשלב הראשון המערך הממוין (החלק השמאלי במערך הקלט) כולל איבר אחד, בשלב השני הוא כולל את שני האיברים הראשונים, לאחר מכן את שלושת האיברים הראשונים וכך הלאה. - - - -  - -### הקוד של האלגוריתם ב[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -```c -INSERTION-SORT (A) -for (j <- 2 to length[A]) do - key <- A[j] - i <- j-1 - while (i > 0 and A[i] > key) do - A[i + 1] <- A[i] - i <- i -1 - A[i + 1] <- key -``` - -
- Insertion Sort Animation -
- -להלן אנימציה (בצד שמאל) של האלגוריתם בפעולה על מערך, כשהמערך ההתחלתי הוא {4 ,2, 7, 8, 1, 3, 5, 6}, והמערך המתקבל בסוף הוא {8, 7, 6, 5, 4, 3, 2, 1}. - -**הסבר מופשט:** -האלגוריתם לוקח את האיבר הראשון ומשווה אותו לכל האיברים שבמקום הנכון (עד כה), ז"א שהאיבר הראשון תמיד יהיה במקומו הנכון - הרי עדיין לא ווידאנו שיש עוד איברים במקום הנכון, ולכן אנו רואים שהאיבר הראשון בדוגמה למעלה, 6, נשאר במקום ומסומן בשחור (אלו האיברים שבטוח במקום הנכון). לאחר מכן נמשיך לאיבר השני ונשווה אותו עם האיברים שבטוח שהם במקום הנכון (עד כה זהו רק 6), ונשים את 5 במקומו הנכון ביחס לאיברים שאותם כבר בדקנו (ז"א ש 5 יתחלף עם 6, כי הוא קטן ממנו), לאחר מכן נגיע לאיבר השלישי (שהוא 3) ונבדוק אותו עם האיברים שנמצאים במקום הנכון (עד כה 5 ו 6), ומכיוון שהוא קטן מ 5, ישר בבדיקה הראשונה (הבדיקה מול האיבר הראשון, שכרגע הינו בעל הערך 5) נראה שהוא (הערך 3) קטן מ 5 ולכן נמקם אותו במקום הראשון - וכך הלאה על כל האיברים. - -אלגוריתם זה (מיון הכנסה) די דומה לאלגוריתם מיון בחירה שהצגנו קודם לכן, ובשניהם יש לולאה מקוננת, אך הלולאה השניה באלגוריתם זה הינה לולאת while (ולא for), ז"א שבמידה שזיהינו שהאיבר שאנו בודקים כעת קטן מהאיבר במקום כלשהו (כמו בדוגמא עם האיבר בעל הערך 3) נעצור את הבדיקה ונכניס אותו למקומו הנכון (בכך נחסוך את שאר הבדיקות). - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים - -1. נקבל מערך: { 5, 7, 1, 3 }. -2. שורה 2: נתחיל לולאת for, מהתא השני עד לתא האחרון ונבצע: - * שורה 3: נכניס את הערך שבתא מס' j (כרגע 1) למשתנה בשם key. - * שורה 4: נכניס למשתנה בשם i את המס' j-1 (כרגע זה יהיה 1). - * שורה 5: ניכנס ללולאת while, בתנאי שכל עוד i גדול מ 0 וגם הערך בתא i גדול מהערך במשתנה key, ונבצע: - * שורה 6: נכניס את הערך בתא i לתא שאחריו ( i+1 ). - * שורה 7: נחסר את i ב 1 (נלך אחורה במערך, כדי לבדוק את האיבר שלפניו באיטרציה הבאה, עד שנגיע ל i=0 או שהערך בתא i גדול מהערך במשתנה key - תנאי הלולאה). - * במעבר הראשון, נראה כי 3 גדול מ 1, ולכן המערך יראה כך: { 5, 7, 3, 3 }. - * שורה 8: נשים את המשתנה key במקום הערך שבתא i+1 (ובעצם נקבל תת מערך ממוין בצד השמאלי של המערך). -3. כרגע המערך יראה כך: { 5, 7, 3, 1 }. -4. נגיע שוב לשורה 2: הפעם i יעלה ל 3 ונבצע: - * שורה 3: נכניס את הערך שבתא מס' j (כרגע 7) למשתנה בשם key. - * שורה 4: נכניס למשתנה בשם i את המס' j-1 (כרגע זה יהיה 2). - * שורה 5: לא ניכנס ללולאת while, כי i גדול מ 0 אבל הערך בתא i (שהוא 3), לאגדול מהערך במשתנה key (שהוא 7). - * שורה 6: נשים את המשתנה key במקום הערך שבתא i+1 (במקום עצמו). -5. כרגע המערך יראה כך: { 5, 7, 3, 1 }. -6. נגיע שוב לשורה 2: הפעם i יעלה ל 4 ונבצע: - * שורה 3: נכניס את הערך שבתא מס' j (כרגע 5) למשתנה בשם key. - * שורה 4: נכניס למשתנה בשם i את המס' j-1 (כרגע זה יהיה 3). - * שורה 5: ניכנס ללולאת while, בתנאי שכל עוד i גדול מ 0 (i שווה ל 3), וגם הערך בתא i (שהוא 7) גדול מהערך במשתנה key (שהוא 5), ונבצע: - * שורה 6: נכניס את הערך בתא i לתא שאחריו ( i+1 ). - * שורה 7: נחסר את i ב 1 (נלך אחורה במערך, כדי לבדוק את האיבר שלפניו באיטרציה הבאה, נראה ש i שהוא 3 לא גדול מ key שהוא 5 ולכן נצא מהלולאה). - * שורה 8: נשים את המשתנה key במקום הערך שבתא i+1 (במקום עצמו). -7. כרגע המערך יראה כך: { 7, 5, 3, 1 }. -8. נגיע שוב לשורה 1: הפעם i יעלה ל 5, אך לא ניכנס שוב ללולאה, מכיוון ש n (מס' התאים במערך) הוא 4, ולפי תנאי הלולאה אנו נכנסים אליה רק כאשר i קטן שווה ל n (שבמקרה שלנו, זה בעצם 4). - -**סיבוכיות זמן ריצה: (O(n^2** (בהשוואה למיון בחירה, בגלל לולאת ה While, כנראה שנחסוך באלגוריתם זה כמה בדיקות. אך אין אנו יכולים להתחייב כי זמן הריצה שלו יהיה קטן יותר, מכיון שזה תלוי בקלט אותו נקבל, ולכן זמן הריצה במקרה הגרוע נשאר אותו הדבר כמו במיון בחירה). -**סיבוכיות מקום: (O(1**. - -> שימו לב: האלגוריתם במיוחד יעיל למיון מספר קטן של פריטים. diff --git a/data/_oldPosts/2013-07-14-bubble-sort.md b/data/_oldPosts/2013-07-14-bubble-sort.md deleted file mode 100644 index 1346b73..0000000 --- a/data/_oldPosts/2013-07-14-bubble-sort.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: מיון בועות (Bubble Sort) -author: nirgn -layout: post -summary: "Bubble Sort - מיון בועות, ידוע גם בתור מיון החלפה, בסיסו, הוא מיון השוואתי בין 2 מספרים, כאשר הוא מבעבע למעלה את האיבר בערך הערך הגדול ביותר." -category: Algorithms ---- -Bubble Sort - מיון בועות, ידוע גם בתור מיון החלפה, בסיסו, הוא מיון השוואתי בין 2 מספרים. - -### עקרון האלגוריתם: - - * נשווה את האיבר האחרון עם האיבר שלפניו. - * במידה והוא קטן ממנו נחליף בינהם, אחרת נמשיך הלאה. - * בסיום הלולאה הפנימית (השוואת כל האיברים מול אלה שלפניהם), נעלה, ונבצע שוב את שלבים 1+2 על כל האיברים למעט האיבר הראשון במערך. - * המשך כך עד שכל האיברים יהיו בחלק השמאלי של המערך (החלק הממויין). - - - -  - -שימו לב: האלגוריתם בדרך כלל בנוי קצת אחרת ומבצע "בעבוע" למעלה של האיבר בעל הערך הגדול ביותר (בדיוק כמו באנימציה בצד שמאל), אך הקוד שאני כתבתי כאן מבצע את זה בצורה הפוכה - הוא "מבעבע" למטה את האיבר בעל הערך הקטן ביותר. - -### הקוד של האלגוריתם ב[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -```c -BUBBLE-SORT(A) -for (i <- 1 to length[A]) do - for (j <- length[A] downto i + 1) do - if (A[j] < A[j - 1] - exchange A[j] <-> A[j - 1] -``` - -
- Bubble Sort Animation -
- -להלן אנימציה (בצד שמאל) של האלגוריתם בפעולה על מערך, כשהמערך ההתחלתי הוא {4 ,2, 7, 8, 1, 3, 5, 6}, והמערך המתקבל בסוף הוא {8, 7, 6, 5, 4, 3, 2, 1}. - -**הסבר מופשט:** -האלגוריתם בודק את האיבר האחרון במערך מול האיבר שלפניו, ובמידה והוא קטן ממנו הופך בניהם, במידה ולא (ז"א שהאיבר האחרון במערך גדול מזה שלפניו) הוא ממשיך הלאה לאיבר שלפניו (זה שלפני האחרון) ובודק אותו עם האיבר שלפניו (השני לפני האחרון). - -בסיום סדרת הבדיקות הזאת נמצא הערך הקטן ביותר במערך וכעת הוא במקום הראשון במערך. כעת נבצע שוב את סדרת הפעולות על כל האיברים הנותרים (כל איברי המערך למעט האיבר הראשון). - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים - -1. נקבל מערך: { 5, 7, 1, 3 }. -2. שורה 2: נתחיל לולאת for, מהתא הראשון עד לתא האחרון ונבצע: - * שורה 3: נתחיל לולאת for, מהתאר האחרון ועד ל i +1 (במקרה הזה התא השני) ונבצע: - * שורה 4: אם האיבר j (כרגע האחרון, 5) קטן מהאיבר שלפניו (7). - * שורה 5: נחליף את 5 ו 7. - * כרגע המערך יראה כך: { 7, 5, 1, 3 }. - * שורה 3: j ירד ל 3, ונבצע: - * שורה 4: אם האיבר j (שהוא 5) קטן מהאיבר שלפניו (1). - * שורה 5: ה if לא מתבצע, כי 5 אינו קטן מ 1. - * המערך עדיין יראה כך: { 7, 5, 1, 3 }. - * שורה 3: j ירד ל 2, ונבצע: - * שורה 4: אם האיבר j (עכשיו 1) קטן מהאיבר שלפניו (3). - * שורה 5: נחליף את 3 ו 1. - * המערך יראה כך: { 7, 5, 3, 1 }. -3. נגיע שוב לשורה 2: ה i יעלה ל 2 ונבצע: - * שורה 3: נתחיל לולאת for, מהתא האחרון ועד ל i +1 (במקרה הזה התא ה 3) ונבצע: - * שורה 4: אם האיבר j (כרגע האחרון, 7) קטן מהאיבר שלפניו (6). - * שורה 5: ה if לא מתבצע, כי 7 לא קטן מ5. - * המערך עדיין יראה כך: { 7, 5, 3, 1 }. - * שורה 3: j ירד ל 3, ונבצע: - * שורה 4: אם האיבר j (עכשיו 5) קטן מהאיבר שלפניו (3). - * שורה 5: ה if לא מתבצע, כי 5 לא קטן מ 3. - * המערך עדיין יראה כך: { 7, 5, 3, 1 }. -4. נגיע שוב לשורה 2: הפעם i יעלה ל 3 ונבצע: - * שורה 3: נתחיל לולאת for" מהתא האחרון ועד ל i + 1 (עכשיו זה שווה ל 4) ונבצע: - * שורה 4: אם האיבר j (האחרון, 7) קטן מהאיבר שלפניו (5). - * שורה 5: ה if לא מתבצע, כי 7 לא קטן מ 5. - * המערך עדיין יראה כך: { 7, 5, 3, 1 }. -5. נגיע שוב לשורה 2: הפעם i יעלה ל 4, הגענו למספר האיברים במערך ( [length[A ), ולכן נצא מהלולאה, וסיימנו את המעבר על האלגוריתם. - -**סיבוכיות זמן ריצה: (O(n^2**. -**סיבוכיות מקום: (O(1**. diff --git a/data/_oldPosts/2013-08-11-merge-sort.md b/data/_oldPosts/2013-08-11-merge-sort.md deleted file mode 100644 index 0928759..0000000 --- a/data/_oldPosts/2013-08-11-merge-sort.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: מיון מיזוג (Merge Sort) -author: nirgn -layout: post -summary: "בפוסט הזה נדבר על אלוג׳ Merge Sort - מיון מיזוג. אלגוריתם זה פועל בשיטת הפרד ומשול, והוא הומצא על ידי המתמטיקאי ג׳ון פון ניומן בשנת 1945. בנוסף לעקרון האלגו׳ הזה נדבר גם באופן כללי על שיטת הפרד ומשול ונסביר אותה." -category: Algorithms ---- -Merge Sort - מיון מיזוג. אלגוריתם זה פועל בשיטת הפרד ומשול, האלגו' הומצא על ידי המתמטיקאי [ג׳ון פון ניומן](https://en.wikipedia.org/wiki/John_von_Neumann) בשנת 1945. להבדיל מהאלגוריתמים שראינו עד כה, לאלגוריתם זה יש 2 שגרות (Merge, ו Merge Sort). - -### מהי שיטת הפרד ומשול? - -
- Merge Sort Animation -
- -**הפרד:** חלק את הבעיה לכמה תת בעיות. -**משול:** פתור את התת בעיות באופן רקורסיבי. אם גודלה של תת בעיה קטן דיו, פשוט פתור אותה ישירות. -**צרף:** צרף את הפתרונות של התת בעיות לכדי פתרון מלא לבעיה המקורית. - - - -  - -### עקרון האלגוריתם - - * אם n=1 (המערך של איבר אחד ממילא ממוין) חזור. - * מיין-מזג את n/2 האיברים הראשונים. - * מיין-מזג את n/2 האיברים האחרונים. - * מזג את 2 תוצאות המיון. - -כמו שניתן לראות באנימציה משמאל, האלגוריתם עובד באופן רקורסבי ומחלק את המערך ל-2 חלקים, וכל חלק ממנו לעוד 2 חלקים, כך עד שנשאר איבר אחד בבסיסו. כעת הבעיה ניתנת לפתרון הרי איבר אחד הוא בטוח ממוין, ולכן כעת נחזור חזרה ונמזג (על ידי השוואה) את 2 התת סדרות (איבר מול איבר), ולאחר מכן, נחזור שוב בחזרה ונמזג עוד 2 תת סדרות (סדרה של 2 איברים מול סדרה של 2 איברים) וכך הלאה. - -  - -### הקוד של האלגוריתם ב[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -(ה ~ נועד לסמן עיגול כלפי מטה) - -```c -MERGE (A, p, q, r) -n1 <- q - p + 1 -n2 <- r - q -create arrays L[1..n1 + 1] and R[1..n2+1] -for (i <- 1 to n1) do - L[i] <- A[p + i - 1] -for (j <- 1 to n2) do - R[j] <- A[q + j] -L[n1 + 1] <- infinity -R[n2 + 1] <- infinity -i <- 1 -j <- 1 -for (k <- p to r) do - if (L[i] =< R[j]) - A[k] <- L[i] - else - A[k] <- R[j] - j <- j + 1 - -MERGE-SORT (A, p, r) -if ( p < r ) - q <- ~(p + r )/ 2~ - MERGE-SORT (A, p, q) - MERGE-SORT (A, q + 1, r) - MERGE (A, p, q, r) -``` - -  - -**הסבר מופשט:** -האלגוריתם מורכב מ-2 שגרות (במילים אחרות: מתודות או פרוצדורות). השגרה הראשית, שאליה קוראים בזמן הפעלת האלגוריתם, הלא היא MERGE-SORT, ושגרת העזר (שנקראת מתוך השגרה הראשית MERGE-SORT) ושמה MERGE. - -MERGE-SORT מקבל את A - המערך שיש למיין, p - משתנה המכיל מצביע לתחילת המערך, ואת r - משתנה המכיל מצביע לסוף המערך. השגרה MERGE-SORT מחלקת את המערך ל-2 (על ידי מצביע לאיבר האמצעי במשתנה q) וקריאה רקורסיבית (קריאה לעצמה) פעמיים, פעם אחת מ p (שמצביע לתחילת המערך המקורי) ועד ל q (שמצביע לאמצע המערך המקורי), ופעם נוספת מ q+1 (האיבר אחרי האמצע במערך המקורי) ועד ל r (שמצביע לסוף המערך המקורי). כך האלגו' מחלק את עצמו כל פעם ל-2 עד שלא מתקיים התנאי p שימו לב כי המיזוג של הסדרות מתבצע ע"י השגרה Merge ולכן היא זאת שמבצעת את רוב העבודה באלגוריתם. - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים - -1. נקבל מערך: { 5, 7, 1, 3 }. -2. שורה 2: מתחילים מ MERGE-SORT, מכיוון ש p - * שורה 5: קוראים שוב לעצמנו, ולכן חוזרים לשורה 1. -7. שורה 2: מכיון ש p (שהיה q + 1, והוא 1) שווה ל r (אותו איבר, לכן גם הוא 1), לא ניכנס לפעולות שבתוך ה If, ונצא ישר מהמתודה (כי יש בה רק if), ז"א שנחזור אחורה (האלגו' שלנו רקורסיבי). - * שורה 6: נקרא למתודה MERGE על { 5, 7 }.
    - * המתודה MERGE תמיין על ידי השוואה את האיברים { 5, 7 }, ולכן התת מערך יראה כך: { 7, 5 }. - * לאחר מכן, נחזור חזרה למעלה, לשוב ל MERGE אך הפעם על { 1, 3 }. - * המתודה MERGE תמיין על ידי השוואה את האיברים, והתת מערך יראה כך: { 3, 1 }. - * לאחר מכן נעלה בפעם האחרונה (נכנסו 3 פעמים, נעלה חזרה ברקורסיה 3 פעמים), ונמיין את התת מערכים { 7, 5 }, ו { 3, 1 } למערך אחד (על ידי השוואה אחד מול השני (1 מול 5, 1 קטן מ5 ולכן 1 יהיה ראשון, לאחר מכן 3 מול 5, 3 קטן מ5 ולכן 3 יהיה שני, ולאחר מכן לא נשארו איברים להשוואה אז "נשפוך" את האיברים שנשארו בתת מערך למערך הראשי. - -  - -> שימו לב, במתודה MERGE: שורות 2 עד 12 הינן "הכנה" לעבודה האמיתית, השורות כוללות חישוב של אורך התתי מערכים, ויצירה של 2 מערכים גדולים יותר (באחד), העתקה של האיברים בתת מערך השמאלי למערך השמאלי החדש והעתקה של האיברים בתת מערך הימיני למערך הימיני החדש. בנוסף, בשורות 9-10 מתבצעת הצבה של זקיפים בתאים האחרונים במערך (בקוד אמיתי כנראה שנציב שם 1-, הרי לא ניתן להציב אינוסף). -ובשורות 13 עד 18 מתבצע המיון האמיתי של האיברים על ידי השוואה של כל אחד מהאיברים לשני. - -  - -**סיבוכיות זמן ריצה: ((O(n*lg(n (למען הסר ספק: lg - זהו log בבסיס 2)**. -**סיבוכיות מקום: (O(n**. diff --git a/data/_oldPosts/2013-09-15-quick-sort.md b/data/_oldPosts/2013-09-15-quick-sort.md deleted file mode 100644 index 48fb614..0000000 --- a/data/_oldPosts/2013-09-15-quick-sort.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: מיון מהיר (Quick Sort) -author: nirgn -layout: post -summary: "בפוסט זה נדבר על האלגו׳ הרקורסיבי Quick Sort (מיון מהיר) שפועל בשיטת הפרד ומשול. האלגוריתם מתאפיין בזמן ריצה ממוצע טוב, ולכן פופלרי." -category: Algorithms ---- -Quick Sort - מיון מהיר. גם אלגוריתם זה הינו רקורסיבי ופועל בשיטת הפרד ומשול. האלגוריתם בוחר איבר אקראי מהמערך (נקרא pivot), ומסדר את כל האיברים (ע"י השוואה) כך שהאיברים הגדולים מאיבר הציר (איבר ה piviot) יופיעו אחריו (בצד הימיני של המערך) והאיברים הקטנים, לפניו (בצד השמאלי של המערך). - -לאחר מכן האלגוריתם מבצע את אותה הפעולה באופן רקורסיבי, ז"א על החלק הימני (החלק של האיברים הגדולים מאיבר הציר) ועל החלק השמאלי (החלק של האיברים הקטנים מאיבר הציר). כמובן שבכל חלק הוא בוחר איבר ציר (pivot) חדש, וכך הלאה עד אשר ישנו איבר אחד (זהו תנאי העצירה). - - - -  - -## עקרון האלגוריתם - - * אם ישנו יותר מאיבר אחד במערך בצע: - * סדר את כל האיברים כך שהאיברים הגדולים מאיבר הציר יופיעו אחריו, והאיברים הקטנים ממנו לפניו. - * חזור רקורסיבית על החלק השמאלי של המערך. - * חזור רקורסיבית על החלק הימיני של המערך. - -  - -### הקוד של האלגוריתם ב[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -```c -PARTITION (A, p, r) -x <- A[r] -i <- p -1 -for (j <- 1 to r - 1) do - if (A[j] <= x) - i <- i +1 - exchange A[i] <-> A[j] -exchange A[i + 1] <-> A[r] -return i + 1 - -QUICKSORT (A, p, r) -if (p < r) - q <- PARTITION (A, p, r) - QUICKSORT (A, p, q - 1) - QUICKSORT(A, q + 1, r) -``` - -
    - Quick Sort Animation -
    - -להלן אנימציה (בצד שמאל) של האלגוריתם בפעולה על מערך, כשהמערך ההתחלתי הוא {4 ,2, 7, 8, 1, 3, 5, 6}, והמערך המתקבל בסוף הוא {8, 7, 6, 5, 4, 3, 2, 1}. - -  - -**הסבר מופשט:** -האלגוריתם (מיון מהיר - Quick Sort) מיישם את הפרדיגמה שהכרנו, הפרד ומשול. אך בניגוד למיון מיזוג (Merge Sort), אנו לא מחלקים את המערך לשני חלקים (כמעט) שווים, אלא בוחרים איבר (pivot) אקראי ומחלקים בצורה כזו שהאיברים הקטנים ממנו נשלחים לחלקו השמאלי והאיברים הגדולים ממנו נשלחים אל חלקו הימני. - -שימו לב כי באלגוריתם זה הצירוף הוא טריוואלי, וכל העבודה מתבצעת בשלב ההפרדה (במתודה Partition). בנוסף, מכיוון ששגרת (מתודה) החלוקה תלויה בבחירת איבר הציר (pivot), לבחירת איבר זה יכולה להיות השפעה גדולה על ביצוע האלגוריתם, ולכן נהוג להפעיל שגרת Random על המערך (לפני הקריאה למיון מהיר). - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים: - -1. נקבל מערך: { 8, 10, 5, 1, 7, 3 }. אנו מתחילים במתודה QUICKSORT, כש A זהו המצביע למערך, p הוא משתנה המצביע לתא הראשון במערך (1), ו r זהו המצביע לתא האחרון במערך (6). -2. שורה 2: (השורה הראשונה בפונ' נועדה לבדיקה שלא חרגנו מגבולות המערך, או שלא בדקנו כבר את כולו), לכן נבדוק אם p - * שורה 2: אם p - - -בהתחשב בידע זה, אנו יודעים שמערך הקלט מכיל מספרים טבעיים מ 1 עד k, ולכן נוכל ליצור מערך נפרד, בשם C, בגודל k איברים (ונאתחל אותו כך שיכיל את הספרה 0 בכל תא). לאחר מכן נעבור על מערך הקלט ובכל פעם שנקרא איבר ממערך הקלט נעלה באחד את האינדקס שלו במערך C (המערך שיצרנו) (עד כאן ביצענו את שלב a באיור למעלה). - -בלולאה השלישית נעבור על המערך C, ונכניס במקום כל אינדקס את הסכום של עצמו פלוס הערך שבאינדקס שלפניו (כך נקבל כמה איברים יש לפניו ונכלול בחישוב את מספר האיברים הקיימים של אותו ערך) (שלב b). - -בלולאה הרביעית נתחיל להכניס את כל האיברים למערך חדש B (בגודל של מערך הקלט - A), על ידי כך שנעבור שוב על מערך A (הפעם מהסוף להתחלה) ובכל פעם שנראה ערך, נלך לאותו אינדקס של הערך במערך C (ז"א שאם ראינו את הערך 3 במערך A נלך לאינדקס 3 במערך C) ונכניס את מס' האינקדס (3) למערך B לפי הערך שבמערך C (אם באינדקס 3 במערך C רשום את הערך 7, נכניס את המספר 3 לתא (אינדקס) מספר 7 במערך B). - -וכך הלאה עד שנסיים לעבור על מערך A, ונקבל את מערך B שהינו העתק של מערך A ,אך ממוין. - -> _שימו לב:_ תכונה חשוב של מיון זה היא שהוא יציב, ז"א שהוא לא משנה את הסדר היחסי בין איברים זהים במיון (אם ישנו 3 פעמים את הערך 5, ולצרוך הדוגמה נקרא להם 5.1, 5.2, 5.3 (לפי הסדר שלהם בקלט), אנו נקבל את אותו הסדר 5.1, 5.2, 5.3 גם במערך הפלט). - -### עקרון האלגוריתם: - -* ניצור מערך בגודל k ונאתחל אותו ל0 (שורות 1-2). -* נעבור על מערך הקלט וכל פעם שנקרא ממנו איבר, נעלה באחד את אותו האינדקס במערך שיצרנו (שורות 3-4). -* נעבור על המערך שיצרנו ולכל אינדקס נכניס את הסכום של עצמו ועוד הערך שלפניו (שורות 5-6). -* נכניס את האיברים למערך החדש (ע"י כך שנעבור על המערך המקורי מהסוף להתחלה ובכל פעם שנראה ערך נלך לאותו האינדקס של הערך במערך שיצרנו ונכניס את מספר האינדקס למערך החדש במיקום של הערך שבמערך שיצרנו) (שורות 7-9). - -  - -### הקוד של האלגוריתם ב [פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -```c -COUNTING-SORT (A, B, k) - for (i <- 0 to k) do - C[i] <- 0 - for (j <- 1 to length[A]) do - C[A[j]] <- C[A[j]] + 1 // C[i] now contains the number of elements equal to i. - for (i <- 1 to k) do - C[i] <- C[i] + C[i - 1] // C[i] now contains the number of elements less then or equal to i. - for (j <- length[A] downto 1) do - B[C[A[j]]] <- A[j] - C[A[j]] <- C[A[j]] - 1 -``` - -  - -### הסבר מופשט: - -לאלגוריתם יש 4 חלקים, יצירת מערך עזר בגודל k ואתחולו. מעבר על מערך הקלט, קריאה של האיברים ממנו והגדלה של האינדקסים במערך שיצרנו בחלק הקודם. מעבר על המערך שיצרנו וחישוב המיקום של כל איבר. ולבסוף הכנסת האיברים למערך חדש (באותו הגודל כמו מערך הקלט), אותו אנו מוצאים כפלט. - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים: - -1. נקבל מערך: {3, 3, 5, 3, 0, 2, 0 }. -2. שורות 1: נעבור על המערך C מ0 ועד k (הספרה הגדולה ביותר במערך הקלט A, שהיא גם הספרה שקובעת מה יהיה גודל המערך C): - * שורה 2: נאתחל את לתא הנוכחי לספרה 0. -3. כרגע מערך הקלט A יראה אותו הדבר, מערך הפלט B עדיין יהיה ריק, ומערך העזר C יהיה { 0, 0, 0, 0, 0, 0 }. -4. שורה 3: נעבור על מערך הקלט A: - * שורה 4: נגדיל ב1 את הערך בתא מספר [A[j במערך C (ז"א אם בתא שאנו מסתכלים עליו כעת קיים הערך 2, נלך לתא מס' 2 במערך C ונגדיל אותו ב1). -5. מערך הקלט A כמובן לא ישתנה, מערך הפלט B עדיין יהיה ריק, ומערך העזר C יהיה {1, 0, 3, 1, 0, 2 }. -6. שורה 5: נעבור על מערך C: - * שורה 6: נכניס לתא את הערך של עצמו פלוס הערך הקיים בתא שלפנינו (מה שיתן לנו את המיקום בו צריך להיות מס' האינדקס במערך המקורי). -7. מערך הקלט A כמובן לא ישתנה, מערך הפלט B עדיין יהיה ריק, ומערך העזר C יהיה {7, 6, 6, 3, 2, 2 }. -8. שורה 7: נעבור על מערך הקלט A מהסוף להתחלה: - * שורה 8: נכניס את הערך ב [A[j למערך B בתא מס' [[C[A[j, ז"א נקרא את הערך ב[A[j ולדוגמה התא האחרון במערך שלנו מכיל את הערך 3 (ונתייחס אליו כרגע) אז נלך לתא מס' 3 במערך C ונקרא את הערך הנמצא שם (שבמקרה זה 6) ולכן נשים את 3 בתא מס' 6 במערך B). - * שורה 9: וכעת נעדכן את הערך בC במיקום [A[j להיות פחות 1, ז"א כדי שלא נדרוס ערכים. אם נמשיך בדוגמה בשורה מעל, אז לאחר שהצבנו בB, יש לעדכן בC את הערך בתא מס' 3, להיות מ6 ל5 . - * לאחר ביצוע של 2 השורות האלו מערך הקלט A כמובן לא ישתנה, מערך הפלט B יהיה {-, 3, -, -, -, -, - }, ומערך העזר C יהיה {7, 6, 5, 3, 2, 2 }. -9. לאחר ביצוע כל הלולאה, מערך הקלט A לא ישתנה, מערך הפלט B יהיה {5, 3, 3, 3, 2, 0, 0 }, ומערך העזר C יהיה {6, 6, 3, 2, 2, 0 }. - -**סיבוכיות זמן ריצה: (O(n + k.** diff --git a/data/_oldPosts/2013-11-17-binary-search.md b/data/_oldPosts/2013-11-17-binary-search.md deleted file mode 100644 index 4707823..0000000 --- a/data/_oldPosts/2013-11-17-binary-search.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: חיפוש בינארי (Binary Search) -author: nirgn -layout: post -summary: "Binary Search - חיפוש בינארי, הוא אלגוריתם רקורסיבי לחיפוש איבר במערך ממוין. מכיוון שהמערך שאנו מקבלים ממוין, אנו ננצל את התוכנה." -category: Algorithms ---- -Binary Search - חיפוש בינארי, הוא אלגוריתם רקורסיבי לחיפוש איבר ב**מערך ממוין**. מכיוון שהמערך שאנו מקבלים ממוין, אנו ננצל את התוכנה הזו ונבדוק את האיבר האמצעי בלבד, במידה והערך שאנו מחפשים קטן ממנו נבצע זאת שוב על החצי השמאלי, במידה וגדול ממנו נבצע זאת על החצי הימני. נמשיך כך עד שהמצביע הימני יהיה קטן מהשמאלי (אז עברנו על כל המערך). - -### עקרון האלגוריתם - - * אם m>x (הערך שאנו מחפשים נמצא במשתנה x) נקרא לעצמנו (רקורסיה) מ l עד m-1 (החצי השמאלי של המערך). - * אחרת נבדוק אם m - -  - -### הקוד של האלגוריתם ב [פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -(ה ~ נועד לסמן עיגול כלפי מטה) - -```c -BINARY-SEARCH (A, l, r, x) -if (r > l) - return "not found" -m <- ~(l+r)/2~ -if (A[m] > x) - return BINARY-SEARCH (A, l, m - 1, x) -else if (A[m] < x) - return BINARY-SEARCH (A, m + 1, r, x) -else return m -``` - -
    - BFS Algorithm -
    - -התמונה בצד שמאל ממחישה כיצד יראה המערך עליו אנו מחפשים, ואת הערכים שנעביר כשנקרא לעצמנו רקורסיבית. - -  - -**הסבר מופשט:** -תנאי הכרחי לאלגוריתם היא הפעולה על מערך ממוין. מכיוון שיש לנו את הידע המקדים שהמערך הינו ממוין, אנו יכולים לנצל את המידע הזה כדי להקטין את זמן הריצה עד ((O(lg(n, ז"א בדיקת חצי מהתאים במערך, במקרה הגרוע!. - -בתחילת האלג' אנו רואים את תנאי היציאה, r < l (אלו איברים שמחזיקים מצביע למערך, וז"א שהמצביע הימני, r, קטן מהמצביע השמאלי, l, ואז בעצם עברנו על כל המערך ולכן נחזיר "not found". לאחר מכן אנו מגדירים את המשתנה m שהינו מצביע לאיבר האמצעי של המערך, ואנו בודקים אם הערך שבתוך המיקום אליו m מצביע גדול או קטן מ x (משתנה המכיל את הערך אותו אנו מחפשים), ובתאם לכך הולכים שמאלה (אם גדול) או ימינה (אם קטן) כדי להמשיך לחפש אותו בחצי המערך הנותר. אם הוא לא קטן ולא גדול, אז הוא שווה, ולכן ב else האחרון נחזיר את m. - -> מכיוון שהמערך ממוין אנו יודעים בוודאות שאם הערך ב [A[m גדול מ x כל האיברים שאחרי m גם גדולים ממנו ולכן אנו יכולים "לזרוק" חצי מהמערך בלי לעבור עליו. - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים: - -* כמו שציינתי בעבר, במדעי המחשב מתחילים לספור מ-0 ולא מ-1, אך באלגוריתמים אותם אני מציג, אנו סופרים מ-1 (מטעמי נוחות), כדי להראות שהנל לא מהווה שינוי מהוותי, נדגים על אלגו' זה את הספירה מ-0 ובנוסף נשים לב כי באלגוריתם הנל (במקרה) אין כל צורך לשנות את הקוד (להבדיל לדוגמה, מהאלגוריתמים הקודמים בהם היו לולאות ואנו נאלץ להתחיל את הספירה מ-0 ולא מ-1). - - 1. נקבל מערך: { 30, 10, 9, 6, 5, 4, 3, 1 }. A זהו מצביע למערך, p זה מצביע לתחילת המערך (תא מס' 0), r מצביע לסוף המערך (תא מס' 7), ו x זהו הערך שאנחנו מחפשים, בואו ניקח לדוגמה את 10. - 2. שורה 2: אם r < p אז.., מכיוון ש r=7 ו p=0, התנאי לא מתקיים ולא ניכנס אליו. - 3. שורה 4: m יהיה שווה ל 2/(0+7) שזה (תא מס') 3 (עיגלנו כלפי מטה). - 4. שורה 5: אם [A[m (שהוא שווה לערך 5), גדול מ x (שהוא 10) אז.., התנאי לא מתקיים. - 5. שורה 7: אחרת, אם [A[m (עדיין 5) קטן מ x (שווה ל-10) אז: - * שורה 8: נקרא לעצמנו, כש p ישתנה ויהיה שווה ל m+1 (שזה תא מס' 4). - * התת מערך שאנו בודקים כרגע נראה כך: { 30, 10, 9, 6, 5 }. - * שורה 2: אם r < p אז.., מכיוון ש r=8 ו p=4, התנאי לא מתקיים ולא ניכנס אליו. - * שורה 4: m יהיה שווה ל 2/(4+8) שזה (תא מס') 6 (עיגלנו כלפי מטה). - * שורה 5: אם [A[m (הערך בתא מס' 6, שזה 10), גדול מ x (שהוא 10) אז.., התנאי לא מתקיים. - * שורה 7: אחרת, אם [A[m (עדיין 10) קטן מ x (שווה ל10) אז.., התנאי לא מתקיים. - * שורה 9: אחרת, נחזיר m (שזה הערך בתא מס' 6, והוא 10 שזה ערך אותו אנו מחפשים). - -**סיבוכיות זמן ריצה: ((O(lg(n**. -**סיבוכיות מקום: (O(1**. diff --git a/data/_oldPosts/2014-02-09-queue.md b/data/_oldPosts/2014-02-09-queue.md deleted file mode 100644 index ff5fe25..0000000 --- a/data/_oldPosts/2014-02-09-queue.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: תור (Queue) -author: nirgn -layout: post -summary: "תור (באנגלית: Queue) הוא הוא מבנה נתונים מופשט אך מזכיר תור (תור רגיל של בני אדם), המדיניות שעל פיה מנוהל התור היא FIFO (ראשי תיבות: First In First Out), שגורמת לו לפעול בדומה לתור בקופת חולים (או כל תור דומה אחר)." -category: Data Structures ---- -תור (באנגלית: Queue) הוא הוא מבנה נתונים מופשט אך מזכיר תור (תור רגיל של בני אדם), המדיניות שעל פיה מנוהל התור היא FIFO (ראשי תיבות: First In First Out), שגורמת לו לפעול בדומה לתור בקופת חולים (או כל תור דומה אחר). לתור יש ראש (head) וזנב (tail). - -כאשר מוסיפים איבר נוסף לתור, הוא תופס את מקומו בזנב התור, בדומה לחולה המגיע כעת לקופה ותופס את מקומו בסוף השורה. האיבר הנמחק מן התור הוא תמיד האיבר שבראש התור, שוב, בדומה לחולה הראשון בתור, שהמתין את משך הזמן הארוך ביותר. - - - -  - -אחת הדרכים למימוש תור היא באמצעות מערך. לתור שני מאפיינים: [head[Q שהוא אינדקס ראש התור או מצביע אליו (תלוי מימוש), ו [tail[Q שהוא אינדקס המקום שבו יוצב האיבר הבא שיוכנס לתור. (בתנאי ששם התור הוא Q כמובן). - -שימו לב כי מקום מס' 1 תמיד בא אחרי מקום מס' n, דהיינו, האיברים מוצבים במערך בסדר מעגלי. וכאשר [head[Q] = tail[Q התור ריק. בנוסף, יש לשים לב שכאשר התוק ריק, ניסיון למחוק ממנו איבר יגרום לחמיקה. וכאשר 1 + [head[Q] = tail[Q התור מלא, וניסיון להוסיף לו איבר יגרום לגלישה. - -  - -המתודות (פרוצדורות) שאציג להלן **כן** מטפלות במצבי השגיאות האלו (חמיקה וגלישה). -להלן המתודות ב[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode): - -**דחיפה -** הכנסת איבר חדש (לסוף) התור. -קוד: - -```c -ENQUEUE(Q, x) -if tail[Q] = length[Q] and head[Q] = 1 or tail[Q] +1 = head[Q] - then error "overflow" -Q[tail[Q]] <- x -if tail[Q] = length[Q] - then tail[Q] <- 1 -else - tail[Q] <- tail[Q] + 1 -``` - - * Q הוא שם התור. - * x הוא האיבר החדש שאותו אנו מכניסים לתור. - * לפני שנכניס את האיבר, נבדוק מצב של גלישה, לכן נבדוק אם הזנב שווה לגודל המערך, ובנוסף שהמצביע לראש התור שווה ל-1 או שהמצביע לזנב ועוד אחד שווה למצביע לראש התור. שני המצבים האלו (המצב הראשון והמצב השני, או המצב הראשון והמצב השלישי) יביאו למצב של גלישה, ולכן נדפיס הודעת שגיאה. - * במידה ויש לנו מקום, נכניס את האיבר (x) לזנב התור. - * לאחר ההכנסה של האיבר, נבדוק האם ישנו עוד מקום בתור, במידה והזנב שווה לגודל המערך, נזיז את הזנב ל-(1-) (ז"א לראש התור), שזה בעצם מסמן מצב שאין לנו עוד מקום בתור. - * אחרת (ז"א שיש עוד מקום בתור), נזיז את הזנב תא אחד קדימה. - -  - -**שליפה -** הוצאת האיבר (מראש) התור. -קוד: - -```c -DEQUEUE(Q) -if head[Q] = tail[Q] - then error "underflow" -x <- Q[head[Q]] -if head[Q] = length[Q] - then head[Q] <- 1 -else - head[Q] <- head[Q] + 1 -return x -``` - - * Q הוא שם התור. - * אם המצביע לראש התור שווה למצביע לזנב התור, אנו במצב של חמיקה. ז"א שהתור ריק ונדפיס הודעת שגיאה. - * במידה ויש איברים בתור, נכניס את האיבר עליו מצביע הזנב למשתנה בשם x. - * ונבדוק האם ראש המחסנית שווה לגודל המערך, במידה וכן (ז"א שניצלנו את כל גודל המערך) נזיז את ראש המערך ל-1 (זה מה שנותן לנו את התכונה המעגלית של התור). - * אחרת נזיז את ראש התור תא אחד קדימה. - * ולבסוף, נחזיר את x. - -  - -**כעת, נדגים את פעולות השינוי Enqueue ו Dequeue:** - -
    - Dequeue & Enqueue -
    - -מימוש התור מתבצע באמצעות מערך [Q[1..12. איברי התור מופיעים רק במשבצות הבהירות. - - 1. **(i)** התור מכיל 5 איברים, במקומות [Q[7..11. - 2. בשלב הבא **(ii)** מוצג התור לאחר הקריאות (Enqueue(Q, 17, ו (Enqueue(Q, 3, ו (Enqueue(Q, 5. - 3. ובשלב האחרון **(iii)** מוצגת תוצאת התור לאחר שהקריאה (Deququq(Q החזירה את ערך המפתח 15 שהיה קודם בראש התור. עתה נמצא בראש התור האיבר בעל המפתח 6. - -(כל אחת מהפעולות האלו מתבצעת בזמן ריצה (O(1). - -  - -### לסיכום - -במבנה הנתונים תור מבצעים שימוש נרחב במדעי המחשב, ולרוב אלו שתי הפעולות היחידות שלו (דחיפה ושליפה). כמו כן, במקרה זה מימשנו את מבנה הנתונים באמצעות מערך, אך ניתן לממשו בדרכים נוספות. - -בנוסף, שימו לב כי מחסנית מאפשרת הנכסה ומחיקה של איברים אך ורק בצד אחד, בעוד תור מאשר הכנסה של איברים בצד אחד ומחיקתם בצד האחר. אם אתם רוצים להרחיב, נסו לממש תור באמצעות שתי מחסנית. diff --git a/data/_oldPosts/2014-03-09-arduino-introduction.md b/data/_oldPosts/2014-03-09-arduino-introduction.md deleted file mode 100644 index 632a4c9..0000000 --- a/data/_oldPosts/2014-03-09-arduino-introduction.md +++ /dev/null @@ -1,295 +0,0 @@ ---- -title: 'ארדואינו (Arduino) - הקדמה' -author: nirgn -layout: post -summary: "אז לפני שנתחיל, קצת הקדמה אישית: לפני כמה חודשים התחלתי להתעניין במיקרו בקר קטן בשם ארדואינו, לאחר חקירה מעמיקה באינטרנט הגעתי לכמה מסקנות: 1. אין עליו הרבה חומר באינטרנט בעברית (לא שזה מפריע, אך מכאן נולד הרעיון לכתוב עליו בבלוג). 2. הגיע הזמן לשחק עם אחד כדי לראות אם זה באמת מה שאני רוצה." -category: Arduino ---- -אז לפני שנתחיל, קצת הקדמה אישית: לפני כמה חודשים התחלתי להתעניין במיקרו בקר קטן בשם ארדואינו ([Arduino](http://arduino.cc/)), לאחר חקירה מעמיקה באינטרנט הגעתי לכמה מסקנות: 1. אין עליו הרבה חומר באינטרנט בעברית (לא שזה מפריע, אך מכאן נולד הרעיון לכתוב עליו בבלוג). 2. הגיע הזמן לשחק עם אחד כדי לראות אם זה באמת מה שאני רוצה. - -בהתחשב בכך שלא הכרתי אף אחד עם הבקר וכל המידע שהיה לי היה ממאמרים ותמונות באינטרנט, ניגשתי ל [Meetup](http://www.meetup.com/) (פלטפורמה לתכנון פגישות / מועדונים / יצירת קהילות) כדי לבדוק האם ישנה קבוצה העוסקת בזה, בה אוכל להתנסות בבקר ולפגוש אנשים מהם ניתן ללמוד עוד יותר. לשמחתי מצאתי את [XLN תל אביב](http://www.meetup.com/XLNXLN/) (חברה נהדרים המקיימים סדנאות makers). שמח ומרוצה נרשמתי למפגש ארדואינו הבא, וכשהגעתי התגלה בפני עולם חדש. (יש לציין כי לפני כן לא התעסקתי באלקטרוניקה מיימי והתעניינתי יותר בצד התוכנה מאשר בחומרה) אך מהר מאוד, ובעזרת כמה מושגים בסיסיים אותם נלמד היום, הבנתי כמה קל, פשוט וכיף זה יכול להיות. - - - -  - -אחרי שעשינו יישור קו, אני מקוה שהפחד מאלקטרוניקה (אם היה) נמוג. בנוסף, אציין כי סדרת הפוסטים (ההסברים והפרויקטים הראשונים) מובססים על [אלו מאתר ארדואינו](http://arduino.cc/en/Tutorial/HomePage). בנוסף, הפוסט הזה יהיה תאורטי בלבד, אציג בו את הרכיבים האקלטרוניים השונים (בהם נשתמש בסדרת הפרוייקטים בפוסטים הבאים), הבקר עצמו (קצת היסטוריה והסבר על מהו הבקר ואיך הוא בנוי וכ'ו). - -  - -### נתחיל ברכיבים השונים: - -
    - Arduino Uno -
    - -**Arduino Uno** - -זהו לוח הפיתוח שיהיה בלב הפרויקטים שלנו, גרסת הלוח נקראת Uno (שינם עוד גרסאות אדרואינו, כל אחת בנויה אחרת ובעלת פיצ'רים שונים, אך הקוד כמובן יתאים לכולן). האדרואינו זה בעצם מחשב פשוט החשוף לכל וככזה אנו יכולים לחבר אליו חלקים על מנת לבנות מעגלים אלקטרונים. בנוסף, אנו יכולים לכתוב אליו על מנת לגרום לו להתממשק ולבצע אינטראקציה מול אותם רכיבים. - -  - -
    - Breadboard -
    - -**לוח מטריצה - Breadboard** - -לוח עליו אנו יכולים לבנות מעגלים אלקטרוניים. הוא משמש בעיקר לפרויקטים ואבי-טיפוס מכיוון שהוא משחרר אותנו מהצורך להלחים חוטים ורכיבים יחד. כל החריצים בשורה מחוברים יחדיו, מה שמאפשר לנו לחבר רכיבים על ידי חיבור כבלים מהם ואל אותם חריצים בשורה (שוב, במקום להלחימם יחד). - -  - -**לחצן סוללה - Battery Snap** - -
    - Battery Snap -
    - -משמש לחיבור סוללה 9V לארדואינו או ללוח המטריצה (הארדואינו יכול להיות מחובר לחשמל גם דרך כבל ה USB ולקבל כוח מהמחשב). - -
    - Capacitors -
    - -**קבלים - Capacitors** - -רכיבים אלה מאחסנים ומשחררים (אוגרים ופורקים) אנרגיה חשמלית. כאשר המתח במעגל גבוהה יותר ממה שמאוחסן בקבלים, הם מאפשרים לזרום לזרום פנימה, מה "שטוען" את הקבלים. כשהמתח במעגל נמוך יותר, האנרגיה המאוחסנת בו משחוררת. לעתים קרובות הקבלים מונחים על פני חריצים של "כוח" ו"אדמה" בקרבה לחיישן או למנוע כדי לעזור למנוע תנודות במתח (לייצב את המתח). - -  - -**מנוע DC** - -
    - DC Motor -
    - -ממיר את האנרגיה החשמלית לאנרגיה מכנית ,סלילי התיל בתוך המנוע הופכים לממוגנטים כאשר זורם דרכם זרם. השדות המגנטים האלו מושכים והודפים את המגנטים וגורמים למוט להסתובב (או להסתחרר). כשהכיוון של החשמל הפוך, המנוע יסתובב בכיוון ההפוך. - -  - -**דיודה - Diode** - -
    - Diode -
    - -הדיודה מבטיחה שהחשמל זורם רק בכיוון אחד (שימושי כאשר יש לנו מנוע או מתח/עומס גבוה אחר במעגל). דיודות הן מקוטבות, כלומר הכיוון שהן ממוקמות במעגל משנה. אם נניח אותן בדרך אחת, הן יאפשרו לזרם לעבור, נניח אותן הפוך, הן יחסמו אותו. הקוטב החיובי (אנודה) בדר"כ מתחברת לנקודה בה האנרגיה במעגל שלנו גבוהה. בעוד הקתודה בדר"כ מתחברת לנקודה בה האנרגיה נמוכה יותר או לקרקע. הקתודה היא בדר"כ עם הסימן של הלקה בצד אחד של גוף הרכיב (פס לקה). - -  - -
    - Cellophane -
    - -**נייר צלופן (בצבעים אדום, ירוק, כחול)** - -בעזרתם נסנן את אורכי הגל השונים של האור. כשהם פועלים ביחד עם נגד תלוי אור הם גורמים לחיישן (של הנגד תלוי האור) להגיב רק לכמות האור בצבע המסונן. - -  - -
    - H-Bridge -
    - -**גשר אייצ'- H Bridge** - -מעגל המאפשר לשלוט בעומס ע"י שליטה בקוטביות המתח, בדר"כ מדובר על מנוע. הגשר בו אנו נשתמש היא מעגל משולב, אך ניתן לבנות גשר כזה גם אם מספר רכיבים בדידים. - -  - -
    - Jumper Wires -
    - -**חוטי גישור - Jumper Wires** - -נשתמש בחוטים האלו כדי לחבר רכיבים מ/ו לאנדרואינו בעזרת לוח המטריצה. - -  - -
    - LEDs -
    - -**דיודות פולטות אור - LEDs** - -סוג של דיודה המאירה כאשר חשמל זורם בכיוון אחד בלבד (דרכה). בטח נתקלתם בכאלו במגוון של מכשירים אלקטרונים (בדר"כ לסימון שהמוצר דולק וכד'). הקוטב החיובי (האנודה) שבדר"כ מחוברת לכוח / זרם / חשמל היא הרגל הארוכה יותר, הקתודה היא הרגל הקצרה יותר. - -  - -
    - LCD -
    - -**תצוגת גביש נוזלי - LCD** - -סוג של תצוגה אלפא נומרית או גרפית המבוססת על גבישים נוזליים. צגי LCD זמינים בגדלים, צורות וסגנונות רבים וניתן לרכוש כאלו בכל חנות אלקטרוניקה. אני משתמש בכזה עם 2 שורות, כשבכל שורה יש 16 תווים. - -  - -
    - Male Header Pins -
    - -**סיכות כותרת זכר - Male Header Pins** - -סיכות אלה משתלבות בשקעי נקבה, כמו אלו שעל לוח הלחם. הסיכות מסייעות להפוך את החיבור של הדברים לקל ופשוט הרבה יותר. - -  - -
    - Optocoupler -
    - -**מצמד אופטי - Optocoupler** - -מאפשר לחבר שני מעגלים שאינם חולקים אספקת חשמל משותפת. בתוכו יש נורת LED קטנה שכאשר מוארת גורמת לקולטי אור הנמצאים בתוכו לסגור מתג פנימי. כשנעביר זרם לפין ה+, הנורה תואר והמתג הפנימי ייסגר. שתי היציאות מחליפות מתג במעגל השני. - -  - -
    - Piezo -
    - -**חיישן פיזואלקטריים - Piezo** - -רכיב חשמלי שניתן להשתמש בו כדי לזהות תנודות וליצור רעשים. - -  - -
    - Photoresistor -
    - -**נגד תמונה - Photoresistor** - -מכונה גם תא פוטואלקטרי או נגד תלוי אור. זהו נגד משתנה המשנה את ההתנגדות שלו על בסיס כמות האור שנופל על שטח הפנים שלו. - -  - -
    - Potentiometer -
    - -**פוטנציומטר - Potentiometer** - -נגד משתנה בעל שלושה פינים. שניים מהפינים מחוברים לקצוות של הנגד באופן קבוע. הפין (רגל) שבאמצע נעה על פני הנגד, ומחלקת אותו לשני חצאים. כאשר הרגלים בצדדים החיצוניים של הפוטנציומטר מחוברות למתח ולקרקע, הרגל האמצעית נותנת את ההבדל במתח (כמו לסובב ידית). - -  - -
    - Button -
    - -**לחצנים** - -מתגים רגעיים שסוגרים מעגל כשלוחצים עליהם. הם נצמדים בקלות ללוח המטריצה ומשמשים להפעלה/כיבוי של אותות. - -  - -
    - Resistors -
    - -**נגדים - Resistors** - -נגדים מתנגדים לזרימה של האנרגיה החשמלית במעגל, ומשנים את המתח והזרם כתוצאה מכך. ערכי הנגד נמדדים באוהם ומסומנים ע"י האות היוונית אומגה – Ω. הפסים הצבעוניים הנמצאים עליהם מצביעים על ערכם. -להלן טבלת הערכים של הצבעים: - -
    - Resistor Table -
    - -  - -
    - Servo Engine -
    - -**מנוע סרוו (Servo)** - -סוג של מנוע מכוון שיכול להסתובב רק 180 מעלות. הוא נשלט ע"י שליחת פולסים חשמליים מהארדואינו, הפולסים האלה אומרים למנוע לאיזה כיוון הוא צריך לזוז. - -  - -
    - Temperature Sensor -
    - -**חיישן טמפרטורה** - -החיישן משנה את תפוקת המתח שלו בהתאם לטמפרטורה של הרכיב. הרגליים החיצוניות מתחברות לכוח ולאדמה, והמתח על הפין המרכזי משתנה בהתאם בהתאם לחום או לקור. - -  - -
    - Tilt Sensor -
    - -**חיישן הטיה** - -סוג של מתג שנפתח ונסגר בהתאם לאוריינטציה שלו. בדר"כ הם כלילים וחלולים עם כדור מתכת בפנים שיוצר חיבור של שני מוליכים כשהוא מוטה בכיוון הנכון. - -  - -
    - Transistors -
    - -**טרנזיסטור** - -מכשיר בעל שלוש רגליים שיכול לפעול כמתג אלקטרוני. שימושי לשליטה ברכיבים בעלי זרם / מתח גבוהה כמו מנועים. סיכה אחת מתחברת לאדמה, האחרת לרכיב, והשלישית לארדואינו. כאשר הרכיב מקבל מתח על הפין שמחובר לארדואינו הוא סוגר את המעגל בין האדמה לבין הרכיב האחר. - -  - -
    - USB -
    - -**כבל USB** - -הארדואינו מתחבר בכבל USB סוג B, ולכן הכבל בו נשתמש יהיה כבל USB מסוג B לסוג A (הסוג הרגיל שיש לנו במחשב). הכבל יאפשר לנו לחבר את מכשיר הארדואינו אונו למחשב לתכנות ובנוסף כדי לקבל חשמל. - -  - -### קצת על הארדואינו (Arduino) - -לאחר שהכרנו בקצרה כל אחד מהרכיבים, נדבר קצת על הארדואינו, הארדואינו הוא רכיב חומרה שהתחיל את דרכו בשנת 2005 כפרויקט לסטודנטים המתמחים באינטראקציות בתחום העיצוב, במכון lvrea שבאיטליה. לוח הארדואינו מורכב מ [מיקרו-בקר](http://en.wikipedia.org/wiki/Microcontroller) בעל 8 סיביות מסדרת AVR של חברת Atmel, ותכונתנו העקרית הינה הדרך הסטנדרטית בה הלוח וכל המחברים שלו חשופים. בנוסף, ניתן לחבר ללוח מגוון רחב של מודלים נוספים הנקראים Shileds (מגנים), כשכל אחד מהם מספק בדר"כ יכולת שונה (כגון בקרה מוטורית, GPS, אתרנט, תצוגת LCD וכד'). - -נכון להיום ישנם 16 גרסאות של חומרת ארדואינו המיוצרות באופן מסחרי (להלן [הרשימה](http://en.wikipedia.org/wiki/List_of_Arduino_boards_and_compatible_systems)). החברה המקורית המייצרת את חומרת הארדואינו היא Italian company Smart Projects, וישנם גם כאלו של SparkFun Electronics האמריקאית (וכמובן מגוון העתקים סינים ב eBay ו Aliexpress). כדי לכתוב ללוח יש להתקין את סביבת הפיתוח הייעודית אליו, אותה ניתן להוריד מאתר ארדואינו [כאן](http://arduino.cc/en/Main/Software#toc1) (הורידו את הגרסה המתאימה למערכת ההפעלה שלכם והשלימו את ההוראות). - -  - -**כיצד הלוח בנוי:** - -
    - Arduino Broad -
    - -
    - Serial Port -
    - -  - -**בדיקה** - -על מנת לבדוק שהכל קשורה והמכשיר מזוהה פתחו את ה IDE (סביבת העבודה של ארדואינו – Sketch), כנסו ל `File` ומשם ל `Examples`, כאן נמצא דוגמאות לקטעי קוד המבצעים פעולות כלשהן כולל הסברים (הערות) בתוך הקוד. כדי לבצע בדיקה פשוטה נבחר ב `Basics` וב `Blink`. יפתח לנו חלון חדש (את הישן ניתן לסגור). - -
    - Tools Board -
    - -לא נעבור על הקוד כעת אלה רק נעלה אותו ללוח הארדואינו שלנו, לכן ניכנס ל `Tools` ואז ל `Serial Port` ונבדק שה v נמצא על החיבור שהארדואינו נמצא עליו (כשנבחר את הלוח תקפוץ לנו הודעה קטנה באיזה חיבור הוא נמצא, וככלל אצבע בווינדוס הוא יהיה על ה COM עם המספר הגבוה ביותר). לאחר מכן נוודא שהוא מזהה שיש לנו את הלוח הנכון ע"י כניסה ל `Tools` ול `Board` ובחירת הלוח המתאים (אני משתמש ב Arduino Uno ועליו אבצע את כל הפרויקטים בעתיד). - -
    - Upload -
    - -כעת נלחץ על החצן המצביע לכיוון ימין (כשנעבור מעליו נראה הודעה של Upload) ולאחר מכן נראה שהקוד שלנו מתקמפל ועולה אל הלוח (בבר התחתון שיופיע). לאחר שהעלינו את הקוד, בלי לבצע כל דבר מעבר לכך, הארדואינו שלנו צריך להתחיל להפעיל את הקוד, ונראה שהנורה של פין מס' 13 מהבהבת, זה כל מה שהקוד צריך לעשות. (ניתן לנסות לעבור עליו לבד ולהבין למה, בעתיד נכתוב את הקוד לבד ואסביר אותו). - -  - -### לסיכום - -אני יודע שהפוסט הזה היה עמוס במידע תיאורטי, אך הוא נועד להיות בתור קופסא אליה תוכלו לחזור כל פעם שאזכיר רכיב אלקטרוני כלשהו בפרויקטים העתידיים. וכמובן שאין מה להתאמץ לזכור הכל על כל רכיב. אני מקווה שלא נתקלתם בבעיות במהלך הבדיקה, אך במידה וכן, כתבו בתגובות ואנסה לעזור כמידת האפשר. diff --git a/data/_oldPosts/2014-03-23-arduino-1.md b/data/_oldPosts/2014-03-23-arduino-1.md deleted file mode 100644 index 37dc9a9..0000000 --- a/data/_oldPosts/2014-03-23-arduino-1.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: '1 - הכרת הכלים, וקצת פרקטיקה' -author: nirgn -layout: post -summary: "בפרויקט הזה נבנה מעגל על מנת להעביר חשמל דרך כמה רכיבים. מעגלים הם לולאות סגורות של חוטים (חוטי גישור) עם מקור כוח כלשהו (לדוג' סוללה) ומשהו נוסף העושה משהו מועיל עם האנרגיה החשמלית, הנקראת עומס." -category: Arduino ---- -חשמל הוא סוג של אנרגיה, בדיוק כמו חום, כוח המשיכה, או אור. אנרגיה חשמלית זורמת דרך מוליכים, כמו חוטים. אנחנו יכולים להמיר אנרגיה חשמלית לצורות אחרות של אנרגיה כדי לעשות משהו מעניין, כמו להדליק אור או לעשות רעש דרך רמקול. הרכיבים בהם נשתמש כדי לבצע דברים כאלה, כמו נורה או רמקול נקראים מתמרים (באנגלית: Transducers), אלו הם רכיבים הממירים אנרגיה חשמלית לצורות אחרות של אנרגיה ולהפך (רכיבים הממירים צורות אחרות של אנרגיה לאנרגיה חשמלית נקראים חיישנים (sensors), וגם הם סוג של מתמרים). בפרויקט הזה נבנה מעגל על מנת להעביר חשמל דרך כמה רכיבים. מעגלים הם לולאות סגורות של חוטים (חוטי גישור) עם מקור כוח כלשהו (לדוג' סוללה) ומשהו נוסף העושה משהו מועיל עם האנרגיה החשמלית, הנקראת עומס. - - - -  - -במעגל, חשמל זורם מנקודה של אנרגיה פוטנציאלית גבוהה יותר (המכונה בדרך כלל כוח או +) לנקודה של אנרגיה פוטנציאלית נמוכה יותר. אדמה או קרקע (המיוצגת לרוב כ - או כ GND) הינה הנקודה האחרונה בה ישנה אנרגיה פוטנציאלית במעגל. במעגל שאנו נבנה החשמל יזרום אך ורק בכיוון אחד. הסוג הזה של מעגל נקרא זרם ישר (או DC). במעגל עם זרם חילופין (AC) החשמל משנה את כיוונו כ 50 עד 60 פעמים בשניה (תלוי איפה אנחנו גרים, זהו סוג החשמל המגיע משקע החשמלי בבית). - -ישנם כמה מושגים שאנחנו צרכים להכיר בעבודה עם מעגלים חשמליים. הראשון הוא זרם (באנגלית: Current) הנמדד באמפרים (או amps) ומסומן באות A, זהו כמות המטען החשמלי הזורמת דרך נקודה מסויימת במעגל. המושג השני הוא מתח (באנגלית: Voltage) הנמדד בוואט ומיוצג ע"י האות V, זהו ההבדל באנרגיה בין נקודה אחת במעגל לאחרת. והאחרון התנגדות (באנגלית: Resistance) נמדדת באוהם ומיוצגת ע"י האות היוונית אומגה Ω, זהו מידת ההתנגדות של רכיב כלשהו לזרם של האנרגיה החשמלית. - -אנלוגיה אחת למושגים האלו היא לחשוב עליהם כמפולת סלעים מצוק. ככל שהצוק גבוה יותר כך הסלעים יצברו יותר אנרגיה כשהם יפגעו בקרקע, גבוה הצוק הוא כמו המתח ([Voltage](http://en.wikipedia.org/wiki/Voltage)) במעגל: ככל שהמתח גבוה יותר במקור הכוח שהמעגל מחובר אליו משתמש ביותר אנרגיה. ככל שיותר סלעים המתגלגלים מהצוק, יותר אנרגיה (זרם - [Current](http://en.wikipedia.org/wiki/Electric_current)) עוברת במורד הצוק. הסלעים עוברים דרך שיחים, עצים, מהמורות וכד' במורד הצוק וכתוצאה מזה מאבדים אנרגיה בתהליך (האנרגיה שבה משתמשים בשביל למחוץ את השיח לדוגמה). השיחים האלו הם כמו ההתנגדות ([Resistance](http://en.wikipedia.org/wiki/Electrical_resistance_and_conductance)) הקיימת במעגל, רכיבים כלשהם המתנגדים לאנרגיה החשמלית והופכים אותה, כתוצאה מכך, לסוג אחר (כלשהו) של אנרגיה. - -  - -**כמה דברים על מעגלים:** - - * צריך שתהיה דרך שלמה ממקור הכוח (החשמל) אל האדמה (או קרקע) כדי לסגור מעגל. מספיק שבמקום אחד המעגל משוחרר ואין לאנרגיה המשך למסלול - המעגל לא יעבוד. - * כל החלקים השונים שבמעגל מבצעים שימוש באנרגיה החשמלית שבו. כל חלק במעגל ממיר חלק מהאנרגיה החשמלית שבמעגל לצורה אחרת של אנרגיה (אור, חום, סאונד וכד'). - * הזרם בנקודה מסוימת במעגל תמיד יהיה אותו הדבר בכניסה וביציאה באותה נקודה מסוימת. - * זרם חשמלי תמיד יחפש את הדרך בה יש כמה שפחות התנגדות עד לאדמה. אם ישנן 2 דרכים, רוב הזרם החשמלי יעבור בדרך בה יש פחות התנגדות. אם נבצע חיבור המחבר את מקור הכוח והקרקע יחד ללא שום התנגדות, אנו נגרום לקצר, הזרם ינסה ללכת בדרך זאת (הכי קצרה). במעגל כזה מקור הכוח והחוטים ימירו את האנרגיה החשמלית לאור וחום לרוב כניצוצות. - -לוח המטריצה זהו המקום העיקרי עליו נבנה את המעגלים (בדומה מאוד ללגו). השורות האופקיות מחוברות יחדיו מתחת לפלסטיק. ובצדדים, השורות האנכיות מחוברות גם הן (ה+/-), להלן תמונה טובה להמחשה: - -
    - Breadboard Strips -
    - -כעת נתחיל לבנות את הפרויקט. לאורך כל הפרויקט אציג אילוסטרציה של המעגל החשמלי שנבנה באותו השלב, ואציג גם איור סכמטי (בכל הפרויקטים אשים דגש על הצגת האיור הסכמתי, זה אולי לא יעזור לכם הרבה אך שווה ללמוד ולהכיר את הסימנים, מכיוון שרוב הפרויקטים באינטרנט והאיורים של המעגלים חשמליים נעשים ע"י איור סכמטי). - -**הרכיבים בהם נשתמש :** - - * **LED -** או דיודה פולטת אור, זהו רכיב הממיר את האנרגיה החשמלית לאנרגיית אור. לדים הן רכיבים מקוטבים, מה שאומר שהם מאפשרים לחשמל לזרום דרכם אך ורק בכיוון אחד. הרגל הארוכה יותר נקראת אנודה (באנגלית: [anode‏‏‏‏](http://en.wikipedia.org/wiki/Anode)) והיא תתחבר למקור הכוח. הרגל הקצרה יותר נקראת קתודה (באנגלית: [cathode‏‏‏‏](http://en.wikipedia.org/wiki/Cathode)) והיא תתחבר לאדמה. כאשר זרם חשמלי מגיע לאנודה של ה LED והקתודה מחוברת לאדמה, ה LED פולט אור. - * **נגד -** (באנגלית: resistor) הוא רכיב המתנגד לזרימה של האנרגיה החשמלית. הנגד ממיר חלק מהאנרגיה החשמלית לחום. כשנשים אותו ביחד עם רכיב ה LED הנגד ישתמש בחלק מהאנרגיה הזו ונורת ה LED תקבל פחות אנרגיה כתוצאה מכך. ע"י כך נמנע מה LED לקבל יותר מדי מתח ובעצם זה מאפשר לנו לספק ל LED בדיוק את כמות האנרגיה שהוא צריך. ללא הנגד, ה LED יהיה בהיר יותר לכמה רגעים, אבל יישרף במהירות. - * **מתג -** המתג קוטע את זרימת החשמל, הוא שובר את המעגל כאשר הוא פתוח וישלים את המעגל כאשר הוא סגור. ישנם סוגים רבים של מתגים אך אלה שאני משתמש בהם נקראים מתגים רגעיים, או לחצנים, מכיוון שהם סוגרים מעגל רק כאשר מופעל עליהם לחץ. - -
    - Button -
    - -  - -בשלב הראשון נבנה מעגל חשמלי פשוט, **_אם הארדואינו שלכם מחובר לחשמל, נתקו אותו לפני שתתחילו בבניה!_**. נחבר את ה 5V ל+ (פלוס) שבלוח המטריצה, ואת ה GND (אדמה) ל- (מינוס) שבלוח המטריצה. משם נחבר ל+ נגד לשורה שבלוח המטריצה (השתמשו בנגד בעל 220Ω) ובאותה שורה בה נמצא הנגד נחבר את הרגל של נורית ה LED (הרגל הארוכה, שמקבל כוח, אנודה). הרגל השנייה של נורית ה LED תתחבר לשורה שמתחת ולאותה שורה נחבר חוט מגשר שיחובר בקצה השני שלו לעמודת ה- שבלוח המטריצה. - -להלן הסכמה ואיור להמחשה: - -
    - Arduino LED -
    - -כעת חברו בחזרה את מקור הכוח. ניתן לראות כי הנורה דולקת תמיד, בנינו מעגל חשמלי שלם והנורה תמיד מקבלת חשמל ולכן תמיד דולקת. - -  - -עכשיו נחבר את המתג, נוציא את הנגד ונחבר אותו קרוב יותר אל החוטים המגשרים מה+ (פלוס) וה- (מינוס). לאחר מכן, נשים מתג מהנגד, נשים את המתג כך שיהיה מחובר ל-2 שורות שונות בלוח המטריצה ב-2 הרגליים שלא מחוברות אחת לשנייה. כעת, בשורה של הרגל השנייה נמקם חוט מגשר אל האנודה של ה LED והרגל השנייה שלה (הקצרה יותר, קתודה) תהיה בשורה אחרת. כעת יש לנו מעגל חשמלי קצת יותר מורכב, ברגע שנלחץ על המתג / לחצן הנורה תאיר, וברגע שנעזוב אותו הנורה תיכבה. שוב, מדובר עדיין על מעגל חשמלי פשוט, ללא קשר לארדואינו (למעט זה שמהארדואינו אנו לוקחים את הכוח, 5V, ומעבירים דרכו לאדמה, GND). - -להלן האיור והסכמה: - -
    - Push Button -
    - -כעת, נמשיך ל-2 סוגים של חיבורים: מעגל טורי, ומעגל מקבילי. במעגל טורי נחבר את הרכיבים כך שיפעלו אחד אחרי השני, בעוד במעגל מקבילי נחבר את הרכיבים כך שיפעלו אחד לצד השני. - -  - -### מעגל טורי - -רכיבים בטור מגיעים בזה אחר זה. **_הסירו את מקור הכוח אליו הארדואינו מחובר_**, הוציאו את נורית ה LED ואת החוט המגשר השחור שגישר בין נורית ה LED ל- (מינוס) בלוח המטריצה. כעת, בחוט המגשר האדום שהוביל לאנודה של נורית ה LED (שהוצאנו כעת) מקמו מתג נוסף כך שהמתג הנוסף יקבל חשמל מאותו חוט מגשר אדום. מהרגל השנייה של המתג השני חברו חוט מגשר נוסף שיוביל לחור אחר בלוח המטריצה אליו תחברו את האנודה (הרגל הארוכה, שמקבל כוח, +) של נורית ה LED. ומהקטודה (הרגל הנמוכה) של נורית ה LED חברו חוט שחור אל ה- (מינוס) שבלוח המטריצה. - -כמו שניתן לראות, חיברנו את המתגים אחד אחרי השני, ועל מנת לחשמל יגיע אל נורית ה LED יש ללחוץ על שניהם כדי שישלימו מעגל חשמלי ביחד. להן האיור והסכמה: - -
    - Two Buttons -
    - -### מעגל מקבילי - -רכיבים מקבילים עובדים זה לצד זה. לכן כעת השאירו את הרכיבים במקומם אך הוציאו את 2 חוטי הגשר בין המתגים ונורת ה LED, מקמו את הראשון מהנגד אל הרגל הראשונה של המתג השני, ועוד אחד מהרגל השנייה של המתג השני אל האנודה (הרגל הארוכה של נורית ה LED). לאחר מכן חברו חוט מגשר שלישי מהרגל השנייה של המתג הראשון, אל האנודה של נורית ה LED. עם 2 החוטים הראשונים חיברנו את המתג השני מהנגד ישירות אל נורית ה LED, ועם החוט השלישי חיברנו גם את המתג הראשון ישירות אל נורית ה LED. כעת יש לנו 2 לחצנים המחוברים במקביל, בעת ובעונה אחת, ישירות אל נורית ה LED. לא משנה אל מי נלחץ (מתג 1/ מתג 2 / או שניהם יחדיו) ייסגר מעגל חשמלי ונורית ה LED תואר. - -להלן האיור והסכמה: - -
    - TwoButtons 2 -
    - -### לסיכום - -עברנו על כמה מושגים בסיסיים (זרם - Current, מתח - Voltage, והתנגדות - Resistance), ראינו איך לוח המטריצה בנוי וכיצד לחבר אליו רכיבים, הכרנו לעומק כמה מושגים (נורית LED, נגד, מתגים, חוטי גישור), ובנינו כמה מעגלים פשוטים, מעגל טורי, ומעגל מקבילי. בפרויקט הבא נתחיל להתעסק עם הארדואינו עצמו - נכתוב קצת קוד שיבצע אינטראקציה עם המעגל אותו נבנה. diff --git a/data/_oldPosts/2014-04-06-arduino-2.md b/data/_oldPosts/2014-04-06-arduino-2.md deleted file mode 100644 index 97087fb..0000000 --- a/data/_oldPosts/2014-04-06-arduino-2.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: '2- הארדואינו מצטרף למשוואה' -author: nirgn -layout: post -summary: "כעת, כשיש לנו את ההבנה הבסיסית באלקטרוניקה, הגיע הזמן להכניס את הארדואינו למשוואה. בפרויקט הזה נבנה משהו שיכול להיראות כמו ממשק של חללית מסרטי המדע הבדיוני של שנות ה-70. נבנה לוח בקרה עם מתג ואורות שנדלקים כשנלחץ על המתג. האור הירוק ידלוק באופן קבוע, וכשנלחץ על המתג האור הירוק יכבה ושני האחרים יתחילו להבהב." -category: Arduino ---- -כעת, כשיש לנו את ההבנה הבסיסית באלקטרוניקה, הגיע הזמן להכניס את הארדואינו למשוואה. בפרויקט הזה נבנה משהו שיכול להיראות כמו ממשק של חללית מסרטי המדע הבדיוני של שנות ה-70. נבנה לוח בקרה עם מתג ואורות שנדלקים כשנלחץ על המתג. האור הירוק ידלוק באופן קבוע, וכשנלחץ על המתג האור הירוק יכבה ושני האחרים יתחילו להבהב. - - - -  - -הפינים בלוח הארדואינו יכולים לזהות רק 2 מצבים: כאשר ישנו מתח בפין קלט, וכאשר אין מתח. סוג הקלט הזה נקרא גם דיגיטלי (או בינארי, מכיוון שיש 2 מצבים בלבד) ובנוסף נתייחס אליהם כ HIGH ו LOW, כאשר HIGH זה כמו להגיד "יש מתח" ו LOW אומר שאין מתח בפין הזה. כאשר נכתוב לפין מסוים HIGH (באמצעות `()digitalWrite`) אנו בעצם מדליקים את אותו פין (וכאשר נכתוב לו LOW נכבה אותו). הפינים הדיגיטלים של הארדואינו יכולים לשמש כפלט וכקלט, ובקוד נגדיר אותם לפי הצורך. כאשר נגדיר אותם כפלט נוכל לדוגמה להדליק איתם נורות LED, וכאשר נגדיר אותם כקלט נוכל לדוגמה לקרוא האם המתג לחוץ או לא. - -יש לציין כי מומלץ להתחיל לחבר מפין 2 והלאה (מכיוון שפינים 1 ו-0 משמשים לתקשורת עם המחשב). - -  - -### חיבור הרכיבים - -ראשית,נחבר את המתח (5v) מלוח הארדואינו ל+ (פלוס) שבלוח המטריצה (בעזרת חוט מגשר) ואת ה GND ל- (מינוס) שבלוח המטריצה, בדיוק כמו בפרויקט הקודם. כעת נמקם 2 נורות LED אדומות ונורת LED אחת ירוקה על גבי לוח המטריצה. נחבר כל קתודה של נורת LED (הרגל הקצרה של נורת ה LED) לאדמה (למינוס בלוח המטריצה) בעזרת נגד של 220Ω (אוהם). כל אנודה (הרגל הארוכה) תתחבר לארדואינו, לפין שונה: ה LED הירוק יתחבר לפין (הדיגיטלי) מס' 3, ו-2 נורות הלד האדומות יתחברו לפינים 4 ו-5. - -עכשיו נמקם את המתג על גבי לוח המטריצה (עדיף שיהיה רחוק קצת מנורות ה LED כדי שלא יהיה צפוף, ויהיה לכם מרחב תמרון) נמקם את המתג באותה צורה שמיקמנו אותו בפרויקט הקודם, כאשר 2 הרגליים האחוריות שלו יתחברו לאותו מעגל כדי להשלים את המעגל ברגע הלחיצה. רגל אחת של המתג נחבר לכוח (לשורת הפלוס בלוח המטריצה) ואת הרגל השניה לפין הדיגיטלי מס' 2. בנוסף, נצטרך להוסיף נגד 10kΩ מהאדמה בלוח המטריצה (שורת המינוס) אל הרגל שמתחברת לפין מס' 2 באדרואינו. הנגד הזה מחבר את פין לאדמה כאשר המתג פתוח (כאשר המתג פתוח - לא לחוץ הוא יקרא LOW, ז"א אין מתח המגיע / עובר דרך המתג). - -להלן סכמה ואיור להמחשה: - -
    - Arduino Project number 2 -
    - -**כמה הערות לפני כתיבת הקוד** - -לכל תוכנית ארדואינו יש 2 פונקציות. פונקציה היא חלק מתכנית מחשב המריצה פקודות ספציפיות. לפונקציה יש שם יחודי ואנו "קוראים" להם בעת הצורך. הפוקנציות שבהן משתמשים בעת כתיבת תוכנית ארדואינו נקראות ()setup ו ()loop. יש להכריז על הפונקציות האלו, ולכתוב לכל אחת מה היא תעשה. ע"י כתיבת ה void (בתרגום: ריק) אנו בעצם אומרים שהפונקציה לא תחזיר כלום (לא תחזיר ערך כלשהו), לאחר מכן אנו כותבים את שם הפונקציה וסוגריים רגילים (הסוגריים ריקים כי אנו לא מקבלים אף פרמטר). לאחר מכן נפתח ונסגור סוגריים מסולסלים, בתוך הסוגריים האלו (המסולסלים) נכתוב את הפקודות שלנו. - -בתוכנית שלנו, ניצור משתנה, לפני שנגיע לחלק העיקרי של התוכנית. המשתנים הם שמות שאנו נותנים לאזורים בזיכרון של הארדואינו, ע"י הצמדת שם לאזור בזיכרון אנו יכולים להתייחס אליו (כדי לשמור או לקרוא ממנו דברים) (דמיינו חלל ריק בתוך קופסא, ברגע שתציירו ריבוע בתוך הקופסא ותקראו לריבוע הזה x תוכלו להתייחס אליו והמחשב ידע למה אתם מתכוונים, תוכלו להגיד לו לשמור דברים בתוך ה x או להגיד לכם מה יש ב x וכד'. אם לא הייתם נותנים שם לריבוע לא הייתם יכולים לקרוא לו בצורה שהמחשב יבין למה אתם מתכוונים). הערכים בתוך המשתנה יכולים להשתנות, ז"א אם הצבתם במשתנה (תא בזיכרון) ערך הוא כמובן לא סופי ואתם יכולים לשנות אותו בעתיד. כדי שיהיה לכם קל לעקוב אחרי התוכנית אותה אתם בונים מומלץ להשתמש בשמות הגיוניים למשתנים, ז"א לא לקרוא x למשתנה השומר את מספר הנורות, אלה לקרוא לו numberOfBulbs (בנוסף, שימו לב שאסור לשים רווחים באמצע שם המשתנה, לכן, כדי שיהיה קל לקרוא את שם המשתנה כתבתי אות גדולה בכל תחילת מילה של המשתנה, מה שנקרא גם [CamelCase](http://en.wikipedia.org/wiki/CamelCase)), זאת מכיוון ש x לא אומר לכם כלום, אתם תצרכו לזכור את זה, ואם תחזרו לתוכנית עוד שבוע או שתתנו אותה למישהו אחר יהיה לו קשה מאוד להבין למה התכוונתם, לכן, שוב, כדאי מאוד לקרוא למשתנים בשמות הגיוניים המתאימים למה שהם צריכים לשמור. - -  - -### כתיבת הקוד - - לפני ההסבר המפורט של כל שורה, כך יראה הקוד הסופי: - -```c -void setup(){ - pinMode(2, INPUT); - pinMode(3, OUTPUT); - pinMode(4, OUTPUT); - pinMode(5, OUTPUT); -} - -void loop(){ - switchState = digitalRead(2); - - if (switchState == LOW) { - // The button is not pressed - digitalWrite(3, HIGH); // greed LED - digitalWrite(4, LOW); // redLED - digitalWrite(5, LOW); // redLED - } else { - // The button is pressed - digitalWrite(3, LOW); - digitalWrite(4, LOW); - digitalWrite(5, HIGH); - delay(250); // Waite for a quarter second - - digitalWrite(4, LOW); - digitalWrite(5, LOW); - delay(250); // Waite for a quarter second - } -} // Go back to the beginning of the loop -``` - -  - -כדי ליישר קו, אסביר כי כדי ליצור משתנה, יש להכריז איזה סוג הוא יהיה, int (קיצור של [Integer](http://en.wikipedia.org/wiki/Integer) - בתרגום: מספר שלם) זהו סוג של משתנה המכיל אך ורק מספרים שלמים (לדוגמה 5, אך לא 4.5, לא מלל, וכ'ו). בנוסף, כל פקודה שלכם למחשב צריכה להסתיים ב ; (נקודה פסיק). - -בנוסף, המבנה בו הארדואינו פועל הוא הרצת הפונקצייה setup פעם אחת, כשהבקר עולה. לכן שם אנו נגדיר את הפינים של הארדואינו להיות קלט או פלט בעזרת פונקציה הנקראת `()pinMode`. נגדיר את הפינים שאליהם מחוברים נורות ה LED להיות `OUTPUT` (פלט), ואת הפין של המתג להיות `INPUT` (קלט) (יש לכתוב את מס' הפין פסיק קלט / פלט, ניתן לראות זאת ב Reference באתר [Arduino.cc](http://arduino.cc/) [כאן](http://arduino.cc/en/Reference/pinMode)). לאחר שהארדואינו הריץ פעם אחת את ה setup הוא יריץ את פונקציית ה loop בלולאה שלא נגמרת (אינסופית) (כל עוד הוא דולק) לכן שם נכתוב את פקודות התוכנית. פה נבדוק את המתח בפין שמוגדר כ INPUT (פין מס' 2), ולפי המתח שנקלוט בפין הזה נדליק או נכבה את נורות ה LED בפיני ה OUTPUT. - -כדי לבדוק את רמת המתח בפין דיגיטלי נשתמש בפונקציה `()digitalRead` שבודקת בפין הנבחר את המתח, כדי להגיד לה איזה פין לבדוק הפונקציה מקבלת פרמטר. פרמטרים הם מידע שמועבר לפונקציה לה אנו קוראים. את התוצאה שהפונקציה תחזיר (רמת המתח) נשמור במשתנה שנקרא לו `switchState` (שווה הינו סימן השמה, ז"א לשים את הצד הימני בתוך הצד השמאלי). שימו לב שכדי להקל עלינו, סביבת הפיתוח של הארדואינו מסמנת בצבעים שונים מילים מוכרות, כמו הדגש על שם הפונקציה, פונקציות המוכרות להם, פרמטרים ידועים (OUTPUT / INPUT), וכ'ו. - -  - -כשיהיה מתח בפין מס' 2 נקבל מהפונ' `()digitalRead` ([ל Reference](http://arduino.cc/en/Reference/digitalRead)) תוצאה של HIGH (או 1), וכשלא יהיה מתח נקבל LOW (או 0). אז לאחר שקראנו את המתח שיש בפין מס' 2 נרצה לדעת האם הוא נמוך או גבוה, לכן נשתמש במשפט if או במילים אחרות: "[משפט תנאי](http://en.wikipedia.org/wiki/Conditional_%28computer_programming%29)", וזהו בדיוק כמו שזה נשמע, משפט של אם -> אז. ז"א אם \___ יקרה אז תבצע \_\\_\_. המשפט בנוי ע"י כתיבת if ולאחריו סוגריים רגילים בתוכם תנאי הבדיקה, לאחר מכן סוגריים מסולסלים ובתוכם מה המחשב צריך לבצע במידה והתנאי מתקיים / נכון. בנוסף, ניתן להוסיף למשפט if, בסופו, את המילה else, ובעצם ע"י כך אנחנו אומרים אם התנאי (if) לא מתקיים, אז \_\___ (תבצע משהו אחר). - -ה else יהיה מורכב ע"י המילה else ואחריה סוגריים מסולסלים שבהם נכתוב מה לבצע במידה ומתקיים ה else (או במילים אחרות לא מתקיים תנאי ה if), (שימו לב של else אין סוגרים רגילים כי לא נכתוב בו תנאי, הוא מתקיים כל פעם שתנאי ה if לא מתקיים). ומכיוון שהסימן = מסמן השמה במחשבים, נתאר שווה ע"י הסימן פעמיים שווה: ==, ע"י כתיבת סימן השווה (==) נשווה 2 דברים (כמו האם התוצאה שקיבלנו מ digitalRead אותה שמרנו במשתנה בשם switchState שווה ל LOW (ואם לא, אז היא שווה ל HIGH מכיוון שאלו 2 הערכים היחידים אותם היא יכולה לקבל). בנוסף, שימו לב שכדי לכתוב הערות בקוד (מלל ממנו המחשב יתעלם) נכתוב // (2 סלשים) ואז את ההערה. - -  - -ניתן לראות בקוד שבתנאי של ה if השוונו אותו ל LOW, מצב שבו אנחנו לא מקבלים מתח, ז"א שהכפתור לא לחוץ - המעגל לא נסגר (מתחת ל if הוספתי הערה שמתארת את המצב) לכן בתוך ה if נכתוב את הפקודות שאנחנו רוצים שהארדואינו יבצע כשהכפתור לא לחוץ (נורת ה LED הירוקה תקבל מתח באופן קבוע ו-2 הנורות האדומות לא). לכן פין מס' 3 (אליו הלד הירוק מחובר) יקבל HIGH ע"י הפונקציה `digitalWrite` (ל [Reference](http://arduino.cc/en/Reference/digitalWrite)) (שעוזרת לנו לכתוב אל הפין), נציין את מס' הפין ואת המתח שיקבל, ול-2 הלדים האדומים נכתוב LOW. - -ב else (המצב בו הכפתור לחוץ) נכתוב לנורת הלד הירוקה (פין מס' 3) שיקבל LOW (לא יקבל מתח) ולאחת מהנורות האדומות HIGH ולשניה LOW על מנת שרק אחת תדלק (אני בחרתי בנורה המחוברת לפין מס' 5, אך הסדר כמובן לא חשוב). לאחר מכן נרצה שהנורה תדלק לכמה רגעים ולא תכבה מיד, לכן בעזרת הפונקציה `()delay` (ל [Reference](http://arduino.cc/en/reference/delay)) נשהה את הרצת התוכנית ל-250 מילי שניות (יש 1000 מילי שניות בשניה אחת), לכן נשהה אותו לרבע שניה ואז נחליף את המצב בפינים מס' 4 ו-5, בגלל שאני בחרתי להדליק קודם את פין מס' 5 עכשיו הוא יקבל LOW ופין מס' 4 יקבל HIGH (בפין מס' 3 אין צורך לגעת, אם לא תגידו לו לעבור למצב אחר הוא ישאר באותו מצב שהשארתם אותו בהוראה האחרונה). - -  - -זכרו שבסוף ה else לא נשאר קוד ולכן פונקציית ה loop תתבצע שוב. בנוסף, נזכור שבמידה והכפתור עדיין לחוץ ה else יחזור להתבצע ואז הנורות האדומות שוב מתחלפות, ובשביל שיהיה זמן השהייה גם בהחלפה הזו לפני שנסיים את הפונקציה נכתוב שוב delay. כעת, כשסיימנו לכתוב את התוכנית נלחץ על ה V על מנת לבדוק אותה (ע"י ה [קומפיילר - מהדר](http://en.wikipedia.org/wiki/Compiler)). במידה ולא קיבלנו כל שגיאה נלחץ על הכפתור שלידו (החץ שפונה ימינה) על מנת להעלות את הקוד לארדואינו. כשהיא תסיים לעלות נראה באופן אוטומטי את הארדואינו מגיב (לבד) לקוד החדש שכתבנו. - -  - -### לסיכום - -בפרויקט הזה יצרנו את תוכנת הארדואינו הראשונה שלנו, התוכנה שולטת בהתנהגות של 3 נורות לד (LED) על בסיס מתג. למדנו על איך תוכנת הארדואינו בנויה (פונקציות setup ו loop), משתנים, משפט תנאי (if בתוספת else), שימוש בפונקציות אחרות המגיעות עם הארדואינו באופן מובנה: לקריאה מפין digitalRead, לכתיבה לפין digitalWrite, ולהשהיית התוכנית לזמן קצוב delay). - -אני ממליץ לשחק עם התוכנית שכתבנו, נסו לשחק עם הזמן של כל delay ולראות איך התוכנית מגיבה, להחליף את סדר הפעלת הלדים האדומים, להחליף את הלדים עצמם על גבי לוח המטריצה ולראות האם התוכנית מגיבה אחרת, הסירו לד אדום אחד ותגרמו ללד אדום שנשאר להבהב לבד כל חצי שניה (או משהו כזה), ותשאלו את עצמכם למה כשאתם מפסיקים ללחוץ על המתג בדיוק כשהנורה המחוברת לפין מס' 5 דולקת, הלד הירוק לא נדלק מיד? ולמה הלד האדום שמחובר לפין מס' 4 דולק אחריו (הרי כבר עזבתם את המתג לפני שהוא נדלק, מה פתאום?!). diff --git a/data/_oldPosts/2014-04-20-computer-networks-introduction.md b/data/_oldPosts/2014-04-20-computer-networks-introduction.md deleted file mode 100644 index d318446..0000000 --- a/data/_oldPosts/2014-04-20-computer-networks-introduction.md +++ /dev/null @@ -1,245 +0,0 @@ ---- -title: 'Computer Networks - הקדמה' -author: nirgn -layout: post -summary: "הפוסט הזה הוא התחלה של סדרת פוסטים על רשתות תקשורת מחשבים. בסדרת הפוסטים אעבור על השכבות השונות של המודל המשולב. יש לציין מראש כי הפוסטים יהיו כבדים (בעלי מלל רב) וטכניים. הפוסטים נועדו למי שולמד רשתות תקשורת מחשבים כחלק מתואר במדעי המחשב ו/או למי שמעוניין ללמוד לבד ו/או לאנשים שרק רוצים להיזכר (אחלק את הפוסטים לשכבות ובתוך כל שכבה לנושאים, עם תוכן עניינים בראש הפוסט)." -category: Computer Networks ---- -הפוסט הזה הוא התחלה של סדרת פוסטים על רשתות תקשורת מחשבים. בסדרת הפוסטים אעבור על השכבות השונות של המודל המשולב. יש לציין מראש כי הפוסטים יהיו כבדים (בעלי מלל רב) וטכניים. הפוסטים נועדו למי שולמד רשתות תקשורת מחשבים כחלק מתואר במדעי המחשב ו/או למי שמעוניין ללמוד לבד ו/או לאנשים שרק רוצים להיזכר (אחלק את הפוסטים לשכבות ובתוך כל שכבה לנושאים, עם תוכן עניינים בראש הפוסט). מפני שהפוסטים גדולים אינני מבטיח כי הם יתפרסמו אחד אחרי השני וסביר להניח כי יקח לי זמן לא מבוטל להכין כל אחד. - -הפוסט הנל מהווה הקדמה וסקירה כללית של הנושאים המרכזיים בתחום הרשתות: - - 1. היבט החומרה. - 2. היבט התוכנה. - 3. המודלים השונים של חלוקה לשכבות. - 4. דוגמאות של רשתות. - 5. תקינת רשתות. - 6. יחידות מדידה. - - - -  - -### 1. היבט החומרה - -**באופן כללי קיימות שתי טכנולוגיות שידור עקריות:** -**רשתות נקודה לנקודה (Point-to-Point) -** רשתות אלו מחברות תחנות אינדבידואליות כדי להעביר פאקטות (Packets) מהמקור לנקודה כלשהי ברשת. לפעמים המנות (Packets) עוברות מסלולים שונים (בעלי אורכים שונים) על מנת להגיע ליעד, לכן מציאה של מסלול טוב (קצר) היא קריטית ברשתות אלה. רשת נקודה לנקודה בעלת שולח אחד בלבד ומקבל אחד בלבד נקראת גם Unicasting (שידור המיועד לתחנה אחת בלבד). - -**רשתות הפצה – (Broadcast) -** בסוג רשתות אלה ישנו ערוץ שידור משותף, וכל שידור לערוץ נשמע בכל התחנות ברשת. ההודעות המשודרות מחולקות למסרים קצרים המכונות מנות או חבילות (Packets), (כל מנה מכילה סימון למי היא מיועדת).שידור כזה מכונה Broadcasting. מערכות Broadcast מסוימות תומכות, בנוסף, בשידור לקבוצה של תחנות, פעולה זו נקראת Multicasting. - -בנוסף, יש לציין כי: - - * המבנה הטיפולוגי של הרשתות אינו קבוע וניתן למצוא טופולוגיות שונות כגון: כוכב, טבעת, עץ, רשת מלאה וכד'. - * יש להבדיל בין טכנולוגיית שידור לבין המאפיין הלוגי של השידור, שיכול להיות: Unicast - שידור המיועד לתחנה אחת בלבד. Broadcast - שידור המיועד לכלל התחנות ברשת. Multicast - שידור המיועד לקבוצה מוגדרת של תחנות. - * כל מאפיין לוגי של שידור יכול להתבצע בכל טכנולוגיית שידור. למשל, כדי ליישם שידור לוגי Unicast ברשת הפועלת בטכנולוגיית הפצה (Broadcast), ניתן לשדר את המנה לכל התחנות ברשת, אך רק התחנה אליה מיועדת המנה תסיר את המסגרת מהערוץ ותעבד את התוכן שלה, ואילו כל שאר התחנות יתעלמו ממנה. - -להלן איור עם דוגמאות למבנים טופולוגיים של רשתות: - -
    - Networks Types -
    - -**קריטריון נוסף לסיווג רשתות הוא גודלן:** - - * **PAN** (ראשי תיבות: Personal Area Network) - רשתות תקשורת אישיות, לדוגמה Bluetooth או RFID. - * **LAN** (ראשי תיבות: Local Area Network) - רשתות תקשורת מקומיות, לדוגמה ראווטר (אלחוטי או קווי). - * **MAN** (ראשי תיבות: Metropolitan Area Network) - רשתות תקשורת אזוריות, לדוגמה רשת טלוויזיה קווית או WiMAX. - * **WAN** (ראשי תיבות: Wide Area Network) - רשתות תקשורת רחבות, הרשת תתפרס על אזור גדול, לרוב מדינה או יבשת. - * **Internetworks** (או Internet) - זו בעצם רשת של רשתות. מה שמחבר בין רשת לרשת נקרא gateway. - -  - -### 2. היבט התוכנה - -כדי להוריד את רמת הסיבוך, רוב הרשתות מאורגנות כמחסנית, בשכבות (או שלבים). המטרה של כל שכבה היא להציע שירות לשכבה שמעליה אך להסתיר ממנה את הדרך בה נעשה (מיושם) השירות הנ"ל, הקונספט הנ"ל מוכר היטב במדעי המחשב ותכנות מונחה עצמים ונקרא אנקפסולציה (או בעברית: כימוס). - -פרוטוקול, באופן בסיסי, הוא הסכם בין שני צדדים לאיך התקשורת תעבור (תישלח ותעובד). לדוגמה, אם אישה הייתה מציגה עצמה לגבר ומושיטה את ידה, הגבר יכול להחליט ללחוץ את ידה או לנשקה, תלוי כמובן אם האישה היא עורכת דין בפגישת עסקים או שהיא נסיכה אירופאית בטקס כלשהו. הפרה של הפרוטוקול תהפוך את התקשורת לקשה עד בלתי אפשרית. במציאות, בפרוטוקולים, כל שכבה מעבדת את המידע ושולחת אותו לשכבה שמתחתיה, עד שאנו מגיעים לשכבה הנמוכה ביותר (כשמתחת לשכבה הראשונה ישנה השכבה הפיזית שם התקשורת האמיתית מתבצעת). - -אחד הדברים החשובים ביותר הוא הגדרה של ממשק נקי בין השכבות, עשייה של זה דורשת מכל שכבה ביצוע של אוסף פונקציות מובנות היטב. בנוסף לכך שזה חוסך בכמות המידע שעוברת משכבה לשכבה, זה מאפשר החלפה (או הטמעה) קלה יותר של שכבה חדשה (או פרוטוקול שלם כלשהו). למעשה, ניתן לשנות פרוטוקול כלשהו בשכבה כלשהי בלי ששאר השכבות ירגישו בזאת. אוסף של שכבות ופרוטוקולים נקראת ארכיטקטורת רשת. - -  - -**למרות כל זאת, השכבות יכולות להציע 2 סוגים של שירותים:** - -**חיבור מונחה הרשת (Connection Oriented) -** פועל על פי המודל חברות הטלפון. כדי לדבר עם מישהו הלקוח ממרים / לוקח את הטלפון, מחייג מספר, מדבר, ולבסוף מנתק. באופן דומה בחיבור מונחה רשת הלקוח קודם כל מקים חיבור, משתמש בחיבור ולבסוף משחרר אותו. האספקט החיוני של החיבור הוא שהוא מתנהג כמו צינור: השולח דוחף ביטים בקצה אחד, והמקבל לוקח אותם בקצה השני. - -**חיבור חסר קשר (Connectionless) -** פועל על פי השיטה של הדואר. כל הודעה (מכתב) נושא את כתובת היעד המלאה, בנוסף כל הודעה כזו מנותבת דרך צמתי הביניים בתוך המערכת באופן עצמאי, ללא תלות של ההודעות שלאחר מכן. כאשר כל צומת ביניים צריכה לקבל את ההודעה במלואה, שליחתה אל הצומת הבאה (זה נקרא: Store-and-Forward Switching). כאשר החלופה היא להתחיל את שליחת ההודעה אל הצומת הבאה עוד לפני שההודעה התקבלה במלואה בצומת הנוכחית (נקרא: Cut-Through Switching). שימו לב כי כאן אין צורך בהקמת קשר ישיר עם כתובת היעד. - -
    - Connection OrientedLess -
    - -כל שירות יכול להיות מאופיין ע"י האמינות שלו. כאשר חלק מהשירותים אמינים מבחינה זו שהם לעולם לא מאבדים מידע (לרוב, שירות אמין מוטמע ע"י כך שהוא מחייב את המקבל לאשר כל הודעה כך שהשולח בטוח שההודעות התקבלו). לא אלאה אתכם בפרטים, בצד שמאל הוספתי טבלה מסכמת של הגרסאות הקיימות בכל אחד מהשירותים. ולמרות שהקונספט של שימוש בשירות לא אמין יראה מוזר, הרי מדוע שמישהו יעדיף שירות לא אמין על פני שירות אמין? הוא בשימוש רב. תחילה, יתכן כי שירות אמין לא יהיה זמין בשכבה מסוימת (לדוגמה אתרנט לא מספק שירות אמין, מנות יכולות להשתבש בדרך, וזה על פרוטוקולים משכבות גבוהות יותר להתמודד עם הבעיה). בנוסף, הוספתי בטבלה דוגמאות לכל שירות, וניתן לראות כי שיחת וידיאו VoIP היא דוגמה מצויינת לשירות לא אמין, חשוב לנו יותר שלא יהיה דיילי והשיחה לא תקפא בגלל שמנה אחת שהשתבשה או לא הגיעה, מאשר שיהיה גליצ' קטן או שיבוש בפיקסל, לשניה באמצע השיחה. - -  - -|Meaning|Primitive| -|:---:|:---:| -|Block wating for an incoming connection|LISTEN| -|Establish a connection with a wating peer|CONNECT| -|Accept an incoming connaction from a peer|ACCEPT| -|Block wating for an incoming message|RECEIVE| -|Send a message to the peer|SEND| -|Terminate a connection|DISCONNECT| - -שירות כלשהו מפורט ע"י קבוצה של פעולות הזמינות / נגישות לתהליכי המשתמש. הפעולות האלו תלויות בסוג השירות המסופק, ואילו אשר מסופקות ע"י חיבור מונחה אינם אילו אשר מסופקות ע"י חיבור חסר קשר. להלן דוגמה קטנה (התמונה בצד שמאל) לפעולות שכנראה יסופקו בשירות של זרם בתים אמין. - - 1. ראשית, השרת מבצע פקודת LISTEN כדי לסמן שהוא מוכן לקבל חיבורים נכנסים. - 2. לאחר מכן הלקוח מבצע פקודת CONNECT כדי להקים חיבור עם השרת. (הקריאה ל CONNECT צריכה לפרט למי להתקשר כך שכנראה יהיה לה פרמטר שבו נכניס את כתובת השרת). מערכת ההפעלה תשלח את לבסוף את המנה ותבקש לבצע חיבור. כעת התהליך בצד הלקוח "קופא" עד שתוחזר תשובה. - 3. כאשר המנה מגיע לשרת מערכת ההפעלה רואה שהמנה מבקשת לבצע חיבור. היא בודקת האם ישנו LISTEN היא חוסמת את הפקודה ומבצעת חיבור ע"י שליחת מנת ACCEPT חזרה ללקוח. ההגעה של התגובה הזו "משחררת" את הלקוח. כעת הלקוח והשרת מחוברים, רצים, ומחליפים בניהם מידע. - 4. כעת השרת נכנס למצב RECEIVE ומתכונן לקבלת הבקשה הראשונה. בדר"כ השרת מבצע את זה ישירות לאחר ה"שחרור" ממצב LISTEN, עוד לפני שהאישור מגיע חזרה ללקוח. - 5. הלקוח מבצע פקודת SEND ושולח בקשה למידע. ההגעה של הבקשה "משחררת" את השרת ממצב RECEIVE, כדי לטפל בבקשה, לאחר שהוא ביצע את העבודה הוא משתמש בפקודה SEND כדי להחזיר תשובה ללקוח. ובהתאמה, ההגעה של פקודת SEND ללקוח "משחררת" אותו כדי לטפל במידע שהגיע. אם ללקוח ישנן עוד בקשות הוא יכול לבצע את ההליך הנ"ל שוב. - 6. כאשר הלקוח מסיים הוא מבצע פקודת DISCONNECT כדי לסיים את החיבור. לרוב, הפעולה משהה את הלקוח ושולחת מנה לשרת שאומרת שהחיבור הסתיים. כאשר השרת מקבל את המנה הזאת גם הוא מבצע DISCONNECT משלו, וכך בעצם משיב אישור ללקוח על המנה של סיום החיבור, ומסיים את החיבור. כאשר המנה של השרת מגיעה חזרה ללקוח, השירות של הלקוח "משתחרר" והחיבור "נשבר". - -כך עובדת תקשורת של חיבור מונחה רשת (בקצרה מאוד ובלי להיכנס ליותר מידי פרטים). כמובן, החיים לא כל כך פשוטים, והמון דברים יכולים להשתבש בדרך, אך נדבר עליהם לעומק בפוסטים מאוחרים יותר. - -  - -
    - TCP-IP OSI Models -
    - -### 3. המודלים השונים של חלוקה לשכבות - -קיימות 2 ארכיטקטורות רשת עיקריות: מודל OSI ומודל TCP/IP. למרות שרוב הפרוטוקולים המקושרים עם מודל ה OSI אינם בשימוש, המודל עצמו עדיין תקף, והפיצ'רים במודל זה עדיין חשובים מאוד. ובמודל ה TCP/IP ההפך הוא הנכון, המודל עצמו אינו בשימוש רב אך הפרוטוקולים המקושרים לו נמצאים בשימוש רחב מאוד (במיוחד ברשת האינטרנט). להלן, בצד שמאל, תמונה מסכמת של השכבות במודל ה OSI וה TCP/IP זה לצד, תוך הקבלה של השכבות המקבילות בניהם. - -  - -**מודל השכבות OSI** (ראשי תיבות: Open System Interconnection) מחלק את רמות התקשורת לשבע שכבות. העקרונות במודל שכבות הן: - - 1. יש ליצור שכבה היכן שיש צורך בהפשטה שונה. - 2. כל שכבה צריכה לבצע פונקציה מוגדרת היטב. - 3. יש לבחור את הפונקציה של כל שכבה תוך התייחסות לפרוטוקולי הסטנדרט הבינלאומיים. - 4. יש לבחור את גבולות השכבה כך שנצמצם את המידע הזורם בין הממשקים של השכבות. - 5. מספר השכבות צריך להיות גדול מספיק כדי שפונקציות שונות לא יהיו יחדיו באותה שכבה מתוך הכרח, אך גם קטן מספיק כדי שהארכיטקטורה לא תהפוך למסורבלת. - -**השכבה הפיזית (The Physical Layer) -** אחראית על העברת זרם ביטים בערוץ תקשורת. אחד הדברים החשובים להם השכבה צריכה לדאוג הוא כאשר צד אחד שולח 1 (ביט) הצד השני יקבל אותו כ-1 ולא כ-0. שאלות טיפוסיות בשכבה זו הן: "איזה אותות חשמליים ייצגו 1 ו-0", "כמה מילי שניות נמשך שידור של ביט" וכד'. בעיות העיצוב של שכבה זו מתמודדים במידה רבה עם ממשקים מכניים, חשמליים, ותזמונים, וכמו גם מדיום השידור עצמו (התשתית הפיזית, ש"מתחת" לשכבה זו). - -**שכבת הערוץ (The Data Link Layer) -** המשימה העיקרית של שכבת הערוץ היא להפוך רצף שידור גולמי (שורה שעתידה להיות משודרת) לשורה בה לא תמצאנה שגיאות שידור שלא ניתנות לגילוי. בעיה נוספת שמתעוררת בשכבה זו (ובשכבות גבוהות יותר) היא כיצד למנוע ממשדר מהיר להציף במידע מקלט איטי. - -**שכבת הרשת (The Network Layer) -** אחת הבעיות העיקריות אתה מתמודדת שכבה זו הוא הקביעה "איך המנות ינותבו מהמקור אל היעד". בנוסף, היא מטפלת בהתנגשויות בין מנות ובאופן כללי יותר באיכות השירות ([QoS](http://en.wikipedia.org/wiki/Quality_of_service)). - -**שכבת התובלה (The Transport Layer) -** התפקיד העיקרי של שכבת התובלה הוא לקבל מידע מהשכבה שמעליה, אם צריך לחלק אותו לחתיכות קטנות יותר, ולהעביר אותו לשכבת הרשת תוך הבטחה שחתיכות המידע האלו יגיעו לצד השני בצורה נכונה (ללא שגיאות). יותר מכך, על כל זאת להיות מבוצע ביעילות ותוך בידוד השכבות העליונות מהשינויים (הבלתי נמנעים) בחומרה שמתבצעים במהלך הזמן. - -**שכבת השיחה (The Session Layer) -** השכבה מאפשרת לשני משתמשים שונים במכונות שונות להקים בניהם שיחה. השכבה מציעה מגוון שירותים כמו dialog control (עוקב אחרי תור מי לשדר), token management (מונע משני המשתמשים לבצע את אותה פעולה ביחד), synchronization (מאפשר למשתמשים להמשיך מאיפה שהפסיקו במקרה שאחד מהם מתנתק), וכד'. - -**שכבת הייצוג (The Presentation Layer) -** בשונה מהשכבות התחתונות, שכבת הייצוג דואגת בעיקר לתחביר והסמנטיקה של המידע המשודר. היא מנהלת את המידע שעתיד להיות משודר (מקודדת / מצפינה / דוחסת). - -**שכבת היישום (The Application Layer) -** השכבה מכילה את מגוון הפרוטוקולים בהם המשתמש עושה שימוש. אחד מהם לדוגמה הנו HTTP ׁ(שמהווה את הבסיס ל WWW). - -  - -**מודל השכבות TCP/IP** (ראשי תיבות: Transmission Control Protocol / Internet Protocol) שמקורו ברשת ה ARPANET, מחלק את רמות התקשורת לחמש שכבות. הרעיון העיקרי העומד בבסיס המודל הוא היכולת לחבר כמה רשתות שונות בצורה חלקה. - -**שכבת הקישור (The Link Layer) -** השכבה התחתונה ביותר מתארת כיצד לקשר בין רשתות בעלות סוגי טכנולוגיות שונות, כגון קווים סידוריים ואתרנט. השכבה יוצרת מראה של רשת אחת בעלת מבנה אחיד עבור השכבות הגבוהות (ברמה של הבדלים טכנולוגיים). - -**שכבת הרשת (The Internet Layer) -** תפקידה העיקרי הוא לאפשר למשתמש לשדר מנות לכל רשת ו"לגרום" להם לנוע ליעד באופן עצמאי (שעלול להיות ברשת אחרת). המנות עשויות להגיע בסדר שונה לחלוטין ממנו נשלחו, ובמקרה זה העבודה של סידורם מחדש היא על שכבות גבוהות יותר. אחד הפרוטוקולים המפורסמים בשכבה זו הוא IP ׁ(ראשי תיבות: Internet Protocol) ופרוטוקול נלווה אליו ICMP (ראשי תיבות: Internet Control Message Protocol) שעוזר לו לתפקד. - -**שכבת התובלה (The Transport Layer) -** נועדה כדי לאפשר לשני עמיתים (אחד במקור ואחד ביעד) לנהל בניהם "שיחה". בשכבה זו נמצאים 2 פרוטוקולים מפורסמים: TCP (ראשי תיבות: Transmission Control Protocol). בקיצור (בעתיד נתעמק), זהו פרוטוקול מונחה חיבור, אמין, המאפשר לזרם בתים שמקרום במחשב אחד להיות מועבר, ללא שגיאה, למכונה אחרת על גבי האינטרנט. לעומתו UDP (ראשי תיבות: User Datagram Protocol) הוא פרוטוקול לא אמין (שבעיקר נועד ליישומים שלא מעוניינים בבקרת הזרימה של TCP). הוא בשימוש נרחב בעיקר לשאילתות בקשה - תשובה משרת / לקוח, ושירותים בהם שידור מהיר חשוב יותר מאשר שידור אמין (כמו שידור ישיר של אודיו / ווידיאו). - -**שכבת היישום (The Application Layer) -** השכבה האחרונה מכילה את הפרוטוקולים ברמה הגבוהה. כמו TELNET (טרמינל ווירטואלי), FTP (העברת קבצים), SMTP (מייל אלקטרוני) וכ'ו. - -  - -לאחר כמה שנים, התברר כי ישנם חסרונות ויתרונות לכל מודל, החוזקה של מודל ה OSI הוא המודל עצמו (ללא שכבות השיחה והייצוג), והחזקות של מודל ה TCP/IP הם הפרוטוקולים (שנמצאים בשימוש נרחב בתעשייה כבר המון שנים). ולכן אנחנו נדבר על מודל משולב, המשלב את התכונות משני המודלים האלו. המודל המשולב עליו נדבר מגדיר חמש שכבות (מתחיל בשכבה הפיזית, לערוץ, לרשת, לתובלה ובסוף לאפליקציה). - -כמו שניתן לראות, ל-2 המודלים יש הרבה במשותף. שניהם מבוססים על קונספט השכבות עם פרוטוקולים עצמאיים. בנוסף, הפונקציונליות של השכבות היא בערך אותו דבר. אך יש להם גם דברים שונים. נתחיל ב OSI, שלושת הקונספטים המרכזיים שלו הם: - - 1. שירותים. - 2. ממשקים. - 3. פרוטוקולים. - -אפשר להגיד שזה שמודל ה OSI עושה הבחנה ברורה בין השלושה זה התרומה הגדולה ביותר שלו. כל שכבה מספקת שירותים לשכבה שמעליה (ההגדרה של השירות מתארת מה השכבה מבצעת, לא כיצד הן ניגשות אליו או איך הוא מבצע את השירות). הממשק אומר לתהליך שבשכבה מעליו כיצד לגשת אליו, מתאר את הפרמטרים הדרושים לו ומה התוצאה אליה יש לצפות. ולבסוף, הפרוטוקולים הנמצאים בשימוש בשכבה מסוימת הם אך ורק העסק של השכבה עצמה, היא יכולה להשתמש באיזה פרוטוקול שתחפוץ, כל עוד תבצע את העבודה כמו שצריך. (בסוגריים נציין כי הקונספט הנ"ל מתיישב יפה מאוד עם הקונספט של תכנות מונחה עצמים (OOP)). - -מודל ה TCP/IP, במקור, אינו מבחין בין שלושת הקונספטים האלו. וכתוצאה מכך מודל ה OSI מחביא טוב יותר את הפרוטוקולים שלו, מה שמאפשר לבצע החלפה שלהם באופן שקוף ופשוט יחסית (והיכולת לבצע זאת באופן שקוף היא אחת הסיבות העיקריות לשימוש בקונספט השכבות מלכתחילה). ישנם עוד כמה שינויים מהותיים בין המודלים, וכמובן המון ביקורת על כל מהם, אך לא ניכנס אליהם כרגע (אם תרצו, יש המון מידע על זה באינטרנט ואתם מוזמנים לחפש). - -  - -### 4. דוגמאות של רשתות - -האינטרנט אינו באמת רשת, אלה אוסף נרחב של רשתות שונות העושות שימוש במגוון פרוטוקולים משותפים ומספקים מגוון שירותים משותפים. זוהי מערכת לא רגילה, מכיוון שהיא אינה תוכננה או נשלטת ע"י / בידי אף אחד. כדי שנבין יותר איך המערכת הזו נוצרה בואו נתחיל מההתחלה. - -  - -**ה ARPANET** - -
    - Telephone System Structure -
    - -הסיפור מתחיל בשנים המאוחרות של 1950, בשיא המלחמה הקרה, מחלקת ההגנה של ארה"ב (U.S. DoD, ראשי תיבות: [United States Department of Defense](http://en.wikipedia.org/wiki/United_States_Department_of_Defense)) רצתה רשת לפיקוד ובקרה שתוכל לשרוד התקפה גרעינית (בזמנו כל התקשורת הצבאית השתמשה בתשתית הטלפוניה הציבורית). רשת הטלפוניה הציבורית נחשבה לפגיעה בגלל המבנה שלה, אותו מבנה שניתן לראות בתמונה משמאל, בו ניתן לראות כי ישנם מרכזיות המחברות בין מרכזיות אחרות (או משתמשי קצה וכד') ואם הן נופלות לא ניתן יהיה להמשיך בתקשורת כי זוהי הדרך היחידה בה המרכזיות מחוברות בניהן. - -בערך בשנת 1960 משרד ההגנה האמריקאי העניק חוזה לתאגיד RAND כדי למצוא פתרון לבעיה האמורה לעיל. אחד מהעובדים של התאגיד, פול ברן (Paul Baran) הציע את העיצוב המבוזר בו גם תחנות הקצה מחוברות אחת לשניה. ומכיוון שהדרך בין כל 2 מרכזיות הייתה כעת יותר גדולה ממה שאות אנלוגי יכול לנוע בלי להיות מעוות, ברן הציע להשתמש בטכנולוגיית מנות דיגיטליות. ברן כתב כמה דוחות למשרד ההגנה האמריקאי המתארים את התכנית שלו, הפנטגון אהב את הקונספט וביקש מ AT&T לבנות אב טיפוס. אך AT&T ביטלה את הרעיון של ברן, התאגיד הגדול והעשיר לא התכוון לתת לאיזה שחצן צעיר להגיד לה איך לבנות מערכת טלפוניה, הם אמרו שהרשת של ברן אינה יכולה להיבנות ובכך הרגו את הרעיון. - -כמה שנים מאוחר יותר ולמשרד ההגנה עדיין לא הייתה רשת לפיקוד ובקרה טובה יותר. וכדי להבין מה קרה הלאה, שוב, נחזור קצת אחורה לאוקטובר 1957. כאשר ברית המועצות השיגה את ארה"ב במירוץ לחלל והצליחה לשגר את הלוויין הראשון ספוטניק ([Sputnik](http://en.wikipedia.org/wiki/Sputnik_1)). הנשיא (דאז) דווייט אייזנהאואר ([Dwight D. Eisenhower](http://en.wikipedia.org/wiki/Dwight_D._Eisenhower)) ניסה להבין מי נרדם בשמירה, ונחרד למצוא את הצבא, חיל הים, והאוויר מתקוטטים על תקציב המחקר של הפנטגון. התגובה המידית שלו הייתה להקים ארגון יחיד שיתמקד במחקר בטחוני, ARPA (ראשי תיבות: [Advanced Research Projects Agency](http://en.wikipedia.org/wiki/DARPA), ששינתה את שמה לDARPA כדי להוסיף Defense (באופן סופי) בשנת ב-1996). ל ARPA לא היה מדענים ומעבדות. האמת, לא היה לה כלום חוץ ממשרד ותקציב קטן (בסטנדרטים של הפנטגון). ARPA עשתה את עבודה ע"י הענקת מענקים וחוזים לאוניברסיטאות וחברות שהרעיונות שלהן נראו לה מבטיחים. - -  - -ב-1967 תשומת הלב של לארי רוברטס ([Larry Roberts](http://en.wikipedia.org/wiki/Lawrence_Roberts_(scientist))), מנהל ב ARPA שניסה להבין כיצד לספק גישה מרחוק למחשב, הופנתה לרשת. הוא יצר קשר עם כמה מומחים, ואחד מהם היה וסלי קלארק ([Wesley Clark](http://en.wikipedia.org/wiki/Wesley_Clark)) שהציע לבנות תת רשת מיתוג מנות. רוברטס, לאחר ספקנות ראשונית, קנה את הרעיון והציג גרסה מעורפלת שלו בכנס ACM SIGPOS (שהיה על עקרונות מערכות הפעלה והתקיים בגטלינבורג, טנסי בסוף 1967. להפתעתו של רוברטס מאמר נוסף בכנס תיאר מערכת כזו, ולא רק תיאר את עיצוב המערכת אלה גם יישום מלא שלה תחת הנהגתו של דונלד דייויס ([Donald Davies](http://en.wikipedia.org/wiki/Donald_Davies)) מהמעבדה הלאומית לפיזיקה של אנגליה ([National Physical Laboratory](http://en.wikipedia.org/wiki/National_Physical_Laboratory_(United_Kingdom))). המערכת של ה NPL לא הייתה מערכת לאומית (היא רק חיברה כמה מחשבים לקמפוס הראשי שלה), אך היא הדגימה שמיתוג מנות יכול לעבוד, ואף יותר מכך, הם ציטטו ישירות מהעבודה המוקדמת של ברן. רוברטס חזר מגטילינבורג נחוש לבנות את מה שיותר מאוחר נודע בתור ה ARPANET. - -ARPA הוציאה מכרז לבניה של הרשת (הכולל תיאור מדויק של עיצוב הרשת והרכיבים). 12 חברות התמודדו עליו, ולבסוף ARPA בחרה ב [BBN](http://en.wikipedia.org/wiki/BBN_Technologies), חברת ייעוץ היושבת בקיימברידג', מסצ'וסטס ובדצמבר 1968 העניקה לה את החוזה לבניה של תת הרשת ולפיתוח התוכנה שלה. בדצמבר 1969 רשת ניסיונית עלתה לאוויר וחיברה 4 אוניברסיטאות במערב ארה"ב. לאחר כמה שנים נוספו יכולות לוויניות ומנות מבוססת תקשורת רדיו. ולאחר מכן שוחררה גרסת תוכנה חדשה המבוססת על פרוטוקול TCP/IP, שפותח באונ' ברקלי ([Berkeley](http://en.wikipedia.org/wiki/Berkeley,_California)) שבקליפורניה. בהמשך, בשנות ה-80 חוברו רשתות נוספות ל ARPANET (במיוחד רשתות LAN), וכשקנה המידה של הרשת גדול נעשה יקר יותר ויותר למצוא hostים, לכן פותח ה DNS (ראשי תיבות: [Domain Name System](http://en.wikipedia.org/wiki/Domain_Name_System)) כדי לארגן את המכונות לתוחמים ואת שמות הhostים לכתובת IP. - -  - -**NSFNET** - -בשנות ה-70 המאוחרות ארגון ה NSF (ראשי תיבות: [National Science Foundation](http://en.wikipedia.org/wiki/National_Science_Foundation)) ראה את ההשפעה העצומה של ה ARPANET על המחקר של האוניברסיטאות המחוברות אליו (היכולת לאפשר למדענים מכל המדינה לחלוק מידע ולבצע שיתופי פעולה בפרויקטי מחקר). אך כדי לקבל גישה ל ARPANET על האוניברסיטה היה להיות בעלת חוזה מחקר ממשרד ההגנה האמריקאי (DoD), והתגובה הראשונית של ה NSF הייתה לממן רשת למדעי המחשב הנקראה CSNET. אך לאחר מכן, בשנות ה-80 המאוחרות, ה NSF החליט לתכנן יורש ל ARPANET שיהיה פתוח לכל האוניברסיטאות. הרשת הייתה מחוברת ע"י קווי 56kbps (אותם אלה ששימשו את הARPANET), אך שכבת התוכנה הייתה שונה לגמרי, היא "דיברה" TCP/IP ישר מההתחלה, והייתה לרשת TCP/IP הראשונה בגודל WAN. - -ההצלחה של הרשת הייתה אדירה, וה NSF חזר מייד לשולחן השירטוטים לתכנן את היורש, סיבים אופטיים שאפשרו מהירות של 448kbps, אך לאחר זמן מה, שוב, הרשת הייתה מוצפת והרשת שודרגה ב-1990 ל1.5Mbps. וכשהצמיחה גדלה, הבין ה NSF כי הממשלה אינה יכולה לתמוך ברשת, באופן פיננסי לעד. בנוסף, ארגונים מסחריים רצו להיכנס פנימה, אך האופי של רשת ה NSF אסר עליהם. לכן הוקם ארגון ללא מטרות רווח בשם ANS (ראשי תיבות:[Advanced Networks and Services](http://en.wikipedia.org/wiki/Advanced_Network_and_Services)), הארגון פעל במשך 5 שנים, שבהם גם שדרג את הרשת למהירות של 45Mbps ושינה את שמה ל ANSNET, אך לאחר 5 השנים הרשת נמכרה ל America Online. עד אז חברות רבות הציעו שירותי IP והיה ברור שהממשלה צריכה לצאת מהתחום. - -  - -**רשתות סלולריות** - -
    - Cellular Network -
    - -אנשים אוהבים לדבר בטלפון, וזה הפך את הרשת הסלולרית לרשת המצליחה ביותר בעולם. יש כיום יותר מ-4 מילארד מנויים (בעולם) לרשת הסלולרית (כדי לקבל פרספקטיבה, זה בערך 60% מאוכלוסיית העולם). הארכיטקטורה של רשת הסלולר השתנתה רבות ב-40 שנה האחרונות, יד ביד עם הצמיחה האדירה שחוותה. הדור הראשון של המכשירים הסלולריים העביר אותות רצפים אנלוגיים ונקרא AMPS, בעוד הדור השני (הנקרא GSM) היה דיגיטלי לגמרי, והדור השלישי (UMTS) גם הוא היה דיגיטלי וכבר הציע מענה לתופעת הגלישה והשימוש ביישומי אינטרנט גם מהמכשיר הנייד (למרות ששוב, הרשת מוצפת והמעבר לדור הרביעי, LTE, מתחיל לתפוס תאוצה). - -ברשת הסלולרית, להבדיל מרשת האינטרנט, המכשיר הנייד נודד באופן קבוע מחיבור לחיבור (כלומר, מתא המכסה שטח אחד לתא המכסה שטח אחר). לכן כמו שניתן לראות באיור משמאל הארכיטקטורה שונה לגמרי. בחלק הראשון נמצא הפרוטוקולים המשמשים לתקשורת על גבי האוויר (בין המכשיר הנייד לתחנות הבסיס), ובדור השלישי, לדוגמה, התקשרות הזו מבוססת על שיטת ה CDMA עליו נרחיב בהמשך. - -החלק השני של הרשת נקרא Core Network, ומאז תחילת הרשת ישנה מלחמה בין אלה התומכים ברשתות מנה (אלה אנשים המגיעים בעיקר מתחום האינטרנט), לאלה התומכים ברשתות מעגלים (אלה אנשים המגיעים בדרך כלל מתחום הטלפוניה). בהמשך נדון על המאפיינים, היתרונות והחסרונות של כל שיטה. אך ההפתעה הגדולה היא שרשת הסלולר בחלק של הליבה משתמשת בציוד השאול מרשתות המנה כמו גם מרשתות מעגלים. - -  - -### 5. תקינת רשתות - -קיימים המון ספקים ויצרנים של ציוד תקשורת, כל אחד עם רעיונותיו שלו לאיך הדברים צריכים להיעשות. ללא תיאום, יהיה בתחום כאוס מוחלט. והדרך היחידה להסכמה ולביצוע תיאום היא תקנים. תקנים מגדירים מה צריך בשביל היכולת לשתף פעולה (לא יותר ולא פחות). לדוגמה: תקן ה802.11 מגדיר המון קצבי שידור, אך לא אומר מתי יש להשתמש באיזה קצב (שזה הגורם המרכזי לביצועים טובים), זה תלוי במי שבונה את המוצר. תקן ה-802.11 עם כל כך הרבה בעיות (הוא בשימוש כל כך נרחב שיש הרבה גופים שמעוניינים לדחוף לצד שלהם, לכן יש המון בעיות תקניות וניטרליות) שיש קבוצה מיוחדת שעובדת רק עליו הנקראת [WiFi Alliance](http://en.wikipedia.org/wiki/Wi-Fi_Alliance). - -תקנים נופלים ל-2 קטגוריות: הראשונה היא תקני 'דה פקטו' (בלטינית: בפועל), אלה שפשוט קרו, ללא תכנון מקדים רשמי כלשהו. ישנם המון תקנים פופולריים שהתחילו ככה, כמו HTTP או Bluetooh. והסוג השני אלה תקני 'דה יורה' (בלטינית: לפי החוק), אלה תקנים אשר תכננן אותם גוף רשמי כלשהו לפני במיוחד. ישנם כמה ארגונים גדולים ובינלאומיים האחראיים לרוב התקינה הבינלאומית: - - * ITU (ראשי תיבות: [International Telecommunication Union](http://en.wikipedia.org/wiki/International_Telecommunication_Union)). ל ITU יש 3 מחלקות, הראשונה ITU-T האחראית על תחום הטלפונים ורשתות התקשורת הסלולריות (נקראה CCITT עד 1993). ITU-R האחראי על טווחים של תדרי רדיו. ו ITU-D המקדם את הפיתוח הטכנולוגי של המידע והתקשורת על מנת לצמצם את הפער הדיגיטלי בין ארצות. - * ISO (ראשי תיבות: [International Standards Organization](http://en.wikipedia.org/wiki/International_Organization_for_Standardization)). זהו מכון התקנים הבינלאומי, והוא עוסק במגוון עצום של נושאים (החל מברגים ואומים עד לציפוי של עמודי טלפון, רשתות דיג ובקיצור כל מה שעולה על דעתכם. ל ISO יש מעל ל-200 וועדות טכניות ומעל ל-17,000 סטנדרטים שהוצאו עד כה. - * שחקן גדול נוסף הינו IEEE (ראשי תיבות: [Institute of Electrical and Electronics Engineers](http://en.wikipedia.org/wiki/Institute_of_Electrical_and_Electronics_Engineers)). בנוסף לכך שהארגון עורך מאות כנסים בכל שנה, יש לו גם קבוצת תקינה המפתחת תקנים בתחום החשמל של ההנדסה והמחשוב (לארגון היו כמה סיפורי הצלחה גדולים מאוד כמו התקנים 802.3 ו-802.11 עליהם נדבר בעתיד). - -  - -### 6. יחידות מדידה - -כדי למנוע בלבול מיותר בניתי טבלה המסכמת את יחידות המידה בהם כנראה תיתקלו במהלך הפוסטים הבאים: - -
    - Units -
    - -כמה נקודות: - - * לא ציינתי זאת, אך הטבלה כמובן מתחילה מ 1bit (סיבית, יחידת המידה הקטנה ביותר), ועוברת ל 1byte (בית, שזה 8 ביטים) ומשם כבר מצויין בטבלה (kilo וכך הלאה). - * כדי שנוכל להבדיל בין מילי למיקרו (שניהם מתחילים ב m), נבחר לייצג מילי בm ומיקרו ב'מיו' (האות היוונית μ). - * כדאי לציין שכדי למדוד זיכרון, דיסק, קבצים וכד', כמקובל בתעשייה יחידות המידה טיפה שונות. ה Kilo שם לדוגמה הוא 10^2 (1024) במקום 3^10 (1000). - * בנוסף, B (גדולה) מציינת "byte" בעוד b (קטנה) מציינת "bits". כבל המספק מהירות שידור של 1kbps בעצם מספק 1,000bits בשניה. - -  - -### לסיכום - -לרשתות מחשבים יש שימושים רבים, לחברות כמו גם לאנשים פרטיים, בבית וגם בחוץ. החברות משתמשות ברשת המחשבים כדי לחלוק מידע, לרוב ע"י שימוש במודל השרת-לקוח. לאנשים פרטיים הרשת מציעה גישה למגוון רחב של מידע ומקור בידור, וכמו כן גם דרך לרכוש ולמכור מוצרים ושירותים. אנשים פרטיים ניגישים לרוב לרשת האינטרנט דרך המכשיר הנייד או דרך ספקית האינטרנט שלהם בבית. - -באופן כללי, ניתן לחלק את הרשתות ל LANs, MANs, WANs ול internetworks. בעוד LAN בדרך כלל מכסה בניין, MAN מכסה עיר, ו WAN כנראה תכסה מדינה או אפילו יבשת. בעוד חלק מהטכנולוגיות ששימשו לבנות את הרשתות האלו הן נקודה-לנקודה (בדרך כלל כבל), אחרות הן רשתות הפצה (broadcast, בדרך כלל אלחוטיות). - -חלק התוכנה של הרשתות נבנה סביב פרוטוקולים, שהם חוקים שמתארים כיצד הפרוטוקול מתקשר. רוב הרשתות תומכות בהיררכיה של פרוטוקולים, כשכל שכבה מספקת שירות לשכבה שמעליה ומבודדת אותם מהפרטים שבהם הפרוטוקול בשכבה שמתחתיה משתמש. מחסנית הפרוטוקולים בדרך כלל מבוססים על מודל ה OSI או מודל ה TCP/IP. - -רשתות תקשורת מספקות שירותים שונים למשתמשים שלהם. שירותים אלה יכולים להיות מופעלים על ידי חיבור מנות חסר קשר, או חיבור מנות מונחה רשת. וכמו כן, יש לזכור שכדי לאפשר למחשבים רבים לדבר אחד עם השני יש צורך בכמות גדולה של תקנים. - -בחלק הבא נצלול הישר לשכבה הראשונה במודל התאורטי שלנו, הלא היא "השכבה הפיזית" - The Physical Layer. מקווה שהצלחתי לפשט את הדברים ולספק הסבר פשוט וממצה, וכמו תמיד, אשמח לענות לשאלות בתגובות או במייל (איך שנוח לכם). diff --git a/data/_oldPosts/2014-05-04-physical-layer.md b/data/_oldPosts/2014-05-04-physical-layer.md deleted file mode 100644 index 8c371db..0000000 --- a/data/_oldPosts/2014-05-04-physical-layer.md +++ /dev/null @@ -1,890 +0,0 @@ ---- -title: 'The Physical Layer - השכבה הפיזית' -author: nirgn -layout: post -summary: "פוסט זה מתמקד באחת השכבות מהמודל שהצגנו בפוסט הקודם, אנו מתחילים מהשכבה הראשונה (מלמטה), הלא היא השכבה הפיזית." -category: Computer Networks ---- -פוסט זה מתמקד באחת השכבות מהמודל שהצגנו בפוסט הקודם, אנו מתחילים מהשכבה הראשונה (מלמטה), הלא היא השכבה הפיזית. -בפוסט אבצע סקירה מלאה של השכבה ואפרט את הנושאים הבאים: - - 1. הבסיס התיאורטי של תקשורת הנתונים. - 2. התמסורת. - 3. תמסורת אלחוטית. - 4. תקשורת לווינים. - 5. אפנון וריבוב דיגיטליים. - 6. רשת הטלפוניה הציבורית. - 7. מערכת הטלפוניה הסלולרית (תאית). - 8. טלוויזיה וכבלים. - - - -  - -### אז לפני שאנחנו מתחילים, מהי השכבה הפיזית? - -השכבה הפיזית מגדירה את החשמל, הזמן ועוד ממשקים שונים בהם הביטים (bits) נשלחים כאותות (signals) על ערוצי תקשורת (channels). השכבה הנ"ל הינה הבסיס עליו בנויה הרשת. - -מידע יכול לעבור על גבי חוטים באמצעות נכסים פיזיים שונים כמו מתח או זרם, ועל ידי ייצוג שונה של ערכים במתח או בזרם באמצעות פונקציה בעלת ערך אחד של זמן, נקרא לה (f(t, אנחנו יכולים למדל את ההתנהגות של האות ולנתח אותו מתמטית. - -  - -### 1. הבסיס התיאורטי של תקשורת הנתונים - -**טורי פורייה** -דבר ראשון, חשוב להבין כי ניתן לקודד מידע ספרתי באמצעות ערכים בדידים כפונקציה של הזמן. לדוגמה, שידור ברמת מתח אחת ייצג את הסיבית 1 ושידור ברמת מתח אחרת ייצג את הסיבית 0 (לא רמת מתח 0 - אין מתח). - -סיפורנו מתחיל בתחילת המאה ה-19, כשהמתמטקאי הצרפתי [Jean-Baptiste Fourier](http://en.wikipedia.org/wiki/Joseph_Fourier) הוכיח כי כל פונקציה מחזורית בעלת מחזור שאורכו T, ניתנת לפירוק כסכום (אינסופי) של פונקציות סינוס וקוסינוס. לפיכך, אם נתייחס אל הגל האנלוגי שנוצר כאל פונקציה מחזורית אינסופית (g(t (כלומר פונ' הבנויה מתבנית בסיסית החוזרת על עצמה מידי T שניות) נוכל, באמצעות התאוריה של פורייה לקרב את הפונ' באמצעות סכום סופי של פונקציות גל (סינוסים וקוסינוסים) בתדרים שונים ו[אמפליטודות](http://he.wikipedia.org/wiki/%D7%9E%D7%A9%D7%A8%D7%A2%D7%AA) שונות (ככל שנסכום יותר איברים בפיתוח פורייה, כך נקבל פונ' קרובה יותר לפונ' המקורית, (g(t). - -  - -**הגבלת רוחב הפס של האותות** -כמה מושגים יבשים להמשך: - - * **רוחב פס (bandwidth) -** למהנדסי אלקטרוניקה: זהו תחום התדרים שניתן להעביר בערוץ, רוחב זה נמדד ביחידות של הרץ (Hetz). רוחב הפס יכול להיות מוגבל בצורה מלאכותית (ע"י מסננים המונעים העברה של תחומי תדרים מסויימים, כפי שבזק ביצעה ברשת הטלפוניה שלה בשנות ה-90), או בצורה טבעית (תכונה של הערוץ הגורמת לעיוות אותות מעל תדר מסוים עד כדי שאינם ניתנין לשחזור). למהנדסי מחשבים, רוחב פס זהו קצב הנתונים המירבי של הערוץ, ונמדד ביחידות של bits/sec (ראשי תיבות: bps). - * **קצב השידור בערוץ (transmission rate) -** כמה סיביות ניתן לשדר בערוץ במשך שניה אחת. שימו לב כי קצב השידור תלוי במרחק בין התחנות, במהירות האיתות (מספר הפעמים בשניה שהאות המשודר יכול לשנות את ערכו), ובמספר האותות המשמשים לשידור הנתונים. קצב זה נמדד ביחידות של סיביות לשניה (bps). - * **מידע דיגיטלי -** מידע שיכול לקבל ערך מתוך קבוצה סופית של ערכים (לדוגמה מספר טלפון, ציון בבחינה וכד'). - * **מידע בינארי -** מקרה פרטי של מידע דיגיטלי, מידע בינארי יכול לקבל ערכים מתוך קבוצה של שני ערכים בלבד (כבוי/דולק, זכר/נקבה, 1/0). - * **מידע אנלוגי -** מידע היכול לקבל ערך מתוך קבוצה רציפה של ערכים (לדוגמה גל קול). - -
    - Analog Vs Digital Signal -
    - -על מנת לאפשר את זיהוי האות המקורב שנשלח (שאנו מוציאים ע"י פיתוח פורייה), יש לשדר די רכיבים בפיתוח פורייה, על מנת שניתן יהיה לשחזר את האות שנשלח. ולפיכך לתקשורת כזו דרוש רוחב פס רחב, ואף אם הפס רחב דיו, שידור מספר רב של תדרים כאלו הוא בעייתי, השהיית ההתפשטות של האות ו[ניחות](http://en.wikipedia.org/wiki/Attenuation) (דעיכה) עוצמת האות תלויים בתדר שלו. ז"א שאם נשדר רכיבי תדרים רבים למרחק גדול, התדרים השונים יעוותו בצורה שונה (בגלל הפרשי הפאזה שבהם יגיעו והניחות השונה שנגרמים מההבדלים בעוצמת האותות) ואין הבטחה כי ההרמוניות (או רכיב / איבר) יגיעו על פי הסדר שהן נשלחו דבר זה יקשה את הפענוח של המידע. - -יש להבין כי עד כה עסקנו בניתוח של אותות דיגיטליים, ז"א שידור של 0 ו-1 כ-0 ו-1 (שידור של אות בינארי, כמו שניתן לראות בתמונה מצד שמאל), וכמו שראינו משימה זו קשה במיוחד. פתרון אפשרי לבעיית השידור של אותות דיגיטליים הוא ביצוע [אפנון](http://he.wikipedia.org/wiki/%D7%90%D7%A4%D7%A0%D7%95%D7%9F) (modulation) של האותות האלו. (כדי לשדר את הגל משתמשים ב[גל נושא](http://he.wikipedia.org/wiki/%D7%92%D7%9C_%D7%A0%D7%95%D7%A9%D7%90) (לרוב גל סינוס) המאופנן לפי תדר, מופע, או [אמפליטודה](http://he.wikipedia.org/wiki/%D7%9E%D7%A9%D7%A8%D7%A2%D7%AA) (או אפילו שילוב של שניהם, ונרחיב עליהם בהמשך)). -* חשוב לציין כי אין תמסורת שיכולה לשדר אותות בלי לאבד כוח בתהליך. - -  - -**החסמים של שנון ונייקוויסט** - -בתחילת 1924, מהדנס ב-AT&T בשם [הארי נייקוויסט](http://en.wikipedia.org/wiki/Harry_Nyquist) הבין כי גם לערוץ מושלם (ללא רעשים) יש יכולת שידור סופית (ז"א מוגבלת). נייקוויסט פיתח נוסחה לחישוב קצב השידור (קצב הנתונים) המקסימלי שניתן להעביר בערוץ בעל רוחב פס סופי (תחום תדרים סופי). נייקוויסט הוכיח כי קצב השידור המקסימלי בערוץ ללא רעשים ברוחב פס H בשימוש של V רמות מתח הוא: (2H*log2(V. ז"א שבערוץ של 3kHz (קילוהרץ) לא ניתן להעביר אות בינארי במהירות הגדולה מ 6,000bps (סיביות לשניה) ע"פ נייקוויסט. בנוסף מצא נייקוויסט כי אם אות שרירותי רץ על רוחב פס בגודל B, ניתן לשחזרו באופן מושלם ומלא ע"י ביצוע של 2B דגימות בדיוק (כמות דגימות גדולה יותר הינה חסרת טעם). - -בשנת 1948, המשיך [קלוד שנון](http://en.wikipedia.org/wiki/Claude_Shannon) את עבודתו של נייקוויסט והרחיב אותה גם למקרה של השפעת רעש רנדומלי על ערוץ תקשורת. כמות הרעש נמדדת ע"י היחס בין עוצמת האות לעוצמת הרעש או SNR (ראשי תיבות: Signal-to-Noise Ratio). אם נקרא לעוצמת האות S ולעוצמת הרעש N, אז יחס זה יהיה מיוצג ע"י S/N. בד"כ היחס מבוטא בעזרת סקאלה של log, אני לא אלאה אתכם ביחס עצמו, רק אציין כי היחידות של סקאלה הזו נקראות דציבלים ([decibels - dB](http://en.wikipedia.org/wiki/Decibel)). - -לבסוף, התוצאה הגדולה של שנון היא קצב השידור המקסימלי של ערוץ עם רעש שרוחב הפס שלו (של הערוץ) מבוטא כ B (הרצים) ויחס האות/רעש שלו הוא S/N. לדוגמה ADSL שמספקת אינטרנט על גבי רשת הטלפוניה, משמשת ברוחב פס בסביבות 1MHz. ה SNR תלוי באופן מובהק במרחק של הבית מקופסת התקשורת (כש SNR של 40dB למרחק קצר של 1-2 ק"מ נחשב לטוב מאוד). עם הנתונים האלו, הערוץ לעולם לא יוכל לספק יותר מ 13Mbps (הנוסחה של שנון: (B*log2(1+S/N, הנוסחה לחישוב S/N היא: (10log10(S/N). - -_שימו לב:_ -החסם של נייקוויסט תלוי ברוחב הפס של הערוץ ובמספר הסיביות המיוצגות ע"י כל אות בלבד, והוא אינו תלוי ברעשים הקיימים בערוץ. רעשים נמדדים לפי היחס אות לרעש. ככל שיש יותר רעשים, כלומר היחס אות לרעש נמוך, כך החסם של שנון יהיה משמעותי יותר, שכן קצב השידור בערוץ יקטן בשל הרעשים שבו. לעומת זאת, בערוץ שבו היחס אות לרעש גבוה, החסם של נייקוויסט עשוי להיות נמוך יותר, כלומר, להגביל את קצב השידור בלא קשר לערכו של החסם של שנון. בערוץ מסוג זה, שבו החסם של נייקוויסט, שאינו תלוי כלל בעוצמת הרעשים, נמוך מהחסם של שנון (ז"א שהוא המגדיר את קצב השידור המקסימלי. אנו תמיד נחשב את שני החסמים וניקח את הנמוך מביניהם), ניתן לומר שהרעשים בערוץ זניחים. - -  - -### 2. התמסורת - -כדי להבין יותר לעומק את השכבה הפיזית, נציג בקצרה כמה אמצעי תחבורה פיזיים שלכל אחד מהם רוחב פס שונה, איחור (delay) שונה, עלות שונה, וקלות התקנה ותחזוקה שונים. - -  - -**אמצעים מגנטיים (Magnetic media)** -אחת הדרכים המקובלות ביותר להעברת מידע היא באמצעות כתיבה של המידע על סרט מגנטי או מדיה ניידת, והעברתה באופן פיזי אל היעד (לדוגמה באמצעות UPS) וקריאת הסרט המגנטי או הדיסק במחשב היעד. אמצעי זה אינו מתוחכם במיוחד אך לרוב הינו כלכלי מאוד, במיוחד עבור נפחים גדולים של מידע. - -  - -**חוטים שזורים (Twisted pairs)** - -
    - Twisted Pair Cable -
    - -אחת מהתמסורות הישנות והנפוצות ביותר הוא חוטים שזורים (ראו תמונה מצד שמאל). חוט שזור מכיל 2 חוטי נחושת מבודדים (לרוב בעובי של 1 מ"מ) השזורים ביחד בדומה מאוד למולקולת DNA. השזירה מתבצעת כדי להבטיח כי הגלים מהחוטים השונים יבטלו זה את זה. ולרוב, האות הינו ההפרש במתחים של שני החוטים השזורים. מערכת הטלפוניה ו ADSL יכולות לרוץ על חוטים אלו. חוטים שזורים יכולים לרוץ כמה קילומטרים ללא הצורך בהגברת האות, אך למרחק ארוך יותר, האות דועך ויש להשתמש ברפיטרים על מנת להגביר את האות בחזרה. רוחב הפס תלוי בעובי החוטים ובמרחק שלהם, אך לא בעיה להגיע לכמה מגה ביטים לשניה לכמה קילומטרים (במרבית המקרים). - -נציין כי עם השנים התבצעו כמה פיתוחים שאפשרו להעלות את רוחב הפס, כמו: הכנסת כמה חוטי נחושת (בדר"כ 4) לחוט שזור אחד כך שכמה חוטים אחראים על כיוון אחד והאחרים על הכיוון השני (העלה / הורדה), או שזירה הדוקה יותר (מביאה לאיכות אות טובה יותר על גבי מרחקים ארוכים יותר), או העלאת רוחב הפס ע"י שימוש באות גבוה יותר. כבלים עבים, איכותיים ובעלי מעטפת מבודדת מסוג חוטים שזורים הוצגו ע"י IBM בתחילת שנות ה-80, אך בשל עלותם הגבוהה לא נחלו הצלחה. - -  - -
    - Coaxial Cable -
    - -**כבל קואקסיאלי (Coaxial cable) בל קואקסיאלי** - -עוד כבל נפוץ הינו הכבל הקואקסיאלי, כבל זה מספק הגנה (בידוד) טוב יותר ורוחב פס גדול יותר (מחוטים שזורים ללא הגנה), כך שנית לפרוס אותו למרחקים גדולים יותר ללא מגברים ולקבל מהירויות גבוהות יותר. - -הכבל בנוי מחוט נחושת במעטפת הפנימית ביותר, מעליו חומר בידוד, לאחר מכן חומר מוליך חיצוני, ולבסוף הכל עטוף בשכבת פלסטיק להגנה. כבלים אלו יכולים לספק רוחב פס של כמה גיגה הרץ והיו בשימוש נרחב במערכת הטלפוניה ככבלים ארוכי טווח (היום, כמעט כולם מוחלפים בסיבים אופטיים). - -  - -**סיבים אופטיים (Fiber optics)** - -
    - Fiber Optics -
    - -לסיב אופטי יש 3 מרכיבי מפתח, מקור האור, יחידת התמסורת, והגלאי. באופן מקובל, פעימת אור מייצגת ביט 1 והעדר האור מייצג 0, יחידת התמסורת היא סיב זכוכית דק ביותר, והגלאי מייצר פעימה חשמלית כל פעם שפוגע בו אור. בעצם מה שעשינו זה להפוך את הפעימה החשמלית לאור, לשלוח את האור על גבי סיב הזכוכית ובקצה השני להפוך אותו חזרה לפעימה חשמלית. - -אבל איך אנחנו יכולים לשלוח את האור בתוך סיב הזכוכית? כשהאור דרך סיב זכוכית מסוג [fused silica](http://en.wikipedia.org/wiki/Fused_quartz) לאוויר, הקרן נשברת, כשאנו שולחים את הקרן בזוויות מסויימות הקרן נשברת כולה חזרה לסיב הזכוכית (מבלי לאבד אף חלק ממנה אל האוויר). ז"א שקרן שפוגעת בגבול שבין סיב הזכוכית לאוויר, בזוויות מסויימת (או גדולה ממנה) לכודה בתוך סיב הזכוכית ואינה יכולה לצאת ממנו, ויכולה להתפשט למשך קילומטרים רבים, כמעט ללא הפסד. - -  - -### 3. תמסורת אלחוטית - -_הספקטרום האלקטרומגנטי_ -כשאלקטרונים זזים, הם יוצרים גלים אלקטרומגנטים שמתפשטים בחלל (אפילו בוואקום). את הגלים האלה, חזה לראשונה הפיזיקאי [ג׳יימס קלרק מקסוול](http://en.wikipedia.org/wiki/James_Clerk_Maxwell) בשנת 1865 (והם נצפו לראשונה ע"י הפיזיקאי [היינריך הרץ](http://en.wikipedia.org/wiki/Heinrich_Hertz) בשנת 1887). -מספר התנודות לשניה של גל כזה נקרא תדר ונמדד ביחידות הרץ, והמרחק בין שתי נקודות מקסימום (או מינימום) רציפות נקרא אורך הגל (ומיוצג באופן אוניברסלי ע"י האות [למדא](http://en.wikipedia.org/wiki/Lambda)). כשאנטנה בגודל המתאים מחוברת למעגל אלקטרוני היא מסוגלת לשדר את הגלים האלקטרומגנטים ביעילות, ולקלטם בצד המקבל שנמצא במרחק ממנה. (בוואקום, כל הגלים האלקטרומגנטים נעים באותה מהירות, ללא קשר לתנודות שלהם. מהירות זאת היא [מהירות האור](http://en.wikipedia.org/wiki/Speed_of_light). בנחושת או בסיבים, המהירות מאטה עד בערך 2/3 ממהירות האור והופכת באופן מועט לתלויה בתנודת הגל). - -
    - Spectrum -
    - -כל ספקטרום התדרים של הרדיו, מיקרו-גל, אינפרא אדום, והאור (הנראה) יכולים לשמש להעברת מידע, ע"י [מודולציה](http://en.wikipedia.org/wiki/Modulation) של ה [אמפליטודה](http://en.wikipedia.org/wiki/Amplitude), ה[תדר](http://en.wikipedia.org/wiki/Frequency) או ה[פאזה (מופע)](http://en.wikipedia.org/wiki/Phase_(waves)). (קרני רנטגן, אור אולטרה סגול, וקרני גמא יהיו אפילו טובים יותר בגלל התדר הגבוה עליו הם עובדים, אך קשה להפיק אותם, לבצע להם מודולציה, הם לא עוברים היטב בתוך מבנים, ומהווים סכנה ליצורים חיים). -ניתן לראות בתמונה משמאל את הסיבה הברורה מדוע סיבים אופטיים מצליחים כל כך, הם נמצאים בסקאלה הגבוהה שם יש המון גיגה הרץ של רוחב פס פנוי לשידור מידע. - -רוב התמסורות משתמשות בתחום קטן יחסית של רצועת התדרים. הם מרכזות את האות שלהם ברצועה הצרה הזו כדי להשתמש בספטקרום באופן יעיל ולהפיק קבצי נתונים סבירים ע"י שידור בעזרת מספיק כוח. לעומת זאת, במקרים נוספים משתמשים ברצועה רחבה יותר, לדוגמה: - - * **FHSS -** (ראשי תיבות: Frequency Hopping Spread Spectrum, בעברית: דילוג בתדר על ספקטרום מתפשט). במקרה הזה השידור קופץ מתדר לתדר מאות פעמים בשניה. שיטה זו פופולרית ביותר לתקשורת צבאית, מפני שהיא מקשה על גילוי השידור וכמעט בלתי אפשרי לתקוע אותה. בנוסף היא מציעה התנגדות טובה לדעיכה של מסלולים מרובים ומצרה את היקף ההפרעות, כדי שהמקבל לא יתקע על תדר לקוי/פגום/חלש למספיק זמן על מנת להשבית את התקשורת. - * **DSSS -** (ראשי תיבות: Direct Sequence Spread Spectrum, בעברית: רצף ישיר על ספקטרום מתפשט). במקרה הזה אנו נעזרים ברצף של קוד על מנת להפיץ את נתוני האות על פס תדרים רחב יותר. בשיטה זו משתמשות בעיקר חברות מסחריות כדרך יעילה מבחינת ספקטרום לתת לכמה אותות לחלוק את אותם התדרים. (שיטה כזאת בה לאותות נותנים קודים שונים נקראת CDMA). - * **UWB -** (ראשי תיבות: Ultra WideBand, בעברית: רצועה אולטרה רחבה). בשיטה זו אנו שולחים סדרה של פעימות מהירות על גבי רצועת תדרים רחבה, ומשנים את עמדות הפעימות בכל פעימה. המעברים המהירים בעמדות מובילים לאות שמתפשט בדלילות על פני פס תדרים רחב מאוד. - -נמשיך לדון בכיצד חלקים השונים של הספקטרום האלקטרומגנטי עובדים עם השיטות השונות, ונתחיל ברדיו. - -  - -**תמסורת רדיו** - -
    - Radio Frequency -
    - -תדרי רדיו (RF - Radio Frequency) קלים ליצירה ויכולים לנוע לאורך מרחקים ארוכים, הם גם חודרים בניינים בקלות יחסית ובשל כך הם פופולריים ביותר לתקשורת, בתוך הבית ומחוצה לו. בנוסף, גלי רדיו נעים לכל הכיוונים מהמקור, כך שהמשדר והמקלט לא חייבים להיות מיושרים פיזית. המאפיינים של גלי רדיו הינם תלוי תדר. בתדרים נמוכים, גלי רדיו עוברים דרך מכשולים היטב, אך הכוח שלהם נופל בצורה חדה ככל שהמרחק מהמקור גדל. בתדרים גבוהים, גלי רדיו נוטים לנוע בקווים ישרים ולקפוץ ממכשולים. בנוסף, תדרי רדיו גבוהים נבלעים ע"י הגשם ומכשולים אחרים במידה גדולה יותר מתדרים נמוכים. - -
    - Ionosphere -
    - -גלי רדיו בתחומי התדרים ה VLF, LF, MF (או בקיצור התדרים מ-4^10 עד 7^10 הרץ) עוקבים אחר הקרקע (כמו בתמונה משמאל - a). גלים אלו ניתנים לגילוי עבור מרחק של בערך 1,000 ק"מ בתדרים הנמוכים (פחות בתדרים הגבוהים יותר). גלי רדיו ברצועות התדרים האלו יכולים לעבור דרך בניינים בקלות, ולכן מכשירי רדיו ניידים מסוגלים לעבוד בתוך הבתים. הבעיה העיקרית בשימוש ברצועות התדרים האלו לתקשורת נתונים היא רוחב הפס הנמוך שלהם. - -לעיתים, בתחומי התדרים HF ו VHF, הגלים נוטים להיבלע ע"י האדמה. למרות זאת, הגלים שכן מגיעים ל[יונוספירה](http://en.wikipedia.org/wiki/Ionosphere) (שכבה של חלקיקים המקיפים את כדור הארץ בגובה של 100 עד 500 ק"מ) מוחזרים על ידה לכדור הארץ (כמו בתמונה משמאל - b) ולכן מאפשרים לבצע תקשורת על גבי מרחק גדול יותר. - -  - -**תמסורת מיקרו-גל** - -מעל 100MHz, הגלים נעים כמעט בקו ישר ולכן יכולים להיות ממוקדים באופן צר. ריכוז של כל האנרגיה הזו לקרן אחת קטנה באמצעות [אנטנה פרבולית](http://en.wikipedia.org/wiki/Parabolic_antenna) (כמו זאת של יס) נותנת יחס אות לרעש גבוה. בנוסף, בדרך הזאת ניתן לסדר בשורה משדרים רבים כדי לתקשר עם מקלטים רבים, ברציפות וללא הפרעה (בהנחה שישנו רווח מספק ביניהם). - -לפני הסיבים האופטיים, במשך זמן רב, תמסורת המיקרו-גל היו לב התקשורת ארוכת הטווח של תעשיית הטלפוניה. כמו שאמרנו, גלי מיקרו-גל נעים בקו ישר, כך שאם מגדלי האנטנות נמצאים במרחק רב אחד מהשני עיקול כדור הארץ יפריע להם (לכן מעת לעת נדרשים רפיטרים), ככל שהמגדלים גבוהים יותר, כך הם יכולים להיות במרחק רב יותר אחד מהשני. בנוסף, בניגוד לגלי רדיו בתדרים נמוכים, מיקרו-גל לא עוברים דרך בניינים בצורה טובה, אך לרוב, הקמה של 2 מגדלים כאלו תהיה זולה יותר מלהניח 50 ק"מ של סיבים דרך הרים או שטחים עירוניים. - -  - -**הפוליטיקה של הספקטרום האלקטרומגנטי** - -כדי למנוע כאוס מוחלט, ישנם הסכמים לאומיים ובין לאומיים להסדרת רשות השימוש בתדרים (מי מורשה להשתמש באיזה תדר). מכיוון שכולם רוצים קצב נתונים גבוה יותר, כולם רוצים עוד [ספקטרום](http://en.wikipedia.org/wiki/Spectrum). ממשלות מקצות ספקטרום לרדיו AM ו FM, לטלוויזיה, לחברות הטלפונים הנייחים, לסלולריים, למשטרה, לתקשורת ימית, לניווט, לצבא. כדי שיהיה ניתן להשתמש בתדרים האלו באופן גלובלי בלי להפריע אחד לשני, וגם לייצר מכשירים שמסוגלים לפעול באופן עולמי, ישנן סוכנויות דוגמת ה [ITU-R](http://www.itu.int/en/ITU-R/pages/default.aspx) המנסות לתאם את ההקצאות האלו (למרות שהמדינות לא מחויבות לקבל את המלצות הסוכנות). - -גם כשחלק מהספקטרום מוקצה לשימוש כלשהו, לדוגמה למכשירים ניידים, ישנה בעיה נוספת של איזו מפעילה תורשה להשתמש באיזה תדר. כדי לבצע את הבחירה הזאת תחילה היו מבצעים "תחרות יופי" בה כל אחת מהחברות הייתה מגיעה ומסבירה איך השימוש שלה בתדר א' יתרום לציבור הכי הרבה. ניתן להבין לבד כי שיטה זו הובילה לשחיתות והוחלפה לאחר מכן לשיטת ה"לוטו", בשיטת הלוטו היו מגרילים את התדרים כך שאין כל השפעה לאף אחד על התדר שכל חברה תקבל, אך שיטה זו הובילה לכך שחברות רגילות (לא מפעילות סלולר) היו נכנסות להגרלה ובמידה וזכו היו לאחר מכן מוכרות את התדר לחברות הסלולר, כך שלאותן חברות היה רווח עצום ללא סיכון. דבר שהוביל לשיטה השלישית שקיימת כיום, השיטה הזו בוצעה לראשונה בשנת 2000 ע"י הממשלה הבריטית בשביל התדרים לדור השלישי, בשיטה זו מבצעים מכרז על התדרים למרבה במחיר. הממשלה הבריטית העריכה כי תרוויח מהמכרז כ-4 מיליארד דולר, אך מפעילות הסלולר כל כך פחדו להישאר בלי תדרים (או עם תדרים פחות טובים) עד שהם נתנו הימורים כל כך גבוהים שהממשלה הבריטית קיבלה 40 מיליארד דולר מהמכרז. דבר שמוביל לבעיה נוספת, המכרז השאיר את המפעילות קרוב מאוד לפשיטת רגל, או במקרה הטוב, חוב גבוה עד כדי כך שידרשו שנים להחזיר את ההשקעה על תשלום הרישיון (דבר שכמובן מוביל לגלגול המחיר לצרכן, תחרות נמוכה (כל המפעילות צריכות להחזיר את הסכום ואף אחת לא מעוניינת להתחרות כל עוד הצרכן משלם), ואף האטת ההתקדמות הטכנולוגית). - -יש לציין כי כל הממשלות שומרות בצד ספקטרום תדרים לשימוש ללא תשלום שנקרא [ISM](http://en.wikipedia.org/wiki/ISM_band) (ראשי תיבות: Industrial, Scientific, Medical). ספקטרום זה משמש למכשירים לפתיחת דלתות המוסך, טלפונים נייחים אלחוטיים, צעצועים הנשלטים ברדיו, מיקרופונים אלחוטיים וכד'. כדי להקטין את ההפרעות של מכשירים אלו לגלים בשאר הספקטרום, ה [FCC](http://www.fcc.gov/) אף הגביל אותם בכוח השידור שלהם (לאזור ה 1 וואט), ואם הם רוצים להפיץ את השידור שלהם למרחק רב יותר, עליהם להשתמש בטכניקות אחרות. - -  - -**תמסורת אינפרא אדום** -גלי אינפרא אדום מונחים משמשים באופן נרחב לתקשורת קצרת טווח, דוגמת שלטים המשמשים לטלויזיה, ל DVD, לסטריאו וכד'. לרוב, הם זולים וקלים לבניה. אך יש להם חיסרון גדול: הם לא עוברים דרך עצמים מוצקים. לעומת זאת עובדה זו יכולה לשמש גם כיתרון, זה אומר שמערכת אינפרא אדום בחדר אחד לא תפריע למערכת אינפרא אדום בחדר אחר. ובשל עובדה זו אין צורך ברישיונות ממשלתיים לסטנדרט זה. גם מבחינת אבטחה, מערכת אינפרא אדום חסינה יותר לציתות בשל העובדה שאינה עוברת דרך עצמים מוצקים, מלדוגמה גלי רדיו. - -  - -**תמסורת אור** - -
    - Light Transmission -
    - -איתות אופטי בלתי מונחה קיים כבר מאות שנים. אך יישום מודרני שלו הוא חיבור רשתות LAN של שני בניינים באמצעות לייזר שמורכב על גג הבניין. איתות בעזרת לייזר הוא חד כיווני, ז"א שכל בניין צריך לייזר משלו וחיישן קריאה משלו. סכמה זו מציעה רוחב פס גדול מאוד בעלות נמוכה, והיא יחסית מאובטחת (קשה לצותת לקרן לייזר צרה). בנוסף, קל מאוד להתקין את המערכת הנל ושלא כמו מיקרו-גל היא לא דורשת רישיון של ה FCC. - -החוזק של המערכת מגיע מהקרן הצרה של הלייזר, אך זוהי גם חולשתו העקרית. כיוון שקשה מאוד לייצר קרן ברוחב 1 מ"מ האמורה לשדר למטרה בגודל של סיכה הנמצאת במרחק של 500 מטר. וכדי להקשות עוד יותר, הלייזר מושפע מרוח ומטמפרטורה שיכולים לעקם את הקרן. - -  - -### 4. תקשורת לווינים - -
    - Van Allen Belts -
    - -בצורתו הפשוטה, ניתן לחשוב על לווין תקשורת כרפיטר מיקרו-גל הנמצא בשמים. הלווין מכיל כמה [טרנספונדרים](http://en.wikipedia.org/wiki/Transponder) (התקן אלקטרוני הקולט ומשדר אותות), שכל אחד מהם מקשיב לחלק קטן מהספקטרום, מגביר את האות הנכנס, ומשדר אותו חזרה בתדר אחר (כדי למנוע הפרעות עם האותות הנכנסים). על פי [חוקי קפלר](http://en.wikipedia.org/wiki/Kepler's_laws_of_planetary_motion), זמן ההקפה של לויין משתנה על פי הרדיוס של המסלול בחזקת 2/3. או בקיצור, ככל שהלווין גבוה יותר כך זמן ההקפה ארוך יותר. בסמוך לפני כדור הארץ זמן ההקפה הוא בערך 90 דק', ובגובה של 35,800 ק"מ (מעל קו המשווה) זמן ההקפה הוא 24 שעות (בגובה של 384,00 ק"מ זמן ההקפה הוא חודש שלם, זמן ההקפה של הירח). - -זמן ההקפה של הלווין הוא חשוב לקביעת מיקומו, אך לא הגורם היחידי לקביעה זו, הגורם השני הוא חגורות ואן אלן. חגורות ואן אלן הן שכבות חלקיקים הטעונים במטען חשמלי, ולכודות בשדה המגנטי של כדור הארץ. כל לווין שנימצא בתוכן יהרס די בקלות ע"י החלקיקים. הגורם הזה הביא לכך שישנם רק 3 אזורים שבם ניתן למקם את הלווינים בצורה בטוחה (באיור משמאל). - -  - -**GEO - לוויני המסלול הגיאוסטציונרי** - -בשנת 1945, [ארתור סי קלארק](http://en.wikipedia.org/wiki/Arthur_C._Clarke) חישב כי לווין בגובה 35,800 ק"מ יראה ללא תנועה (מכיוון שלוקח לו 24 שעות להשלים סיבוב סביב כדור הארץ בדיוק כמו הזמן שלוקח לכדור הארץ להשלים סיבוב סביב עצמו) וכך לא צריך יהיה לעקוב אחריו (אלא רק לכוון אליו אנטנות פשוטות פעם אחת בלבד). הוא המשיך ותיאר מערכת תקשורת שלמה העושה שימוש בלווינים גיאוסטציונרים (כולל המסלול, פנאלים סולריים, תדרי רדיו, ונהלי שיגור). למרבה הצער הוא ביטל את הלויין בטענה שהוא לא שימושי, מכיוון שבלתי אפשרי לשים מגבר רעב לכוח ושביר, בצינור וואקום לחוג במסלול. - -המצאת הטרנזיסטור שינתה את כל זה, ולווין התקשורת הראשון, [טלסטאר](http://en.wikipedia.org/wiki/Telstar), שוגר ביולי 1962. מאז, תעשיית הלווינים הפכה להיות תעשייה של מיליארדי דולרים וזהו ההיבט היחידי (עד כה) של החלל החיצון שהפך להיות מאוד רווחי. עם הטכנולוגיה הקיימת היום, המרחק המינימלי שניתן לשים 2 לווינים אחד מהשני בלי הפרעות הוא 2 מעלות. ובהתחשב בכך שיש לכדור הארץ 360 מעלות, זה אומר שניתן לשים 180 לווינים בשמים בעת ובעונה אחת. - -אף על פי כן, כל משדר יכול להשתמש בכמה תדרים כדי להגדיל את רוחב הפס שלו. מכיוון שיש מספר מוגבל של לווינים שיכולים להיות בשמים בעת ובעונה אחת, כדי למנוע כאוס בנושא, הקצאת מיקומי מסלול ללווינים נעשית על ידי ה [ITU](http://en.wikipedia.org/wiki/International_Telecommunication_Union). תהליך ההקצאה הוא מאוד פוליטי, וארצות מתפתחות ואפילו כאלו שעדיין נמצאות ב"עידן האבן" דורשות הקצאה למסלול (כדי להציע אותו אח"כ למרבה במחיר), ואם זה לא מספיק גרוע, גם חברות תקשורת, טלוויזיה, ממשלות, וגופים צבאיים רוצים חתיכה מהעוגה. - -יש לציין כי לווינים לא נשארים לעד. הלווינים המודרנים די גדולים ושוקלים בסביבות 5,000 ק"ג, וצורכים כמה קילווואטים אחדים של כוח חשמלי המופק מהפנאלים הסולריים. ההשפעה של השמש, הירח, וכוח העבודה הפלנטרי נוטה להרחיק אותם מהמקום ומהאורנטצייה שהוקצאה להם, בשביל להשאיר אותם במקומם ישנו אפקט נגדי שמתבצע ע"י מנועי רקטות שמחוברים ללווין. הכיוונונים הקטנים האלו נקראים [station keeping](http://en.wikipedia.org/wiki/Orbital_station-keeping). אחרי שהמנועים לכיוונינים מתעייפים (אחרי בערך 10 שנים), הלווין מתחיל לנטות ואז יש לכבות אותו. לבסוף הלווין יוצא ממסלולו וחוזר לארץ, בעת החזרה הוא נשרף בכניסה לאטמוספריה (בפעמים נדירות מאוד הוא מתרסק לכדור הארץ). - -
    - Band Table -
    - -בנוסף, כמות הלווינים היא לא הבעיה היחידה, גם התדרים מהווים בעיה, מכיוון שלעיתים קרובות, תדרי ה Downlink מפריעים לתדרי המיקרו-גל. לכן ה ITU הקצה רצועות תדרים ספציפיות לשימוש לווינים. הראשיים מבינהם מופיעים באיור משמאל. - -הרצועה הראשונה שעוצבה לתקשורת מסחרית היה ה C, שני טווחי תדרים מוקצים בתוכה, אחד לתנועה יורדת והשני לתנועה עולה (ללווין) (2 טווחים דרושים כדי לאפשר לתנועה בשני הצדדים באותו הזמן). הערוצים האלו (1.5GHz ו 1.6GHz) כבר צפופים מפני שמפעילים משתמשים בהם לקישורי מיקרו-גל בין יבשתיים. הרצועות L ו S נוספו בשנת 2000 אחרי הסכמים בין לאומיים, אך גם הם עמוסים ואף צרים מבחינת רוחב פס. הרצועה הבאה הזמינה לתקשורת מסחרית היא Ku, הרצועה הזו היא (עוד) לא צפופה ובתדרים הגבוהים שלה, לווינים מסוגלים להיות במרחק של מעלה אחת בלבד אחד מהשני בלי להפריע לתקשורת. אך לרצועה זו קיימת בעיה אחרת: גשם. הגשם סופג ("בולע") את הטווחי המיקרו-גל הקצרים האלו בצורה טובה מידי. הרצועה האחרונה היא Ka, אך בשל עלויות הציוד הגבוהות היא אינה בשימוש נירחב במיוחד. יש לציין כי בנוסף לתדרים המסחריים האלו, קיימים עוד המון תדרים בשימושים של הממשלות והצבאות השונים. - -ללווין מודרני ישנם בסביבות 40 משדרים, ובהתחלה כל משדר היה פועל כצינור עצמאי (רוחב הפס הכולל היה מחולק לרצועות תדרים קטנות באופן קבוע). אך בשנים האחרונות כל קרן של משדר מחולקת לתאי זמן, כשכל משתמש לוקח בתורו תא (נרחיב בהמשך על הטכניקות האלו). - -
    - VASTs -
    - -אחד מהפיתוחים האחרונים בתחום תקשורת הלווינים היה ה'מיקרו תחנות' הזולות והקטנות שנקראות [VSAT](http://en.wikipedia.org/wiki/Very-small-aperture_terminal) (ראשי תיבות: Very Small Aperture Terminals). למסופים הקטנים האלו יש אנטנה בגודל (בערך) מטר אחד בלבד (לעומת 10 מטר ללוויני GEO סטנדרטים), קצב העלאה שלהם בדר"כ טוב עד 1Mbps, וההורדה עד כמה מגה ביטים לשניה. ברוב הפעמים למערכות ה VSAT אין מספיק כוח כדי לתקשר אחד עם השני ישירות (דרך הלווין), לכן ישנה תחנת קרקע מיוחדת הנקראת hub עם אנטנה גדולה שתפקידה להעביר את התנועה בין ה VSATים. (יש לציין כי טכניקה זו גורמת לעיכוב (delay) גדול יותר אך זה מתבצע תמורת תחנות קצה זולות יותר). - -לתקשורת לווינים יש כמה מאפיינים שונים מאוד מקישורית נקודה לנקודה יבשתית. נתחיל בכך שאף שהאות נע ללוווין ומהלווין במהירות האור (כמעט 300,000 קמ"ש/שניה) המרחק הרב בין תחנת הקצה ללווין גורם לעיכוב מורגש אצל לוויני GEO, באיזור ה270 מיילי שניות (וכ 540 מילי שניות ל VSAT המחובר ל hub). בעיה נוספת היא שקרן האור פוגעת באזור גדול, וכך השידור המתבצע מיועד לכל התחנות, כל התחנות יכולות לקלוט אותו (למרות שניתן לדמות שידור נקודה לנקודה, אך שידור זה יהיה יקר יותר). מצד אחד זהו יכול להיות יעיל, אך מצד שני, מנקודת הפרטיות, לווינים הם נוראיים: כל אחד יכול לשמוע הכל, ולכן הצפנה היא הכרחית לתקשורת מאובטחת. בנוסף, בשל הגובה הרב בו לווינים אלו נמצאים (36,000 ק"מ) הם משלימים הקפה של כדור הארץ רק כל 24 שעות, אך כדי לכסות את כל שטח כדור הארץ דרושים אך ורק 3 לווינים כאלו. - -  - -**MEO - לוויני המסלול האמצעי** - -לווינים אלו נמצאים בגובה הרבה יותר נמוך מלוויני GEO (כ-18,00 ק"מ), וממוקמים בין 2 חגורות ואן אלן. הם נעים באיטיות לאורך קו האורך ולוקח להם (בערך) 6 שעות להקיף את כדור הארץ (בגלל תנועתם בשמים יש לעקוב אחרי מיקומם). בנוסף, מפני שהם בגובה נמוך יותר, כל אחד מכסה שטח קטן יותר ודרושים 10 לווינים כאלו כדי לכסות את כל שטח כדור הארץ. אך מנגד, הם דורשים משדרים חלשים יותר (כי מרחק השידור קטן יותר). יש לציין כי לווינים אלו משמשים בעיקר לתקשורת GPS. - -  - -**LEO - לוויני מסלול נמוך** - -לווינים אלו נמצאים בגובה עוד יותר נמוך (כמה מאות ק"מ), ובשל גובה זה העיכוב הקיים מתחנת הקרקע ללווין הוא כמה מילי שניות אחדות. בנוסף, בשל גובהם הנמוך הם מכסים פחות שטח,וכתוצאה מכך נדרשים יותר לווינים כדי לכסות את כל כדור הארץ (כ-50), בנוסף,תחנות הקרקע דורשות משדרים קטנים אף יותר. - -בשלושים השנים הראשונות של עידן הלווין, הגובה הנ"ל של הלווינים היה כמעט ללא שימוש, מפני שבגובה הנמוך הלווינים יצאו מהטווח מהר מאוד. פרויקט מפורסם של לווינים בגובה זה הוא פרויקט ה[אירידיום](http://en.wikipedia.org/wiki/Iridium_Communications) שתוכנן ע"י מוטורולה בשנת 1990 והושק בנובמבר 1998. מוטורולה ביקשה מה FCC לשגר 77 לווינים (ועל כך שם הפרויקט). הרעיון היה לכסות את כל כדור הארץ בלווינים כך שברגע שלווין אחד יוצא מהטווח אחר נכנס להחליפו (על תחנות הקרקע לבצע מעברים, handoffs, מלווין אחד למשנהו כדי לשמור על רציפות התקשורת). - -
    - Iridium -
    - -לאחר 7 שנים השירות החל לעבוד, אך הדרישה לתקשורת טלפונית לווינית הייתה נמוכה בשל ההתפתחות והגידול של רשתות הטלפונים הנידיים. כתוצאה מכך אירידיום נכשלה והכריזה על פשיטת רגל באוגוסט 1999. הלווינים והנכסים של הפרויקט (ששוים 5 מיליארד דולר) נמכרו במכירה פומבית ב-25 מיליון דולר, והפרויקט יצא שוב לדרך במרץ 2001 ורק גדל מאז. השירות מספק שיחות קוליות, תעבורת מידע, שירות איתור, פקס, וניווט בכל מקום בעולם ביבשה, במים ובאוויר. הלווינים ממקומים בגובה של 750 ק"מ ובמרחק של 32 מעלות זה מזה. לכל לווין יש מקסימום 48 קרנים (לשידורים), וקיבולת של 3840 ערוצים (שכל אחד מהם אחראי על שירות אחר). מה שמעניין בפרויקט הזה הוא שהתקשורת בין שני אנשים מתבצעת בחלל (כמו שניתן לראות באיור a משמאל, בניגוד ל b שמתבצע בקרקע). - -  - -## 5. אפנון וריבוב דיגיטליים - -אחרי שעברנו על המאפיינים של ערוצי תקשורת קווית ואלחוטית, נפנה את תשומת ליבנו לבעיה של שליחת מידע דיגיטלי. ערוצי תקשורת קווית ואלחוטית נושאים אותות אנלוגיים, כמו מתח (המשתנה ברציפות), עוצמת אור, או עוצמת קול. כדי לשלוח מידע דיגיטלי,אנחנו צריכים למצוא דרך לייצג ביטים ע"י אותות אנלוגיים. תהליך ההפיכה בין ביטים לאותות מיוצג על ידי מושג שנקרא אפנון (ובאנגלית: [digital modulation](http://en.wikipedia.org/wiki/Modulation), ומכאן בא השם של המודם). - -בחלק זה נדבר גם על ריבוב. ערוצים חולקים הרבה פעמים כמה אותות, אחרי הכל זה הרבה יותר נוח להשתמש בחוט אחד כדי להעביר כמה אותות מאשר להתקין חוט לכל אות. החלוקה הזאת נקראת ריבוב (ובאנגלית: [multiplexing](http://en.wikipedia.org/wiki/Multiplexing)) וניתן להשיגה בכמה דרכים. - -  - -
    - Baseband -
    - -**תמסורת Baseband** -הדרך הכי ישירה לבצע אפנון דיגיטלי היא להשתמש במתח חיובי לייצוג 1 ומתח שלילי לייצוג 0. ולסיבים אופטיים 1 יהיה נוכחות של אור ו-0 הוא אי הנוכחות של האור. השיטה הזאת נקראת [NRZ](http://en.wikipedia.org/wiki/Non-return-to-zero). ברגע ששלחנו, האות NRZ מתפשט בקו, והצד המקבל הופך אותו חזרה לביטים ע"י לקיחת דגימות של האות במרווחי זמן קבועים (כמו שניתן לראות באיור משמאל ב-b). -האות לא יראה בדיוק כמו שנשלח, הוא יחלש וישובש על ידי הערוץ והרעש של המקבל. כדי לפענח אותו לביטים, הצד המקבל ממפה את הגל האנלוגי והופך אותו למה שהוא הכי קרוב (הכי קרוב למתח חיובי או למתח שלילי). NRZ מהווה בסיס מצוין, אך לא מבצעים בו שימוש רב במציאות, אלה רק לעיתים רחוקות. יש עוד שיטות מורכבות יותר שיכולות להפוך ביטים לאותות ועומדות בדרישות גבוהות יותר. - -  - -**יעילות רוחב הפס** -עם NRZ ניתן להשלים "סיבוב" של רמות חיוביות ושליליות במקסימום (הכי מהר) 2 ביטים (במקרה בינארי, 1 ו-0). זה אומר שאנחנו צריכים רוחב פס של לפחות B/2 כשקצב השידור שלנו הוא B ביטים/לשניה. היחס הזה מגיע מהמשוואה של נייקויסט. זהו חסם בסיסי, כך שאנחנו לא יכולים להריץ את השיטה NRZ מהר יותר בלי להשתמש ברוחב פס גדול יותר. אך פעמים רבות, רוחב פס הינו משאב מוגבל. גם בערוצים קווים, אותות בתדירות גבוהה נחלשים יותר ויותר, מה שהופך אותם לפחות שימושיים, ובנוסף הם דורשים אלקטרוניקה יותר מהירה. - -אסטרטגיה אחת לשימוש ברוחב פס מוגבל באופן יעיל יותר היא שימוש בשתי שכבות של אותות. על ידי שימוש ב-4 מתחים, לדוגמה, אנחנו יכולים לשלוח 2 ביטים בבת אחת כסימן/אות (ייצוג) אחד. עיצוב זה יעבוד כל עוד האות בצד המקבל חזק מספיק כדי להבדיל בין 4 הרמות. כעת, הקצב שבו האות משתנה הוא חצי מקצב השידור ולכן אנחנו צריכים פחות רוחב פס. - -לקצב בו האות משתנה קוראים [Symbol rate](http://en.wikipedia.org/wiki/Symbol_rate) (שימו לב להבדל מ bit rate). קצב הביטים הינו קצב האות כפול מספר הביטים לאות. symbol rate ידוע לפעמים גם כ [baud](http://en.wikipedia.org/wiki/Baud) rate (זהו שם ישן שהוחלף). - -  - -**התאוששות שעון** -לכל השיטות שהופכות ביטים לאותות, הצד המקבל חייב לדעת שכשאות אחד נגמר הבא אחריו מתחיל, בקיצור לתזמן את הפעילות, כדי לפענח נכון את הביטים. אך עם NRZ האותות האלו הם רמות מתח פשוטות, וכמות גדולה של אפסים (או אחדים) רצופים ניראים כאות אחד רצוף מפני שלא מבצעים שינוי לרמת המתח. לאחר כמה זמן יהיה קשה להבדיל בינהם, 15 אפסים יראו דומה מאוד ל-16 כאלו, אלה אם יש לנו [שעון מדויק](http://en.wikipedia.org/wiki/Clock_signal) מאוד. - -שעון מדויק אכן יפתור את הבעיה, אך הוא מייקר מאוד את הציוד ובפועל לא קיים בכרטיסי הרשת הביתיים והסטנדרטים, כרטיסי הרשת מיוצרים לרוב במזרח ואין הקפדה על איכות החומרים והגבישים, בשל הרצון לחסוך בעלויות החומרים (מה שמתגלגל אל צרכן הקצה בסופו של דבר ונראה בדמות מוצר זול במיוחד). - -אסטרטגיה אחת היא לשלוח באופן נפרד את זמן השעון של האות אל הצד המקבל, כך שיבוצע סנכרון בין כרטיס הרשת של הצד המקבל והשולח. אך זה יהיה בזבוז משאבים, הרי אם אנחנו יכולים לשלוח עוד אות באותו רוחב פס, למה שלא נשלח עליו עוד מידע?! - -טריק אחר הוא לערבב את השעון של האות עם האות של המידע ע"י ביצוע [XOR](http://en.wikipedia.org/wiki/Exclusive_or) שלהם ביחד (כך שאנו לא צריכים להשתמש בעוד שורה), במקרה הזה ברגע שאנחנו מבצעים XOR לרמה 0, מתבצע שינוי מרמה נמוכה לרמה גבוהה. וב-1 מתבצע שינוי מרמה גבוהה לרמה נמוכה. שיטה זו נקראת [קוד מנצ׳סטר](http://en.wikipedia.org/wiki/Manchester_code) וניתן לראותה באיור (למעלה משמאל) ב-d. היתרון שלה הוא שיש פחות טעויות בקריאת הביטים, אך החסרון הוא שנדרש רוחב פס כפול מאשר שנדרש ב NRZ כדי להעביר את אותו המידע (מכיוון שהפולסים הם בחצי מהרוחב). - -אסטרטגיה אחרת (בה נעשה שימוש בתקן הפופולרי USB) מבוססת על הרעיון שאנחנו צריכים לקודד את המידע בצורה כזו שנבטיח שיש מספיק מעברים באות. ז"א שאם המעברים יהיו בזמן הדגימה (ולא בין דגימה לדגימה) יהיה קל יותר להישאר מסונכרנים. צעד בדרך זו מתבצע בשיטה [NRZI](http://en.wikipedia.org/wiki/Non-return-to-zero#Non-Return-to-Zero_Inverted_.28NRZI.29), בה קידוד של 1 הוא שינוי וקידוד של 0 הוא ללא שינוי (לא מדובר על בין רמות המתח, אלה רק השינוי ברמות המתח כשלא משנה איזה שינוי (לאיזה כיוון) העיקר שיהיה שינוי כשנקודד 1), שיטה זו מופיע באיור (למעלה משמאל) ב-c. - -עכשיו, כשאנו מקודדים 1 יש שינוי של המתח ואנחנו נשארים מסונכרנים בצורה עקיפה, גם אם יש רצף של 1ים. אך כשנקבל רצף של 0ים, אנחנו עדיין יכולים לאבד את הסנכרון, כי ברצף של 0 לא מתבצע שינוי והמתח נשאר כשהיה לאורך כל הרצף. קווי טלפון דיגיטליים ישנים בארה"ב, הנקראו T1, דרשו שלא יישלחו יותר מ-15 אפסים רצוף כדי שיוכלו לעבוד בצורה תקינה, אז כדי באמת לתקן את הבעיה אנחנו יכולים לפרק את רצף ה0ים ולמפות אותם לקבוצות קטנות של ביטים כך שלא יהיו המון 0ים רצופים. - -
    - 4B-5B -
    - -הקוד המוכר שמבצע את העובדה הזו נקרא [4B/5B](http://en.wikipedia.org/wiki/4B5B). וכל 4 ביטים ממופים לתבנית של 5 ביטים, כשקיימת טבלת תרגום קבועה. השיטה של 5 ביטים נבחרה כדי שלא יהיה רצף של יותר משלושה אפסים רצופים. ובטבלה משמאל אנו רואים את רצף כל האפשרויות שיכול להיות במיפוי זה. מכיוון שאנו מוסיפים עוד ביט לכל 4 ביטים, אנחנו מוסיפים עוד 25% ביטים, אך זה יותר טוב מהוספה של עוד 100% ביטים שהיינו מוסיפים בקוד מנצסטר. - -  - -**אותות מאוזנים** -אותות שיש להם מתח חיובי ושלילי באותה רמה, בזמנים קצרים, נקראים אותו מאוזנים. -האיזון עוזר לספק מעברים להתאוששות שעון, מכיוון שיש ערבוב של מתח שלילי וחיובי. בנוסף הוא מספק דרך פשוטה לפענח את האות ששידרו אלינו, כי האות הממוצע ניתן למדידה, כך שגם אם היה עיוות בדרך, כל עוד העיוות קטן יחסית אנחנו יכולים לראות לאן הממוצע נוטה. - -דרך ישירה ופשוטה לבנות קוד מאוזן היא להשתמש ב-2 רמות מתחים לייצוג 1 (לדוגמה 1v+ ו 1v-) ו 0v כדי לייצג 0. כדי לשלוח 1, המשדר שולח לסירוגין 1v+ ו 1v- כך שהם יצאו בממוצע. דרך זאת נקראת (קידוד דו קוטבי)[http://en.wikipedia.org/wiki/Bipolar_encoding] וניתן לראות אותו באיור (שמאל למעלה) ב-e. - -  - -**תמסורת Passband** -לפעמים, נרצה תחום תדרים שלא מתחיל ב-0 כדי לשלוח מידע בערוץ (לדוגמה, לערוצים אלחוטיים זה לא פרקטי לשלוח אות בתדר נמוך מאוד בגלל גודל האנטנה. וגם בתקשורת קווית, לשלוח אות בתחום תדר מסויים זה מועיל כדי לאפשר לכמה סוגי אותות להישלח במקביל). אך אילוצי רגולציה והצורך למנוע הפרעות מכתיבים, בדרך כלל, את הבחירה של התדרים. הסוג הזה של התמסורת, שבו תחום שרירותי של תדרים משמש להעביר את האות נקרא passband. - -הערך האבסולוטי של התדר אינו חשוב לקיבולת שלו. זה אומר שאנחנו יכולים להסיט אות בשידור baseband (ראו את טבלת התדרים בסעיף 4) שעובד בתדר 0 עד B הרץ, למעלה כך שבשידור passband הוא יעבוד בתדר S עד S+B הרץ, מבלי לשנות את כמות המידע שהוא יכול לשאת, אפילו אם האות יראה שונה. בצד המקבל אנחנו מסיטים את התדר בחזרה למטה (ל baseband), היכן שיותר נוח לגלות את האותות. - -
    - Passband -
    - -אפנון מודרני מתבצע באמצעות ויסות או אפנון של האות שיושב ב passband, אנחנו יכולים [לאפנן](http://en.wikipedia.org/wiki/Modulation) את ה[אמפליטודה (משרעת)](http://en.wikipedia.org/wiki/Amplitude_modulation), את ה[תדר](http://en.wikipedia.org/wiki/Frequency_modulation), או את ה[מופע (פאזה)](http://en.wikipedia.org/wiki/Phase_modulation) של האות. - - * **ASK (ראשי תיבות: Amplitude Shift Keting) -** שני אפמפליטודות (או יותר) משמשות לייצוג של 0 ו-1. דוגמה לכך נמצאת באיור משמאל, ב-b. כשהאמפליטודה של הגל משתנה ב-0 ונשארת ב-1. - * **FSK (ראשי תיבות: Frequency Shift Keying) -** משתמשים בשתי (או יותר) טונים. דוגמה לכך נמצאת באיור משמאל, ב-c. - * **PSK (ראשי תיבות: Phase Shift Keying) -** הגל אינו משתנה ב-0, וכדי לייצג אחד מציג את ההפוך של עצמו (180 מעלות). דוגמה לכך נמצאת באיור משמאל, ב-d. - -בנוסף, ניתן לשלב בין סוגי האיפנונים וכך לשדר יותר ביטים לאות. אך רק פאזה או תדר יכולים להיות משולבים באותו הזמן, מכיוון שהם קשורים זה לזה, כשהתדר הוא קצב השינוי של הפאזה לאורך זמן. - -
    - Constellation Diagram -
    - -בדרך כלל, אפנון אמפליטודה ופאזה משולבים ביחד. באיור משמאל ניתן לראות 3 דוגמאות לשילוב של פאזה ואמפליטודה. בדוגמאות משמאל אנחנו רואים 3 דיאגרמות, הדיאגרמות האלו נקראות [תרשים קונסטלציה](http://en.wikipedia.org/wiki/Constellation_diagram). ב-a (שהיא דיאגרמת ייצוג ל[QPSK](http://en.wikipedia.org/wiki/Phase-shift_keying#Quadrature_phase-shift_keying_.28QPSK.29)) אנחנו רואים נקודות במרחק שווה אחת מהשניה ב-45, 135, 225 ו-315 מעלות. את הפאזה של הנקודה מודדים על ידי הזווית של הקו מראשית הצירים לנקודה, לפי הכיוון החיובי של ציר ה x. ואת האמפליטודה של הנקודה מודדים לפי המרחק של הנקודה מראשית הצירים. ב-b אנחנו רואים קונסטלציה צפופה יותר. כאן יש 16 שילובים של אמפליטודה ופאזה, כך שסכמת האפנון יכולה לשדר 4 ביטים לאות. תרשים הקונסטלציה הזה נקרא [QAM-16](http://en.wikipedia.org/wiki/Quadrature_amplitude_modulation) (ראשי תיבות: Quadrature Amplitude Modulation). ב-c רואים קונסטלציה הנקראת QAM-64, בעלת 64 שילובים של אמפליטודות ופאזות, כך שכל אות יכול להעביר 6 ביטים. - -תרשימי הקונסטלציה שראינו עד כה מאפשרים בנייה קלה יותר של מכשירים שישדרו אותות כשילובים של ערכים של כל ציר, מאשר שילוב של ערכים של פאזה ואפליטודה. אך אף אחת מהקונסטלציות שראינו עד כה לא מראה כיצד ביטים מוקצים לאותות. כשמבצעים את ההקצאה, ישנה חשיבות שהתפרצות רעש קטנה בצד המקבל לא תגרום ליותר מידי שגיאות ביטים. זה יכול לקרות אם נקצה ערכי ביטים רצופים לאותות סמוכים. - -ב QAM-16, לדוגמה, אם אות אחד מייצג 0111 והאות השכן מייצג 1000, אם בצד המקבל ישנה שגיאה והוא בטעות מרים את האות השכן זה יגרום לכל הביטים להיות שגויים. פתרון טוב יותר הוא למפות ביטים לאותות, כך שאותות שכנים יבדלו רק במיקום של ביט אחד. המיפוי הזה נקרא [קוד גריי (אפור)](http://en.wikipedia.org/wiki/Gray_code)) (נרחיב עליו בהמשך). עכשיו, אם הצד המקבל יפענח את האות בטעות, תיהיה טעות רק בביט אחד (כמובן במקרה הצפוי בו הצד המקבל פיענח אות שקרוב לאות הנשלח). - -  - -**ריבוב בחלוקת תדר** -[ריבוב בחלוקת תדר](http://en.wikipedia.org/wiki/Frequency-division_multiplexing) (או Frequency Division Multiplexing) מנצל את תמסורת ה passband כדי לחלוק את הערוץ. הוא מחלק את הספקטרום (קשת התדרים) לרצועות תדרים, כשלכל משתמש יש רשות בלעדית על רצועה כדי לשלוח את האות שלו. תדרי רדיו AM מדגימים שימוש בריבוב בחלוקה זו. הספקטרום המוקצה הוא באזור ה 1MHz (בערך 500 עד 1500kHz). התדרים השונים מוקצים לערוצים לוגים שונים (תחנות), כל פעולה יושבת על חלק מהספקטרום, כשיש להשאיר רווח בערוץ הפנימי (בתוך הערוץ, בין התדרים) גדול מספיק כדי למנוע הפרעות. - -
    - Frequency Division Multiplexing -
    - -כמו שניתן לראות בתמונה משמאל, אנחנו רואים ערוץ טלפון (קולי) שעליו מבוצע FDM (ריבוב בחלוקת תדר) ל-3 ערוצים שונים. פילטרים שונים מגבילים את הרוחב פס לבערך 3100Hz לכל רמת ערוץ קול. כשכל הערוצים מתחברים יחדיו לערוץ אחד, לכל ערוץ מוקצב רוחב פס של 4000Hz. העודף הזה (900Hz) נקרא [guard band](http://en.wikipedia.org/wiki/Guard_band), והוא נועד לשמור על הערוצים מופרדים היטב. - -קודם כל מעלים כל ערוץ בתדר מסויים, כל אחד בסכום אחר. לאחר מכן ניתן לשלב אותם יחדיו מכיוון שאין 2 ערוצים שתופסים את אותו החלק בספקטרום. בנוסף, שימו לב כי למרות שיש רווחים בין הערוצים (תודות ל guard band), ישנה חפיפה מסויימת בין ערוצים שכנים. החפיפה קיימת מכיוון שלמסננים (פילטרים) אמיתיים אין קצוות חדים אידיאליים, זה אומר שעליה פתאומית בקצה של ערוץ אחד תיהיה מורגשת בערוץ הסמוך לו כרעש לא תרמי (ההפך מ[רעש תרמי, או רעש נייקוויסט](http://en.wikipedia.org/wiki/Johnson%E2%80%93Nyquist_noise)). - -בתמונה למעלה משמאל, רואים ב a את רוחב הפס המקורי, לאחר מכן ב b את רוחב הפס מועלה בתדר, וב c את הערוץ המרובב (הסופי). בריבוב זה נעשה שימוש בתעשיית הטלפוניה (כדי לרבב מספר שיחות על אותו התדר) במשך הרבה שנים, אך היום ריבוב בחלוקת זמן הוא המועדף (למרות זאת, FDM נמצא עדיין בשימוש גבוה בתקשורת הטלפוניה, הסלולרית, והלווינית). - -
    - Orthogonal Frequency-division Multiplexing -
    - -כששולחים מידע דיגיטלי, ניתן לחלק את הספקטרום ביעילות מבלי להשתמש במגני פס (guard bands) ובכך לא לבזבז רוחב פס יקר, וזה בדיוק מה ש OFDM (ראשי תיבות: [Orthogonal Frequency Division Multiplexing](http://en.wikipedia.org/wiki/Orthogonal_frequency-division_multiplexing)) עושה. רוחב הפס של הערוץ מחולק להמון תתי מובילים שבאופן עצמאי שולחים מידע. התתי מובילים האלו ארוזים ביחד על תחום תדר (כלשהו). כך שהאותות מכל מוביל מתפשטים לסמוכים אליהם. אך כמו שניתן לראות באיור משמאל, תגובת התדר של כל מוביל מתוכננת להיות שווה לאפס במרכז של התתי מובילים הסמוכים אליו. לכן, ניתן לדגום את התתי מובילים במרכז התדר שלהם בלי רעש משכניהם. כדי שזה יעבוד, אנחנו צריכים משתנה זמן כלשהו, שיחזור על עצמו כל חלק זמן קבוע של סמל האות, כך שיהיה להם את תגובת התדר הרצויה. למרות זאת, [התקורה](http://he.wikipedia.org/wiki/%D7%94%D7%95%D7%A6%D7%90%D7%95%D7%AA_%D7%AA%D7%A7%D7%95%D7%A8%D7%94) היא הרבה פחות משנחוצה להרבה מגני פס (guards bands). - -הרעיון של OFDM קיים כבר זמן רב, אך רק בעשור האחרון הוא אומץ בצורה רחבה, בעקבות ההבנה שאפשר להטמיע OFDM ביעילות (במונחי פירוק פורייה של מידע דיגיטלי) על כל התתי מובילים (במקום לבצע אפנון נפרד של כל תת מוביל). בדרך כלל, זרם אחד בשיעור גבוה של מידע דיגיטלי מחולק להרבה תת זרמים בשיעורים נמוכים שמשודרים על כמה תתי מובילים במקביל. החלוקה הזו היא יקרת ערך, מכיוון שבנפילה של ערוץ קל יותר להתמודד ברמה של תת מוביל. - -  - -**ריבוב בחלוקת זמן** - -
    - Time Divistion Multiplexing -
    - -אלטרנטיבה לריבוב בחלוקת תדר, היא ריבוב בחלוקת זמן - TDM (ראשי תיבות: Time Division Multiplexing). ב TDM המשתמשים משדרים בתורות (במבנה סיבובי) כשכל אחד, בתורו, עושה שימוש בכל רוחב הפס לפרץ זמן קצר וקבוע. ניתן לראות משמאל דוגמה ל-3 משתמשים שמשדרים בשיטה זו. - -ביטים מכל משתמש נלקחים בזמן קבוע ומשודרים אל היעד. כדי שהשיטה תעבוד, על כל המשתמשים להיות מסונכרנים, וכדי להשיג את זה מבצעים שימוש ב [guard time](http://en.wikipedia.org/wiki/Guard_interval) (שומרי מרווח) אנלוגיים. - -  - -**ריבוב בחלוקת קוד** - -CDM (ראשי תיבות: Code Division Multiplexing) עובד בצורה שונה לגמרי מ FDM או TDM. הוא צורה של תקשורת ספקטרום מתפשטת, בה אות בעל רצועה (/פס) צרה מתפשט החוצה על גבי תדר ברצועה רחבה יותר. כך הוא יותר "סובלני" להפרעות ורעשים, וגם מאפשר לכמה אותות (מכמה משתמשים) לחלוק את אותה רצועת התדר. מפני שריבוב הזה ידוע יותר בשל האפשרות של כמה משתמשים לחלוק את אותה רצועה הוא ידוע יותר בשם CDMA (ראשי תיבות: Code Division Multiple Access). - -CDMA מאפשר לכל תחנה לשדר על כל הספקטרום של התדר כל הזמן, כשהתשדורות מופרדות באמצעות קוד. לפני שניגש לאלגוריתם, להלן אנלוגיה שתסביר יותר טוב את ההבדלים בין הריבובים: נניח שאנו בשדה תעופה מול הדלפק כדי לדבר עם אחד העובדים, TDM זהו בעצם 2 אנשים (לדוגמה) שמדברים עם העובד בתורות. FDM זה 2 אנשים שמדברים ביחד, אך אחד בקול גבוה והשני בקול נמוך, כך שאנחנו עדיין יכולים להבחין איזה קול מגיע מאיזה אדם. ב CDMA, שוב, 2 האנשים מדברים ביחד אך כל אדם מדבר בשפה שונה, אחד אנגלית ואחד צרפתית (לדוגמה), כך שאנחנו עדיין יכולים להבחין עם מי אנחנו מדברים, ואם אני מדבר עם האדם הצרפתי אני מחשיב כרעש כל דבר שאינו צרפתית. - -ב CDMA, כל ביט מחולק ל m פרקי זמן קצרים הנקראים chips. בדרך כלל יש כ-64 או 128 chipים לכל ביט, אך לפישוט ההסבר נשתמש בדוגמה שלנו ב-8 chipים לביט. לכל תחנה מוקצה קוד יחודי בן m ביטים שנקרא רצף chipים. לנוחות ההסבר אנו מסמנים בסימון דו קוטבי את הקודים כרצף של 1- ו 1+ ונראה את רצף הchipים בסוגריים. - -אז כדי לשלוח 1, התחנה צריכה לשלוח את הרצף chipים שלה, וכדי לשלוח 0 היא צריכה לשלוח את ההופכי מהרצף. אלה הן התבניות היחידות הניתנות לשליחה. דוגמה: אם לתחנה A מוקצה רצף הchip הבא (1+, 1+, 1-, 1-, 1+, 1+, 1-, 1-, 1-), אז כדי לשלוח 1 אנו שולחים את הרצף הנל, וכדי לשלוח 0 נשלח את הרצף (1-, 1-, 1+, 1-, 1-, 1+, 1+, 1+) . האמת היא שאותות עם רמות הזרמים האלה נשלחים, אך אנחנו חושבים במונחים של רצף (ניתן לראות את רמות הזרמים ב (b) להבדיל מ (a). - -
    - Walsh Codes -
    - -בתמונה לעיל, בסעיף (a), אנו רואים 4 תחנות כשלכל אחת יש קוד בינרי,[אורתוגונלי](http://en.wikipedia.org/wiki/Orthogonality) (הכוונה שחיבור כל האיברים במיקומים הזהים, של 2 תחנות, יתן 0) משלה (בשביל ליצר קוד רצף אורותוגונלי שכזה משתמשים ב [Walsh codes](http://en.wikipedia.org/wiki/Hadamard_code)), (בשביל 4 תחנות לא היינו צריכים m=8 כדי לתת קוד יחודיי לכל תחנה, אך מפני שהתחלנו עם אורך הרצף הנל נמשיך איתו). תוכנת האורתוגונליות תיווכח כקריטית מאוחר יותר. שימו לב שכל S\*S שווה ל-1 (S זהוי תחנה כלשהי). וכל S\*s שווה ל-1- (נהוג לסמן S עם קו מעליו וזהו ההפוכי של S, אך בגלל שאין סימן כזה במקלדת כתבתי s קטנה). כמו כן S\*T שווה ל-0 (T זהוי גם תחנה כלשהי אך שונה מ S).וגם עם ההופכי של T, שזה S\*t שווה ל-0. - -בכל זמן, תחנה יכולה לשדר 1 (ע"י שידור של רצף הקוד האותוגונלי שלה) או 0 (ע"י שידור ההופכי של הקוד) או לא לשדר כלום. ונניח כרגע כי כל התחנות מסונכרנות כך שכל הקודים (רצף chipים) מתחילים באותו הרגע. כשכמה תחנות משדרות בו זמנית הרצפים מתאחדים לינארית, לדוגמה אם 3 תחנות משדרות 1+ ותחנה רביעית משדרת 1-, אנחנו נקבל 2+. לכן ב (c) אנחנו רואים 6 דוגמאות לתחנה אחת או יותר המשדרות רצף של 1 (ז"א כל אחת את הקוד האותוגונלי שלה). בדוגמה S1 אנחנו רואים רק את C משדרת, ובדוגמה S2 אנחנו רואים את B ואת C משדרות ביחד, לכן ב S2 אנחנו מקבלים חיבור של האיברים (לדוגמה האיבר הראשון יוצא 2- מכיוון שהאיבר הראשון של B הוא 1- וגם של C הוא 1-). - -כדי לפענח את הזרם הנשלח מכל תחנה, הצד המקבל צריך לדעת מראש את הקוד של התחנה. והוא מבצע את הפענוח ע"י חישוב הזרם שקיבל כפול התחנה שאליה הוא מעוניין להקשיב חלקי m. אם ניקח את הדוגמה הרביעית, תחנה A שידרה 1, תחנה B שידרה 0, תחנה C שידרה 1, ותחנה D לא שידרה כלל. אם נרצה להקשיב לתחנה C, נכפיל את הקוד שקיבלנו בקוד של C (כמו בדוגמה S4*C שנמצאת בסעיף (d) בתמונה למעלה), נחלק ב m (שבמקרה הנל הוא 8) ונקבל 1 שזה מה ש C שידרה. - -* יש לזכור ש 1+ מסמן ביט 1, 1- מסמן את הביט 0, ו-0 מסמן חוסר שידור, לכן כשאנו מקשיבים ל C בדוגמה S3 יוצא לנו 0 (כי הוא לא שידר כלל). - -במציאות, במערכת CDMA ללא רעש (כמו שלמדנו כאן) מספר התחנות שיכולות לשדר במקביל הוא די גדול, ע"י שימוש ברצפי קוד ארוכים יותר. בשביל 2 בחזקת n תחנות Walsh code יכול לספק 2 בחזקת n רצפי קוד אורתוגונלים באורך 2 בחזקת n. אך ההגבלה מתבצעת ע"י הסנכרון, הסנכרון המדויק שחישבנו אצל המקבל, בדוגמה לעיל הוא אפילו לא קרוב להיות מציאותי במקרים מסויימים (כמו ברשתות סלולר, בהם CDMA אומץ ונפרס כבר משנות ה-90). אי הסנכרון הנ"ל מביא להחלטות אחרות, ואנחנו נחזור לכאן בהמשך. - -  - -### 6. רשת הטלפוניה הציבורית - -כשרוצים לחבר 2 מחשבים, הדרך הקלה ביותר היא למתוח כבל בינהם, וזאת הדרך בה רשתות LAN עובדות. אך כשהמרחק גדול, או כשיש הרבה מחשבים, או כשהכבל צריך לעבור דרך אזור ציבורי, העלויות של העברת כבל פרטי, לרוב, אינן כדאיות. יתר על כן, כמעט בכל מדינה בעולם, העברת קווי הולכה פרטיים באזור (או מתחת לאזור) ציבורי אסורה על פי חוק. מה שמצריך ממתכנני הרשת לבצע שימוש במתקני תקשורת קיימים. - -המתקנים האלו, במיוחד PSTN (ראשי תיבות: [Public Switched Telephone Network](http://en.wikipedia.org/wiki/Public_switched_telephone_network)) תוכננו, לרוב, לפני שנים רבות, למטרה שונה לגמרי (שידור קול אנושי בצורה שתאפשר זיהוי של הצד השני). וכדי שנראה את גודל הבעיה, קחו בחשבון שהכבל הנצרך יכול להעביר מידע בין 2 מחשבים במהירות של 1Gbps או יותר (ראינו בסעיף 2 – תמסורות), בעוד ADSL טיפוסי (שהוא החלופה המהירה למודם טלפוני) מציע מהירות באזור של 1Mbps. - -אך למרות כל זה, מערכת הטלפוניה מקושרת היטב עם תקשורת המחשבים. לרוב, מסיבות של עלויות, הלקוחות היו מחוברים לספקיות ע"י רשת הטלפוניה, במיוחד, בק"מ האחרון. כל זה משתנה לאחרונה ע"י הכניסה המסיבית של טכנולוגיית הפייבר, אך זה לוקח זמן וכסף, ולכן עדיין בק"מ האחרון יש המון לקוחות שמחוברים ע"י רשת הטלפוניה. - -  - -**מבנה הרשת** - -
    - PSTN structure -
    - -כבר בשנת 1876, כשאלכסנדר גרהם בל רשם פטנט על הטלפון, הייתה דרישה גדולה להמצאה החדשה. השוק הראשוני היה של טלפונים, אנשים קנו טלפונים (נייחים, ביתיים) והמכשירים הגיעו בזוגות. והיה על הלקוח לחברם עם חוט יחיד בינהם. אם בעל טלפון רצה לדבר עם n בעלי טלפונים אחרים, היה עליו למתוח חוטים נפרדים לכל n הבתים. תוך שנה ערים שלמות היו מכוסות בחוטים שנמתחו על גגות הבתים והעצים, מכל טלפון לכל טלפון אחר, כמו שניתן לראות באיור משמאל ב (a). - -להגנתו, בל ראה את הבעיה מוקדם והקים את חברת Bell Telephone Company, שפתחה את משרד המיתוג הראשון ב-1878 (ב [New Haven, Connecticut](https://www.google.co.il/maps/place/New+Haven,+CT,+USA/data=!4m2!3m1!1s0x89e7d8443a8070e5:0xf6a354c659b264ed?sa=X&ei=sPjPVMXABIXPaMnigNgC&sqi=2&ved=0CKkBEPIBMBI)). כמו באיור משמאל, ב (b), החברה הריצה חוט מכל בית או משרד של לקוח אליה. על הטלפון היה גל ארכובה, וכשהלקוח רצה להתקשר, הוא היה מרים את השפורפרת ומזיז את גל הארכובה כדי ליצור צלצול בחברת המיתוג ולמשוך את צומת הלב של המפעיל, שאז היה מחבר את הלקוח אל מי שרצה להתקשר, באמצעות מגשר. - -במהרה, השיטה של משרד המיתוג של בל התפשטה והלקוחות רצו לבצע שיחות למרחק גדול, בין ערים. ולכן בל התחיל לחבר את המשרדים, והבעיה ההתחלתית חזרה על עצמה (חיבור של כל משרד מיתוג עם כל משרד מיתוג). לכן הומצא משרד מיתוג ברמה שניה ובמהרה היה צורך לחבר את משרדי המיתוג ברמה השניה (כמו שניתן לראות בתמונה משמאל למעלה ב (c)). עד שלבסוף ההיררכיה גדלה עד ל-5 רמות משרדים. - -עד 1890 שלושת המרכיבים העקריים היו קיימים: משרדי המיתוג, החוטים בין הלקוחות ומשרדי המיתוג (שעד עכשיו התפתחו לחוטים שזורים, בעלי בידוד, עם רגל לאדמה), וחיבור ארוך טווח בין משרדי המיתוג. למרות שהיו פיתוחים בשלושת המרכיבים האלו, השיטה של בל נשארה פחות או יותר דומה במשך 100 שנה (התיאור הבא מופשט מאוד, אך מסביר היטב ומעביר את רוח הדברים). - -לכל טלפון יש חוטי נחושת שיוצאים ממנו והולכים עד למשרד הקצה של חברת הטלפון (היום, אלה קופסאות הטלפון בשכונה שלכם), משרד הקצה הזה נקרא מרכזייה, המרחק בינהם הוא בדרך כלל בין 1-10 ק"מ. בארה"ב לבד ישנם, בערך, 22,000 משרדי קצה. החוטים האלו ידועים בשם לולאה מקומית (local loop) והם חוטים שזורים (תקשורת אנלוגית). - -אם מנוי המחובר למרכזייה כלשהי מתקשר אל מנויי המחובר לאותה מרכזייה, מנגון המיתוג במרכזייה מקים חיבור אלקטרוני ישיר בין שני ה local loops. החיבור הזה נשאר פעיל כל זמן השיחה. מנגד, אם מנוי המחובר למרכזייה A מעוניין להתקשר למנוי המחובר למרכזייה B, מבצעים שימוש בפרוצדורה אחרת. לכל מרכזייה יש כמות קווים יוצאים אל מרכזיית מיתוג (או כמה) אחרים באזור, המרכזיות האלו נקראות toll office. הקווים היוצאים מהמרכזייה אל מרכזיית המיתוג נקראים [toll connecting trunks](http://en.wikipedia.org/wiki/Toll_switching_trunk) (ואלה סיבים אופטיים), אם למנויים יש מרכזיית מיתוג משותפת, המיתוג יקרה כאן. באיור למעלה מצד שמאל, ניתן לראות את שלושת המרכיבים האלו (הנקודות העגולות השחורות הקטנות הן הטלפונים, המרכזיות הן הנקודות העגולות השחורות הגדולות יותר, והמרכזיית מיתוג זה הריבועים). לבסוף, אם למנויים אין מרכזיית מיתוג משותפת, יוקם חיבור בין מרכזיות המיתוג. מרכזיות המיתוג מתקשרות בעזרת [interoffice trunks](http://encyclopedia2.thefreedictionary.com/interoffice+trunk) (סיבים אופטים בעלי רוחב פס גבוה במיוחד). -להלן מבנה הרשת: - -
    - Local Loops -
    - -  - -**לולאה מקומית: מודם, ADSL, פייבר** -נתחיל בחלק שרוב האנשים מכירים: שני חוטי הלולאה המקומית, המגיעים מהמרכזייה של חברת הטלפון אל הבתים. לרוב, מתייחסים אל הלולאה המקומית כ'ק"מ האחרון' (למרות שהאורך שלה יכול כמה קילומטרים) והיא נושאת אות אנלוגי. - -הרבה מאמץ מוקדש לדחיסת מידע על חוטי הנחושת של הלולאה המקומית הפרוסים כבר (מודמים שולחים מידע דיגיטלי בין המחשבים על הערוצים הצרים של תקשורת הטלפוניה, שבכלל תוכננו לספק שידור שיחות קוליות). גם המודם וגם ADSL מתעסקים בהגבלות של הרשת (הלולאה המקומית) הישנה (רוחב פס צר, הנחתה ועיוות אותות, ורגישות לרעש אלקטרוני כמו התנגשות שידור). - -  - -**מודם טלפון** - -
    - Modem -
    - -כדי לשלוח ביטים ברשת לולאה מקומית (או כל ערוץ פיזי אחר) חייבים להמירם לאותות אנלוגים שיכולים להישלח על גבי הערוץ. ההמרה הזו מושגת באמצעות שיטות האפנון (מודולציה) עליהם דיברנו בסעיף 5 (אפנון וריבוב דיגיטליים). בקצה השני האות האנלוגי מומר חזרה לביטים. המכשיר שמבצע את פעולת האפנון נקרא מודם (modem) - קיצור של [modulator demodulator](http://en.wikipedia.org/wiki/Modem). קיימים המון סוגים של מודמים: מודם טלפון, מודם DSL, מודם קווי, מודם אלחוטי וכ'ו. המודם גם יכול להיות בנוי כחלק מהמחשב (מה שנפוץ היום במודם טלפוני) או כקופסה נפרדת (שנפוץ במודם DSL וקווי). המודם ממוקם בין המחשב (דיגטלי) למערכת הטלפון (אנלוגי) כמו שניתן לראות באיוור משמאל. - -מודם טלפוני משמש כדי לשלוח ביטים בין 2 מחשבים על גבי קו טלפוני ברמת קול, במקום שיחות קוליות שבדרך כלל עוברות על הקווים. הקושי העיקרי הוא השליחה על קו הטלפון, שכן קו טלפון מוגבל ל 3100Hz, רוחב הפס הזה הוא 1/4 מרוחב הפס שימש לתקשורת Ethernet או ל-802.11 (wifi). בואו נעשה את החשבון, לפי נייקוויסט גם בקו מושלם (ללא רעשים כלל, מה שקו טלפון בהחלט לא) של 3000Hz, אין טעם לשלוח סמלים בקצב גדול יותר מאשר 6000 באוד. במציאות, רוב המודמים שולחים בקצב של 2400 סמלים/שניה, או 2400 באוד. ומתמקדים בשליחת כמה ביטים לסמל תוך כדי כך שהם מאפשרים תנועה לשני הכיוונים באותו הזמן (ע"י שימוש בתדרים שונים לכיוונים השונים). - -מודם של 2400bps משתמש במתח 0 וולט כדי לשלוח 0 לוגי ומתח של 1 וולט כדי לשלוח 1 לוגי, עם ביט 1 לסמל. אם נעלה רמה אחת למעלה, המודם יכול לשלוח 4 סמלים שונים (כמו 4 הפאזות המאופנות בשיטת QPSK שהצגנו כבר), כך שאם 2 ביטים/סמל אנחנו יכולים להשיג קצב נתונים של 4800bps. קצב נתונים גבוה יותר יכול להיות מושג ע"י קונסטלציה גדולה יותר. אך ככל שיש יותר סמלים, אפילו כמות קטנה של רעש יכולה לגרום לתוצאה של טעות. כדי להוריד את הסיכוי לטעות, ישנם סטנדרטים לתיקון וגילוי טעויות אותם נכיר בהמשך. - -סטנדרט ה-[v.32](http://en.wikipedia.org/wiki/List_of_ITU-T_V-series_recommendations) משתמש בקונסטלציה של 32 נקודות כדי לשדר 4 ביטים של מידע ועוד ביט אחד לבדיקה, סה"כ 5 ביטים לסמל ב-2400 באוד, כדי להשיג 9,600bps. הצעד הבא הוא 14,400bps ונקרא [v.32bis](http://en.wikipedia.org/wiki/List_of_ITU-T_V-series_recommendations). הוא משדר 6 ביטים של מידע ועוד ביט אחד לבדיקה, סה"כ 7 ביטים לסמל ב-2400 באוד. אחריו מגיע ה-[v.34](http://en.wikipedia.org/wiki/List_of_ITU-T_V-series_recommendations) שמשיג 28,800bps ומשדר סה"כ 12 ביטים לסמל ב-2400 באוד (כאן, לקונסטולציה יש אלפי נקודות). ואחרון בסדרה הוא ה-[v.34bis](http://en.wikipedia.org/wiki/List_of_ITU-T_V-series_recommendations) שמשדר סה"כ 14 ביטים לסמל ב-2400 באוד ומשיג 33,600bps. - -אז למה אנחנו עוצרים כאן? הסיבה שמודם סטנדרטי עוצר ב 33,600bps היא שלפי חסם שנון, הגבולות של מערכת הטלפוניה הם ב 35kbps (בהתחשב באורך ה local loops ואיכות הקווים). אך יש דרך לשנות את הסיטואציה הזו. במרכזיות, האות האנלוגי מומר חזרה לצורת שידור דיגיטלית שממשיכה בתוך רשת הטלפוניה. והגבלת ה 35kbps היא לסיטואציה שבה יש 2 local loops, אחד בכל קצה. כל אחד מהם מוסיף רעש לאות. אם נוכל להיפטר מאחד מהם, נוכל להגביר את ה SNR (יחס אות/רעש) והקצב המקסימלי יהיה כפול! - -השיטה שלעיל, היא השיטה שאיפשרה את מודמים ה 56kbps. צד אחד,לרוב ה ISP (ראשי תיבות: ספק שירותי אינטרנט) מקבל מידע דיגיטלי באיכות גבוהה מהמרכזייה הקרובה. זה קורה כאשר צד אחד של החיבור הוא בעל אות באיכות גבוה, כמו שקורה ברוב ספקיות ה ISP, וקצב הנתונים המקסימלי הוא 70kbps (כשבין 2 משתמשים ביתיים עם מודם וקווים אנלוגיים, המקסימום האפשרי הוא עדיין 33.6kbps). הסיבה שמשתמשים במודמים 56kbps ולא 70kbps קשורה לחסם נייקוויסט, כל ערוץ טלפוני הוא ברוחב של 4000Hz (כולל ה guard bands), לכן מספר הדגימות לשניה שיש לקחת כדי לבנות בחזרה הוא 8000. מספר הביטים בארה"ב לדגימה הוא 8 בארה"ב (כשאחד מהם משמש לבקרה) וזה נותן 56,000 ביטים/שניה. (באירופה לא משתמשים בביט בקרה וכל הביטים זמינים למשתמשים ולכן הם יכולים להשיג 64,000kbps. אך מכיוון שנדרש סטנדרט בינלאומי, הוחלט ללכת על ה 56kbps). התוצאה הסופית היא הסטנדרטים [v.90](http://en.wikipedia.org/wiki/List_of_ITU-T_V-series_recommendations) ו-[v.92](http://en.wikipedia.org/wiki/V.92). - -  - -**קווי מנויים דיגיטליים** - -עד שתעשיית הטלפוניה הגיעה (סוף סוף) ל 56kbps, תעשיית הטלוויזיה הציעה מהירויות של 10Mbps (בארה"ב גם תעשיית הטלוויזיה מספקת אינטרנט). חיבור האינטרנט הפך לחלק מרכזי וחשוב מהרווחים של תעשיית הטלפוניה, והם החלו להבין כי הם צריכים מוצר מתחרה. המענה שלהם היה שירות דיגיטלי חדש על ה local loop. בהתחלה, היו הרבה הצעות חופפות של מהירות גבוהות, כולם תחת השם xDSL (ראשי תיבות: Digital Subscriber Line, ה x הינו משתנה לפי הסטנדרט). - -הסיבה שמודמים כל כך איטיים היא שהטלפונים הומצאו על מנת לשאת קול אנושי, וכל מערכת הטלפוניה, בראש ובראשונה, הותאמה למטרה הזו. שידור מידע, היה האח החורג. כל לולאה מקומית מסתיימת במרכזייה, ושם החוט רץ דרך פילטר שמסנן את כל התדרים מתחת ל 300Hz ומעל 3400Hz (כמובן שהחתך אינו נקי, 300Hz ו 3400Hz הם בתווך ה 3dB כך שרוחב הפס הוא בדר"כ 4000Hz, אפילו שהמרחק אמור להיות 3100Hz). זה נעשה כדי שחברת הטלפוניה תוכל לספק יותר ערוצים (יותר לקוחות) פר מרכזייה, ועל הדרך גם הציוד יכול להיות זול ופשוט יותר (לא צריך לספק רוחב פס גדול). - -
    - xDSL -
    - -הטריק ב xDSL הוא שחברות הטלפוניה הורידו את הפילטרים, וכך כל רוחב הפס של הלולאה המקומית זמין למשתמשים. ההגבלה הופכת מהגבלה מלאכותית להגבלה שתלויה ביכולת הפיזית של הלולאה המקומית, שתומכת בערך ב 1MHz (ולא ה 3100Hz המלאכותיים שנוצרו ע"י הפילטר). לצערנו, הכושר של הלולאה המקומית נופל די במהירות עם המרחק של הלקוח מהמרכזייה (האות נחלש לאורך הכבל). כמובן שזה גם תלוי בעובי ואיכות החוטים השזורים. באיור מצד שמאל ניתן לראות את רוחב הפס הפוטנציאלי כפונקציה של המרחק (באיור יוצאים מנקודת הנחה ששאר התנאים אופטימלים). - -xDSL תוכנן לכמה מטרות: - - 1. שימוש בלולאות המקומיות (חוטים שזורים קטגוריה 3) הקיימות. - 2. שמירה על החיבורים הקיימים לטלפונים ופקסים. - 3. קצב השידור צריך להיות גבוה בהרבה מ 56kbps. - 4. הם צרכים להיות פעילים תמיד, עם חיוב חודשי ולא לפי זמן. - -
    - OFDM -
    - -כדי להשיג את המטרות שהציבו לעצמן חברות הטלפוניה הספקטרום הקיים (בדיוק 1.1MHz) של הלולאה המקומית, חולק ל-256 ערוצים עצמאיים של 4312.5Hz כל אחד (כמו שניתן לראות בתמונה משמאל). סכמת ה [OFDM](http://en.wikipedia.org/wiki/Orthogonal_frequency-division_multiplexing) (ריבוב בחלוקת תדר, דיברנו עליו למעלה), משמשת כדי לשלוח מידע על הערוצים האלו. ערוץ 0 משמש ל POTS (ראשי תיבות: Plain Old Telephone Service). ערוצים 1-5 ללא שימוש כלל, כדי לשמור שהתדרים של הקול ושל המידע לא יפריעו אחד לשני. שאר ה-250 ערוצים משמשים להעלה והורדה של מידע (ספקים מחלקים לרוב את רוחב הפס כך ש80%-90% מהערוצים שלו מיועדים להורדה, מכיוון שלרוב, זהו השימוש העקרי של המשתמשים, ומפה נגזרת האות "A" ב ADSL המייצגת Asynchronous). - -הסטנדרט הבינלאומי ADSL (שגם ידוע בתור [G.dmt](http://en.wikipedia.org/wiki/G.992.1)) התקבל בשנת 1999 ואפשר מהירויות הורדה של עד 8Mbps והעלה של עד 1Mbps. הוא הוחלף בשנת 2002 לגרסה השניה שלו שנקראה [ADSL2](http://en.wikipedia.org/wiki/G.992.3), עם שיפור במהירות ההורדה לעד 12Mbps והעלה עד 1Mbps. היום יש לנו את [+ADSL2](http://en.wikipedia.org/wiki/G.992.5), המכפילה את מהירות ההורדה לעד 24Mbps ע"י הכפלת רוחב הפס ל 2.2MHz (חוטים שזורים שונים). - -
    - A tpical arrangement of ADSL -
    - -בכל ערוץ, מתבצע אפנון QAM (גם עליו דיברנו בסעיף הקודם) בקצב של (בערך) 4000 סמלים/שניה. איכות כל ערוץ מנוטרת באופן סדיר ולפיכך מתאימים את הקונסטלציה של האפנון, ולכן לכל ערוץ יתכן קצב נתונים שונה. בערוץ בעל SNR (יחס אות לרעש) גבוה יכולים להישלח עד 15 ביטים לסמל, ועד ל-2 ביטים, ביט אחד או אפילו 0 ביטים בערוץ בעל SNR נמוך. בתמונה מצד שמאל אנחנו רואים סידור טיפוסי של ADSL. בסכמה הזו, טכנאי חברת הטלפוניה צריך להגיע לבית הלקוח כדי להתקין NID (ראשי תיבות: Network Interface Device), בקרבת מקום ל NID (או לפעמים הם מגיעים ביחד באופן מובנה) ישנו Splitter, המפצל הוא פילטר אנלוגי המפריד בין הרצועה לשימוש ה POTS (טווח 0-4000Hz) לדאטה. הטלפון או הפקס מחוברים אליו ישירות, בעוד המחשב מחובר למודם (בדרך כלל באמצעות כבל Ethernet) שמעבד את האות ומאפנן אותו (OFDM). - -בקצה הלולאה המקומית, במרכזייה, מותקן גם Splitter, כאן הוא מסנן בין האות של הקול (שמועבר למתג של הקול), וכל אות מעל 26kHz מופנה למכשיר הנקרא DSLAM (ראשי תיבות: Digital Subscriber Line Access Multiplexer), שמכיל מעבד לאות הדיגיטלי המקביל לזה הקיים במודל ADSL. כשהביטים שוחזרו מהאות, הפאקטות נשלחות אל הספקית (ISP). - -  - -**סיבים עד הבית** - -פריסת לולאות מקומיות מנחושת מגבילות את הביצועים של ה ADSL והמודמים. כדי שחברות הטלפוניה יוכלו לספק מהירויות גבוהות יותר, הן משדרגות את הלולאות המקומיות בכל הזדמנות שיש להן, ע"י התקנה של סיבים אופטיים עד לבית הלקוח (או המשרד). לתוצאה הזו קוראים FttH (ראשי תיבות: Fiber To The Home). בעוד הטכנולוגיה קיימת כבר זמן מה, הפריסה הנרחבת המריאה בעיקר משנת 2005. - -כמו החוטי נחושת, גם הלולאות המקומיות מסיבים הן פאסיביות. זה אומר שלא דרוש ציוד חשמלי כדי להגביר את האות או תהליך דומה. הסיב פשוט נושא את האות מהבית למרכזייה. בדרך כלל, הסיב מהבית מתחבר כך שרק סיב אחד מגיע אל המרכזייה (לקבוצה של עד 100 בתים). בצד של ההורדה, קיימים מפצלים אופטיים שמחלקים את האות מהמרכזייה כדי שיגיע לכל הבתים. כמובן שהצפנה היא דבר הכרחי לאבטחה כדי שרק בית אחד יוכל לפענח את האות. בצד של ההעלאה, מחברים אופטיים ממזגים את האות מהבתים לאות אחד שמתקבל במרכזייה. - -
    - PONs -
    - -הארכיטקטורה הזו נקראת PON (ראשי תיבות: Passive Optical Network), וניתן לראותה בתמונה משמאל. שיתוף התמסורת בצד ההורדה, ועוד אחד לצד ההעלאה היא דבר נפוץ. אפילו לאחר הפיצול, רוחב הפס האדיר, ואי הדילול של האות הקיים בסיבים מאפשרים ל PON לספק קצב נתונים גבוה למרחק של עד 20 ק"מ. המהירות הממשית תלויה בסוג ה PON, וקיימים 2 סוגים נפוצים: GPONs (ראשי תיבות: Gigabit-capable PONs), שמוגדר ע"י ה ITU. ו EPONs (ראשי תיבות: Ethernet PONs) שמוגדר ע"י ה IEEE. כששניהם מספקים בסביבות האחד גיגה ביט. - -כדי לחלק את קיבולת הכבל בין הבתים, צריך איזשהו פרוטוקול. בצד ההורדה, המרכזייה שולחת את המידע לכל בית באיזה סדר שהיא רוצה. אך בצד ההעלאה, המידע לא יכול להישלח באותו הזמן, אחרת אותות שונים יתנגשו. בנוסף, הבית לא יכול לשמוע את השידור של שאר הבתים, כך שהם לא יכולים להקשיב לקו ולבדוק שניתן לשדר. הפתרון הוא ציוד בבית, שיעניק תאי זמן לבתים לשידור, ע"י המרכזייה. כדי שזה יעבוד, ישנו תהליך המתאים את זמני השידור מהבתים, כך שכל האותות שיתקבלו במרכזייה יהיו מסונכרנים. - -  - -**Trunking וריבוב (Multiplexing)** - -[Trunking](http://en.wikipedia.org/wiki/Trunking) היא דרך של המערכת כדי לספק גישה ללקוחות רבים ע"י שיתוף מערכת של קווים או תדרים, במקום לספק אותם בנפרד. זהו מבנה המקביל למבנה של עץ. הגזע (Trunk) הוא ערוץ שידור יחיד בין שתי נקודות, כל נקודה יכולה להיות מרכז המיתוג או הצומת. הגזעים מובילים אלפי, אפילו מיליוני, שידורים במקביל. - -השיתוף חשוב להשגת קנה מידה גדול, מכיוון שעלויות ההתקנה והתחזוקה של גזע בעל רוחב פס גבוה, הם בדיוק כמו אחד בעל רוחב פס נמוך. השיתוף מושג באמצעות סוגים שונים של ריבוב TDM וריבוב FDM. - -  - -**הפיכת אותות קול (אנלוגיים) לדיגיטליים** -בתחילת הדרך, הליבה של מערכת הטלפוניה טיפלה בשיחות כמידע אנלוגי. נעשה שימוש רב בטכניקת FDM כדי לרבב את הערוצים ברוחב פס 4000Hz (שהם 3100Hz עם מרווחי (guard) רצועה). כמובן שעדיין נעשה שימוש ב FDM היום, על גבי חוטי נחשות וערוצי מיקרו-גל. אך FDM דורש מעגל אנלוגי (דבר שלא נעשה ע"י המחשב). לעומת זאת, ב TDM ניתן לטפל ע"י אלטרוניקה דיגיטלית, ולכן הוא הפך לנפוץ הרבה יותר בשנים האחרונות. - -מכיוון ש TDM משמש למידע דיגיטלי, והלולאות המקומיות מטפלות במידע אנלוגי, יש להמיר את המידע מאנלוגי לדיגיטלי במרכזייה (היכן שכל הלולאות המקומיות העצמאיות מגיעות ביחד ומתחברות לגזע (trunk). האותות האנלוגים מומרים לדיגיטלים ע"י מכשיר שנקרא קודק ([codec](http://en.wikipedia.org/wiki/Codec)), שזה קיצור של coder-decoder. הקודק לוקח 8000 דגימות לשניה (125 מילי שניות/דגימה) בשל חסם נייקוויסט (עליו דיברנו בתחילת הפוסט, והוא הוכיח כי מספר הדגימות הנ"ל הוא מספיק בכדי לשחזר את המידע מערוץ ברוחב פס 4kHz). כל דגימה של האמפליטודה של האות מכומתת למילת קוד בת 8 ביטים. הטכניקה הזו נקראת [PCM](http://en.wikipedia.org/wiki/Pulse-code_modulation) (ראשי תיבות: Pulse Code Modulation), והיא מהווה את הבסיס למערכת הטלפוניה המודרנית. - -קיימים 2 סוגים של כימות: u-low שנפוץ בעיקר בארה"ב ויפן, ו A-low שנפוץ באירופה ובשאר העולם. אך 2 הגרסאות נמצאות תחת הסטנדרט [ITU G.711](http://en.wikipedia.org/wiki/G.711). - -  - -**ריבוב בחלוקת זמן** - -TDM (ראשי תיבות: Time Division Multiplexing), מבוסס על PCM, משמש להעביר כמה שיחות על גבי גזעים (Trunks) ע"י שליחת דגימה מכל שיחה, כל 125 מילי שניות. השיטה בה משתמשים בצפון אמריקה ויפן נקראת T1 (יותר נכון DS1, והספקית נקראת T1, אך בתעשייה השם שנקלט הוא פשוט T1 לכן נמשיך איתו) ובה, כל מסגרת מחולקת ל-24 ערוצים המרובבים ביחד. כל אחד מה-24 ערוצים, בתורו, זוכה להכניס 8 ביטים למסגרת. ז"א שהמסגרת מכילה 24*8 = 192 ביטים, ועוד אחד למטרות בקרה, ז"א 193 ביטים כל 125 מילי שניות, מה שנותן 1.544Mbps. - -
    - TDM -
    - -חלק מהביטים במסגרת משמשים לאיתות ועוד אחרים לסנכרון. בגרסה אחת, הביטים נפרסים לאורך כל המסגרת (מתפרסים לכל אורך 24 הערוצים), שיטה זו נקראת [Extended superframe](http://en.wikipedia.org/wiki/Extended_superframe). שישה ביטים (במקומות ה-4, 8, 12, 16, 20 ו-24) משמשים כדי ליצור את התבנית 001011. ובאופן רגיל, המקבל יחפש את התבנית הזו כדי לא לאבד את הסינכרון. עוד 6 ביטים משמשים כדי לשלוח קוד לבדיקת שגיאות (בהמשך נרחיב על נושא בדיקת השגיאות). 12 הביטים הנותרים משמשים לשליטה במידע ותחזוק רגיל של הרשת (כמו ביצועים טובים יותר, ומנגנוני אישור (עליהם נרחיב בהמשך)). - -מחוץ לארה"ב ויפן, מבצעים שימוש בשיטה הנקראת E1 המספקת 2.048Mbps. בשיטה זו ישנם 32 דגימות בנות 8 ביטים כל אחת שארוזות לתוך מסגרת הנשלחת כל 125 מילי שניות. 30 מהערוצים משמשים לשליחת מידע, ועוד 2 משמשים לאיתות וסנכרון. ז"א שכל 4 מסגרות מספקות 64 ביטים לאיתות וסנכרון, חצי מהם משמשים לאיתות והחצי השני משמשים לסנכרון (או במקרים פרטיים לדברים אחרים, כל מדינה והחלטת השימוש שלה). - -
    - T1 to T2 to T3 to T4 -
    - -ריבוב בחלוקת זמן מאפשר לכמה תשתיתי T1 לבצע ריבוב לתשתית גדולה יותר, בדיוק כמו באיור משמאל. בצד השמאלי ביותר אנחנו רואים 4 תשתיות של T1 המרובבים כ-4 ערוצים לתוך T2. הריבוב לתוך T2 נעשה ביט אחרי ביט (ולא בייט אחרי בייט, הרי יש 24 בייטים (כל בייט מכיל 8 ביטים)). כדי לספק מקום ל-4 ערוצי T1, אנחנו צרכים תשתית ברוחב פס של 6.176 (1.544*4), אך בפועל, T2 מספק 6.312Mbps. הביטים אקסטרה שיש לנו משמשים למסגור (בדיוק כמו הביט הראשון בכל מסגרת של T1) ואישוש (במקרה וביטים נאבדים בדרך). ברמה הבאה, 7 T2 מתחברים ל T3, ולאחריו 6 T3 מתחברים ל T4. - -הסכמה בארה"ב כמו שהבנתם היא 4,7,6. אך הסטנדרט של ה ITU קורא לבצע ריבוב בכל רמה ל-4 מסגרות. בנוסף, גם המסגור והביטים השמורים להתאוששות שונים בארה"ב מאשר הסטנדרט של ה ITU. הסטנדרט של ה ITU מצריך היררכיה של 2.048, 8.949, 34.304, 139.264, 565.148 Mbps. - -  - -**SONET / SDH** - -בשנים הראשונות של הסיבים האופטיים, לכל חברת טלפוניה הייתה מערכת TDM לסיבים אופטיים אישית וקניינית. אך החיבור של חברות הטלפוניה (כדי להעביר פאקטות מאחת לשניה) היה קשה עכב אי הסטנדרליזציה. וב-1985, [bellcore](http://en.wikipedia.org/wiki/Telcordia_Technologies) (חברת מחקר ופיתוח שהוקמה בשנת 1982 מתוך הפירוק של AT&T) החלה לעבוד על סטנדרט הנקרא [SONET](http://en.wikipedia.org/wiki/Synchronous_optical_networking) (ראשי תיבות: Synchronous Optical NETwork). - -לאחר מכן ITU הצטרפה למאמץ, מה שהביא לסטנדרט ה SONET והמלצות מקבילות של ה ITU (מספר G.707, G.708, G.709) ב-1989 הנקראות SDH (ראשי תיבות: Synchronous Digital Hierarchy). רוב התנועה במערכת הטלפוניה למרחקים ארוכים (לא הכבלים מהמרכזיות לבית הלקוח וכד') משתמשים בגזעים (trunks) המריצים SONET בשכבה הפיזית. - -לתכנון ה SONET היו 4 יעדיים עקריים: - - 1. על SONET היה לאפשר לספקים שונים לשתף פעולה. השגת המטרה הזו דרשה הגדרה של סטנדרט איתות משותף ביחס לאורך הגל, תזמון, מבנה המסוגר וכ'ו. - 2. נדרשו אמצעים לאיחוד המערכת האמריקאיות, האירופאיות והיפניות. כולן היו מבוססות על ערוצי 64kbps PCM, אך שולבו בדרכים שונות. - 3. על SONET היה לספק דרך לבצע ריבוב לכמה ערוצים דיגטלים. באותו הזמן בארה"ב בוצע שימוש ב T3 במהירות 44.736Mbps. וגם T4 היה מוגדר (אך עדיין לא בשימוש). חלק מהמשימה של SONET היה להמשיך את ההיררכיה הזו עד ל gigabits/sec (ואפילו אחרי). - 4. SONET הייתה צריכה לספק תמיכה ל OAM (ראשי תיבות: Operations, Administration, Maintenance), שהכרחיים לניהול הרשת (מערכות קודמות לא ביצעו זו בצורה מוצלחת). - -החלטה מוקדמת הייתה לבנות את ה SONET כמערכת TDM מסורתית, כשכל רוחב הפס של הסיב מוקדש לערוץ אחד שמחולק לתאי זמן לתת הערוצים. ככזה, SONET היא מערכת מסונכרנת. כל שולח ומקבל קשורים לשעון משותף. הביטים בקו SONET נשלחים במרווחים מדוייקים מאוד, הנשלטים ע"י השעון הראשי (השעון מדויק ברמה של 1 חלקי 9^10). - -המסגרת הבסיסית ב SONET היא בלוק של 810 בייטים הנשלחים כל 125 מילי שניות, ומכיוון ש SONET מסונכרן, המסגרות נשלחות בלי קשר לאם יש מידע לשלוח או אין. שליחת 8000 מסגרות לשניה מתאים במדויק לקצב הדגימות בערוץ PCM המשמש בכל מערכת הטלפוניה הדיגיטלית. מסגרות SONET בנות ה-810 בתים מתוארת הכי טוב בצורה של מלבן בעל 90 עמודות ו-9 שורות. ואם נחשב את המהירות, 8*810 יתן לנו 6480 ביטים, הנשלחים 8000 פעם לשניה, נותנים לנו 51.84Mbps. זהו המערך הבסיסי של ערוץ SONET, והוא נקרא STS-1 (ראשי תיבות: Synchronous Transport Signal-1). -* כל הגזעי SONET הם מכפלות של STS-1. - -
    - SONET -
    - -שלושת העמודות הראשונות של כל פריים שמורות למידע של מערכת הניהול. בבלוק משמאל, שלוש העמודות הראשונות הן תקורה לחלקה, ואחריהן 6 העמודות הבאות משמשות כתקורת שורה. התקורה של החלקה, נוצרת ונבדקת בהתחלה ובסוף של כל חלקה (כל מסגרת SONET שנשלחת כל 125 מילי שניות), בעוד התקורה של השורה נוצרת ונבדקת בתחילת ובסוף כל שורה. - -משדר SONET שולח מסגרות בעלות 810 בתים, ללא מרווחים בינהן, גם כשאין בהן מידע. מנקודת המבט של המקבל, הוא רואה זרם ביטים רציף, אז איך הוא יודע איפה מתחילה כל מסגרת? בכל מסגרת 2 הבתים הראשונים מכילים תבנית קבועה שהצד המקבל מחפש. ה-87 עמודות הנשארות בכל מסגרת מכילות 50.112Mbps של מידע של המשתמש (8000\*8\*9*87). ה SPE (ראשי תיבות: Synchronous Payload Envelope), שמכילה את המידע של המשתמש, אינה מתחילה תמיד בשורה 1 עמודה 4. אלא יכולה להתחיל בכל מקום במסגרת. מצביע לבית הראשון של ה SPE נמצא בשורה הראשונה של תקורת השורה. - -היכולת של ה SPE להתחיל בכל מקום במסגרת SONET (ואפילו להתרחב על 2 מסגרות, כמו שניתן לראות באיור למעלה משמאל), מאפשרת גמישות גבוה למערכת. לדוגמה: אם "מטען" מגיע (בקשה של המשתמש לשלוח או לקבל מידע) בזמן שנבנה מסגרת דמה (כמו שאמרנו, כשאין מידע לשלוח, הוא שולח מסגרות דמה על מנת להמשיך לשלוח כל הזמן). המטען יכול להיכנס למסגרת הנוכחית (בחלקה שלא נבנתה עדיין), במקום לחכות לבניית המסגרת הבאה. - -  - -**ריבוב בחלוקת אורך גל** - -
    - WDM -
    - -נוסף לכל צורת הריבוב שראינו עד כה (חלוקת תדר / חלוקת זמן / חלוקת קוד), ישנה עוד צורת ריבוב בה משתמשים לא מעט, ואפילו ביחד עם ריבוב בחלוקת זמן (TDM) (כדי לרתום את רוחב הפס העצום של סיבים אופטיים) הנקראת WDM (ראשי תיבות: Wavelength Division Multiplexing). את עקרון העבודה הבסיסי של WDM על סיבים, ניתן לראות באיור משמאל. - -באיור ניתן לראות בחלקו התחתון, 4 סיבים המשתלבים לאחד ב combiner, כל אחד מהם עם אורך הגל שלו (בחלקו העליון של האיור ניתן לראות את אורך הגל של כל סיב). ארבעת הקרניים (אמרנו שבסיב אופטי עוברת קרן אור) משתלבות לסיב משותף אחד על מנת לשדר את המידע ליעד רחוק. ביעד של הסיב ישנו מפצל, splitter, המפצל אותם לכמות הקרניים שהיו בצד הנכנס. למרות הפיצול כל קרן מכילה את כל האותות, ז"א במקום קרן אחת יש לנו 4 קרניים זהות שכל אחת מהן הולכת ליעד אחר, ולפי כל יעד, על הסיב ישנו מסנן, filter, ייעודי המסנן את כל אורכי הגל למעט אחד מהם. - -האמת שאין חדש תחת השמש, הפעולה שתיארנו לעיל היא ריבוב בחלוקת תדר, רק לתדרים גבוהים מאוד (לא מספר תדרים תחת ספקטרום אחד, אלא מספר תדרים שכל אחד מהם בספקטרום משלו). אז מה הסיבה ש WDM פופולרי כל כך? מכיוון שהאנרגיה בערוץ אחד היא בדר"כ רוב של כמה גיגהרץ (בגלל שזו המגבלה הנוכחית של כמה מהר אנחנו יכולים להמיר בין אותות אלקטרונים ואופטיים). ע"י כך שנריץ כמה ערוצים במקביל, כל אחד באורך גל שונה, סך רוחב הפס יוגדל לינארית במספר הערוצים. מכיון שרוחב הפס של סיב אחד הוא בערך 25,000GHz, יש תאורתית מקום ל-2,500 ערוצים של 10Gbps (אפילו ב 1bit ל Hz). - -אחד מהמניעים של טכנולוגיית ה WDM היה הפיתוח של כל המכשור האופטי. פעם, כל 100 ק"מ היה צורך לפצל את הערוצים, להמיר כל אחד מהאותות בערוצים לאות אלקטרוני, להגביר את האות, ולהמירו חזרה לאותות אופטיים ומשם חזרה לשילוב של הערוצים. היום, המגברים אופטיים, ויכולים להגביר את האות עד 1000 ק"מ בלי הצורך לבצע המרה חזרה לאות אלקטרוני. - -בתמונה שלמעלה מצד שמאל, אנו רואים מערכת WDM קבועה. ביטים מהסיב הנכנס 1 (הביטים מסומנים בעזרת למאדה 1) מגיעים לסיב היוצא 3 (חפשו את הביטים למאדה 1) וכד'. אך אפשרי גם לבנות מערכת WDM המסוגלת לבצע החלפות, גם בתחום האופטי. במכשיר שכזה הפילטר היו מתוכנן ע"י שימוש ב[אינטרפרומטריה](http://en.wikipedia.org/wiki/Interferometry) (טכניקה לפיצול ואיחוד של גל) [Fabry-Perot](http://en.wikipedia.org/wiki/Fabry%E2%80%93P%C3%A9rot_interferometer) או ב [Mach-Zehnder](http://en.wikipedia.org/wiki/Mach%E2%80%93Zehnder_interferometer). - -  - -**מיתוג** - -מנקודת המבט של מהנדס הטלפון הממוצע, מערכת הטלפון מחולקת ל-2 חלקים עיקריים: החלק החיצוני (הלולאות המקומיות - local loops, הצמתים - trunks), והחלק הפנימי (המתגים - switches). עד כה דנו בחלק החיצוני, כעת הגיע הזמן להסתכל על החלק הפנימי. - -כיום, משתמשים בשתי שיטות מיתוג שונות: מיתוג מעגל (circuit switching), ומיתוג מנות (packet switching). מערכת הטלפוניה המסורתית מבוססת על מיתוג מעגלי, אך מיתוג מנות מתחיל לחדור עם העליה ב VOIP (ראשי תיבות: Voice Over IP). - -
    - Circuit Switching -
    - -  - -**מיתוג מעגל** - -בעקרון, כשאתם (או המחשב שלכם) מבצע שיחה טלפונית, ציוד המיתוג במערכת הטלפונית מחפש דרך (אמיתית, על הכבל) מהטלפון שלכם, כל הדרך אל היעד. הטכניקה הזו מודגמת באיור מצד שמאל (a). כל אחד מ-6 המלבנים מייצג מרכזייה, ובמקרה הזה לכל מרכזייה יש 3 קווים נכנסים ו-3 יוצאים. כשהשיחה עוברת במרכזייה נוצר חיבור פיזי מהצד בו השיחה נכנסה לצד בו היא יוצאת. - -בימים הראשונים של תעשיית הטלפון, החיבור נעשה באופן ידני ע"י מרכזניות שחיברו כבל מגשר לשקע של השיחה הנכנסת ולשקע של שיחת היעד. ובמאה ה-19, קצת לאחר המצאת הטלפון, הומצא ציוד המיתוג המעגלי האוטומטי, ע"י קברן בשם [Almon B. Strowger](http://en.wikipedia.org/wiki/Almon_Brown_Strowger), ולהלן הסיפור מאחורי ההמצאה: קצת לאחר המצאת הטלפון, כשמישהו מת אחד הקרובים היה מתקשר למפעילה המקומית ואומר "בבקשה תקשרי אותי עם הקברן", לצערו של מר סטראוג'ר היו 2 קברנים בעיירה, הוא עצמו ועוד בחור. אשתו של הבחור השני הייתה אחת המרכזניות במפעילת הטלפון המקומית, ואתם יכולים לנחש לאן זה הולך. בקיצור, מהר מאוד הוא הבין שאם לא ימציא את ציוד המיתוג האוטומטי הוא יפשוט את הרגל. - -
    - Packet Switching -
    - -כמובן שמאז הציוד הפיזי השתנה, אך הרעיון המקורי נשאר כשהיה: כששיחה הוקמה, דרך יעודיית בין הצדדים "תיבנה" ותישאר מחוברת (ללא שינוי) כל עוד השיחה מתקיימת. וזוהי תכונה של מיתוג מעגלי, הצורך שלו להקים חיבור שלם, מקצה לקצה, לפני שעוד נשלח איזשהו מידע. בשל תכונה זו, הזמן בין סיום החיוג לתחילת צלצול הטלפון ביעד יכול בקלות להיות 10 שניות, ואפילו יותר במרחקים ארוכים או שיחות בינלאומיות. בזמן הזה, מערכת הטלפון "צדה" אחר דרך קישור, כמו שניתן לראות בתמונה משמאל (a). - -אך מהרגע שהוקם חיבור, העיכוב היחיד של המידע הוא העיכוב של האות האלקטרומגנטי שנשלח בתשתית, שזה בערך 5 מילי שניות ל-1,000 ק"מ. - -  - -**מיתוג מנות** - -האלטרנטיבה המודרנית יותר למיתוג מעגלי, זהו מיתוג מנות, הניתן לראותו בתמונה הראשונה למעלה (בתחילת מיתוג מעגל) משמאל, ב (b). הרעיון כאן, הוא שהמנות המכילות מידע נשלחות ישר כשהן מוכנות, ואין צורך להקים חיבור ישיר לפני כן (בניגוד למיתוג מעגלי). כל מנה נשלחת לבדה, ועל תחנות המיתוג לאחסן ולשדר את המנות על גבי התשתית, כל אחד ליעדה. - -במיתוג מעגלי, מפני שהדרך קבועה, כל המידע מגיע בסדר בו הוא נשלח, ולעומתו במיתוג מנות, יכול להיות שמנה א' שיצאה לפני מנה ב' תגיע אחריה. בנוסף כדי לא לתת למשתמשים לנצל את רוחב הפס של תחנות המיתוג האחרות (בדרך), קיימת מגבלה של גודל המנות הניתנות לשליחה. - -מיתוג מנות ומעגלי שונים בעוד דרכים. אחד מהם לדוגמה הוא שמפני שבמיתוג מנות לא נשמר במיוחד רוחב פס, יכול להיות שהמנות תצטרכנה לחכות עד שישודרו מתחנת המיתוג (וכאן אנחנו נתקלים פעם ראשונה במושג חדש הנקרא תורים (Queue) או תור עיכוב (Queuing Delay)). אך מנגד, אם רוחב הפס נשמר למשתמש ספציפי, ואין כרגע זרימה של נתונים, זהו בזבוז של רוחב פס. רוחב הפס השמור אינו יכול להיות משומש ע"י ישומים אחרים. מיתוג מנות אינו מבזבז רוחב פס ולכן יעיל יותר מבחינה מערכתית. - -בנוסף, מיתוג מנות עמיד יותר בפני תקלות ממיתוג מעגלי. למעשה זוהי הסיבה העקרית שלשמה הוא הומצא. אם תחנת מיתוג נופלת, במיתוג מעגלי, המעגל המשתמש בה "נהרס" ואי אפשר לשדר יותר מידע בנתיב הזה. במיתוג מנות, המנות נשלחות בדרך חלופית, "מסביב" לתחנות מיתוג המתות. - -להלן תמונה המסכמת את כל ההבדלים בין מיתוג מנות למיתוג מעגלי: - -|Packet Switched|Circuit Switched|Item| -|:---:|:---:|:---:| -|Not needed|Required|Call setup| -|No|Yes|Dedicated physical path| -|No|Yes|Each packet follows the same route| -|No|Yes|Packets arrive in order| -|No|Yes|Is a switch crash fatal| -|Dynamic|Fixed|Bandwidth available| -|On every packet|At setup time|Time of possible congestion| -|No|Yes|Potentially wasted bandwidth| -|Yes|No|Store-and-forward transmission| -|Per packet|Per minute|Charging| - -  - -### 7. מערכת הטלפוניה הסלולרית (תאית) - -גם אם מערכת הטלפוניה המסורתית (עליה דיברנו בחלק הקודם) תצליח לספק כמה גיגה בייטים ע"י סיבים אופטים מקצה לקצה (כולל הק"מ האחרון), היא לא תצליח לספק קבוצה הולכת וגדלה של משתמשים: אנשים בדרכים. היום, אנשים מצפים להיות מסוגלים לבצע שיחות טלפון, לבדוק מיילים, לגלוש וכד' בזמן נסיעה באוטו, בטיסות, בבריכה הציבורית, בזמן ריצה בפארק וכד', ובשל כך יש עניין מתמיד וגבוה ברשתות הטלפוניה האלחוטיות. - -מערכת הטלפוניה האלחוטית משמשת לתקשורת WAN (ראשי תיבות: Wide Area Network). הטלפונים הנידיים (או הסלולרים) עברו 3 דורות מובהקים, ומקובל לציין אותם באמצעות 1G, 2G, 3G והם: - - 1. קול אנלוגי. - 2. קול דיגיטלי. - 3. קול ונתונים דיגיטליים (אינטרנט). - -מערכת הטלפוניה הסלולרית הראשונה בארה"ב תוכננה ע"י AT&T והונהגה בכל המדינה ע"י ה [FCC](http://en.wikipedia.org/wiki/Federal_Communications_Commission). כתוצאה מכך, לכל ארה"ב הייתה מערכת אחת (אנלוגית). ומכשירים ניידים שנקנו בקליפורניה (לדוגמה) עבדו בלי בעיה גם בניו יורק. בניגוד לכך, כשהטלפונים הניידים הגיעו לאירופה, לכל מדינה הייתה את השיטה והמערכת שלה. מה שהוביל לבלגן אחד גדול. אירופה למדה מהטעות הזו, ובדור השני, הדיגיטלי, היא הקימה סטנדרט אחיד (GSM). כך שהרבה מכשירים ניידים אירופאים עובדים בכל מקום באירופה. אך אז בארה"ב החליטו כי הממשלה לא צריכה להתערב בסטנדרטים של השוק, דבר שהוביל ליצירת כמה מערכות (2 עקריות) וכך טלפון נייד שעובד באחת לא יעבוד בשניה. - -למרות ההתחלה המזהירה של ארה"ב, בדור השני, השימוש בטלפונים ניידים באירופה היה גדול משמעותית מבארה"ב. חלק מהסיבה לכך היא המערכת היחידה. הסיבה השניה היא שהמספרים של המכשירים הניידים בארה"ב היו מעורבבים עם המספרים של הטלפונים הביתיים המסורותיים. כך שאין דרך לדעת אם היית מתקשר לטלפון ביתי (בעלות זולה) או לטלפון נייד (בעלות יקרה הרבה יותר). וכדי למנוע מאנשים להיזהר ולהיות עצבניים בהוצאת שיחות, חברות הטלפוניה החליטו לחייב את מקבל השיחה במקום מי שמוציא אותה. כתוצאה מכך הרבה אנשים היססו לקנות טלפונים ניידים מדאגה לקבלת חשבון מנופח, רק מהצורך לענות לשיחות מתקבלות. - -  - -**הדור הראשון (1G) של הטלפונים הניידים: קול אנלוגי** - -בתחילת המאה ה-20, טלפוני-רדיו ניידים שימשו רק לתקשורת צבאית וימית, אך ב-1946 המערכת הראשונה לטלפון ברכב הותקנה. למערכת היה משדר אחד (גדול), על גבי בניין גבוה, ותדר אחד שימש לשלוח ולקבל שידורים. כדי לדבר, המשתמש היה צריך ללחוץ על כפתור שהפעיל את המשדר וביטל את המקלט ומכאן שמו. המערכות היו ידועות בתור [PTT](http://en.wikipedia.org/wiki/Push-to-talk) (ראשי תיבות: Push To Talk) והן הותקנו בכמה ערים בתחילת שנות ה-50, ושימשו בעיקר את נהגי המוניות, ניידות המשטרה וכד'. - -בשנות ה-60, הותקן [IMTS](http://en.wikipedia.org/wiki/Improved_Mobile_Telephone_Service) (ראשי תיבות: Improved Mobile Telephone System). גם המערכת הזו נעזרה במשדר גדול (שצריך 200Watt) על גבי גבעה, אך היו לה 2 תדרים, אחד כדי לשלוח ואחד לקבל. IMTS תמכה ב-23 ערוצים שנפרסו מ 150MHz עד ל 450MHz. בשל המספר הקטן של הערוצים, לפעמים, משתמשים היו צריכים לחכות זמן רב עד שהיו מקבלים צליל חיוג, מה שהגביל מאוד את השימוש והפך אותה ללא מעשית. - -  - -**מערכת טלפון ניידות מתקדמות** - -כל זה השתנה עם [AMPS](http://en.wikipedia.org/wiki/Advanced_Mobile_Phone_System) (ראשי תיבות: Advanced Mobile Phone System), שהומצאה במעבדות בל ([Bell Labs](http://en.wikipedia.org/wiki/Bell_Labs)) והותקנה לראשונה, בארה"ב ב-1982. (המערכת הייתה בשימוש גם באנגליה ונקראה שם TACS, וביפן שם נקראה MSC-L1). מערכת ה AMPS בוטלה לחלוטין ב2008. - -כל מערכת הטלפוניה מחולקות לאזורים גיאוגרפים הנקראים "תאים" (באנגלית cells) וזאת הסיבה שטלפונים ניידים נקראים גם טלפונים סלולריים (cellphones). ב AMPS התאים הם בין 10 ל-20 ק"מ (במערכות דיגיטליות הם קטנים יותר), כל תא עושה שימוש בסט מסוים של תדרים, ובאותו סט (טווח קטן) של תדרים לא מתבצע שימוש בתאים השכנים (הצמודים אליו) (סט זה יכול להיות בשימוש ע"י תאים אחרים, אך עליהם להיות רחוקים ממנו, ולא צמודים אליו). - -במערכת IMTS שהצגנו קודם לכן כל תא מקיף בערך 100 ק"מ, אך בתחום הזה יש רק תדר אחד, בעוד במערכת AMPS יש 100 תאים של 10 ק"מ (באותו אזור של 100 ק"מ ב IMTS) כך שכל 10-15 תאים על אותו תדר (אך חשוב שהם לא יהיו תאים שכנים, כמו שציינו כבר). העיצוב הזה של המערכת מגביר את יכולת המערכת לתמוך ביותר שיחות בו זמנית. תאים קטנים יותר אומר שנדרש פחות כוח וזה מוביל למשדרים קטנים וזולים יותר. - -
    - Cells -
    - -באיור משמאל ניתן לראות את הרעיון של התאים (a), נהוג לציירם כמשושה אך במציאות הם יותר עגולים וכמובן אינם כה סימטרים. ניתן לראות באיור כי גם כל התאים באותו גודל ומקובצים בקבוצות של 7 תאים. כל אות (בתוך התא) מסמלת קבוצה של תדרים (שימו לב כי לכל קבוצת תדרים הנמצאת בתאים שונים יש 2 תאים המפרידים ביניהם כדי למנוע הפרעות). באזורים בהם מספר המשתמשים גדל עד לנקודה בה יש עומס על המערכת, ניתן להוריד את ההספק של המשדר באנטנה באזור על מנת לחלק את האזור לתאים קטנים יותר (כמובן שיש לפרוס עוד אנטנות ולהתחשב בחילוק של התדרים כך שיהיה חוצץ של 2 תאים לפחות עד לחזרה על אותו סט תדרים). עקרון זה מודגם באיור משמאל ב(b). - -מפעילות הסלולר יוצרות לפעמים מיקרו תאים כאלו, בעזרת אנטנות ניידות המקושרת ע"י לווין, על מנת לתת כיסוי באופן זמני למקום זמני (כמו באירועי ספורט בהם מתקבצים קבוצה גדולה של אנשים במקום אחד לכמה שעות, או בהפגנה הגדולה שהייתה ב-2011 וכד'). - -באמצע כל תא ישנה תחנת קרקע אליה כל התשדורות (השיחות) מועברות. תחנת הקרקע מכילה מחשב ומשדר / מקלט המחובר לאנטנה. במערכת קטנה, כל תחנות הבסיס מחוברות למכשיר הנקרא [MSC](http://en.wikipedia.org/wiki/Network_switching_subsystem#Mobile_switching_center_.28MSC.29) (ראשי תיבות: Mobile Switching Center), ובמערכת גדולה ידרשו כמה MSC כשהם מחוברים ל MSC ברמה שניה, וכך הלאה. MSC הוא בעקרון מרכזייה והם מחוברים לפחות לעוד מרכזייה (MSC) אחת (בדיוק כמו במערכת הטלפוניה המסורתית). ה MSC מתקשר עם תחנת הבסיס (האנטנה), בינם לבין עצמם, ועם מערכת ה PSTN (רשת הטלפוניה הציבורית מהסעיף הקודם), בעזרת מערכת מיתוג מנות. - -בכל רגע, כל טלפון נייד נמצא בתא ספציפי ותחת אותה תחנת בסיס (אנטנה). כאשר הטלפון הנייד עוזב את התא, תחנת הבסיס האחראית עליו שמה לב שהאות נחלש ושואלת את התחנות מסביבה מה חוזק האות שכל תחנה מקבלת ממנו. כאשר התשובות מגיעות, תחנת הבסיס מעבירה את הבעלות על אותו טלפון נייד לתחנת הבסיס המקבלת את האות החזק ביותר מאותו טלפון נייד. העברת הבעלות מתבצעת ע"י יידוע לאותו טלפון מי "הבוס" החדש שלו. אם הטלפון הנייד בזמן שיחה, הוא מתבקש להחליף לערוץ (סט תדרים) חדש (בו התחנה החדשה משתמשת), תהליך זה נקרא מסירה (handoff) והוא לוקח בערך 30 מילי שניות. תהליך הבדיקה והיידוע מתבצע ע"י ה MSC, תחנות הבסיס הם אנטות רדיו בעלות מקלט ומשדר, ובעקרון די טיפשות. - -  - -**ערוצים** - -AMPS משתמש בריבוב FDM כדי להפריד בין הערוצים. המערכת עושה שימוש ב-832 ערוצים דו כיוונים, כל ערוץ כזה מכיל זוג ערוצים חד כיווניים. הסידור הזה ידוע כ [FDD](http://en.wikipedia.org/wiki/Duplex_(telecommunications)) (ראשי תיבות: Frequency Division Duplex). מה שנוצר בעצם זה 832 ערוצים חד כיווניים מ 824MHz עד 849MHz המשמשים לתקשורת מהטלפון לתחנת הבסיס, ו-832 ערוצים חד כיווניים מ 869MHz עד 894MHz המשמשים לתקשורת מתחנת הבסיס אל הטלפון. כל ערוץ חד כיווני כזה הוא ברוחב 30kHz. - -832 הערוצים מחולקים ל-4 קטגוריות: - - 1. ערוצי שליטה (Control) - מתחנת הבסיס לטלפון הנייד, משמשים לניהול המערכת. - 2. ערוצי איתור (Paging) - מתחנת הבסיס לטלפון הנייד, מיידעים את הטלפון הנייד. - 3. ערוצי גישה (Access) - דו כיווניים, משמשים להתקנת שיחה ומסירת ערוצים. - 4. ערוצי מידע (Data) - דו כיווניים, נושאים קול או מידע. - -מכיוון שכל קטגוריה צריכה מס' ערוצים להעביר את המידע שלה, בסופו של דבר נשארים בערך 45 ערוצים (מתוך ה-832) כדי להעביר בהם מידע. - -  - -**ניהול שיחה** - -לכל טלפון נייד בטכנולוגיית AMPS יש מספר סריאלי באורך 32 ביט, ומספר טלפון באורך 10 ספרות, המידע הזה שמור בזכרון, במכשיר, המיועד לקריאה בלבד. מספר הטלפון מיוצג ע"י 3 ספרות לאזור החיוג (השמורות ב-10 ביטים), ו-7 ספרות של מספר המנוי (השמורות ב-24 ביטים). - -כשהטלפון מופעל הוא סורק 21 ערוצי שליטה קבועים, המתוכנתים מראש, ומוצא את האות החזק מבינהם. לאחר מכן הטלפון משדר לתחנה את 32 הביטים של המס' הסיריאלי ואת 34 הביטים של מס' הטלפון, המידע הזה נשלח בצורה דיגיטלית (למרות שהערוץ אנלוגי), כמה פעמים, עם קוד לתיקון שגיאות (נלמד על קודים כאלו בהמשך). כאשר תחנת הבסיס שומעת את ההכרזה הזו היא מעבירה את ההכרזה ל MSC שמקליט את הקיום של הלקוח החדש שלו ומיידע את MSC הבית של הלקוח (זה שהיה קודם) במיקום הנוכחי של הלקוח. באופן נורמלי, פעולת הרישום מתבצעת פעם ב-15 דק'. - -כדי לבצע שיחה, המשתמש מכניס את המספר אליו הוא מעוניין לחייג, בטלפון הנייד, ולוחץ על send, לאחר מכן הטלפון הנייד מעביר את המספר איתו יש ליצור קשר ואת הזהות שלו עצמו, על גבי ערוצי הגישה (אם קיימת התנגשות הוא מנסה שוב), כאשר תחנת הבסיס שומעת את הבקשה היא מיידעת את ה MSC. אם המספר איתו יש ליצור קשר שייך לאותה חברה, ה MSC מחפש ערוץ פנוי ומשדר אותו חזרה (בעזרת תחנת הבסיס) לטלפון הנייד על גבי ערוצי הגישה. הטלפון הנייד מחליף באופן אוטומטי לערוץ המידע הנחבר ומחכה שהצד השני יענה. - -שיחות נכנסות עובדות באופן שונה, נתחיל בכך שטלפון במצב פנוי (Idle) מאזין תמיד לערוץ האיתור כדי לגלות הודעות המיועדות אליו. כאשר מתבצעת שיחה, נשלחת מנה מ MSC הבית (בו הטלפון הנייד שחייג, נמצא) כדי לאתר איפה היעד (הטלפון אליו מחייגים) נמצא, לאחר מכן נשלחת המנה אל ה MSC בו היעד נמצא, ומשם לתחנת הבסיס שבו הוא נמצא, תחנת הבסיס שולחת שידור broadcast על גבי ערוץ האיתור בסגנון "יחידה 14, האם את שם?", הטלפון הנייד מגיב ("כן") ואז מתבצע שידור נוסף (עדיין על גבי ערוץ האיתור) המיידע את הטלפון הנייד כי יש לו שיחה בערוץ x, המכשיר הנייד מחליף לערוץ שניתן לו ומתחיל לצלצל. - -  - -**הדור השני (2G) של הטלפונים הניידים: קול דיגיטלי** - -הדור הראשון של הטלפון הנייד היה אנלוגי, הדור השני דיגיטלי. למעבר לאות דיגיטלי יש כמה יתרונות מפתח: הוא מאפשר יכולת גדולה יותר, שמושגת ע"י דחיסה של האות. המעבר מאפשר גם הצפנה של האות, ולבסוף הוא מאפשר גם שירותים חדשים כמו הודעות טקסט (SMS). - -בדיוק כמו שבדור הראשון לא הייתה סטנדרטיזציה, כך גם לא היה בדור השני. כמה מערכות שונות פותחו, אך 3 מהם נפרסו בצורה רחבה. [D-AMPS](http://en.wikipedia.org/wiki/Advanced_Mobile_Phone_System#Digital_AMPS) (ראשי תיבות: Digital Advanced Mobile Phone System) זוהי גרסה דיגיטלית של AMPS עם אותו עקרון, אך מתבצע שימוש גם ב TDM כדי לרבב מס' שיחות על אותו ערוץ תדר. השני הוא [GSM](http://en.wikipedia.org/wiki/GSM) (ראשי תיבות: Global System for Mobile Communications) העושה שימוש בריבוב של TDM ו FDM. והאחרון [CDMA](http://en.wikipedia.org/wiki/Code_division_multiple_access) (ראשי תיבות: Code Division Multiple Access), זוהי מערכת שונה לגמרי שלא עושה שימוש ב FDM או ב TDM, למרות שזו אינה המערכת השולטת בדור השני (הלא היא GSM שהייתה בשימוש נרחב ביותר בדור הזה) הטכנולוגיה שלה היא הבסיס למערכות הדור השלישי. - -  - -**GSM - Global System for Mobile Communications** - -GSM החל את חיו בשנות ה-80 כמאמץ לייצר סטנדרט 2G אירופאי אחיד. המערכת הראשונה הונחה כבר בשנת 91 והייתה להצלחה, ונעשה מובן כי GSM לא יהיה סטנדרט אירופאי בלבד. מערכת ה GSM (כמו גם שאר המערכות שנציין בהמשך) מבוססות על מערכות הדור הראשון ומשמרות את החלוקה לתאים, השימוש החוזר בתדרים והניידות מתא לתא באמצעות תהליך המסירה (handoff). השוני בינהם הוא בפרטים. כמו כן ישנם גם הרבה שינויים עליהם לא נדבר כאן, כמו היבטים הנדסיים של המערכת, ובמיוחד העיצוב של המקלט (כדי להתמודד עם התפשטות וריבוי אותות), וסנכרון של המשדרים והמקלטים. - -
    - AMPS -
    - -באיור משמאל ניתן לראות שהארכיטקטורה של GSM ושל AMPS די דומות, למרות שלרכיבים יש שמות שונים. הטלפון הנייד מחולק לברזל עצמו (המכשיר) ול [SIM](http://en.wikipedia.org/wiki/Subscriber_identity_module) (ראשי תיבות: Subscriber Identity Module), הסים מפעיל את המכשיר ומאפשר לרשת ולטלפון הנייד לזהות אחד את השני, ובנוסף מצפין את השיחות בינהם. - -הטלפון הנייד "מדבר" עם תחנת הבסיס דרך ממשק אוויר. כל תחנת בסיס מחוברת ל BSC (ראשי תיבות: Base Station Controller) השולטת במשאבי הרדיו של התא ובנוסף מטפלת בתהליך המסירה (handoff). ה BSC מחובר ל MSC שאחראי על ניתוב השיחות ובנוסף מחובר לרשת ה PSTN. כדי לדעת לנתב את השיחות, ה MSC צריך לדעת איפה המנוי נמצא, ולכן הוא שומר מסד נתונים של הטלפונים באזור אותו הוא מנהל, מסד הנתונים הזה נקרא VLR (ראשי תיבות: Visitor Location Register). בנוסף, קיים עוד מסד נתונים המכיל את המיקום האחרון של כל טלפון (ברשת כולה) ונקרא HLR (ראשי תיבות: Home Location Register). - -
    - Frequency Range -
    - -GSM פועלת על טווח עולמי של תדרים הכולל את 900MHz, 1800MHz, 1900MHz. ברשת הנל מוקצה ספקטרום רחב יותר מזה שב AMPS כדי לתמוך במספר גדול יותר של משתמשים. GSM היא מערכת סלולרית המבצעת שימוש בריבוב בחלוקת תדר [Duplex](http://en.wikipedia.org/wiki/Duplex_(telecommunications)) (דו-קומתי) כמו AMPS, זה אומר שכל טלפון נייד משדר על תדר אחד ומקבל בשני (בתדר אחר) גבוה יותר. למרות זאת, שלא כמו AMPS, ב GSM כל זוג תדרים מרובבים ביחד בחלוקת זמן. בדרך זאת זוג התדרים יכולים להיות מחולקים לכמה טלפונים ניידים. כדי לטפל בכמה טלפונים, ערוצי GSM רחבים יותר מהערוצים ב AMPS (רוחב של 200kHz לעומת 30kHz ב AMPS). ניתן לראות ערוץ כזה ברוחב 200kHz בתמונה משמאל. - -למערכת GSM הפועלת באזור ה 900MHz יש 124 זוגות של ערוצים. כל ערוץ ברוחב 200kHz ותומך ב-8 ערוצים (או יותר נכון תתי-ערוצים) (כמו שציינו, בעזרת ריבוב בחלוקת זמן), כל טלפון מוקצה לחריץ זמן בזוג הערוצים. תיאורטית ניתן לספק בכל תא 992 ערוצים, אך הרבה מהערוצים אינם זמינים, וזאת על מנת להימנע מהתנגשות עם התאים השכנים. באיור משמאל 8 תאי הזמן המושחרים שייכים לאותו חיבור, 4 מהם לאותו כיוון. - -
    - TDM Slot -
    - -ה TDM שרואים באיור למעלה משמאל הוא חלק קטן ממערכת מסגור היררכית גדולה יותר. לכל חריץ TDM יש גם מבנה מסוים. באיור משמאל ניתן לראות גרסה פשוטה יותר של ההירככיה הזו. ניתן לראות בתמונה שכל חריץ TDM מכיל 148 ביטים ש"מעסיקים" את הערוץ ל-577 מיקרו שניות (כולל 30 מיקרו שניות השמורות אחרי כל חריץ למרווח ביטחון). כל חריץ כזה מתחיל ומסתיים ב-3 אפסים בשביל תיחום המסגרת, ובנוסף הוא מכיל שני שדות מידע באורך 57 ביטים לקול או מידע. בין 2 שדות המידע יש שדה סנכרון באורך 26 ביטים שבו המקבל מבצע שימוש על מנת להסתנכרן לגבולות המסגרת של השולח. - -חריץ מידע כזה נשלח כל 547 מיקרו שניות, אך מסגרת כולה משודרת כל 4.615 מילי שניות, מכיוון שהוא חולקת את הערוץ עם עוד 7 משתמשים. קצב השידור של כל ערוץ כזה הוא 270,833bps המחולקים בין 8 משתמשים. כמו שניתן לראות 8 מסגרות מידע כאלו מרכיבות מסגרת TDM אחת, ו-26 כאלו מרכיבות מסגרת ברמה גבוהה יותר הנשלחת כל 120 מילי שניות. מתוך ה-26 האלו, חריץ 12 שמור לשליטה וחריץ 25 שמור לשימוש עתידי, כך שרק 24 חריצים נשארים לשימוש המשתמשים. (חריץ 12 השמור לשליטה משמש לעדכון המיקום, רישום בתחנת הבסיס, והקמת שיחה). - -לבסוף, GSM שונה מ AMPS גם באופן בו הוא מטפל בתלהיך המסירה (handoff). בעוד ב AMPS ה MSC מטפל בתהליך הזה לבד (בלי עזרה של המכשיר הנייד), ב GSM המכשיר מודד את איכות האות שלו מהתחנות בסביבה (בחריצים שלא בשימוש או בזמן Idle), ושולח את המידע הזה ל BSC, ה BSC קובע בעזרת המידע הזה מתי הטלפון הנייד עוזב תא אחד ונכנס לאחר ומבצע את תהליך המסירה. עיצוב זה של התהליך נקרא MAHO (ראשי תיבות: Mobile Assisted HandOff). - -  - -**הדור השלישי (3G) של הטלפונים הניידים: קול ומידע דיגיטלי** - -הדור הראשון של הטלפונים הניידים היה קול אנלוגי, הדור השני היה קול דיגיטלי, והדור השלישי של הטלפונים הניידים (הנקרא גם 3G) מתמקד בקול ומידע דיגיטלי. היו כמה גורמים שהניעו את התעשייה לדור השלישי: הראשון הוא שכמות התעבורה של המידע שעוברת ברשתות, Data, כבר עברה את כמות המידע שמגיע מהעברת קול, והכמות גדלה אקספוננציאלית. השני הוא שתעשיית הטלפון, הבידור והמחשב כולם הפכו לדיגיטלים והם מתכנסים בקצב מהיר. רוב האנשים עוברים למכשירים קלים וניידים כדי לאפשר לעצמם לגלוש באינטרנט, לשלוח מיילים, לשחק בנייד, לראות סרטים / סדרות וכד', הדור השלישי מתמקד בלספק את רוחב הפס הדרוש לכך כדי לשמור על המשתמשים האלו מרוצים. - -כדי להשיג זאת הוצעו כמו הצעות IMT (ראשי תיבות: International Mobile Telecommunications) ולאחר ניפוי נשארו 2: - - 1. WCDMA (ראשי תיבות: Wideband CDMA) שהוצעה ע"י אריקסון ונתמכה ע"י האיחוד האירופאי שקרא לה UMTS (ראשי תיבות: Universal Mobile Telecommunications System). - 2. CDMA2000 שהוצעה ע"י קוואלקום ונתמכה ע"י ארה"ב. - -שתי המערכות דומות אחת לשניה (יותר מאשר שונות) והן מבוססות על CDMA (מערכת WCDMA משתמשת בערוצים ברוחב 5MHz בעוד CDMA2000 משתמשת בערוצים ברוחב 1.25MHz). והאמת היא שאם היינו שמים את המהנדסים של קוואלקום ואריקסון בחדר אחד, הם כנראה היו מגיעים לתקן אחיד ללא כל בעיות, אולם הבעיה פה לא הייתה הנדסית, אלא פוליטית. האירופאים דחפו לרשת שתעבוד במקביל ל GSM, והאמריקאים רצו רשת שתתמוך בזאת שכבר פרוסה אצלם (IS-95). בנוסף, כל אחד תמך בחברה המקומית שלו (קליפורניה ושוודיה). - -CDMA לא משתמש בריבוב TDM או FDM, במקום זאת הוא עושה שימוש בסוג של ערבוב, בו כל משתמש משדר על אותו תדר באותו זמן. כשעקרון זה הוצג לראשונה, התעשייה התייחסה אליו באותה תגובה שקיבל קולומבוס מהמלכה איזבלה כשהציע להגיע להודו ע"י הפלגה לכיוון השני. למרות זאת, ובגלל ההתעקשות של קוואלקום, CDMA הצליח במערכת דור 2 (2G) ב IS-95 ונעשה לבסיס עבור מערכות דור 3. - -כדי ש CDMA יעבוד בסביבה הסלולרית יש להתאים אותו יותר מהטכניקה הבסיסית שתיארנו כבר בחלק הקודם. באופן סצפיפי, תיארנו CDMA מסונכרן, שבו רצף ה chip אורטוגונלי (מאונך) בדיוק. העיצוב הזה עובד כאשר כל המשתמשים מסונכרנים על זמן ההתחלה וכל הקודים (רצף ה chipים) שלהם מתחילים באותו הרגע, תנאי זה מתקיים כשמדובר בתחנת הבסיס, שכן תחנת הבסיס משדרת לכל הטלפונים הניידים בתא שלה, ויכולה לשדר את הקודים (רצף ה chipים) של כל הטלפונים הניידים, באותו הזמן, לכולם (ז"א שהאותות יהיו מאונכים אחד לשני וניתן יהיה להפרידם). אך ברגע שאנו רוצים לשדר מהטלפון לתחנה, התחנה לא תוכל להפריד שידורים של כמה טלפונים מכיוון שהתחנת הבסיס תשמע את השידורים שלהם בזמנים שונים. כדי לאפשר לטלפון הנייד לשלוח מידע לתחנת הבסיס ללא סנכרון, אנחנו רוצים רצף chipים שיהיו אורתוגונלים אחד לשני בכל הקיזוזים האפשריים (שחיבור כל האיברים במיקום הזהים, של 2 תחנות כלשהן יתן 0), ואנו רוצים זאת לא רק כשהם מסונכרנים לזמן ההתחלה. - -למרות שלא ניתן למצוא רצף chip אורתוגונלי בדיוק למקרה הכללי הזה, רצפים [Pseudorandom](http://en.wikipedia.org/wiki/Pseudorandom_number_generator) (מחולל רצפים פסאודו אקראיים) מתקרבים מספיק. וזה מאפשר למקבל לסנן את השידורים הבלתי רצויים מהשדר המתקבל. ולכן הרצפים הפסאודו רנדומליים מאפשרים לתחנת הבסיס לקבל שידורי CDMA מטלפונים ניידים עצמאיים (לא מסונכרנים). אולם, ההנחה העקרית שהנחנו הינה שכל רמות הכוח של המכשירים יהיו אותו הדבר בצד המקבל (במקרה שלנו, תחנת הבסיס). אותם רמות כוח שמתקבלות בתחנת הבסיס תלוית בכמה רחוק המשדר נמצא ולפיכך בכמה כוח הם צרכים כדי לשדר. אז כיצד אנחנו יודעים שההנחה אכן נכונה? כדי להבטיח את נכונותה כל מכשיר ישדר לתחנת הבסיס ברמת הכוח ההופכית שהוא קיבל מתחנת הבסיס (במילים אחרות: טלפון נייד שקיבל אות חלש מתחנת הבסיס ישתמש ביותר כוח מאחד שקיבל אות חזק מתחנת הבסיס), ולשם דיוק רב יותר, כל תחנת בסיס תספק פידבק למכשיר (להגדיל, להנמיך, או להשאיר) על כוח השידור (הפידבק מתבצע 1500 פעמים בשניה, מכיוון ששליטה טובה בכוח השידור חשובה כדי לצמצם הפרעות ורעשים למינימום הניתן). - -עוד שיפורים מסכמת ה CDMA הבסיסית מתבצעים כדי לאפשר למשתמשים שונים לשדר מידע בקצבים שונים. הטריק הזה מושג באופן טבעי ב CDMA ע"י קיבוע של הקצב בו משדרים רצפי chipים (קודים) והקצאה של אורך רצף (קוד) שונה. לדוגמה, ב WCDMA קצב השידור של רצף chip הוא 3.84Mchips/sec והפקת הקוד משתנה מרצף chip של 4 עד ל-256. ברצף chip עם קוד של 256, נשאר בערך 12kbps (אחרי תיקון טעויות), והרוחב הזה מספיק לשיחת טלפון קולית. אך אם נקצה רצף chip של 4 קודים, קצב שליחת המידע של המשתמש יגיע עד (בערך) 1Mbps. - -אחרי שטיפלנו בבעיות שמנעו מ CDMA לעבוד, נתאר את שלושת היתרונות העקריים שלו: - -
    - Soft Handoff -
    - - 1. בראש ובראשונה CDMA משפר את היכולת ע"י היתרון של שימוש בחלקי זמן קטנים שבהם המשדרים שקטים. בכל שיחת טלפון, צד אחד של השיחה נמצא בשקט (לא מדבר ולפיכך לא משדר מידע) כל זמן שהצד השני מדבר. בממוצע הקו "עסוק" כ40% מהזמן. אך חלקי הזמן האלו הם קטנים וקשה לצפות אותם, ולכן מערכת TDM ו FDM, לא מסוגלות לבצע שימוש בחריצי הזמן השקטים האלו. לעומתם, ב CDMA, בכך שאתה לא משדר, אתה (בתור משתמש אחד) מוריד את ההפרעות למשתמשים האחרים (באותו התא), וברגע שמדובר על כמות של משתמשים שלא מפריעים (כל אחד לזמן קצר, כל פעם) אחוז ההפרעה הכללי בתא יורד, ולכן ניתן לתת שירות למספר גדול יותר של שיחות בו זמנית. - 2. ב CDMA, כל תא משתמש באותו התדר (שלא כמו ב GSM וב AMPS, אין צורך לבצע ריבוב בחלוקת תדר על מנת להפריד בין השידורים של המשתמשים השונים). היתרון הוא שזה מונע מהמהנדסים לבצע תכנון תדרים מסובך ומגדיל את היכולת של התא (במקום חלוקה צרה של רצועת תדר, בתא מבוצע שימוש בכל רצועת התדר האפשרית, החלוקה נעשית כמובן ע"י הקוד). בנוסף, זה מאפשר לתחנת הבסיס לבצע שימוש בכמה [אנטנות כיווניות](http://en.wikipedia.org/wiki/Sector_antenna) (במקום ב[אנטנה Omnidirectional](http://en.wikipedia.org/wiki/Omnidirectional_antenna)), אנטנות כיווניות מרכזות את האות לכיוון מסויים ומפחיתות את האות, ומכאן גם את ההפרעות בכיוונים אחרים (כמובן שהתחנה צריכה לעקוב אחרי המשתמש כשהוא נע מסקטור לסקטור (מאנטנה כיוונית לאנטנה כיוונית) בתוך התא, אך זה קל לבצע ב CDMA כי כולן משתמשות באותם תדרים). - 3. CDMA מאפשר לבצע מסירה רכה ([soft handoff](http://en.wikipedia.org/wiki/Soft_handover)), שבו תחנת הבסיס החדשה מקושרת לטלפון הנייד לפני שתחנת הבסיס הישנה התנתקה ממנו. בדרך הזו, כמות השיחות המתנתקות בזמן תנועה ירד משמעותית. CDMA מצליח לבצע זאת מכיוון שכל התחנות עובודת באותו התדר, והטלפון הנייד לא צריך להחליף תדר כדי להתחבר לתחנה החדשה. ניתן לראות איור של הפעולה בצד שמאל למעלה. - -  - -### 8. טלוויזיה וכבלים - -לאחר שעברנו על מערכת הטלפוניה הציבורית (הקווית) והסלולרית, ישנו עוד שחקן שיהיה בתפקיד חשוב שמשווע לחיבור אינטרנטי: רשתות הטלוויזיה בכבלים. - -  - -**אנטנת טלוויזיה קהילתית** - -
    - Headend -
    - -חברות הכבלים יזמו בסוף שנות ה-40, דרך לספק קליטה טובה יותר לבתים באזורים מרוחקים או הרריים. תחילה, המערכת הכילה אנטנה גדולה על גבי גבעה (כדי לקלוט את האות של רשתות הטלוויזיה), מגבר הנקרא headend (על מנת לחזק את האות), וכבל קואקסיאלי (כדי להעביר את האות לבתים של האנשים). ניתן לראות את הסכמה של הדרך הראשונית הזו בצד שמאל. בגלל החלוקה הקהילתית של האנטנה, בשנים הראשונות, טלוויזיה בכבלים נקראה אנטנת טלוויזיה קהילתית. - -ב-1974, חברת [טיים](http://en.wikipedia.org/wiki/Time_Inc.) העלו ערוץ חדש, עם תכנים חדשים (סרטים) שהיה מופץ באופן בלעדי בכבלים. במהרה החלו לעקוב אחריהם עוד ערוצים שהציעו את מרכולתם באופן בלעדי בכבלים, והתמחו בתכנים ספציפים כגון חדשות, ספורט, בישול וכ'ו. התפתחות הזו האיצה 2 שינויים בתעשייה: הראשון, התאגידים הגדולים החלו לקנות מערכות כבלים והניחו כבלים חדשים כדי להשיג עוד מנויים. השני, כעת היה צורך לחבר כמה מערכות, לעיתים קרובות בערים מרוחקות זו מזו, על מנת להפיץ את ערוצי הכבלים החדשים. חברות הכבלים החלו להניח כבלים בין הערים על מנת לחבר את כולם למערכת אחת. - -  - -**אינטרנט על גבי הכבלים** - -
    - HFC -
    - -במהלך השנים, מערכת הכבלים גדלה והוחלפה, בין הערים, בסיב ברוחב פס מהיר. מערכות בעלות סיב למרחקים ארוכים וכבל קואקסיאלי לבתים (כמו במערכות הכבלים) נקראות מערכות HFC (ראשי תיבות: [Hybrid Fiber Coax](http://en.wikipedia.org/wiki/Hybrid_fibre-coaxial)).מי שאחראי על הפיכת הממשק מאלקטרוני לאופטי (ולהפך) אלה ה Fiber nodes. מכיוון שרוחב הפס של הסיב יותר גדול מזה של הכבל הקואקסיאלי, כל צומת (Fiber nodes) מספקת מידע לכמה כבלים קואקסיאלים. ניתן לראות מערכת HFC כזו באיור (a) משמאל. - -במהלך העשור האחרון, הרבה חברות כבלים החליטו להיכנס לעסקי האינטרנט (ISP) ואף לטלפוניה. אך היו כמה בעיות טכניות שהקשו עליהן את הכניסה החלקה, בראש ובראשונה, כל מגברי האות שהיו פועלים לצד אחד בלבד היו צרכים להיות מוחלפים בכאלה שעובדים לשני הצדדים (דו-כיווניים) כדי לתמוך בהעלאה בנוסף להורדה. בזמן שהם ביצעו את ההחלפה הזו לאורך כל הרשת, חברות הכבלים שכרו חיבורים מחברות הטלפוניה (על גבי רשת הטלפוניה כמובן) להעלאה בלבד. - -אך ישנו שוני מהותי נוסף בין המערכת HFC באיור (a) משמאל, למערכת הטלפוניה באיור (b) משמאל שהרבה יותר קשה לפתרון. במערכת HFC, כבל אחד שעובר בשכונה מחולק לכל הבתים, בעוד במערכת הטלפוניה לכל בית יש את הלולאה מקומית (local loop) (זוג חוטים שזורים) אישיים. בעוד לשידור הפצה (Broadcast) זהו מצב מתאים באופן טבעי (כל התוכניות מופצות על הכבל, וזה לא משנה אם ישנם 10 צופים או 10,000 צופים), אך כשאותו הכבל משמש לחיבור לאינטרנט, זה משנה אם יש 10 משתמשים או 10,000. אם אחד המשתמשים מחליט להוריד קובץ גדול, רוחב הפס שאמור לשמש את השכנים (על אותו הכבל) קטן. תעשיית הכבלים פתרה את הבעיה הזו ע"י פיצול של כבלים ארוכים ופריסה של עוד כבלים קואקסיאלים באותו שטח, וחיבור של כל אחד מהם ישירות אל הצומת (fiber node). בדרך כלל צומת כזו מסוגלת לנהל כ-500 עד 2,000 בתים. - -  - -**הקצאת ספקטרום** -ביטול כל ערוצי הטלוויזיה בכבלים, ושימוש של התשתית רק בשביל לספק גישה לאינטרנט, בטח יצור כמות מכובדת של לקוחות זועמים, ובגלל זה חברות הכבלים מהססות בנושא. בנוסף, רוב הערים מבצעות רגולציה כבדה על השימושים של הכבל ומה עובר בו. לכן ספק כבלים לא יורשה לעשות זאת, גם אם ירצה. כתוצאה מכך הם צרכים למצוא דרך לאינטרנט ולטלוויזיה להתקיים ביחד על אותו כבל (אותה תשתית). - -
    - Spectrum Allocation -
    - -הפתרון הוא לבנות ריבוב בחלוקת תדר. ערוצי הכבלים בצפון אמריקה עובדים על 54MHz – 550MHz (חוץ מרדיו FM), כל ערוץ ברוחב 6MHz (כולל מגני פס – guard bands), ויכול לשאת ערוץ טלוויזיה אנלוגי אחד או כמה ערוצי טלוויזיה דיגיטליים. באירופה הקצה התחתון הוא בערך ב 65MHz והערוצים הם ברוחב של 6-8MHz (בגלל הרזולוציה הגבוהה יותר שדורשים PAL ו SECAM), חוץ מזה הסכמה דומה. את סכמת החלוקה ניתן לראות באיור משמאל, וכמו שניתן לראות הערוצי העלאה הינם ברצועה 5-42MHz (קצת יותר גבוה באירופה) ובתדרים הגבוהים משתמשים להורדה. - -שימו לב שמכיוון שכל האותות של הטלוויזיה הם בכיוון הורדה, ניתן להשתמש במגברי אות (amplifiers) להעלאה שעובדים רק בטווחים 5-42MHz ובמגברי אות להורדה שעובדים רק בטווחים 54MHz ומעלה. בנוסף, כדי לשדרג את המגברים, המפעילה צריכה לשדרג גם את ה headend, ממגבר "טיפש" למערכת מחשוב דיגיטלית בעלת סיב עם רוחב פס רחב כדי להתממשק עם ISP. לעיתים החברות שידרגו גם את השם מ headend ל [CMTS](http://en.wikipedia.org/wiki/Cable_modem_termination_system) (ראשי תיבות: Cable Modem Termination System). - -  - -**מודם כבלים** -כמו שאנו יודעים, גישה לאינטרנט דורשת מודם, שמחובר מצד אחד למחשב ומהצד השני לרשת הכבלים (במקרה הזה). בימים הראשונים של האינטרנט על גבי רשת הכבלים, לכל ספקית היה כבל משלה למודם, שהותקן במיוחד ע"י טכנאי החברה. אך במהרה נראה היה כי סטנדרט פתוח ייצור תחרות גדולה יותר, יוריד את המחירים, יעודד שימוש נרחב יותר, ואף יגרום ללקוחות לרכוש את הכבלים בחנויות ולהתקינם באופן עצמאי (בדומה לשוק הראווטרים כיום). - -בהמשך לכך, חברות הכבלים הגדולות שיתפו פעולה עם חברה הנקראת [CableLabs](http://www.cablelabs.com/) על מנת לייצר סטנדרט לכבלי מודמים ולבחון את המוצרים בתאמה לתקן. הסטדנרט אותו היא יצרה נקרא [DOCSIS](http://en.wikipedia.org/wiki/DOCSIS) (ראשי תיבות: Data Over Cable Service Interface Spcification). הגרסה הראשונה שלו (1.0) שוחררה בשנת 1997 ולאחריה יצאה הגרסה 2.0 בשנת 2001, התקן בגרסתו השניה התמקד בהגדלת קצבי העלאה על מנת לאפשר תמיכה טובה יותר בשירותים סימטריים (כמו טלפונית IP, או VoIP). והגרסה האחרונה של התקן, 3.0, ששוחררה ב-2006, עושה שימוש בפס רחב יותר כדי להגדיל את הקבצים בשני הכיוונים (העלאה והורדה). -* את טבלת המהירויות של כל תקן ניתן לראות [כאן](http://en.wikipedia.org/wiki/DOCSIS#Speed_tables). -** בנוסף, יש לציין כי קיים סטנדרט אירופאי מקביל הנקרא EuroDOCSIS. - -ממשק המודם-למחשב הוא פשוט, בדרך כלל הוא מתבצע דרך חיבור Ethernet (ולפעמים דרך USB). לעומתו, הקצה השני (מהמודם-לרשת) מסובך הרבה יותר, והוא עושה שימוש ב FDM, TDM ו CDMA כדי לשתף את רוחב הפס בין המנויים. כשאנו מחברים כבל אתרנט מהשקע בקיר אל המודם, הוא סורק את זרם הנתונים המתקבל בערוץ ההורדה בחיפוש אחר מנה מיוחדת שמשודרת ע"י ה headend מפעם לפעם, כדי לספק את הפרמטרים של המערכת למודמים שהתחברו כרגע, וכשהמודם מוצא את המנה הזו, הוא (המודם החדש) מכריז על נוכחותו על גבי אחד מערוצי העלאה. ה headend מגיב ע"י ייעוד של ערוצי העלאה והקצאתם לאותו מודם (יש לציין כי ההקצאה יכולה להשתנות לאחר מכן אם ה headend יראה כי יש בכך צורך על מנת לאזן את העומס). - -השימוש בערוצי 6MHz או 8MHz הוא חלק מריבוב ה FDM. כל מודם שולח מידע דרך הכבל שלו על גבי ערוץ העלאה אחד וערוץ הורדה אחד (או כמה ערוצים כאלו בגרסה 3.0). הסכמה הרגילה הינה לקיחה של כל ערוץ הורדה 6MHz (או 8) ולאפנן אותו עם QAM-64 (תרשים קונסטלציה בעל 64 שילובים של אמפליטודות ופאזות) או, אם איכות הכבל טובה באופן יוצא דופן QAM-256. עם ערוץ ברוחב 6MHz ובאפנון QAM-64 ניתן לשדר ב 36Mbps (כשמפחיתים מזה את התקורה נשאר לנו 27Mbps, וב QAM-256 לאחר התקורה נשאר 39Mbps). - -להעלאה, יש יותר הפרעות RF (תדרי רדיו - Radio Frequency) מכיוון שהמערכת לא תוכננה במקור למידע, ורעש מכמה מנויים מתועל אל ה headend כך שדרושה סכמה שמרנית יותר. הסכמות כאן משתנו מ QPSK ועד ל QAM-128, כשכמה מהסמלים משמשים להגנת שגיאות בעזרת אפנון [Trellis Code](http://en.wikipedia.org/wiki/Trellis_modulation). לאחר מכן עושים שימוש ב TDM כדי לחלוק את רוחב הפס בהעלאה לשימוש של כמה מנויים. אחרת השידורים שלהם יתנגשו ב headend. הזמן מחולק למיני חריצים ומנויים שונים שולחים בחריצים שונים. כדי לגרום לזה לעבוד כל מודם קובע את המרחק שלו מה headend ע"י שליחה של מנה מיוחדת אל ה headend ורואה כמה זמן לוקח לו לקבל תשובה (תהליך זה נקרא [ranging](http://en.wikipedia.org/wiki/Ranging)). ה headend מכריז על תחילת סיבוב חדש של מיני חריצים, אך יריית הפתיחה הזאת לא נשמעת בכל המודמים באופן אחיד (באותו הזמן) בגלל המרחק שלהם מה headend וזמן ההגעה שדרוש למנה "לחלחל" בכבל. בכך שכל מודם יודע מה המרחק שלו מה headend, כל מודם יכול לחשב לפני כמה זמן המיני חריץ הראשון התחיל באמת. (מיני חריץ הוא תלוי אורך הרשת, מנה טיפוסית היא 8 בתים). - -
    - Upload Download Scheme -
    - -בזמן האתחול, ה headend מקצה לכל מודם מיני חריץ לשימוש לשם בקשה לרוחב פס להעלאה. וכשהמחשב רוצה לשלוח מנה, הוא מעביר את המנה אל המודם, שמבקש את מס' המיני חריצים הדרושים לו. אם הבקשה התקבלה, ה headend שולח אישור למודם (בערוץ ההורדה) שאומר למודם איזה מיני חריצים שמורים למנה שלו. לאחר מכן המנה נשלחת מתחילת המיני חריץ הראשון השמור לה (ניתן לבקש מיני חריצים נוספים בשביל עוד מנות על גבי הכותרת (header) של המנה - ניגע בזה יותר בשכבות הבאות). - -ככלל, מודמים מרובים יוקצו לאותו מיני חריץ, מה שיוביל להתנגשות, וישנם 2 דרכים שונות לטפל בזה: הראשונה היא שימוש בריבוב CDMA על מנת לחלוק את המיני חריץ. זה פותר את הבעיה כי כמו שאנחנו יודעים, בעזרת רצף קוד CDMA כל המנויים יכולים לשלוח מידע בו זמנית. הדרך השנייה היא לא ע"י שימוש ב CDMA, ובמקרה הזה לא יהיה אישור לבקשה בגלל ההתנגשות. במקרה הזה המודם מחכה זמן אקראי ומנסה לשלוח שוב, אם הוא מצליח-מה טוב, אם לא-הוא מחכה זמן כפול מהזמן האקראי שחיכה מוקדם (למי שכבר מכיר, האלגוריתם הזה הוא פשוט ALOHA מחורץ עם השהייה בזמן מעריכי). - -ערוצי ההורדה מנוהלים באופן שונה מערוצי העלאה. כהתחלה, יש רק שולח אחד (ה headend), כך שלא יכולה להיווצר התנגשות ואין צורך במיני חריצים (ריבוב בחלוקת זמן - TDM). בנוסף, התנועה על גבי ערוצי ההורדה היא לרוב גדולה הרבה יותר מערוצי העלאה, לכן יש שימוש במנה בעלת גדול קבוע - 204 בתים (כשבחלק ממנה נעשה שימוש בקוד תיקון טעויות [Reed-Solomon](http://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction) ועוד תקורה לשימושים שונים, מה שמשאיר 184 בתים). - -  - -### לסיכום - -השכבה הפיזית היא הבסיס לרשת כולה. הטבע מטיל שתי מגבלות מהותיות על כל הערוצים, ואלו קובעות את רוחב הפס שלהם. המגבלות האלו הן חסם נייקוויסט (המטפל בערוצים ללא רעש) וחסם שנון (המטפל בערוצים בעלי רעש). - -תמסורת (בעברית: תווך) יכולה להיות מודרכת או לא מודרכת. התמסורות המודרכות (או חסומות) העיקריות הם חוטים שזורים, כבל הקואקסיאלי, וסיבים אופטיים. בעוד תמסורות לא מודרכות כוללות: גלי רדיו, גלי מיקרו-גל, אינפרא אדום, לייזרים (על גבי האוויר), ולווינים. - -שיטות אפנון דיגיטליות שולחות ביטים על גבי תמסורות מודרכות ולא מודרכות כאותות אנלוגיים. קוי קוד פועלים ב baseband, ואתות יכולים להיות ממקומים על גבי passband בעזרת אפנון האמפליטודה, תדר, והפאזה. בנוסף, ערוצים יכולים להיות משותפים בין משתמשים עם ריבוב בחלוקת זמן, תדר, וקוד. - -הרכיב העקרי של מערכות הטלפוניה ברמת WAN אלה הלולאות המקומיות (local loops), צמתי trunks, והמתגים. ADSL מציע מהירות של עד 40Mbps על גבי לולאות מקומיות. ו PON מביא את הסיב עד לבית (הק"מ האחרון) ומספק מהירויות גבוהות עוד יותר. ה Trunks מעבירים מידע דיגיטלי. הם מאופננים בעזרת WDM כדי לספק מספר רב קישורים בעלי יכולת גבוהה על גבי סיבים אחדים, כמו כן הם גם מרובבים בעזרת TDM כדי לשתף כל קישור כזה בין כמה משתמשים. - -טלפונים ניידים נמצאים היום בתפוצה רחבה לשם תקשורת קול, ומידע (תחום שהולך וגדל), והם עברו 3 דורות. הדור הראשון, 1G, היה אנלוגי ונשלט ע"י AMPS. הדור השני, 2G, היה דיגיטלי כש GSM היה הנפוץ ביותר. והדור השלישי, 3G, גם הוא דיגיטלי ומבוסס על CDMA, ועושה שימוש ב WCDMA וב CDMA2000. - -מערכת חלופית לגישה לאינטרנט היא מערכת הכבלים. היא התפתחה מתשתית של כבל קואקסיאלי לתשתית המשולבת סיב אופטי וכבל קואקסיאלי, ומטלוויזיה לטוויזיה ואינטרנט. באופן פוטנציאלי היא מציעה רוחב פס גבוהה, אך רוחב הפס הזה מחולק עם שאר המשתמשים ולכן המהירות תלויה באופן רב בכמות המשתמשים המחוברים לרשת זו. - -מקווה שהצלחתי לחדש דבר או שניים, ואפילו (למי שכבר מכיר) להוריד כמה אסימונים. השתדלתי לכתוב כמה שיותר (אך לא שלא לצורך), להרחיב ולפשט הסברים מסובכים, ואם יש שאלות אשמח לענות עליהן בתגובות. diff --git a/data/_oldPosts/2014-05-18-linked-list.md b/data/_oldPosts/2014-05-18-linked-list.md deleted file mode 100644 index f9ca235..0000000 --- a/data/_oldPosts/2014-05-18-linked-list.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: רשימה מקושרת (Linked List) -author: nirgn -layout: post -summary: "רשימה מקושרת היא מבנה נתונים שבו העצמים ערוכים בסדר לינארי. אולם בניגוד למערך, שבו הסדר הלינארי נקבע על ידי אינדקסים, ברשימה מקושרת הסדר נקבע על ידי מצביעים הכלולים בכל אחד מן העצמים." -category: Data Structures ---- -רשימה מקושרת היא מבנה נתונים שבו העצמים ערוכים בסדר לינארי. אולם בניגוד למערך, שבו הסדר הלינארי נקבע ע"י אינדקסים, ברשימה מקושרת הסדר נקבע ע"י מצביעים הכלולים בכל אחד מן העצמים. - - - -באמצעות רשימה מקושרת ניתן לייצא קבוצות דינמיות באופן פשוט וגמיש (אם כי לא בהכרח ביעילות). רשימה יכולה להיות חד-מקושרת או דו-מקושרת, ממוינת או לא ממוינת, מעגלית או לא מעגלית. -ברשימה חד מקושרת (singly linked) האיברים אינם מכילים את השדה prev. -ברשימה ממוינת (sorted), הסדר הלינארי של איברי הרשימה מתאים לסדר הלינארי של המפתחות המאוחסנים בהם, איבר המינימום הוא ראש הרשימה ואיבר המקסימום הוא הזנב. -ברשימה בלתי ממוינת (unsorted), האיברים מופיעים בסדר כלשהו. -ברשימה מעגלית (circular list), המצביע prev של ראש הרשימה מצביע על זנבה, והמצביע next של זנב הרשימה מצביע על ראשה. רשימה כזו ניתן לראות כמעגל של איברים. - -כפי שניתן לראות בתמונה למטה, L הוא עצם המכיל שדה מפתח key ושני שדות נוספים של מצביעים: next ו prev. בהינתן איבר x ברשימה, `[next[x` מצביע על האיבר העוקב לו ברשימה המקושרת, ו `[prev[x` מצביע על האיבר הקודם לו. אם `prev[x] = NIL`, אין ברשימה איבר עוקב ל x (ז"א שהוא האיבר האחרון, או זנב (tail) הרשימה). באותו אופן `[head[L` מצביע על האיבר הראשון ברשימה. אם `head[L] = NIL`, הרשימה ריקה. - - -ב (i) אנו רואים רשימה דו מקושרת L המייצגת את הקבוצה {16 ,9 ,4 ,1}. כל איבר ברשימה הוא עצם בעל שדה מפתח ושדות מצביעים (המיוצגים כאן ע"י חיצים) לעצם הבא (next) ולעצם הקודם (prev). השדה next של זנב הרשימה והשדה prev של ראש הרשימה - ערכם NIL (במיוצג כאן ע"י אלכסון), ו `[head[L` מצביע על ראש הרשימה. השלב השני (ii) הוא לאחר ביצע `(LIST-INSERT(L, x`, כאשר `key[x] = 25`, לכן כעת העצם החדש בעל ערך המפתח 25 נמצא בראש הרשימה. העצם החדש של ראש הרשימה (25) מצביע על ראש הרשימה הקודם (שהמפתח שלו 9). והשלב השלישי (iii) הוא לאחר קריאה ל `(LIST-DELETE(L, x`, כאשר x מצביע על עצם אשר המפתח שלו הוא 4. - -  - -**חיפוש ברשימה מקושרת** - -השגרה מוצאת את האיבר הראשון בעל המפתח k ברשימה L באמצעות חיפוש לינארי פשוט, ומחזירה מצביע לאיבר זה (אם אינה מוצאת ברשימה איבר בעל המפתח k, היא מחזירה NIL). - -```c -LIST-SEARCH (L, k) -x <- head[L] -while (x != NIL and key[x] != k) do - x <- next[x] -return x -``` -זמן הריצה (O(n. - -  - -**הכנסה לרשימה מקושרת** - -בהינתן איבר x אשר שדה המפתח שלו כבר מכיל ערך, השגרה תכניס אותו לראש הרשימה המקושרת. - -```c -LIST-INSERT (L, x) -next[x] <- head[L] -if (head[L] != NIL) - prev[head[L]] <- x -head[L] <- x -prev[x] <- NIL -``` -זמן הריצה (O(1. - -  - -**מחיקה מרשימה מקושרת** - -השגרה מוחקת איבר x מהרשימה המקושרת L. היא מקבלת מצביע לx ומסירה אותו באמצעות עדכון מצביעים. מפני שהשגרה מקבלת מצביע ולא האיבר, אם אנו רוצים למחוק ערך נתון, יש קודם לחפשו ברשימה המקושרת (באמצעות השגרה LIST-SEARCH, כדי לקבל מצביע לאותו איבר, ורק לאחר מכן למחוק אותו בעזרת מצביע זה). -> יש לציין כי השגרה מבצעת טיפול מיוחד במקרי הקצה (ראש וזנב הרשימה). - -```c -LIST-DELETE (L, x) -if (prev[x] != NIL) - next[prev[x]] <- next[x] -else head[L] <- next[x] -if (next[x] != NIL) - prev[next[x]] <- prev[x] -``` -זמן הריצה (O(1. - -  - -### זקיפים - -זקיף (באנגלית: Sentinel) הוא עצם דמה המאפשר לנו לפשט את הטיפול במקרי הקצה. לדוגמה, נוסיף לרשימה L עצם `[nil[L`, המייצג NIL אולם כולל את כל השדות של איברי הרשימה האחרים. כל התייחסות בקוד לNIL תוחלף בהתייחסות לזקיף `[nil[L`. כפי שנראה באיור שלמטה שינוי זה הופך רשימה דו מקושרת רגילה לרשימה דו מקושרת מעגלית עם זקיף, כאשר הזקיף `[nil[L` מוצב בין ראש הרשימה לבין זנבה. -השדה `[[next[nil[L` מצביע על ראש הרשימה, ו `[[prev[nil[L` מצביע על זנבה. ובאופן דומה השגה next של זנב הרשימה והשדה prev של ראש הרשימה מצביעים שניהם על `[nil[L`. ומכיוון ש `[[next[nil[L` מצביע על ראש הרשימה, נוכל לוותר על המאפיין `[head[L` ולהחליף את ההתייחסות אליו ב `[[next[nil[L`. - -  - -**חיפוש ברשימה מקושרת** - -הקוד של LIST-SEARCH אינו משתנה, פרט להתייחסויות ל NIL ול [head[L, שמשנים אותן כמו שתיארנו לעיל. - -```c -LIST-SEARCH (L, k) -x <- head[L] -while (x != NIL and key[x] != k) do - x <- next[x] -return x -``` - -  - -**הכנסה לרשימה מקושרת** - -```c -LIST-INSERT (L, x) -next[x] <- next[nil[L]] -prev[next[nil[L]] <- x -next[nil[L]] <- x -prev[x] <- nil[L] -``` - -מחיקה מרשימה מקושרת: הקוד נשאר כשהיה - ללא שינוי. diff --git a/data/_oldPosts/2014-06-01-arduino-3.md b/data/_oldPosts/2014-06-01-arduino-3.md deleted file mode 100644 index 773d19a..0000000 --- a/data/_oldPosts/2014-06-01-arduino-3.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: '3 - מוסיפים חיישנים למעגל' -author: nirgn -layout: post -summary: "מתגים הם דבר נהדר, אך בעולם האמיתי יש הרבה יותר מ On ו Off. למרות שהארדואינו הוא כלי דיגיטלי הוא יכול לקבל מידע מחיישנים אנלוגיים כדי למדוד דברים כמו טמפרטורה או אור. כדי שנוכל לעשות את זה, נשתמש בממיר המובנה של הארדואינו מאנלוגי לדיגיטלי (ADC, ראשי תיבות: Analog-to-Digital Converter)." -category: Arduino ---- -מתגים הם דבר נהדר, אך בעולם האמיתי יש הרבה יותר מ On ו Off. למרות שהארדואינו הוא כלי דיגיטלי הוא יכול לקבל מידע מחיישנים אנלוגיים כדי למדוד דברים כמו טמפרטורה או אור. כדי שנוכל לעשות את זה, נשתמש בממיר המובנה של הארדואינו מאנלוגי לדיגיטלי (ADC, ראשי תיבות: Analog-to-Digital Converter). הפינים האנלוגיים הנמצאים מ A0 עד A5 מחזירים ערך בין 0-1023, שממפה את הטווח שבין 0 ל-5 וולט. - - - -  - -בפרויקט הזה נבצע שימוש בחיישן טמפרטורה על מנת למדוד כמה חם העור שלנו. לחיישן יש 3 פינים: הראשון מתחבר לאדמה, השני מתחבר למקור כוח, והשלישי מחזיר פלט בדמות משתנה של מתח. ב Sketch (ה IDE של הארדואינו), נקרא את הפלט מהחיישן ונשתמש בפלט זה כדי להדליק ולכבות נורת LED, שבעצם תצביע כמה חמה היד / אצבע שלנו. - -> יש כמה סוגים של חיישנים, מה שאני אשתמש בו הוא TMP36, סוג החיישן נוח לשימוש בפרויקט הזה מכיוון שהוא מוציא כפלט מתח שמשתנה באופן ישיר ופורפורציונלי לטמפרטורה במעלות סלצזיוס. - -ה Sketch מגיע עם כלי הנקרא serial monitor המאפשר לנו לדווח חזרה תוצאות מהמיקרו-בקר. בעזרת ה serial monitor, אנחנו יכולים להשיג מידע על מצב החיישנים ולקבל מושג על מה שקורה במעגל החשמלי ובקוד, בזמן ריצה. - -  - -### חיבור הרכיבים - -בדיוק כפי שעשינו עד כה, נחבר ללוח המטריצה 5V ו GND (אדמה) בעזרת חוטים מגשרים. לאחר מכן נמקם את שלושת נורות ה LED על גבי לוח המטריצה ולקתודה (הרגל הקצרה) של כל LED נחבר נגד 220Ω אל המינוס (אדמה) שבלוח המטריצה. לאנודה (הרגל הארוכה) נחבר חוט מגשר אל הפינים 2,3,4 שבלוח הארדואינו (בהתאמה), הנורות יהיו אינדיקטורים למצבים השונים. - -כעת נמקם את חיישן הטמפרטורה על גבי לוח המטריצה, כשהצד העגול שלו פונה החוצה (הפוך מהארדואינו) מכיוון שסדר ההרגלים חשוב. נחבר את הרגל השמאלית (מסתכלים מהצד השטוח) אל מקור הכוח (עמודת הפלוס בלוח המטריצה), והרגל הימנית אל האדמה (עמודת המינוס בלוח המטריצה). את הרגל האמצעית של החיישן נחבר אל פין A0 (פין אנלוגי) שנמצא על גבי לוח המטריצה. -להלן סכמה ואיור להמחשה: - -
    - Arduino Project number 3 -
    - -  - -### הקוד - -קבועים דומים למשתנים בכך שהם מאפשרים לנו לתת שמות ייחודים, אך בניגוד למשתנים הם אינם יכולים להשתנות במהלך התוכנית (ולכן השם קבוע), נותנים להם ערכים אך ורק פעם אחת (משתנה final למי שמגיע מתכנות, או ערך סופי).  כדי שיהיה לנו קל יותר, ניתן שם לפין האנלוגי (הלא הוא A0), כמובן שיש לתת שם הגיוני, על מנת שיהיה יותר קל לזכור ולקרוא את התוכנית, נקרא לו sensorPin. וניצור קבוע נוסף שישמור את הטמפרטורה ההתחלתית, נקרא לו baselineTemp (כרגע הכנסתי לתוכו את המס' 20, ומכיוון שהוא float – המכיל מספרים שלמים, נכתוב 20.0). -*כדי ליצור קבוע בארדואינו כותבים `const` בתחילת המשתנה. - -נכתוב את התכנית כך שעבור כל 2 מעלות נוספות (מעל הטמפרטורה ההתחלתית / הבסיסית) עוד נורת LED תדלק. כעת, נכריז על הפונקציה הראשונה: **()setup** ובתוכה נכתוב פקודה חדשה הנקראת `Serial.begin` (שימו דגש על אותיות קטנות / גדולות), הפקודה פותחת חיבור בין הארדואינו לבין המחשב כדי שנראה את הערכים מהקלט האנלוגי (חיישן הטמפרטורה) על גבי המחשב. הפרמטר 9600 שאנו מכניסים בפקודה הזו, הוא המהירות בו הארדואינו יתקשר, 9600 ביטים לשניה. - -לאחר מכן, [נגדיר את הפינים](http://arduino.cc/en/Reference/PinMode) של נורות ה LED כפיני פלט (OUTPUT) וניתן להם את הערך LOW (לא מקבלים מתח). אך במקום לכתוב אחד אחד, לכל פין 2 שורות קוד (סה"כ 6 שורות קוד), נבצע את זה בלולאה. [לולאת for](http://arduino.cc/en/Reference/For) (סוג הלולאה שאנחנו נשתמש בה כעת) הינה טכניקה לביצוע פקודה או סט פקודות כלשהם מספר רב פעמים (ידוע מראש, כמה שאנו נגדיר). נכתוב for ונפתח סוגריים על מנת לכתוב את מבנה הלולאה, נגדיר משתנה [int](http://arduino.cc/en/Reference/Int) בשם pinNumber שיהיה שווה ל-2 (על מנת להתחיל מהפין השני, זהו הפין הראשון אליו מחוברת נורת LED), לאחר מכן נסיים את הפקודה בנקודה פסיק (;) ונכתוב את התנאי, "כל עוד המשתנה pinNumber קטן מ-5" {זאת אומרת שנרוץ מ-2 (כולל) עד 5 (לא כולל)} תבצע את הלולאה ושוב נסיים את הפקודה בנקודה פסיק. ולבסוף נכתוב מה קורה כל פעם שהבקר מסיים לעבור על גוף הלולאה פעם אחת, ובמקרה שלנו מגדיל את pinNumber באחד (`++pinNumber` זוהי כתיבה מקוצרת של הוספת 1, בדיוק כמו לכתוב pinNumber = pinNumber + 1) וסיימנו את מבנה הלולאה אז נסגור את הסוגריים. - -כעת נפתח סוגריים מסולסלים על מנת לכתוב את גוף הלולאה, נכתוב את הפקודה [pinMode](http://arduino.cc/en/Reference/PinMode) שבעזרתה אנו מגדירים את המצב של הפינים, הפקודה מקבלת 2 פרמרטים, הראשון מספר הפין שהוא יהיה כל פעם אחר, תלוי במצב הלולאה, לכן נכתוב pinNumber, ונגדיר את כל הפינים להיות פלט, לכן נכתוב פסיק ואז OUTPUT. הפקודה השניה תיהיה לכתוב לכל הפינים להיות כבויים, נבצע זאת בעזרת הפקודה [digitalWrite](http://arduino.cc/en/Reference/DigitalWrite) המקבלת 2 פרמטרים, הראשון הוא מס' הפין (שוב, יהיה pinNumber) והשני הוא המצב דולק/מכובה (יהיה LOW). - -  - -סיימנו את ה setup ולכן נסגור את הסוגריים המסולסלים, כדי שיהיה קל לקרוא נעשה שורה רווח ונכריז על הפונקציה השנייה בה אנו משתמשים: **()loop** ונפתח סוגריים מסולסלים. הפקודה הראשונה אותה נכתוב בפונ' זו היא הגדרת משתנה בשם sensorVal שיהיה מסוג [int](http://arduino.cc/en/Reference/Int) (מספרים שלמים), במשתנה זה נכניס את הקלט מהחיישן, לכן נכתוב שווה (=) ואת הפקודה [()analogRead](http://arduino.cc/en/Reference/AnalogRead) המקבלת פרמטר אחד (מס' הפין האנלוגי ממנו מתקבל הקלט). בתחילת התוכנית הגדרנו עיצור בשם sensorPin המכיל את מס' הפין האנלוגי אליו מחובר החיישן (A0), לכן נכתוב בסוגריים של הפקודה `sensorPin`, ונסיים אותה בנקודה פסיק. - -הפונקציה [()Serial.print](http://www.arduino.cc/en/Serial/Print) שולחת מידע מהארדואינו אל המחשב המחובר אליו. נוכל לראות את המידע הזה במסך ה Serial monitor (לחצן עם זכוכית מגדלת בצד הימיני-עליון של הIDE). אם נשים בתוך הסוגריים של הפונקציה גרשיים של ציטוט, הפונקציה פשוט תדפיס את מה שבגרשיים, אך אם נשים משתנה כלשהו (ללא הגרשיים) הפונקציה תדפיס את הערך שהמשתנה מכיל. לכן נכתוב פעמיים את הפונקציה `()Serial.print`, כדי שיהיה מובן על מה אנו מסתכלים, בראשונה נכתוב טקסט: " `:Sensor Value` (כתבו את הטקסט עם הגרשיים על מנת שהפונקציה תדפיס את הטקסט ולא תחפש משתנה בשם זה. ובשנייה נכתוב את הערך של החיישן, לכן בתוך הסוגריים נכתוב `sensorVal`(שהינו הקלט מהחיישן). - -כפי שאמרנו הערך שמתקבל מהחיישן ,מתקבל בערכים של 0-1023 (ז"א 1024 אפשרויות), וכדי להפוך את הערך הנ"ל לערך של מתח (בין 0 ל-5 וולט) נחלק אותו ב-1024 ונכפיל ב-5. יש לזכור שהערך יכול לצאת מספר לא שלם (עם נקודה עשרונית) לכן יש לשמור אותו במשתנה שיכול להכיל נקודה עשרונית, כמו [float](http://arduino.cc/en/Reference/Float). למשתנה החדש נקרא בשם הגיוני, כמו voltage, ושימו לב לשים סוגריים על מנת לשמור על סדר פעולות חשבון. בנוסף, כדי שנוכל לראות מה הולך, בואו נדפיס גם את הערך הזה. שוב ע"י 2 פקודות `()Serial.print`, הראשונה תכיל טקסט, והשניה את המשתנה. - -יש לזכור שמה שאנו רוצים למדוד הוא המעלות בצלזיוס, לכן אנו צריכים שוב להפוך מערך של מתח למעלות צלזיוס. שוב ניצור משתנה חדש בשם temperature (מסוג float). את הערך שקיבלו ב voltage נחסיר ב-0.5 ולאחר מכן נכפיל אותו ב-100. ושוב נדפיס את הערך בעזרת הפונקציה `()Serial.print`. (שימו לב שבפקודת הדפסה האחרונה הוספתי [println](http://arduino.cc/en/Serial/Println) במקום print, זו היא פונקציה קצת שונה, שיוצרת שורה חדשה לאחר ההדפסה, ז"א שהשורה הבאה שתודפס תהיה בשורה חדשה, נפרדת). - -  - -לבסוף, נכתוב מספר if-ים על מנת לקבוע אילו נורות LED ידלקו ומתי. נשתמש בטמפרטורה ההתחלתית השמורה במשתנה baselineTemp כנקודת פתיחה, נדליק עוד נורת LED בכל עליה של 2 מעלות מעבר לטמפרטורה ההתחלתית. לכן נתחיל בכך שאם הטמפרטורה הנוכחית קטנה מהטמפרטורה ההתחלתית (שהגדרנו אותה להיות 20, כל הנורות יהיו על LOW (כבויות). -אחרת, אם (במילים אחרות: `else if`), הטמפרטורה הנוכחית שווה או גדולה מהטמפרטורה ההתחלתית+2, וגם קטנה מהטמפרטורה ההתחלתית+4, תדליק את נורה אחת (זהוי המחוברת לפין הדיגיטלי 2). -אחרת, אם הטמפרטורה שווה או גדולה מהטמפרטורה ההתחלתית+4 וגם קטנה מהטמפרטורה ההתחלתית+6, תדליק 2 נורות (פין 2 ופין 3). -אחרת, אם הטמפרטורה שווה או גדולה מהטמפרטורה ההתחלתית+6 תדליק את כל הנורות. - -שימו לב שאת הפקודה וגם (בדיקה של 2 מצבים בתוך משפט if אחד) מבצעים עם האופרטור `&&`, ז"א שגם החלק הראשון יהיה נכון וגם החלק השני יהיה נכון, אם אחד מהם לא נכון, גוף ה if אינו מתבצע. בנוסף, שימו לב שמכיוון שיש מספר פקודות בכל if , יש צריכים לשים סוגריים מסולסלים, אחרת התכנית תתייחס רק לפקודה הראשונה כאילו רק היא בתוך ה if והשאר מחוצה לו. - -לאחר שסיימנו את הבדיקות, נזכור שאנו בתוך פונקציית ה loop, לכן הפונקציה תפעל כל עוד הארדואינו פועל. ז"א תיקח דגימה של הטמפרטורה, תהפוך אותה למתח, ולאחר מכן למעלות צלזיוס, ולבסוף תבדוק את קבוצת ה if-ים ותקבע איזה נורות LED להדליק / לכבות. לכן בסוף התוכנית נכתוב את הפונקציה [()delay](http://arduino.cc/en/Reference/Delay) עם המס' אחד בתוכה (מכיוון שאם נקרא מהחיישן בתדירות גבוה מידי המספרים שנקרא לא יהיו יציבים (הוא לא יספיק להתקרר לפני שנזיז את האצבע, בכל זאת זה לא החיישן האיכותי בעולם..) - -כך יראה הקוד הסופי: - -```c -const int sensorPin = A0; -const float baselineTemp = 24.0; - -void setup(){ - Serial.begin(9600); // open a serial port - - for(int pinNumber=2; pinNumber < 5; pinNumber++){ - pinMode(pinNumber, OUTPUT); - digitalWrite(pinNumber, LOW); - } -} - -void loop(){ - int sensorVal = analogRead(sensorPin); - Serial.print("Sensor Value: "); - Serial.print(sensorVal); - - // convert the ADC reading to voltage - float voltage = (sensorVal/1024.0) * 5.0; - Serial.print(", Volts: "); - Serial.print(voltage); - - // convert the voltage to temperature in degrees - float temperature = (voltage - 0.5) * 100; - Serial.print(", degrees C: "); - Serial.println(temperature); - - if (temperature < baselineTemp){ - digitalWrite(2, LOW); - digitalWrite(3, LOW); - digitalWrite(4, LOW); - }else if (temperature >= beaselineTemp+2 && temperature < beselineTemp+4){ - digitalWrite(2, HIGH); - digitalWrite(3, HIGH); - digitalWrite(4, LOW); - }else if (temperature >= beaselineTemp+6){ - digitalWrite(2, HIGH); - digitalWrite(3, HIGH); - digitalWrite(4, HIGH); - } - dealy(1); -} -``` - -  - -### לסיכום - -לבסוף, תבדקו בעזרת ה Serial monitor את הטמפרטורה שהחיישן דוגם ושחקו עם המשתנים בטמפרטורה ההתחלתית והעליה של הטמפרטורות במשפטי ה if על מנת שזה יתאים לסביבה שלכם ולמעלות אצלכם. - -אז בפרויקט הזה קראנו מדדים מחיישן אנלוגי (טמפרטורה), והדלקנו מס' נורות שונה בהתאם לטמפרטורה שקראנו. למדנו עוד כמה פונקציות כדי לבצע בקרה ולהדפיס את המשתנים השונים, כתבנו בפעם הראשונה לולאת for על מנת לחסוך שורות קוד בעת ההגדרה של הפנים (של נורות ה LED), ועשינו כמה חישובים מתמטיים כדי להגיע לתוצאות שרצינו. אני חושב שהפרויקט הזה מהווה קפיצת מדרגה, למדנו עוד פונקציות, בנינו מעגל חשמלי מורכב יותר, אך הכי חשוב, התחלנו להתחבר לסביבה שלנו, לקרוא ממנה נתונים ולהגיב אליהם בהתאם. diff --git a/data/_oldPosts/2014-06-15-git-1.md b/data/_oldPosts/2014-06-15-git-1.md deleted file mode 100644 index 11b1a26..0000000 --- a/data/_oldPosts/2014-06-15-git-1.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -title: 'Git - חלק 1 (הקדמה)' -author: nirgn -layout: post -summary: "אני מניח שכולכם שמעתם על האתר GitHub ואולי גם על המערכת לניהול קבצים המפורסמת Git. שניהם עולים לכותרות בשנים האחרונות בעיקר בגלל הפופולריות הגדולה שהם תופסים ובתור סטודנט חשבתי שיהיה שימושי ללמוד Git. בנוסף, החלטתי לכתוב את סדרת הפוסטים הנוכחית תוך כדי למידה (כמובן שבדיילי של כמה שבועות לכל פוסט על מנת שאוכל ללמוד, ליישם ולכתוב). המטרה של הסדרה היא ללמוד Git מא' ועד ת' ותוך כדי לעזור לעוד אנשים שמעוניינים ללמוד את הנושא, או סתם להרחיב את הידע, או אפילו שימוש כרפרנס עתידי." -category: Git ---- -אני מניח שכולכם שמעתם על האתר GitHub ואולי גם על המערכת לניהול קבצים המפורסמת Git. שניהם עולים לכותרות בשנים האחרונות בעיקר בגלל הפופולריות הגדולה שהם תופסים ובתור סטודנט חשבתי שיהיה שימושי ללמוד Git. בנוסף, החלטתי לכתוב את סדרת הפוסטים הנוכחית תוך כדי למידה (כמובן שבדיילי של כמה שבועות לכל פוסט על מנת שאוכל ללמוד, ליישם ולכתוב). המטרה של הסדרה היא ללמוד Git מא' ועד ת' ותוך כדי לעזור לעוד אנשים שמעוניינים ללמוד את הנושא, או סתם להרחיב את הידע, או אפילו שימוש כרפרנס עתידי. - -> כדי שיהיה ברור, הפוסט **כן** יהווה מדריך למידה ל Git. - -  - -### רקע כללי - -גיט (באנגלית: Git) היא מערכת ניהול קבצים מבוזרת הנוצרה ע"י -[לינוס טורבאלדס](http://en.wikipedia.org/wiki/Linus_Torvalds) בשנת 2005. - -**למה אני צריך בכלל מערכת לניהול קבצים?** -נניח שאתם חלק מצוות העובד על פרויקט כלשהו, אתם מגיעים לעבודה, מורידים את הגרסה העדכנית של הפרויקט, מבצעים בו כמה שינויים ומעלים אותו בחזרה. הכל טוב ויפה אם רק אתם אלה שעבדתם עליו, אך כמו שאמרתי אתם חלק מצוות מפתחים שעובד על אותו הפרויקט, כשאתם עובדים עליו ישנם עוד אנשים שעובדים עליו ממש באותו הזמן, וכשתרצו להעלות אותו בחזרה, תצטרכו לשלב בין 2 הגרסאות (נניח ואתם הוספתם איזשהו פיצ'ר וחבר לצוות ביצע תיקון לאיזה באג), בקיצור כאב ראש.. אז זה הדבר הראשון שמערכת לניהול קבצים עושה בשבילכם (היא מנסה לשלב בין 2 הגרסאות). - -הדבר השני, היא מהווה מעין קפסולת זמן. מערכת הקבצים תשמור את כל הגרסאות שהיו לאותו הפרויקט ותנהל אותם, במידה ותרצו לחזור לגרסה ישנה יותר – אין בעיה! אם ותרצו לדעת מה השינויים בין גרסה לגרסה – אין בעיה! אם תרצו לדעת מתי הגרסה פורסמה או מי העלה אותה – אין בעיה! - -**מה זה בעצם "מבוזרת"?** -עד לא ממזמן מערכות לניהול קבצים השתמשו במאגר (repository) מרכזי, ז"א שכל חברי הצוות שעובדים על הפרויקט ומבצעים שינויים, מעלים אותו למאגר אחד, שרת אחד. מערכות לניהול קבצים אחרות, דוגמת Git, הן מבוזרות, ז"א שלכל חבר צוות יש העתק שלם של המאגר (repository ובקיצור repo) אצלו באופן מקומי. וזה נותן את היכולת לבצע commit במהירות, היכולת לעבוד על הפרויקט גם כשלא מחוברים, וכמובן גיבוי, גם אם העתק אחד מושמד, לכל חברי הצוות יש העתק של המאגר. - -**איך GitHub קשורה לכאן?** -[GitHub](https://github.com/) זהו שירות אחסון עבור פרויקטים בהם משתמשים בתוכנת Git לניהול הגרסאות. השירות הוקם באפריל 2008 ומספק שירות בתשלום למאגרים (repo) פרטיים ושירות חינמי לפרויקטי קוד פתוח. בנוסף, האתר מהווה מעין רשת חברתית ומאפשר למפתחים לשתף את הפרויקטים ואת ההתקדמות שלהם בכתיבת הקוד, משתמשים אחרים יכולים לדווח על באגים ולכתוב להם פאצ'ים, ניתן לעקוב אחרי מפתחים אחרים, לסמן פרויקטים מעודפים וכ'ו. - -  - -### פקודות בסיסיות - -כמו רוב הכלים של שרתי הפקודה, git מגיעה עם מערכת 'עזרה'. לכן אם ניתקע, תמיד אפשר לכתוב את הפקודה `git help` וזה יתן לנו רשימה של כל הפקודות. ואם נרצה להיות יותר ספציפיים נוכל לכתוב `git help config` (ובמקום ה config כל פקודה קיימת אחרת). - -ניתן להוריד את התוכנה [מכאן](http://git-scm.com/downloads), ותהליך ההתקנה מאוד מאוד פשוט, לכן לא אעבור עליו. אך הדבר הראשון שתרצו לעשות לאחר שהתקנתם Git הוא להגדיר את שם המשתמש שלכם ואת האימייל, ותבצעו זאת ע"י כתיבת הפקודות: - -```bash -git config --global user.name "Nir Galon" -git config --global user.email "nirgn975@gmail.com" -``` - -כמובן שאת השם משתמש והאימייל בין הגרשיים תחליפו בשלכם. - -אז הורדנו והגדרנו git ואנחנו מוכנים לעבוד על המאגר הראשון שלנו, הדבר הראשון שאנחנו צריכים זו תיקייה, אז ניצור אחת אם אין לנו (אם זה פרויקט קיים סביר להניח שהוא נמצא אצלכם בתיקייה מיוחדת כבר), ע"י הפקודה `mkdir nameOfDir` (כמובן שתבחרו באיזה שם שתרצו), וננווט בשורת הפקודה אל התיקייה עם הפקודה `cd nameOfDir`. בשלב הזה אנחנו יכולים להתחיל לעבוד על הפרויקט, או מיד לאתחל את התיקייה, כך או כך, ברגע שנרצה לאתחל (אם זה מיד, במהלך או אחרי העבודה) נכתוב את הפקודה `git init`, זה יצור לנו מאגר גיט (git repo) מקומי (לא על אף שרת, אלה רק על המחשב שלנו). -* המאגר יהיה מוחבא בתיקייה מוסתרת בשם "git." בתוך התיקייה של הפרויקט. - -  - -### התנהלות - -לפני שנמשיך, ארצה לדבר על ההתנהלות עם git, או יותר נכון workflow. ברשותכם, אשאיל את השמות של חברי הצוות שלנו מדמויות מוכרות אחרות: אליס ובוב. נניח שאליס יוצרת קובץ README.txt שמתחיל כקובץ ללא מעקב (ז"א שהמערכת לניהול קבצים, Git, אינה עוקבת אחרי הקובץ, לא מגבה אותו, לא עוקבת אחרי שינויים בו, וכד'). כדי להתחיל לעקוב אחרי הקובץ אנחנו צריכים להוסיף אותו ל"אזור היערכות" (בעצם אנחנו מתכוננים לקחת תמונת בזק של המצב הנוכחי). ולבסוף אנחנו מבצעים commit שזהו בעצם לקיחת snapshot של הקבצים ששמנו ב"אזור ההיערכות". - -כעת, נניח שאליס עובדת על קובץ ה README.txt (עושה כמה שינויים), ואפילו מוסיפה קובץ נוסף בשם LICENSE. כעת, היא שוב צריכה להוסיף את הקבצים ל"אזור ההיערכות", ולבצע commit (לקיחת snapshot נוסף, של המצב החדש). - -וזה פחות או יותר ההתנהלות כרגע, אנו נבצע קצת עבודה, נשלח את הקבצים לאזור היערכות (אולי נבצע עוד עבודה, ניצור קובץ חדש וכד' וגם אותו נצרף אח"כ לאזור היערכות). וכשסיימנו לצרף את כל הקבצים לאזור ההיערכות, ניקח snapshot ע"י ביצוע פקודות ה commit. - -  - -### נחזור לשורת הפקודה - -אחת הפקודות החשובות ביותר היא `git status`, היא תאפשר לנו לבדוק איזה שינויים התרחשו מהפעם האחרונה שביצענו commit. אם נדמה כתיבה של הפקודה לאחר שיצרנו את המאגר וקובץ README.txt (ז"א ישר לאחר הפקודה git init, ויצירת קובץ חדש, ללא והוספה שלו לאזור ההיערכות או ביצוע commit). נקבל חזרה את הקובץ ותיאור שלו למטה (ניתן לראות בקוד למטה). ניתן לראות כי בתיאור נאמר לנו שישנו קובץ שלא נמצא באזור ההיערכות, ז"א שהמערכת לניהול קבצים (Git) אינה עוקבת אחריו, והוא README.txt. וכלי הפקודה אף מייעץ לנו להשתמש בפקודה `git add` על מנת להתחיל לעקוב אחריו (ז"א להוסיף אותו לאזור ההיערכות). - -```bash -$ git status -# On branch master -# -# Initial commit -# -# Untracked files: -# (user "git add <file>.." to include in what will be committed) -# -# README.txt -nothing added to commit but untracked files present (use "git add" to track) -``` - -אז בואו נתחיל לעקוב אחריו, נכתוב את הפקודה `git add README.txt` ואם נכתוב שוב את הפקודה `git status` נראה שהמערכת עוקבת אחרי הקובץ (כמו שניתן לראות: "new file: README.txt") והוא מוכן ל commit (בעברית זה ישמע קצת מוזר, אולי "מוכן להיות מבוצע"). - -```bash -$ git add README.txt - -$ git status -# On branch master -# -# Initial commit -# -# Changes to be committed: -# (use "git rm --cached <file>.." to unstage) -# -# new file: README.txt -# -``` - -ועכשיו אנחנו מוכנים לביצוע ה commit הראשון שלנו. נעשה זאת עם הפקודה `".git commit -m "Create a Readme file` (שימו לב שאחרי הפקודה אנחנו שמים גרשיים ובתוכם תיאור של ה commit, הגרשיים והמלל שבתוכם הינם חלק מהפקודה!). כמו שאמרנו הפקודה יוצרת את ה commit הראשון שלנו, בעצם לוקחת snapshot של אזור ההיערכות, וה snapshot הזה מתווסף ל"ציר הזמן" של הפרויקט.  - -```bash -$ git commit -m "Create a README." - -[master abe28da] Create a REAME. - 1 files changed, 1 insertions(+), 0 deletions(-) - create mode 100644 README.txt -``` - - לפני שנסביר מה זה ציר הזמן, אם נכתוב שוב את הפקודה `git status` נראה כי אין עוד מה לבצע לו commit, בעצם אין עוד שינויים או קבצים חדשים שלא ביצענו להם commit. בנוסף, הפקודה `git status` אומרת לנו שאנחנו בענף master (בשורה "On branch master"). בעקרון, כל מה שצריך להבין בשלב הזה הוא שיש לנו ענף אחד בציר הזמן של הפרויקט, וקוראים לו master (בהמשך נרד לעומק של הענפים האלו). - -```bash -$ git status -# On branch master -nothing to commit (working directory clean) -``` - -  - -עכשיו נניח שאליס ביצעה כמה שינויים בקובץ README.txt, ואף הוסיפה קובץ נוסף – LICENSE, כעת נריץ שוב את הפקודה `git status` ונראה כי הקובץ שאנו עוקבים אחריו (הלא הוא README.txt) שונה (המערכת עוקבת אחרי הקובץ, היא שמה עליו עין, ככה שהיא יודעת שהוא שונה). ובנוסף, נוצר קובץ חדש בתיקייה, אחריו המערכת לא עוקבת, בשם LICENSE. - -```bash -$ git status -# On branch master -# Changed but not updated: -# -# modified: README.txt -# -# Untracked files: -# -# LICENSE -no changes added to commit -``` - -כדי לבצע commit לשני הקבצים, יש להוסיף אותם קודם לאזור ההיערכות, ואפשר לעשות זאת ע"י הפקודה `git add` וכתיבת שני הקבצים (עם רווח בינהם), כך: `git add README.txt LICENSE` או שאפשר לכתוב `git add -all` שתוסיף את כל השינויים (קבצים חדשים, שינויים בקבצים ישנים ומחיקת קבצים) לאזור ההיערכות. כעת, אם נריץ שוב את הפקודה `git status` נראה שיש לנו 2 קבצים (אחד חדש, והשני ששונה) המכונים באזור ההיערכות, כדי להיות commit. - -```bash -$ git add README.txt LICENSE - - OR - -$ git add --all - -$ git status -# On branch master -# Changes to be committed: -# -# new file: LICENSE -# modified: README.txt -# -``` - -  - -אז נבצע commit לאזור ההיערכות, על ידי כתיבת הפקודה `"git commit -m "Add License and finish Readme`, ושוב יצרנו snapshot רגעי בענף master, וניתן לראות תיאור של מה שונה. - -```bash -$ git commit -m "Add LICENSE and finish README." - -[master 1b0019c] Add LICENSE and finish README. - 2 files changed, 21 insertions(+), 0 deletions(-) - create mode 100644 LICENSE -``` - -בתמונה משמאל ניסיתי לצייר את ציר הזמן של הענף master, הנקודה הראשונה (לידה כתוב 1) היא ה commit הראשון שביצענו, והשניה (לידה כתוב 2) היא ה commit הנוכחי שביצענו. ליד הפקודה בעצם שמתי תמונה של מצלמה המסמלת את לקיחת ה snapshot, וה snapshot הזה מצביע ל commit השני. - -
    - Snapshot -
    - -אז יש לנו שני commit. אבל איך אנחנו יודעים מה הם? כיצד מסתכלים על ההיסטוריה של ציר הזמן? בשביל זה יש את הפקודה `git log`. וכשנריץ אותה, נראה שיש לנו שני commit, נראה את הכותב של כל אחד, את התאריך, ואת תיאור השינויים שאותו כותב כתב. ואתם יכולים לתאר לעצמכם, כשאתם עובדים על פרויקט בצוות, תיאור ה commit הינו דבר חשוב מאוד, הוא צריך להיות מובן, תמציתי ולתאר בדיוק מהם השינויים (ותנסו לכתוב בלשון הווה ולא עבר, למרות שבעתיד, כנראה שזה יהיה חלק מההיסטוריה). - -  - -כעת, בואו נחזור טיפה אחורה, לפקודה `git add` שמוסיפה את הקבצים לאזור ההיערכות. ראינו עד כה 2 דרכים להוסיף קבצים: - - * ` - -אתם בטח תצפו שכדי לגרום לנורות לדהות (fade out) כל שצריך הוא להוריד את המתח, אך זה לא כזה פשוט. הארדואינו אינו יכול לשנות את המתח בפיני היציאה שלו, הוא פולט אך ורק 5V. לכן נצטרך להשתמש בטכניקה הנקראת PWN ׁ (ראשי תיבות: Pulse Width Modulation) על מנת לגרום לאור של נורות הLED לדעוך. -PWN הופך (בזמן קבוע) במהירות את הפלט בפין מ'גבוה' (HIGH) ל'נמוך' (LOW), החלפה זו מתרחשת בזמן מהיר יותר מאשר זה שהעין האנושית מסוגלת לקלוט (בדומה לאופן בו סרטים עובדים, ע"י החלפת מספר תמונות סטטיות במהירות כדי ליצור אשליה של תנועה). - -כשאנו הופכים במהירות את הפלט בפין מHIGH לLOW (בעצם 1 ו 0) אנו משנים את המתח. אחוז הזמן בו הסיכה מקבלת מתח HIGH נקרא "מחזור עבודה" (Duty Cycle). לדוגמה: כאשר הפין נמצא חצי מהזמן על HIGH וחצי על LOW במשך הזמן הקבוע, מחזור העבודה הוא 50%. ומחזור עבודה נמוך יתן לנו אור עמום מאשר אחוז גבוה במחזור העבודה. - -שימו לב כי לארדואינו אונו יש 6 פינים המסוגלים לבצע את שיטת הPWN והם מסומנים בתילדה (סימן ה: ~). פינים אלה הינם הפינים הדיגיטליים 3,5,6,9,10 ו 11. בנוסף, עבור הקלט בפרויקט הזה נשתמש בנגד תלוי אור (באנגלית: Photoresistor), החיישן משנה את ההתנגדות שלו בהתאם לכמות האור הפוגעת בו (ואם תחברו רגל אחת של הנגד לארדואינו, תוכלו למדוד את השינוי בהתנגדות ע"י מדידת המתח מהפין). - -  - -### חיבור הרכיבים - -חברו ללוח המטריצה חוטים מעמודות ה+ וה-, אל ה5V וה GND (בהתאמה, בדיוק כפי שעשינו עד כה). כעת בחלק התחתון של לוח המטריצה נמקם 3 נגדים תלויי אור (Photoresistors) ככה שהם יחצו את התעלה המחלקת את לוח המטריצה לשניים. בצד הרחוק של לוח המטריצה נחבר 3 חוטים מגשרים לעמודת ה+, כדי שהנגדים יקבלו מתח, ואת עמודת ה+ הזו נחבר לעמודת ה+ הראשונה (הקרובה יותר לארדואינו, זאת שחיברנו אליה בהתחלה את ה5V). בצד השני של הנגדים תלויי אור נחבר נגדים רגילים של 10K Ω (קיצור של 10 קילו אוהם) לכל אחד מצד ה- של הנגדים תלויי האור (3 נגדים תלויי אור סה"כ, לכן 3 נגדים של 10K Ω). בנוסף, בצד של הנגדים נחבר חוט מגשר אל פיני הקלט האנלוגיים: A0, A1, A2. - -כדי לסנן את האור, ניקח 3 מלבנים של ג'ל בצבע (Wikipedia - Color Gel) ונחבר אותם לנגדים תלויי אור, הראשון, המחובר לA0 יהיה בצבע אדום. השני, המחובר לA1, יהיה בצבע ירוק. והשלישי, המחובר לA2 יהיה בצבע כחול. - -כעת נחבר נורת לד RGB שתקלוט את האור מ3 הנגדים תלויי האור ותראה לנו את הצבע המשולב שמופק מהם. לנורה הזו (בניגוד מנורת LED רגילה) יש 4 רגליים, אחד לכל צבע (אדום, ירוק, וכחול) ועוד רגל לאדמה. הרגל הארוכה ביותר (נמצאת באמצע) היא הרגל לאדמה, והיחידה שלידה היא הרגל לנורה האדומה, שתי הרגליים בצד השני שלה הם ירוק וכחול (כשהכחול הוא הפנימי והירוק הוא החיצוני). לרגליים של הצבעים נחבר נגד רגיל 220Ω, ולאחריו חוט מגשר לפינים הדיגיטליים 9,10, 11. מהם נוציא את הפלט של הצבעים (שאנחנו קולטים מהנגדים תלויי האור). -להלן סכמה ואיור להמחשה: - -
    - Arduino Project number 4 -
    - -  - -### הקוד - -לפני תחילת הקוד ניצור 6 משתנים קבועים, ועוד 6 משתנים רגילים. - -ניצור משתנה קבוע שישמור את מס' הפין שלכל צבע (כל הפינים מתחברים לרגליים שונות של נורת RGB אחת), משתנה קבוע שישמור את פין החיישן של כל צבע (שלושת נגדים תלויי האור), משתנה רגיל שישמור את הערך של כל צבע (כך נדע איזה ערך לתת לנורת הLED. נחשב אותו מאוחר יותר, לכן כרגע נכניס אליו 0), ומשתנה רגיל שישמור את הערך שנקלוט מהחיישנים (אנחנו עדיין לא קולטים דבר, אז נציב 0 בנתיים). - -משהגדרנו את 12 המשתנים, נמשיך לאזור הsetup (למי שלא זוכר, זהו האזור שרץ לפני ביצוע התכנית - פונקציית loop, והוא רץ/מתבצע פעם אחת בלבד). לכן, כאן, נפתח חיבור תקשורת בין הארדואינו למחשב, ע"י הפקודה ()Serial.begin ונגדיר את מהירות התקשורת להיות 9600bps. בנוסף, נגדיר את הפינים המחוברים לנורת RGB כפיני פלט, זכרו שלא צריך לכתוב את מס' הפין עצמו, שמרנו את מס' הפין במשתנה קבוע (שלא ניתנו לשנותו) בשם greenLedPin (ובאופן דומה לצבעים הנוספים), וכמובן לא לשכוח לסגור את הפונקציה עם סוגריים מסולסלים. -* מה שכתבנו עד כאן ניתן לראות בתמונה משמאל. - - -כעת, נתחיל את פונקציית הלולאה - ()loop, שבעצם מהווה את התכנית (למי שלא זוכר, היא הפונקציה שרצה בלולאה אינסופית, כל עוד הארדואינו פועל, ומבצעת את הפקודות הכתובות בתוכה). בנוסף, אזכיר כי הדבר הראשון שעושים הוא להכריז על הפונקציה, ע"י כתיבת הערך אותו היא מחזירה (במידה ויש כזה, במידה ואין, ז"א שהיא מחזירה כלום, נכתוב void - ריק). לאחר מכן נכתוב את שם הפונקציה (loop) ואז נפתח סוגריים מסולסלים ונסגור אותם, בניהם נכתוב את גוף התכנית. - - -בתוך פונקציית הלולאה נתחיל לקרוא את המשתנים מהנגדים תלויי האור, במרווח של 5 מילי שניות בין קריאה בין כל נגד. ז"א נשתמש בפוקנציה ()analogRead ובתוכה נכניס את הפין (זכרו, כל מס' פין שמרנו במשתנה קבוע בשם greenSensorPin (ובאופן דומה לשאר הצבעים), לכן במקום להכניס את מס' הפין לתוך פונקציית ה analogRead נכניס את המשתנה הקבוע), ואת הערך שאנו קוראים מכל פין אנלוגי נכניס למשתנה שהכנו במיוחד בשבילו (greenSensorValue, ובאופן דומה לשאר הצבעים), בעזרת סימן ההשמה (סימן השווה, = ). בנוסף, נכניס מרווח קטן בין הקריאות מכיוון שלadb (הממיר המובנה של הארדואינו מאנלוגי לדיגיטלי) לוקח כמה מילי שניות לבצע את הפעולה. מרווח של 5 מילי שניות יספיק. - -כעת, לשם הבדיקה, נדפיס את הערכים, כדי להדפיס נעזר בפקודה ()Serial.print. הt\ שווה ללחיצה על tab (מכניס רווח השווה ל6 של מקש הspace). בנוסף, כדי להדפיס את הערכים אותם קלטנו נדפיס את הערכים במשתנים greenLedPin אליהם קלטנו את הערכים מהפין האנלוגי בפסקה הקודמת. -* ניתן לראות את מה שכתבנו עד כה בתמונה משמאל. - -בשביל הטריק בעזרתו ניתן לשנות את בהירות נורת הLED (טכניקת PWN) נשתמש בפקודה ()analogWrite הכותבת .... הפונקציה מקבלת 2 ערכים (נקראים פרמטרים), הראשון הפין אליו יש לכתוב את הערך, והשני הערך אותו יש לכתוב (נע בין 0-255). הערך של הפרמטר השני מייצג את מחזור העבודה שבו הארדואינו יוצא פלט אל הפין. ערך של 255 יכוון את הפין לHIGH כל הזמן, מה שיהפוך את הLED לבהיר ביותר שהוא יכול להיות. ערך של 127 (חצי) יכוון את הפין להיות HIGH חצי מהזמן, מה שיגרום לLED להיות עמום יותר. 0 יכוון את הפין להיות LOW כל הזמן, מה שיכבה את הLED. -כדי להפוך את הקריאות מהחיישן (שכזכור קורא ערכים בין 0-1023) לערך בין 0-255 (שכזכור זה מה שהפונקציה analogWrire מקבלת) יש לחלק ב4, לכן נוסיף 3 שורות לכל 3 הצבעים, נחלק את המשתנה שבו שמור הערך שקלטנו (נמצא ב greenSensorValue למי שלא זוכר, ובאופן דומה דומה בשאר הצבעים), ואת הערך החדש (אחרי החילוק ל4) נשמור במשתנה שהגדרנו מראש, בשם greenValue (באופן דומה לשאר הצבעים). - -כעת, כדי לוודא שאכן הדברים בוצעו, שוב, נבצע הדפסה של כל הערכים, הפעם של המשתנים אחרי החילוק ל4 (ז"א של greenValue, ובאופן דומה לשאר הצבעים). ולבסוף נכתוב בעזרת הפקודה ()analogWrite את הערכים לנורת הRGB. -* מה שכתבנו עד כה (בעצם כל התכנית) ניתן לראות בתמונה משמאל. -** את הערכים שהחיישן דוגם, מדפיס, מחלק ב4, ומדפיס שוב ניתן לראות בעזרת ה Serial monitor (ציור של זכוכית מגדלת בצד הימני בשורה של שאר הפעולות). - -  - -### לסיכום - -בפרויקט הזה קלטנו גלי אור שונים (אדום, ירוק, וכחול) והוצאנו אותם כפלט לנורת LED מסוג RGB, שבעצם משלבת את 3 האורות ויוצרת צבע אחד. אם תסתירו את אחד החיישנים בעזרת האצבע, לדוגמה הכחול, האור המופק מהנורה כמעט ולא יכיל גוון כחול (בכל זאת, האצבע שלכם לא חוסמת באופן מושלם..). בנוסף, שימו לב שהאור לא נעשה עמום או בהיר באופן לינארי, וכשהLED חצי בהיר זה נראה כאילו הוא מפסיק להיות בהיר יותר. זה משום שהעיניים שלנו לא תופסות בהירות באופן לינארי. הבהירות של האור אינה תלויה רק בערך אותו אנו מעבירים כפלט לנורה (בעזרת הפקודה analogWrite), אלא גם במרחק שבו האור מתפזר, מהמרחק של העין שלנו ממקור האור, וכמובן שבהירות של האור יחסית לשאר האור שבחדר. - -ניתן לחשוב על דרכים לחזק את נושא הבהירות, כמו לעשות חור בגולה חלולה או בכדור פינג פונג, ולשים אותם על הLED על מנת שיתפזר בשטח קטן יותר (יהיה מעיין נורה קטנה). בנוסף, ניתן לחשוב על דרכים בהם אפשר להשתמש בפרויקט הזה על מנת לסמן לנו מהו מזג האוויר בחוץ (כמובן שבאופן לא כל כך מדויק בלשון המעטה), (חשבו על גלי האור בספקטרום, הרי האור האדום חם יותר מכחול וירוק..) diff --git a/data/_oldPosts/2014-09-07-arduino-5.md b/data/_oldPosts/2014-09-07-arduino-5.md deleted file mode 100644 index 6bc2f54..0000000 --- a/data/_oldPosts/2014-09-07-arduino-5.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: '5 - מנוע סרוו' -author: nirgn -layout: post -summary: "" -category: Arduino ---- -בפרויקט הזה נעשה שימוש ברכיב חדש, מנוע סרוו (Servo Motor). מנועי סרוו הם סוג מיוחד של מנוע, כזה שאינו מסתובב במעגל, אלא עובר למיקום מסויים ונשאר שם עד שאנו אומרים לו לנוע שוב. המנועים האלו, בדר"כ, מסתובבים רק 180 מעלות (חצי עיגול). - - - -בדומה לאופן בו השתמשנו בפולסים בשביל נורת הLed (טכניקת PWN) בפרויקט הקודם, מנועי סרוו מצפים למספר פעימות שאומר להם לאיזו זווית לעבור. אותם הפולסים מגיעים תמיד באותם מרווחי זמן, אך אורכם משתנה בין 1,000 ל 2,000 מיקרו שניות. בעוד שאפשרי לכתוב קוד ליצירת פולסים אלה, תוכנת ה Sketch של ה Arduino מגיעה עם ספרייה המאפשרת לנו לשלוט במנוע בקלות. - -מפני שמנוע הסרוו מסתובב רק 180 מעלות, ובכניסה האנלוגית (אותה אנו קוראים בעזרת הפונקצייה ()analogRead) אנו מקבלים ערכים הנעים בין 0 ל 1023, אנחנו צריכים להשתמש בפונקצייה הנקראת ()map על מנת לשנות את קנה המידה שהערכים מגיעים מהפוטנציומטר (בעצם, ע"י הפוטנציומטר נזיז את מנוע הסרוו). - -אחד הדברים הטובים בקהילת ה Arduino היא האנשים המוכשרים שמרחיבים את הפונקציונליות של המיקרו-בקר באמצעות ספריות נוספות (כל אחד יכול לכתוב ספרייה ובכך להרחיב את הפונקציונליות של ה Arduino). ישנן ספריות למגוון רחב של חיישנים והתקנים אחרים שהמשתמשים תרמו לקהילה. תוכנת ה Sketch מגיעה עם מספר ספריות השימושיות לעבודה עם החומרה והנתונים בהם היא אמורה לתמוך, ואחת הספריות איתן היא מגיעה מיועדת לשימוש עם מנועי סרוו. בקוד שנכתוב, נייבא את הספרייה וכתוצאה מכך כל הפונקציות לעבודה עם מנועי הסרוו יהיו זמינות לנו לשימוש חופשי, ולא נצטרך לכתוב אותם מחדש (היות שיש מי שכבר כתב ותרם את העבודה שלו). - -  - -### חיבור הרכיבים - -חברו ללוח המטריצה חוטים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). מקמו פוטנציומטר על גבי לוח המטריצה וחברו רגל אחת שלו ל 5v ואת השניה לאדמה (GND) בעזרת חוטים מגשרים מעמודות ה+ וה- (לא משנה איזה מהרגלים). פוטנציומטר זהו סוג של מחלק מתח, כשמסובבים את הידית, היחס בין הפין האמצעי למקור הכוח משתנה. ניתן לקרוא את השינוי הזה ע"י קלט אנלוגי, לכן נחבר את הפין האמצעי לפין האנלוגי 0 (או A0). (זה ישלוט על המצב של מנוע הסרבו). - -למנוע הסרוו יש 3 חוטים שיוצאים ממנו, האדום הוא מקור הכוח, השחור הוא לאדמה, והלבן מקבל מידע (מהארדואינו במקרה שלנו) ומיועד לשליטה במנוע הסרוו. חברו את הכבל האדום והשחור ללוח המטריצה ואת הלבן ישירות לארדואינו לפין הדיגיטלי מס' 9. בלוח המטריצה חברו חוטים מגשרים לכבל השחור והאדום מעמודות ה+ וה-. - -כאשר מנוע הסרוו מתחיל את התזוזה שלו, הוא צורך זרם גבוה מאשר כשהוא כבר בתזוזה. דבר כזה יגרום לשקע במתח על גבי הלוח. לכן נניח קבל 100uf בצמוד לכוח ולאדמה (החוטים אדום ושחור שיוצאים ממנוע הסרוו ומחוברים ללוח המטריצה) כדי שיאגור את המטען החשמלי שהסרוו אינו משתמש בו, הקבל "ישטח" כל שינוי מתח שיקרה. בנוסף, ניתן להניח קבל נוסף באותן העמודות של הפוטנציומטר. שיטה זאת נקראת "ניתוק קבלים" (או באנגלית Decoupling capacitor), באלקטרוניקה זה אומר מניעת צימוד של מערכות, ובמקרה שלנו מניעת צימוד של מעגלים חשמליים שונים ע"י קבלים (רעש אלקטרוני שנגרם ממערכת, מעגל חשמלי, יושתק ע"י הקבל, וכך יפחית את האפקט על שאר המעגל הכללי). את הכבלים חברו כך שהרגל הקצרה (קתודה, מסומנת על הקבל בפס שחור) תהיה מחוברת לאדמה (חוט מגשר שחור) והרגל הארוכה יותר (אנודה) תהיה מחוברת למקור הכוח (חוט מגשר אדום). שימו לב, השלב הזה קריטי, אם תשימו אותם הפוך הקבל יכול להתפוצץ! -להלן סכמה ואיור להמחשה: - -
    - Arduino Project number 5 -
    - -  - -### הקוד - -לפני שנתחיל לכתוב את הקוד נייבא את ספריית הסרוו שדיברנו עליה בתחילת הפוסט. בשביל לייבא ניעזר בפונקציה include# ונכתוב את שם הספרייה ב<> (יש לציין כי הפקודה אינה מסתיימת בנקודה פסיק). שם הספרייה של מנוע הסרוו היא Servo.h. לאחר מכן, בשורה הבא נוכל ליצור משתנה מופע, משתנה המופע הזה נקרא אובייקט (נקרא לו myServo) מסוג Servo. מה שעשינו הוא ליצור אובייקט בשם myServo שמקבל את כל התוכנות והיכולות של Servo שייבאנו מהספרייה שלו. - - -לאחר מכן ניצור משתנה קבוע (זוכרים const?) בשם potPin שישמור את מס' הפין האנלוגי שאליו מחובר הפוטנציומטר (כדי לקרוא ממנו מידע). לאחר מכן ניצור משתנה בשם potVal מסוג int (שומר מספרים שלמים) כדי להחזיק את המספר שאנו קוראים מהפוטנציומטר (אמור להיות הזווית שעל מנוע הסרוו לזוז, אך עדיין לא בערכים המתאימים למנוע הסרוו), ועוד משתנה מסוג int בשם angle שישמור את הזווית אליה רוצים שמנוע הסרוו יזוז. - -כעת, נכתוב את פונקציית ה setup (האזור שרץ אך ורק פעם אחת, לפני ביצוע התכנית - פונקציית ה loop). הדבר הראשון שנעשה זה להגיד לארדואינו לאיזה פין מחובר מנוע הסרוו (על מנת שידע לשלוח לו את המידע מאוחר יותר). נעשה זאת ע"י קריאה לאובייקט שלנו (myServo) נקודה ואז שם הפונקציה (במקרה שלנו attach) ונפתח ונסגור סוגריים רגילים (בסוף הפקודה לא לשכוח נקודה פסיק). בתוך הסוגריים של הפונקציה attach (שפועלת על האובייקט myServo) נכניס את מס' הפין שאליו מחובר מנוע הסרוו, אני חיברתי אותו ל9). לאחר מכן, כמו תמיד, נפתח חיבור תקשורת בין הארדואינו למחשב (כדי שנוכל לקרוא ולהדפיס משתנים, נעשה זאת בשביל לבצע בדיקה ולראות את המשתנים). את חיבור התקשורת נעשה עם הפקודה ()Seiral.begin ונגדיר את מהירות התקשורת להיות 9600bps (ראשי תיבות של bit per second). -* ניתן לראות בתמונה משמאל את מה שכתבנו עד כה. - - -נעבור לכתיבת התכנית עצמה - פונקציית loop. נתחיל בקריאת המשתנה מהפוטנציומטר (קריאת משתנה אנלוגי מתבצע עם analogRead, זוכרים?), נקרא אותו מהמשתנה potPin שמכיל את מס' הפין שאליו מחובר הפוטנציומטר ונכניס את המשתנה מהקריאה למשתנה potVal שיצרנו מבעוד מועד. כעת נדפיס טקסט שנדע שהדבר הבא שיודפס זה הערך של המשתנה potVal, ולאחר מכן נדפיס את הערך של potVal. - - -כמו שאמרנו קודם לכן, בכניסה האנלוגית אנו מקבלים ערכים הנעים בין 0 ל1023, אך מנוע הסרוו מקבל ערכים בין 0 ל179 (180 מספרים סה"כ. זהו מספר המעלות אליו הוא צריך לנוע). לכן בשביל לבצע את ההמרה של הערכים לערכים המתאימים למנוע הסרוו (כאלה שהוא מקבל) נשתמש בפונקציה ()map ונשמור את הערכים ב angle. הפונקציה השימושית הזו מאזנת (מלשון מאזניים) מספרים בשבילנו (במקרה שלנו שינוי של ערכים בין 0-1023 לערכים בין 0-179). היא מקבלת 5 ארגומנטים. הראשון הוא המספר אותו יש לשנות, השני מס' המינימום של ערך הקלט (המס' המינימלי שהוא יכול להיות), השלישי מס' המקסימום של ערך הקלט, הרביעי מס' המינימום של ערך הפלט (המס' המינימלי שהוא יוכל להיות), החמישי מס' המקסימום של ערך הפלט. לאחר מכן גם את המשתנה הזה (קודם טקסט שנדע מה הערך הבא אומר, ולאחר מכן את הערך עצמו). - -לבסוף, הגיע הזמן להזיז את מנוע הסרוו עם הפקודה ()servo.write אשר מקבלת ארגומנט אחד שהינו הזווית אליה יש לזוז (אליה יש להזיז את מנוע הסרבו), במקום ה servo נשים כמובן את שם הסרוו שלנו (קראנו לו myServo). ולאחר מכן נכניס מרווח קטן על מנת שלסרוו יהיה זמן לזוז למיקום. -* ניתן לראות בתמונה משמאל את מה שכתבנו עד כה. - -  - -### לסיכום - -בפרויקט הזה למדנו כיצד לייבא ספריות כתובות לרכיבים שאין להם פונקציות כתובות מראש ב Sketch. ניתן לראות את ה API (ראשי תיבות: Application programming interface) של הספרייה בה השתמשנו באתר ארדואינו, כאן, ולבדוק איזה פונקציות היא מכילה ומה ניתן לעשות איתה. בנוסף, למדנו על 3 רכיבים חדשים (פוטנציומטר, מנוע סרוו, וקבלים). כשתריצו את הפרויקט, פתחו את ה Serial monitor (זכוכית מגדלת בצד הימיני בשורה של שאר הפעולות) שם תראו את הערכים אותם הארדואינו מדפיס, שימו לב ליחס בין potVal ל angle כדי להבין טוב יותר את הפונקציה ()map שבה השתמשנו. diff --git a/data/_oldPosts/2014-09-21-arduino-6.md b/data/_oldPosts/2014-09-21-arduino-6.md deleted file mode 100644 index 181b93f..0000000 --- a/data/_oldPosts/2014-09-21-arduino-6.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: '6 - טרמין אור' -author: nirgn -layout: post -summary: "" -category: Arduino ---- - -הגיע הזמן לעשות קצת רעש, בפרויקט הזה נבנה טרמין מבוסס אור באמצעות רכיב הנגד תלוי אור (photoresistor) ופיזואלקטרי (piezo). - - - -טרמין הוא כלי המפיק צילילים על בסיס תנועות הידיים שסביבו. הטרמין מזהה היכן ידיו של הנגן ביחס לשתי אנטנות ע"י קריאת השדה האלקטרומגנטי שסביבן. האנטנות מחוברות למעגל אנלוגי שיוצר את הצליל (אנטנה אחת שולטת בתדר והאחרת שולטת בעוצמה של הצליל). הארדואינו אינו יכול לשכפל את הקולות במדויק אך הוא יכול לחקות אותם באמצעות הפונקציה ()tone. - -במקום לקרוא את השדה האלקטרומגנטי עם ה Arduino, אנחנו נזהה באמצעות הנגד תלוי האור (photoresistor) את כמות האור, וע"י הזזת היד מעל הנגד תלוי האור נשנה את כמות האור שהחיישן קולט (כמו שעשינו בפרויקט הרביעי - גלי אור שונים (צבעים) ונורת RGB), והשינוי במתח בפין האנלוגי יקבע איזה תדר להשמיע. אנחנו נחבר את הנגד תלוי האור ל Arduino באמצעות נגד קבוע 10KΩ (בדיוק כמו בפרויקט הרביעי). וכמו בפרויקט שעבר, אנחנו קוראים את הכניסה האנלוגית בעזרת הפונקציה ()analogRead ומקבלים ערכים הנעים בין 0 ל1023, אך הערכים המתקבלים מהנגד תלוי האור קטנים יותר ומוגבלים ע"י הנגד הקבוע המחובר לקרקע (ל-) והנגד תלוי האור (החיישן הקולט את כמות האור), ולכן נשתמש שוב בפונקציה ()map על מנת לשנות את קנה המידה של הערכים המגיעים מהפין האנלוגי. - -  - -### חיבור הרכיבים - -חברו ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). חברו את הפיזואלקטרי (piezo) ללוח המטריצה,(לא משנה איך, אין הבדל בין הרגליים) לשורה שבה נמצאת רגל אחת חברו חוט מקשר לאדמה (-), ולשורה של הרגל השנייה חברו חוט מגשר לפין הדיגיטלי מס' 8 (על מנת לשדר לרכיב באיזה תדר להשמיע את הצליל). - -את הנגד תלוי אור (photoresistor) חברו ללוח המטריצה כשאתם מחברים רגל אחת ל 5V (+) והרגל השניה ל GND (-) (לא משנה באיזה סדר, שימו לב שאין הבדל בין הרגליים). בנוסף נחבר חוט מגשר מהפין האנלוגי A0 לרגל שמחוברת לאדמה (GND, -) -להלן סכמה ואיור להמחשה: - -
    - Arduino Project number 6 -
    - -  - -### הקוד - -הקוד הפעם יהיה קצר יחסית. ניצור שלושה משתני Int, הראשון בשם sensorValue כדי לשמור את הערך שנקרא עם ()analogRead מהנגד תלוי אור, השני יקרא sensorLow ונשמור בו את הערך 1023, והשלישי יקרא sensorHigh ונשמור בו את הערך 0 (כשנפעיל לראשונה את הארדואינו נקרא ונשווה את ערכי המקסימום והמינימום האמיתיים). -לאחר מכן ניצור עוד משתנה מסוג int אך הוא יהיה קבוע (להזכירם const), ויקרא ledPin. נשתמש בו כמציין (indicator) לכך שהחיישן סיים לתכייל, נכניס אליו את הערך 13 כי זהו הפין שלידו יש נורה וכשהנורה דולקת נדע שהחיישן מבצע כיול, כשהיא תתכבה נדע שהחיישן סיים לבצע את הכיול. - -נמשיך לפוקנציית ה ()setup: -נגדיר את הכיוון של פין 13 (קלט/פלט) עם הפקודה ()pinMode, נכניס לתוכה כפרמטר את מס' הפין (ששמרנו במשתנה ledPin) ונכוון אותה ל OUTPUT כדי להגדירה כפלט. בשורה הבאה נגדיר את הנורה בפין 13 להידלק עם הפקודה ()digitalWrite ולתוכה נכניס את מס' הפין (שוב, שמרנו אותו במשנתה ledPin) וכדי להגיד לו להידלק נעביר פרמטר נוסף, המילה השמורה HIGH (זוכרים את ההבדל בין HIGH ל LOW? - מקבל מתח ולא מקבל מתח (בהתאמה)). - - -הפעם נשתמש בלולאה חדשה הנקראת 'לולאת while' (דומה ללולאת for מפרויקט 3) ההבדל בין לולאת for ל while הוא שב for אנו מגדירים מראש כמה פעמים נבצע את סט הפקודות שבתוכה, ובלולאת while סט הפקודות שבתוכה מתבצע כל עוד תנאי כלשהו מתקיים (מתקיים = נכון - true) (אם הוא תמיד יתקיים ניתקע בלולאה אינסופית). אז נכתוב ()while ובתוך הסוגריים נכתוב את תנאי הלולאה. התנאי שאנו רוצים הוא 'כל עוד לא עברו 5 שניות', וניעזר בפונקציה ()millis כדי לבדוק את הזמן הנוכחי. הפונקציה millis מחזירה כמה זמן (במילי שניות) הארדואינו פועל מהפעם האחרונה שהדלקנו אותו, ולכן התנאי שלנו יהיה כל עוד millis קטן מ 5000 נבצע את גוף הלולאה (סט הפקודות), אחרת, נדלג על גוף הלולאה. - -כעת נפתח סוגריים מסולסלים כדי לכתוב את גוף הלולאה (סט הפקודות), דבר ראשון נקרא את הערך מהחיישן בפין האנלוגי A0, עם הפקודה ()analogRead ונשמור את הערך במשתנה sensorValue. לאחר מכן נשתמש בתנאי if כדי לדעת היכן להציב את הערך, אם ה sensorValue גדול מ sensorHigh אנחנו צריכים להחליף את הערך שב sensorHigh בערך שנמצא ב sensorValue, ושוב לבצע זאת עם sensorLow בתנאי if נוסף. ולבסוף לסגור את הלולאה עם סוגריים מסולסלים. בנוסף, לפני שנסגור את הסוגריים המסוסלים של פונקציית ה setup נזכור לכבות את הנורה של פין 13 (הרי קראנו כבר את הערכים במשך 5 שניות והכנסו אותם למקום הנכון שלהם, ז"א סיימנו לכייל), ונבצע זאת עם הפקודה ()digitalWrite שתקבל את מס' הפין (השמור במשתנה ledPin ואת המילה השמורה LOW). - - -ולבסוף פונקציית ה ()loop: -דבר ראשון נקרא שוב את הערך מהפין האנלוגי A0 ונשמור אותו במשתנה sensorValue (כדי לדעת כל הזמן מתי החיישן מקבל פחות/יותר אור). כעת ניצור משתנה בשם pitch (לא שמרנו אותו בהתחלה כי אנחנו רוצים אותו כמשתנה זמני, רק לפוקנצייה הזאת) ונשמור בתוכו את הערך של sensorValue לאחר שנמפה אותו בעזרת הפונקצייה ()map. ל ()map נעביר כפרמטר ראשון את sensorValue כמובן, כפרמטר השני והשלישי נעביר לו את הגבולות המינימליים והמקסימליים (sensorLow ו sensorHigh), ולאחר מכן את המספר 50 והמספר 4000 (המספרים האלו יגידו את טווח התדרים שהארדינו יפיק). - -אחרי שקיבלנו את הערך נעביר אותו לפיזואלקטרי (piezo) עם הפונקציה ()tone כדי להשמיע צליל. לפונקציה ()tone נעביר כפרמטר ראשון את הפין אליו יש להוציא כקלט את הצליל (חיברנו את רכיב ה piezo לפין מס' 8), איזה תדר להשמיע (שמרנו את הערך במשתנה שיצרנו למעלה בשם pitch), ולבסוף למשך כמה זמן לנגן את התו (נכניס 20 אך אתם יכולים לשחק עם הערך הנל). ולבסוף אנחנו צריכים לתת קצת זמן לתו להתנגן אז ניצור דיליי של 10 מילי שניות עם הפקודה ()delay. - -  - -### לסיכום - -בפרויקט הזה הכרנו רכיב חדש הנקרא פיזואלקטרי (piezo) שמשמיע תווים וגרמנו לו להשמיע תווים ביחס לכמות האור שאנו קולטים מהחיישן של הנגד תלוי אור. השתמשנו בכמה פונקציות חיצוניות המובנות בספריית הארדואינו כדי להקל על עצמנו בעבודה (כמו map במקום לבצע את החשובים לבד, ו tone כדי לשדר צלילים). ולבסוף ראינו סוג חדש של לולאות הנקרא while. - -לא לשכוח שכשאתם מפעילים את הפרויקט, זכרו שהארדואינו מכייל את עצמו במשך ה 5 שניות הראשונות, אז חכו שהנורה של פין 13 תכבה לפני שאתם מצפים לשמוע צליל כלשהו. diff --git a/data/_oldPosts/2014-10-19-arduino-7.md b/data/_oldPosts/2014-10-19-arduino-7.md deleted file mode 100644 index 1db137c..0000000 --- a/data/_oldPosts/2014-10-19-arduino-7.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: '7 - מכשיר מקלדת' -author: nirgn -layout: post -summary: "" -category: Arduino ---- -בפרויקט הזה, נבנה, בעזרת כמה נגדים וכפתורים, מקלדת מוזיקלית קטנה. אנחנו יכולים לחבר כל כפתור לפין דיגיטלי ולקרוא אם הוא נלחץ או לא (אם הערך המתקבל הוא LOW או HIGH), אך נעשה זאת חכם יותר ע"י בניית דבר הנקרא סולם נגדים (Resistor ladder). - - - -סולם נגדים זהוי דרך לקרוא מספר מתקים באמצעות כניסה אנלוגית אחת (טכניקה מועילה במקרה ואנו מוצאים את עצמנו במחסור של כניסות דיגיטליות). נחבר את המתגים (כפתורים) אחד אחרי השני על גבי הלוח, כך שרמת המתח שה Arduino מקבל תשתנה כל פעם שנלחץ על כפתור שונה. - -  - -### חיבור הרכיבים - -חברו ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). חברו את הפיזואלק (piezo) ללוח המטריצה,(לא משנה איך, אין הבדל בין הרגליים) לשורה שבה נמצאת רגל אחת חברו חוט מקשר לאדמה (-), ולשורה של הרגל השנייה חברו חוט מגשר לפין הדיגיטלי מס' 8 (על מנת לשדר לרכיב את תדר הצליל). - -את המתגים חברו ללוח המטריצה כפי שמודגם באיור (כפי שחיברנו אותם עד כה, כאשר 2 רגליים של אותו צד בצד אחד של לוח המטריצה ו2 הרגליים של הצד השני שלו מעבר למחיצה של לוח המטריצה). נחבר את הרגל הראשונה של המתג הראשון לעמודת ה+ בלוח המטריצה (בעזרת חוט מגשר), ואת הרגל השניה של הלחצן הראשון לרגל השניה של הלחצן השני (שוב, בעזרת חוט מגשר), ניקח חוט מגשר נוסף ונחבר גם אותו לרגל השניה של המתג השני ואת צידו השני לרגל השניה של המתג השלישי. וכך גם נעשה מהרגל השניה של המתג השלישי לרגל השניה של המתג הרביעי. ולבסוף נחבר (בעזרת חוט מגשר) את הרגל השניה של המתג הרביעי לפין האנלוגי A0. - -כעת נחבר לכולם נגדים. מהרגל הראשונה של המתג השני לעמודת ה+ נשים נגד 220Ω, מהרגל הראשונה של המתג השלישי לעמוד ה+ נשים נגד 10KΩ (קיצור ל kilohm), מהרגל הראשונה של המתג הרביעי לעמודת ה+ נשים נגד 1MΩ (קיצור של megohm), ולבסוף נשים נגד 10KΩ נוסף מהרגל השניה של המתג הרביעי לעמודת ה-. כל אחד מהנגדים האלו מתפקד במחלק מתח. המספרים בינהם שונים כדי שכל אחד מהם יתנגד בכמות שונה לזרם וכך (על פי הערך שנקרא מהפין האנלוגי A0) נוכל לדעת על איזה כפתור לחצנו. -להלן סכמה ואיור להמחשה: - -
    - Arduino Project number 7 -
    - -  - -### הקוד - -בתוכנית הזאת נציג מבנה חדש לשמירת נתונים הנקרא מערך (קראו כאן בהרחבה). דבר ראשון שנעשה זה ליצור מבנה כזה, השומר מספרים שלמים (int), נקרא לו notes, והוא ישמור את כל התדרים שלנו (חיפוש קצר בגוגל הביא את התוצאה הזאת שפירטה את ההרצים המקבילים של התווים, ניתן לראות בתמונה שעיגלתי את המספרים ללמעלה והכנסתי את התווים C, D, E, F). - -בפוקנציית ה ()setup: -נפתח קישור בין הארדואינו למחשב (בגלל שאח"כ נבקש להדפיס את הערכים שנקלוט מהכפתורים למען בדיקה (ואם נצטרך לבצע debugging)). - -ובפונקציית ה ()loop: -נקרא את הערך שבפין A0 עם הפקודה analogRead, ונשים את הערך שנקבל במשתנה חדש (מסוג int) שנקרא לו keyVal. בגלל שהנגד שמחבר כל מתג לכוח (עמודת ה+) שונה, נקבל ערך שונה כל פעם שנלחץ על מתג שונה, כדי לראות את הערכים (דרך ה serial monitor) נדפיס אותם (את הערך שב keyVal) עם הפקודה ()Serial.println. -כעת צריך למפות את הערך שב keyVal לתו שאנו רוצים להשמיע לכל מתג, נבצע זאת עם סדרה של if/else. שימו לב שלכל הנגדים יש טעויות קטנות לכן יכול להיות שהמספרים הבאים לא יתאימו לכם בדיוק, כוונו אותם בעזרת המספרים שאתם רואים מה serial monitor. בנוסף, כדי לנסות להתגבר על מרווח הטעות הקטן של כל נגד הזנתי את התנאי ב if להיות בין ערכים ולא ערך מדויק (ז"א קטן ממספר כלשהו וגדול ממספר כלשהו אחר). - - -נתחיל ב If הראשון אותו כיוונתי להיות בדיוק 1023 (זוכרים? הקלט שלנו מפין אנלוגי נע בין 0-1023), לכן זה צריך להיות הצליל של המתג הראשון, זה ללא הנגד, הוא רק משלים מעגל, אין נגד שמתנגד לזרם ולכן אנו מקבלים את הערך הגבוהה ביותר. אם התנאי נכון נבצע את הצליל שבתא הראשון - 0, במערך notes שיצרנו בהתחלה. את הצליל נשמיע בעזרת הפונקציה ()tone ונכוון אותו לפין 8 אליו מחובר ה piezo. -ב if השני הצבנו נגד 220Ω, והערכים יהיו בין 990 ל 1010, אם הלחצן ילחץ נשמיע את התו שבתא השני, תא מס' 1 במערך notes. -ב If השלישי הצבנו נגד 10KΩ והערכים שיתקבלו יהיו בין 505 ל515, כעת נשמיע את התו הנמצא בתא מס' 2 (התא השלישי במערך notes). -ובלחצן האחרון, בו הצבנו נגד 1MΩ, הערכים שיתקבלו יהיו בין 5-10, ונשמיע את התו האחרון במערך, הנמצא בתא מס' 3 (התא הרביעי והאחרון). -בסופו של דבר נכתוב else נוסף, במידה והערך שיתקבל לא יהיה בטווחים האלו, כנראה שאנו מקבלים 0 (מכיוון שאף מתג לא משלים את המעגל), ועל כן אנו צריכים לשלוח ל piezo פקודה להפסיק לנגן את התו ששלחנו לו קודם, לכן נשתמש בפוקנציה החדשה ()noTone שתקבל כפרמטר רק את הפין אליו היא שולחת את הפקודה. - -  - -### לסיכום - -הבהרות: -אינני זוכר אם ביצעתי את ההבהרות האלו בפוסטים הקודמים, אך הפרויקט הנל מכיל מספיק חומר כדי לבצע אותן כעת, גם בתור חזרה. את הפונקציות ()tone ו ()noTone, שאנו משתמשים בהן, אנו מקבלים כחלק מהפונקציות המבונות בארדואינו. ניתן לראות כאן את כל הפונקציות שאנו מקבלים "בחינם", ואת ()tone ואת ()noTone בפרט. - -חישובים: -כיצד אנו יודעים איזה ערכים לשים ב if? איך אנחנו מחשבים את הנגד שאנו צריכים? -כאן לא היינו צריכים לחשב את הנגד, אין כאן נורת LED שעומדת במקסימום מיליאמפר כלשהו ואנחנו צריכים להוריד את המתח (בעזרת נגד) בשבילה. כאן הכנסנו את הנגדים שאנו רוצים כדי ליצור הבדל במתח, כדי שנידע על איזה כפתור לחצנו לפי המתח המתקבל. - -אז איך אפשר לחשב את המתח המתקבל? -על פי חוק אוהם, מתח (V) = זרם (I) * התנגדות (R). -כשאנו מודדים את עוצמת הזרם במעגל שאנו בונים, אנו מקבלים ערך כלשהו בטווח ה'מיליאמפר' (אלף אמפר). אנו עובדים עם לוח הארדואינו שנותן לנו מתח של 5 וולט באופן קבוע, לכן ה V אצלנו הוא קבוע, ואנחנו נשחק עם ה I וה R. -5 (מתח) חלקי 220 אוהם (התנגדות) שווה ל 0.0227 אמפר (זרם). -5 חלקי 10,000 אוהם שווה ל (1/2000) אמפר. -5 חלקי 1,000,000 אוהם שווה ל (1/200000) אמפר. - -מה זה נותן לנו? אנו יודעים שדרך פין אנלוגי אנו יכולים לקבל ערכים הנעים בין 0-1023, ז"א 1024 ערכים שונים. אם נכפיל את זה באמפר, נידע מה המס' שצריך לרדת לנו מ1024 כתוצאה מההתנגדות של הנגד. -לדוגמא: 1024*0.0227 שווה ל 23, ז"א שב if השני אנחנו צריכים לקבל בערך 1001. וב if השלישי אנחנו צריכים לקבל חצי, בגלל ש 1024*(1/2000) שווה ל 0.512, ו 1024-512 שווה ל 512, ז"א נקבל בערך 512. - -אם נרצה לבדוק את ההפך, לדוגמה יש לנו נורת led ואנחנו רוצים להתאים לה נגד, אנחנו יודעים שהארדואינו מספק 5 וולט, ונורת לד צורכת בערך 20 אמפר. לכן 5 חלקי 0.02 (1 אמפר חלקי 100 שווה ל1 מילי אמפר) שווה ל 250, אך מכיוון שיש לנו רק נגד של 220 אוהם נשים אותו ונקבל את הערך הכי קרוב לאידיאלי. אם לא נחבר נגד הנורה תישרף מכיון שהיא תקבל 40 מיליאמפר (במקום 0.02) (הרבה יותר ממה שהיא מסוגלת להתמודד איתו) (לוח הארדואינו אונו שלנו מספק 40 מיליאמפר (40mA) לכל פין יציאה/כניסה, כך כתוב ב Summary של הלוח כאן, מהיצאה של המתח של 5V). - -אז בפרויקט הזה למדנו על סולם נגדים, הכרנו פונקציה חדשה (noTone) ומבנה נתונים חדש (מערך). כמו כן עשינו חזרה לגבי מאיפה אנו מקבלים את הפונקציות החינמיות האלו, וכיצד אנו יודעים איזה ערכים הן מקבלות, ואיך אנחנו מחשבים את ערכי הנגד/מיליאמפר בעזרת הנוסחה של חוק אוהם. diff --git a/data/_oldPosts/2014-11-16-arduino-8.md b/data/_oldPosts/2014-11-16-arduino-8.md deleted file mode 100644 index e8ccb3e..0000000 --- a/data/_oldPosts/2014-11-16-arduino-8.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: '8- שעון חול דיגיטלי' -author: nirgn -layout: post -summary: "" -category: Arduino ---- -בפרויקט הזה, נבנה שעון חול דיגיטלי למשך שעה אחת, כשהוא יתן לנו אינדיקציה (ע"י הדלקת נורת led) כל 10 דק'. - - - -עד כה, כשרצינו שמשהו יקרה כל פרק זמן ספציפי השתמשנו בפונקציה ()delay על מנת לבצע עיכוב של כמה שניות לפני חזרה על ה loop. זה שימושי, אבל מגביל. מכיוון שכאשר ה Arduino קורא לפונ' ()delay הוא מקפיא את מצבו הנוכחי לזמן שהכנסנו כפרמטר בפונק ()delay, וזה אומר שהוא לא יכול לקלוט ערכים, לבצע חישובים או ולהוציא פלט בזמן הזה. בנוסף, אם אנו רוצים שמשהו יקרה כל מס' שניות קבוע, לדוג' 10 שניות, לקרוא ל ()delay של 10 שניות יהיה מסובך, כי כיצד אנו יודעים כמה זמן לוקח לארדואינו לבצע את הפעולות האטומיות (התוכנית עצמה) שכתבנו? כיצד נכניס את זה בחישוב? לאורך זמן (שעה, יום, שבוע) התוכנית תצא מסנכרון. - -על כן, ישנה פונ' מובנת אחרת שעוזרת לנו לפתור את הבעיה הזאת, כבר השתמשנו בה בפרויקט 6. וזאת הפונ' ()millis (ניתן לקרוא עליה בהרחבה כאן), שעוקבת אחרי הזמן שה Arduino פועל באלפיות השניה. - -עד כה, הצהרנו על משתנים כ int (מספרים שלמים). אך לא הסברנו כיצד זה בא לידי ביטוי בזיכרון. int זהו משתנה לשמירת מספר שלם (Integer) ב16 סיביות (ביטים), בגלל הגבלת כמות הסיביות הוא יכול לשמור ערכים הנעים בין 32,767 ל 32,768-. אלה כמובן מספרים גדולים, אך אם ה Arduino יספור עם ()millis נצא מטווח הערכים כבר לאחר דקה (1,000*60). לכן נשתמש במשתנה מסוג חדש, הנקרא long ומחזיק מספרים באורך של 32 סיביות (ביטים). המשתנה החדש הזה יכול להחזיק מספרים בין 2,147,483,647 ל 2,147,483,648-. ומכיוון שאנו לא יכולים להריץ את הזמן לאחור כדי לקבל מספרים שליליים נשתמש ב unsigned long. כשמשתנה כלשהו נקרא unsigned הוא מקבל אך ורק ערכים חיוביים, לכן ה unsigned long יתחיל לספור מ0 (ולא מ2,147,483,648-) ונקבל ערכים עד 4,294,967,295 (ניתן לקרוא עליו בהרחבה כאן). תוכלו לחשב ולבדוק שהמספר הזה מספיק כדי לאחסן כמעט 50 ימים. - -אז איך בעצם נוכל לחשב כמה זמן עבר? ע"י לקיחת דיגמה עם ()millis בתחילת הפעולה של התוכנית וע"י לקיחת דגימה נוספת והשוואתה לדגימה הראשונה, אם נחסיר את הדגימה הנוכחית מהדגימה הראשונה ונגלה שהמספר שווה או גדול מ10 שניות, נידע שעברו 10 שניות. - -התכנון הוא להשתמש במתג מרקורי (מתג הטיה), כל פעם שנשנה את מצבו נתחיל מחזור (ספירה) חדש של הדלקת נורות ה LED. מתג ההטיה עובד בדיוק כמו מתג רגיל בכך שהוא חיישן on/off, בדרך כלל יש להם חלל קטן בתוכם וכדור מתכת, כאשר נטה אותו בדרך הנכונה הכדור יתגלגל לצד אחד של החלל ומחבר את שתי הפינות בלוח המטריצה שלנו, מה שסוגר את המתג (כך הוא מזהה את הכיוון בו הוא נמצא). בפרויקט שלנו נשתמש בו כקלט דיגיטלי. - -  - -### חיבור הרכיבים - -חברו ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). מקמו 6 נורות LED על גבי לוח המטריצה כשאל האנודה של כל אחת מהן (הרגל הארוכה) חברו חוט מגשר אל הפינים הדיגיטליים 2-7 (כולל), ומהרגל הקצרה חברו נגד 220Ω אל עמודת ה- (מינוס) של לוח המטריצה). - -מקמו את מתג ההטיה על גבי לוח המטריצה כשהחץ שעל ראש המתג צריך להיות למעלה-במעלי לוח המטריצה. -להלן סכמה ואיור להמחשה: - -
    - Arduino Project number 8 -
    - -  - -### הקוד - -נתחיל בהגדרת המשתנים הגלובלים: -תחילה ניצור משתנה int, קבוע, בשם switchPin כדי לשמור את מס' הפין של מתג ההטיה. -לאחר מכן ניצור משתנה unsigned מסוג long בשם previousTime, על מנת לשמור את הזמן האחרון בו בוצע שינוי (בו נדלק led). -ניצור עוד שתי משתנים מסוג int, הראשון בשם switchState שישמור את המצב הנוכחי של מתג ההטיה, והשני בשם prevSwitchState שישמור את המצב הקודם של מתג ההטיה. את שתיהם, כרגע, נאתחל ל 0. -ניצור משתנה מסוג int בשם led שישמור איזה לד (ע"י המספר שלו) הוא הבא בתור שיש להדליקו (נכניס לתוכו 2 כי הלד הראשון שמחובר לפין הדיגיטלי הוא פין מס' 2). -ולבסוף, המשתנה האחרון יהיה מסוג long ונקרא לו interval. המשתנה ישמור את הזמן (באלפיות השניה) שאנו רוצים להמתין בין הדלקת כל נורה (אם נכפיל אותו ב6 נקבל את זמן שעון החול כולו). - -בפוקנציית ה ()setup: -דבר ראשון אנו נכריז על הפינים הדיגיטלים 2-7 אליהם מחוברים נורות הלד כפיני output, בעזרת הפונ' ()pinMode. נבצע זאת בלולאה מ2 עד 8 (לא כולל) כדי שנוכל לגשת להיעזר במשתנה x (שסופר את הלולאה) כמספר הפין שיש לאתחל. -ונכריז על פין מס' 8 ששמור במשתנה בשם switchPin כ input כדי לקלוט את הערך ממתג ההטיה. - -בפונקציית ה ()loop: - -הדבר הראשון שנעשה כשה Arduino מתחיל את התוכנית (לאחר כל ההכרזות וההגדרות) הוא לקחת את הזמן הנוכחי ולהכניס אותו למשתנה חדש בשם currentTime (גם הוא יהיה unsigned long). - -כעת, נבדוק בעזרת if האם עבר מספיק זמן: -בתנאי ה if נחסיר מהזמן שלקחנו כעת (currentTime) את הזמן שלקחנו בהתחלה (previousTime) ונבדוק האם זה גדול מה interval (המשתנה השומר בתוכו את פרק הזמן הספציפי בו יש להדליק את הנורה באלפיות השניה). אם currentTime פחות הזמן ההתחלתי (previousTime ששוה ל0, כי הזמן שבו ה Arduino התחיל לפעול הוא 0 אלפיות השניה) גדול מ 600,000 אלפיות השניה, ז"א שעברו 10 דק'. לכן נכניס את הערך שב currentTime לתוך previousTime (על מנת להתחיל מחזור חדש של 600,000 אלפיות השניה), נדליק את ה led הבא בתור שיש להדליקו (מספרו נמצא במשתנה led) עם הפונ' ()digitalWrite, ולבסוף נעלה את led באחד (במקום לכתוב led=led+1, ישנו קיצור מקובל ע"י כתיבת ++led), ולבסוף נכניס לתוך ה if הזה עוד if בו נדבוק האם הגענו ללד מס' 7 (אני לא כתבתי כלום בתוכו, החלטתי שלא לבצע דבר, אך אתם יכולים לכתוב מה שעולה על רוחכם, כמו לולאה שתכבה את כל הלדים ולהתחיל את המשתנה led מחדש להיות 2) ולבסוף נסגור את ה if. - - -כעת אחרי בדיקת הזמן, נרצה לבדוק האם הפכו לנו את שעון החול, במקרה שלנו יותר נכון הטו. אם הטו אותו נתחיל את הספירה מחדש, במידה ולא נמשיך כרגיל. דבר ראשון נקרא את הערך ממתג ההטיה המחובר לפין מס' 8 ששמור במשתנה switchPin, נבצע זאת עם הפונ' ()digitalRead, ונשמור את הערך במשתנה switchState. - -ונבצע בדיקה, בעזרת משפט if, כדי לבדוק האם מתג ההטיה במצב אחר ממה שהיה (המצב הקודם שמור במשתנה בשם prevSwitchState). במידה והם שונים נאתחל את שעון החול, ז"א נעבור עם לולאה על כל הפינים ונאתחל בעזרת הפונ' digitalWrtie את הפינים להיות כבויים (LOW), לאחר מכן נאתחל את הפין ההתחלתי (השמור במשתנה בשם led) להיות 2, ולבסוף נאתחל את הזמן (ע"י הצבת הערך שב cureentTime במשתנה previousTime). ונסגור את ה if. - -בסוף פונ' ה loop, נבצע הצבה של הערך ממתג ההטיה (שמרנו אותו במשתנה switchState) בתוך prevSwitchState, על מנת שנוכל גם בלולאה הבאה להשוות את הערך ממתג ההטיה לערך החדש שיהיה שם (אם נשנה אותו) או לאותו אחד (אם לא נזיז את מתג ההטיה). - -  - -### לסיכום - -אז הכרנו רכיב חדש הנקרא מתג מרקורי (או מתג הטיה), עשינו שימוש נוסף (מחוכם יותר) בפונ' ()millis, בלולאות, משפטי if, השוואות וכד'. הפרויקט שבנינו הוא שעון חול דיגיטלי, הוא מתפקד כמו שעון חול רגיל, למשך שעה אחת בלבד אך ישנם נורות לד הנדלקות כל 10 דק' כדי לסמן לנו שעברו 10 דק'. כשאנו רוצים להתחיל את השעון מחדש, כל שיש לעושת הוא להטות את הפרויקט הצידה כדי שנקבל קריאה שונה ממתג ההטיה. - -במידה ואתם רוצים לשנות את הזמן הקבוע בו נורה נדלקת יש לשנות את המשתנה interval (עכשיו הוא נמצא על 600,000 מילי שניות = 10 דק', כדי לבצע בדיקה, כשבניתי את הפרויקט, החלפתי אותו ל 1,000 = 1 שניה). diff --git a/data/_oldPosts/2015-02-01-arduino-9.md b/data/_oldPosts/2015-02-01-arduino-9.md deleted file mode 100644 index 2a20784..0000000 --- a/data/_oldPosts/2015-02-01-arduino-9.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: '9 - מנוע DC' -author: nirgn -layout: post -summary: "בפרויקט הזה, נחבר מנוע אל הארדואינו שיפעל על פי הוראה מאיתנו (ע”י לחיצה על המתג). בנוסף להכרת רכיב המנוע, נכיר את הדיודה והטרנזיסטור." -category: Arduino ---- -בפרויקט הזה, נחבר מנוע אל הארדואינו שיפעל על פי הוראה מאיתנו (ע"י לחיצה על המתג). בנוסף להכרת רכיב המנוע, נכיר את הדיודה והטרנזיסטור. - -שליטה על מנוע בעזרת ה Arduino היא דבר מסובך יותר משליטה על נורת LED לדוגמה. ראשית, מכיוון שמנועים דורשים יותר זרם מאשר שהפינים של ה Arduino מסוגלים לספק. שנית, מכיוון שמנועים מסוגלים להפיק זרם משל עצמם, דבר שיכול לפגוע במעגל החשמלי שבנינו (אם אנחנו לא מודעים ומתכוננים לכך מראש). אז למה אנחנו בכלל משתמשים בהם? כי הם מגניבים, הם גורמים לדבר בעולם הפיזי לזוז, וזה שווה את הסיבוכים! - - - -  - -להזיז דברים זהוי פעולה שדורשת המון אנרגיה, לכן מנועים דורשים, בדרך כלל, יותר זרם מאשר מה שה Arduino מסוגל לספק (מנועים מסויימים דורשים גם מתח גבוה יותר). ה Arduino מספק 40 מיליאמפר (40mA) בכל פין, הרבה פחות ממה שרוב המנועים דורשים כדי לעבוד. - -טרנזיסטורים הם רכיבים המאפשרים לנו לשלוט במקור כוח בעל זרם ומתח גבוהים, מהיציאה (בעלת הזרם הנמוך) של ה Arduino. ישנם סוגים רבים (ושונים) של טרנזיסטורים, אבל כולם עובדים על אותו העיקרון. ניתן לחשוב עליהם כעל מתגים דיגיטליים. כאשר אנו נספק מתח לאחד הפינים של הטרנזיסטור (ישנם שלושה פינים סה"כ) הנקרא gate, הוא יסגור את המעגל בין שתי הפינים האחרים (הנקראים source ו drain). בדרך זו, אנו יכולים להדליק ולכבות (לסגור ולפתוח) מעגל בעל זרם / מתח גבוהה משל ה Arduino. - -מנועים הם סוג של מכשירים השראתים. [השראה](http://en.wikipedia.org/wiki/Electromagnetic_induction) היא תהליך שבו זרם חשמלי המשתנה בחוט יכול ליצור שדה מגנטי משתנה סביב החוט. כאשר [מנוע](http://en.wikipedia.org/wiki/Electric_motor) מקבל חשמל, הסליל יוצר שדה מגנטי, הגורם לגל (לרוטר) להסתובב. אך גם ההפך הוא נכון: מנוע יכול לייצר חשמל כאשר הגל מסתובב בכיוון ההפוך. נסו לחבר נורת LED למנוע ולסבוב את המוט (אם לא קורה דבר, נסו לסובב אותו לכיוון השני), הנורה צריכה להאיר, הפכתם את המנוע שלכם לגנרטור קטן (כאשר תפסיקו לסובב, המנוע יספק מתח בכיוון ההפוך מזה הנוכחי שנתתם לו. המתח ההפוך הזה נקרא גם "[counter-electromotive force](http://en.wikipedia.org/wiki/Counter-electromotive_force)" (או בקיצור back-emf) והוא עלול לגרום נזק לטרנזיסטור, בשל כך עלינו למקמם בינהם דיודה, הדיודה מאפשרת לחשמל לזרום בכיוון אחד בלבד, וכך מגנה על שאר המעגל. - -  - -### חיבור הרכיבים - -חברו ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND בארדואינו (בהתאמה, כפי שעשינו עד כה). הוסיפו מתג ללוח המטריצה, כשרגל אחת שלו מחוברת לכוח (+) והרגל השניה לפין מס' 2, מהרגל של המתג המחוברת לפין מס' 2 חברו, נגד 10KΩ לשורה אחרת בלוח המטריצה ומהשורה הזאת חברו חוט מגשר לעמודת המינוס (ניתן לחבר את הנגד ישר לעמודת ה-, אצלי הנגד היה קצר מידי מכדי להגיע ישירות). - -כשמשתמשים במעגלים עם מתחים שונים, צריך לחבר את המינוס שלהם (GND) ביחד, כדי לספק מינוס משותף. לכן נחבר בעזרת חוט מגשר את שתי עמודות המינוס של לוח המטריצה, כעת נוכל לחבר סוללה 9V לעמודות בצד השני של לוח המטריצה (לפלוס ולמינוס). - -את הטרנזיסטור נמקם על לוח המטריצה כשגב המתכת שלו פונה לעבר הסלולה והמנוע (הרחק מהארדואינו). הפין העליון נקרא gate נחבר ממנו חוט מגשר אל פין מס' 9. שינוי במתח על פין זה (פין השער) יחבר את 2 הפינים האחרים של הטרנזיסטור. הפין האמצעי (drain), אותו נחבר למנוע עם חוט מגשר ממנו אל עבר החלק השני של לוח המטריצה. ולבסוף הפין האחרון (התחתון ביותר) נקרא source, את הפין הזה נחבר אל המינוס (האדמה). כשהארדואינו יספק כוח לפין gate (דרך פין מס' 9) הוא יפעיל את הטרנזיסטור והפין האמצעי (drain) יחובר לפין התחתון (source). - -לבסוף, נחבר את המנוע אל לוח המטריצה. את ה+ (החוט האדום) נחבר לעמודת ה+ (הכוח) בלוח המטריצה (זאת בצד השני של לוח המטריצה, שמחוברת אל סוללת ה 9V), ואת החוט השחור נחבר לוח המטריצה אחרי החוט המגשר שהגיע מהפין drain. בנוסף, נחבר דיודה, הדיודה היא רכיב מקוטב (לכן הכיוון של מיקומן משנה), הן מבטיחות שהחשמל יזרום רק בכיוון אחד. שימו לב שעל הדיודה, באחד מצדדיה, ישנו פס, זהו הקצה השלילי, או קתודה. הקצה השני הוא החיוב, האנודה. חברו את האנודה (החיובי) לאדמה (ליד איפה שחיברו את החוט השחור שיוצא מהמנוע), ואת הקצה השלילי, הקתודה אל עמודת הפלוס בלוח המטריצה. זה יראה הפוך, והאמת שזה נכון. הדיודה תעזור לנו למנוע מתח חוזר (שנוצר ע"י המנוע אם נסובב אותו לצד השני, כי מתח חוזר זורם בכיוון ההפוך). - -להלן סכמה ואיור להמחשה: - -
    - Wiring Sketch -
    - -### הקוד - -הקוד דומה מאוד לקוד שהשתמשנו בו כדי להפעיל נורת LED בעזרת מתג. נגדיר 2 משתנים קבועים מסוג [Int](http://arduino.cc/en/Reference/Int), הראשון בשם switchPin שישמר לנו את מס' הפין אליו מחובר המתג. והשני motorPin שישמור לנו את מס' הפין אליו מחובר המנוע (דרך הטרנזיסטור). לאחר מכן נגדיר משתנה בשם switchState מסוג int ונכניס לתוכו את הערך 0 (בעתיד הוא ישמור לנו את הערך מהמתג, כך נדע אם הוא לחוץ או לא). - -**בפוקנציית ה ()setup:** - -נגדיר, בעזרת הפונקציה [pinMode](http://arduino.cc/en/Reference/PinMode), את הפינים הדיגיטלים להיות פלט / קלט. את הפין שמחובר לטרנזיסטור (ולמנוע) נגדיר להיות פלט, כדי להוציא אליו זרם. ואת הפין של המתג נגדיר להיות קלט כדי לקרוא ממנו את הזרם. - -**בפונקציית ה ()loop:** - -דבר ראשון שנעשה הוא לקרוא את מצב המתג עם הפונקציה [digitalRead](http://arduino.cc/en/Reference/DigitalRead), נכניס לתוכה את הפין אליו מחובר המתג, ששמרנו במשתנה הקבוע switchPin, ואת הערך נשמור במשתנה switchState שהגדרנו בהתחלה. - -לאחר מכן נבדוק האם הוא לחוץ או לא (סוגר מעגל או לא) ע"י משפט [if / else](http://arduino.cc/en/Reference/Else). ב if נבדוק האם המשתנה שווה ל HIGH (המילה השמורה לכך שיש זרם), במידה ויש, נשלח זרם למנוע (דרך הטרנזיסטור) עם הפונקציה [digitalWrite](http://arduino.cc/en/Reference/DigitalWrite)(נכניס לתוכה את מס' הפין, השמור במשתנה motorPin, ואת הערך HIGH כדי לשלוח זרם). אחרת (ז"א אם ה If לא נכון, ז"א שאנו לא לוחצים על המתג והמעגל החשמלי נפתח) אנו לא מקבלים מתח ולכן עלינו לנתק את המתח למנוע, לכן נשלח אליו (דרך הטרנזיסטור שמחובר אליו) את הערך LOW. ברגע שהטרנזסיטור יפסיק לקבל מתח מפין מס' 9 הוא יפתח את המעגל של המנוע והמנוע יפסיק לפעול. - -כך יראה הקוד הסופי: - -```c -const int switchPin = 2; -const int motorPin = 9; -int switchState = 0; - -void setup(){ - pinMode(motorPin, OUTPUT); - pinMode(switchPin, INPUT); -} - -void loop(){ - switchState = digitalRead(switchPin); - - if (switchState == HIGH){ - digitalWrite(motorPin, HIGH); - }else{ - digitalWrite(motorPin, LOW); - } -} -``` - -  - -### לסיכום - -אז הפרויקט הזה היה קצר וקטן, אך חשוב בגלל הרכיבים והטכניקות החדשות שלמדנו. הפרויקט התמקד בהפעלת מנוע חשמלי, וכדי להפעילו השתמשנו בטרנזיסטור (על מנת לשלוט בפעולה של המנוע ולא להפעילו באופן רציף), ודיודה על מנת להגן על הרכיבים במעגל החשמלי שלנו. - -> אולי תהיתם למה משתמשים באותן השמות לרגליים של נורות ה LED והדיודות, וזה כי נורות LED הן דיודות. ישנם סוגים רבים של דיודות, אבל כולם חולקים תכונה אחת: הם מאפשרי לזרם לזרום מהאנודה לקתודה, אך לא להפך. diff --git a/data/_oldPosts/2015-02-15-arduino-10.md b/data/_oldPosts/2015-02-15-arduino-10.md deleted file mode 100644 index fe10bfa..0000000 --- a/data/_oldPosts/2015-02-15-arduino-10.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -title: '10 - מנוע DC, המשך' -author: nirgn -layout: post -summary: "בפרויקט הזה, נמשיך לשחק עם המנוע שחיברנו לארדואינו בפוסט הקודם, אך הפעם נחבר 2 מתגים, הראשון יכבה וידליק את המנוע, והשני יהפוך את כיוון הפעולה שלו. ולבסוף נוסיף פוטנציומטר כדי לשלוט על המהירות בה המנוע מסתובב." -category: Arduino ---- -בפרויקט הזה, נמשיך לשחק עם המנוע שחיברנו לארדואינו בפוסט הקודם, אך הפעם נחבר 2 מתגים, הראשון יכבה וידליק את המנוע, והשני יהפוך את כיוון הפעולה שלו. ולבסוף נוסיף פוטנציומטר כדי לשלוט על המהירות בה המנוע מסתובב. - -בפרויקט הקודם גרמנו למנוע להסתובב בכיוון אחד. אם היינו הופכים את ה+ וה- המנוע היה מסתובב לכיוון השני. כמובן שזה לא מעשי להפוך את החיבורים בכל פעם שאנו רוצים להפוך את כיוון הסיבוב, לכן נבצע שימוש ברכיב חדש הנקרא [H-bridge](http://en.wikipedia.org/wiki/H_bridge) (גשר H). - - - -  - -H-bridge הוא סוג של רכיב הידוע גם כרכיב מעגלים משולבים (IC – [Integrated Circuits](http://en.wikipedia.org/wiki/Integrated_circuit)). מעגלים משולבים הם רכיבים המחזיקים מעגלים גדולים באריזה קטנה. הם מפשטים את המעגלים המרוכבים ע"י הצבה שלהם במקום חלק מהמעגל. לדוגמא, ל H-bridge יש כמה טרנזיסטורים מובנים בתוכו (כדי לבנות את המעגל שבתוך ה H-bridge לבד היינו כנראה צריכים לוח מטריצה נוסף). - -ניתן לגשת למעגל בתוך ה IC דרך הפינים (סיכות) שיוצאות מצדדיו. לרכיבי IC שונים יש כמות פינים שונה, ואין צורך להשתמש בכולם בכל מעגל שהוא. בנוסף, נוח יותר להתייחס לפינים כאל מספר במקום כאל פונקציה. כשאתם מסתכלים על רכיב IC, החלק עם הגומה תמיד נחשב לחלק העליון (נראה כמו U), וניתן למספר את הפינים ע"י מספור שלהם מהפין הראשון הנמצא בפינה השמאלית העליונה. - -  - -### חיבור הרכיבים - -חברו ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). חברו את החוטים המגשרים של הסוללה לעמודות ה+ וה- בצד השני של לוח המטריצה, וחברו חוט מגשר לשתי עמודות ה- (כדי לספק קרקע משותפת). - -הוסיפו שני מתגים ללוח המטריצה כך שיתיישבו על החוצץ של הלוח. את הרגל הראשונה (השמאלית העליונה) חברו לעמודת ה+ של הצד שלה (בעזרת חוט מגשר), ואת הרגל שמתחתיה חברו לפין הדיגיטלי מס' 5. בנוסף, חברו נגד 10K אוהם מהרגל הרביעית (הימינית התחתונה) לעמודת המינוס של הצד השני של לוח המטריצה. בצעו זאת שוב עם המתג השני, מקמו אותו מתחת למתג הראשון וחברו אותו לפין מס' 4. (המתג הראשון המחובר לפין 5 ישלוט על הכיבוי / הדלקה, בעוד המתג השני, המחובר לפין 4 ישלוט על כיוון הסיבוב). - -מתחת למתגים חברו ללוח המטריצה פוטנציומטר (לצד השמאלי של הלוח), אם אתם זוכרים, לפוטנציומטר יש 3 רגליים, הרגל הראשונה (העליונה) מתחברת לכוח (עמודת ה+), הרגל האמצעית מתחברת לפין האנלוגי (חברו אותו ל A0), והרגל האחרונה (התחתונה) מתחברת לאדמה (עמודת ה-). - -מקמו את ה H-bridge באמצע לוח המטריצה (כך שכמו המתגים, יתיישב על החוצץ ויחובר ל-2 צדדי לוח המטריצה, לא לשכוח שהגומה, U, צריכה להיות בראש הגשר). את פין מס' 1 של הגשר (זוכרים? הפין השמאלי העליון) חברו לפין הדיגיטלי מס' 9 של הארדואינו, כשהמתח (5V, HIGH) יגיע אליה הוא תפעיל את המנוע, וכשהוא לא יקבל מתח (0V, LOW) הוא יכבה את המנוע. - -חברו את פין מס' 2 של הגשר לפין הדיגיטלי מס' 3 של הארדואינו, ואת פין מס' 7 של הגשר לפין הדיגיטלי מס' 2 של הארדואינו. עם הפינים האלה נתקשר עם המנוע ונגיד לו לאיזה כיוון להסתובב. אם פין מס' 3 יתן מתח LOW ופין מס' 2 יתן HIGH המנוע יסתובב לכיוון אחד, ואם הפוך (פין מס' 3 יתן מתח HIGH ופין מס' 2 יתן LOW) המנוע יסתובב לכיוון השני (אם 2 הפינים יהיו LOW או HIGH יחדיו, המנוע יפסיק להסתובב). - -ה H-bridge מקבל את הכוח שלו דרך פין מס' 16 אז חברו אותו לעמודת ה+. ואת הפינים 4 ו-5 חברו לאדמה. את המנוע נחבר לפינים מס' 3 ו-6, כשזה לא משנה איך מכיוון שהם יחליפו בינהם את המתח (פעם הראשון יתן מתח והשני לא ובמידה ונשנה כיוון אז השני יתן והראשון לא). לבסוף, נחבר את פין מס' 8 של הגשר אל עמודת הפלוס של הסוללה. זה הפין "השואב" את המתח מהסוללה והגשר יעביר את אותו המתח למנוע (הרי המנוע מחובר לגשר, ולא לסוללה). - -להלן סכמה ואיור להמחשה: - -
    - Wiring Sketch -
    - -### הקוד - -אז לפני שנתחיל לכתוב את התוכנית עצמה, כמו תמיד, נכתוב את המשתנים הקבועים שיהוו תחליף למספרי הפינים, כדי שלא נצטרך להתעסק עם עוד מספרים בלי הגיון מסודר. פינים מס' 2 ו-3 יהיו פיני השליטה שלנו על הגשר (דרכם נשנה את כיוון הסיבוב של המנוע, אליהם נשלח את הפקודה) לכן נקרא להם controlPin1 ו controlPin2 (בהתאמה). לאחר מכן פין 9 (שמקשור לגשר) יהיה זה שיכבה / יפעיל את המנוע (אליו נשלח את הפקודה) ונקרא לו enablePin. פין 4 יהיה של המתג השני, הוא אחראי על החלפת כיוון הסיבוב (ממנו נקבל את פקודת שינוי הכיוון) ולכן נקרא לו directionSwitchPin. ופין מס' 5 אחראי על הפעלה / כיבוי של המנוע (ממנו נקבל את פקודת ההפעלה / כיבוי) ולכן נקרא לו onOffSwitchStateSwitchPin, ולבסוף הפין האנלוגי A0 (שמחובר לפוטנציומטר), ממנו נקבל את ערכי מהירות הסיבוב ונקרא לו potPin. - -כעת נגדיר את משתני העזר לתוכנית, המשתנים הראשונים יהיו משתני עזר שיחזיקו לנו את הערכים מהקריאות של המתגים והפונטציומטר. הראשון יחזיק לנו את הערך מהמתג הראשון, נקרא לו onOffSwitchState, השני יחזיק לנו את הערך הקודם של המתג הראשון (כדי שנוכל לבדוק האם הוא ישתנה, ז"א האם לחצו על המתג) אז נקרא לו previousOnOffSwitchState, השלישי יחזיק לנו את הערך מהמתג השני, של השינוי כיוון, נקרא לו directionSwitchState, ושוב כדי לראות האם הוא לחצו עליו או לא נצטרך להשוות אותו עם הערך הקודם שקראנו מהמתג הזה, לכן ניצור עוד משתנה שישמור את הערך הקודם, ונקרא לו preciousDirectionSwitchState, לאחר מכן ניצור משתנה בשם motorSpeed שישמור לנו את מהירות הסיבוב, ומשתנה בשם motorEnabled שיזכור האם המנוע פועל כרגע או לא, וכמובן משתנה בשם motorDIrection שיעקוב אחרי כיוון הסיבוב של המנוע (1 או 0, ימינה או שמאלה. זהו הערך היחידי שנאתחל אותו מהתחלה להיות 1 ולא 0). - -  - -**בפוקנציית ה ()setup:** - -[נגדיר את הפינים](http://arduino.cc/en/Reference/PinMode) להיות קלט / פלט: - - * directionSwitchPin יהיה במצב קלט, הוא שומר את ערכי המתג השני, ועל פי ערכים אלו נידע האם יש לשנות את כיוון סיבוב המנוע. - * onOffSwitchStateSwitchPin גם יהיה במצב קלט, ממנו נקלוט את ערכי המתג הראשון (וכך נידע האם לכבות / להדליק את המנוע). - * controlPin1 ו controlPin2 יהיו פלט, מכיוון שאליהם אנו שולחים את המתח שקובע את כיוון הסיבוב של המנוע. - * enablePin יהיה פלט, דרכו נכבה ונדליק את פעולת המנוע. - -לבסוף, כדי לוודא שהמנוע מתחיל במצב כבוי, נכתוב (בעזרת הפונ' [()digitalWrite](http://arduino.cc/en/Reference/DigitalWrite)) לפין מס' 9 (enablePin) להיות כבוי (ז"א מתח LOW). - -  - -**בפונקציית ה ()loop:** - -הדבר הראשון שאנחנו צריכים לעשות בפונ' ה loop הוא לקרוא האם ביקשו להדליק את המנוע, ז"א לחצו על המתג הראשון. לכן, נקרא את הערך מהמתג (שמספרו שמור במשתנה onOffSwitchStateSwitchPin) בעזרת הפונ' [()digitalRead](http://arduino.cc/en/Reference/DigitalRead) ונשמור את הערך שנקבל במשתנה בשם onOffSwitchState. לאחר מכן נחכה מאית שניה ונקרא גם את הערך מ directionSwitchPin כדי לדעת אם ביקשו לשנות את הכיוון של המנוע. ולבסוף נקרא את הערך מהפין האנלוגי potPin (בעזרת הפונ' [()analogRead](http://arduino.cc/en/Reference/AnalogRead)) ונחלק את הערך ב-4 (על מנת להתאימו לערכים של המנוע), ונשמור את הערך במשתנה בשם motorSpeed. אלו הם הדברים הראשונים שיש לעשות, לקרוא את הערכים משתי המתגים ומהפוטנציומטר, על מנת לדעת אם הם השתנו, ז"א האם ביקשו לבצע פעולה כלשהי. רק לאחר מכן אנו יכולים לבדוק האם הם אכן השתנו ולפעול בהתאם. - -  - -נבדוק האם ביקשו להדליק / לכבות את המנוע, נבצע זאת ע"י פקודת [if](http://arduino.cc/en/Reference/If) מקוננת (ז"א 2 פקודות if, אחת בתוך השניה), קודם כל נבדוק האם הערך שקראנו עכשיו (השמור במשתנה onOffSwitchState) שונה מהערך שקראנו בפעם הקודמת (השמור במשתנה previousDirectionSwitchState) (בפעם הראשונה לא שמור שם כלום חוץ מהערך ההתחלתי אותו הצבנו כשיצרנו את המשתנה, והוא 0, ז"א LOW) (את הבדיקה האם הם שווים אנו מבצעים ע"י פעמיים הסימן שווה, ==, את הבדיקה האם שתי ערכים שונים אחד מהשני מבצעים ע"י סימן קריאה ושווה, =!). במידה והאם שונים, ניכנס לתוך ה if, ואז נשאל שוב (עם עוד if) האם הערך שקראנו (onOffSwitchState) שווה ל HIGH, במידה וכן אנו צריכים להפוך את הערך שבמשתנה motorEnable (ז"א אם הוא היה 0 כעת הוא יהיה 1, ולהפך. נבצע זאת עם סימן הקריאה לפני המשתנה, המסמן שלילה. והשווה הוא כדי להציב אותו בתוך עצמו. אח"כ אנו נבדוק למה המשתנה שווה כדי לדעת איזה מתח לשלוח לגשר). - -נבצע אותו הדבר עם הכיוון, נכתוב if מקונן (שתיים, אחד בתוך השני) כשב if הראשון נבדוק האם הכיוון השתנה (ז"א האם הכיוון שקראנו כעת, directionSwitchState, שונה מהכיוון שקראנו בפעם האחרונה, previousDirectionSwitchState). במידה והוא השתנה, נבדוק האם הוא שווה ל-1 (HIGH), ובמידה ושווה נחליף את הערך במשתנה השומר לנו את הכיוון של המנוע (motorDirection). - -אחרי הבדיקות, נתחיל לשלוח את הערכים המתאימים לגשר (שבתורו יפעיל / יכבה את המנוע). ע"י משפט [if / else](http://arduino.cc/en/Reference/Else) נבדוק את כיוון המנוע הנוכחי (ז"א האם הערך motorDirection שווה ל-1, אם לא אנחנו הוא שווה ל-0, ואז ניכנס ל else). אם הוא שווה ל-1, נשלח (בעזרת הפונ' [()digitalWrite](http://arduino.cc/en/Reference/DigitalWrite)), ערך HIGH ל controlPin1 וערך LOW ל controlPin2, אחרת ההפך (LOW ל controlPin1 וערך HIGH ל controlPin2). (האמת שזה לא משנה, אתם גם יכולים להחליף בינהם, מה שזה בעצם אומר שהגשר יחליף את ערכי המתח למנוע, במקום את החוט האדום ב+ והשחור ב-, ואז להחליף, אנחנו פשוט משחקים עם המתח המוזרם לכל חוט). - -וכמובן שאנו צריכים גם לבדוק האם צריך לכבות את המנוע או לא, שוב ניעזר במשפט [if / else](http://arduino.cc/en/Reference/Else), אם motorEnable שווה ל-1, שהרי המנוע צריך לפעול, לכן נשלח (בעזרת הפונ' [()analogWrite](http://arduino.cc/en/Reference/AnalogWrite)) לפין האנלוגי 9 (שערכו שמור במשתנה enablePin) את הערך שבו הוא צריך להסתובב (ששמור במשתנה motorSpeed) (פין מס' 9 מחובר לגשר והוא זה שמפעיל / מכבה אותו על פי הזרם שהוא מקבל). במידה והערך הוא 0 ז"א LOW, שהרי המנוע צריך להיות מכובה, לכן נשלח לפין מס' 9 את המהירות שבו הוא צריך להסתובב שהיא 0. - -  - -לבסוף, לפני היציאה מה loop, כל שנשאר הוא לשמור את המשתנים הנוכחיים כמשתנים הקודמים (על מנת שבלולאה הבאה של הפונ' loop, שכזכור פועלת בלולאה אינסופית כל עוד הארדואינו מקבל חשמל, נקרא את הערכים החדשים ונשווה אותם לאלה מהפעם הזאת). נציב את ערך הכיוון (שנמצא במשתנה directionSwitchState למשתנה previousDirectionSwitchState) ואת הערך של המתג ההפעלה / כיבוי (שנמצא במשתנה onOffSwitchState למשתנה previousOnOffSwitchState). - - כך יראה הקוד הסופי: - -```c -const int controlPin1 = 2; -const int controlPin2 = 3; -const int enablePin = 9; -const int directionSwitchPin = 4; -const int onOffSwitchStateSwitchPin = 5; -const int potPin = A0; -int onOffSwitchState = 0; -int preciousOnOffSwitchState = 0; -int directionSwitchState = 0; -int previousDirectionSwitchState = 0; -int motorEnable = 0; -int motorSpeed = 0; -int motorDirection = 1; - -void setup(){ - pinMode(directionSwitchPin, INPUT); - pinMode(onOffSwitchStateSwitchPin, INPUT); - pinMode(controlPin1, OUTPUT); - pinMode(controlPin2, OUTPUT); - pinMode(enablePin, OUTPUT); - digitalWrite(enablePin, LOW); -} - -void loop(){ - onOffSwitchState = digitalRead(onOffSwitchStateSwitchPin); - dealy(1); - directionSwitchState = digitalRead(directionSwitchPin); - motorSpeed = analogRead(potPin)/4; - if (onOffSwitchState !=previousOnOffSwitchState){ - if (onOffSwitchState == HIGH){ - motorEnable = !motorEnable; - } - } - if (directionSwitchState != previousDirectionSwitchState){ - if(directionSwitchState == HIGH){ - motorDirection = !motorDirection; - } - } - if (motorDirection == 1){ - digitlWrite(controlPin1, HIGH); - digitalWrite(contaolPin2, LOW); - }else{ - digitalWrite(controlPin1, LOW); - digitalWrite(controlPin2, HIGH); - } - if (motorEnable == 1){ - analogWrite(enablePin, motorSpeed); - }else{ - analogWrite(enablePin, 0); - } - previousDirectionSwitchState = directionSwitchState; - previousOnOffSwitchState = onOffSwitchState; -} -``` - -  - -### לסיכום - -הפרויקט הזה היה ארוך ומורכב יותר. המשכנו לדבר על המנוע ושילבנו פונקציות קודמות שלמדנו ורכיבים שונים (מתגים ופוטנציומטר). בנוסף, למדנו על H-bridge - גשר, והבנו מהם מעגלים משולבים. אני מקווה שהצלחתם להפעיל את הפרויקט, ובמידה ואתם צריכים עזרה או שיש לכם איזשהי שאלה אשמח לעזור בתגובות. - -אם אתם רוצים להפוך את הפרויקט לשימושי יותר, חשבו על כך שהפעולה העיקרית שאתם עושים היא החלפת הכיוון של סיבוב המנוע מצד ימין לצד שמאל ולהפך, איזה דברים דורשים פעולה כזאת? ניתן לחשוב על שבשבת, על מנעול (סיבוב לצד אחד נועל וסיבוב לצד שני פותח), מאורר (כיוון המאורר), או אפילו רכב על שלט (אם נחבר גלגל שיניים למנוע בצורה אורכית, סיבוב ימינה / שמאלה יניע את הגלגלים קדימה / אחורה). diff --git a/data/_oldPosts/2015-03-01-arduino-11.md b/data/_oldPosts/2015-03-01-arduino-11.md deleted file mode 100644 index 5d2fcc1..0000000 --- a/data/_oldPosts/2015-03-01-arduino-11.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: '11 - כדור 8 קסום, שימוש ב LCD' -author: nirgn -summary: "בפרויקט הזה, נבנה את הצעצוע הקלאסי magic 8-ball. נשתמש בפעם הראשונה במסך LCD כדי להציג את הטקסט, ומתג הטייה על מנת לבדוק האם ניערנו את הכדור." -hero-image: "categories/arduino.png" -layout: post -category: Arduino ---- -בפרויקט הזה, נבנה את הצעצוע הקלאסי [magic 8-ball](http://en.wikipedia.org/wiki/Magic_8-Ball). אך נבנה אותו בצורה אחרת, ועם פחות אפשרויות (8 במקום 20, בשביל הקטנת קטע הקוד) נשתמש בפעם הראשונה במסך LCD כדי להציג את הטקסט, ומתג הטייה על מנת לבדוק האם ניערנו את הכדור (כדי לשאול שאלה). - -מתג ההטייה כאמור יעזור לנו לחקות את תנועת הניעור / טלטול הקלאסית של הכדור על מנת לראות את התשובה. בעוד מסך ה LCD יספק לנו אותה (נחבר לפרויקט גם פוטנציומטר כדי לשלוט כל המסך). - -מסך ה LCD שבו אשתמש יכול להציג מציג 32 תווים אלפאנומריים (16 עמודות ו-2 שורות). למסך יש הרבה סיכות (חלקן משמשות לכוח וחלקן משמות לתקשורת והעברת מידע), אנו לא נחבר את כולן (כי אין לנו צורך בכך), אך כמות החוטים שנצטרך לחבר תהפוך את הפרויקט לקצת מסובך (לא מבחינת הבנה, אלא מבחינת כמות החוטים, אז שימו לב). - - - -  - -### חיבור הרכיבים - -כמו תמיד, חברו ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). מקמו את מתג ההטייה על גבי לוח המטריצה, וחברו קצה אחד שלו לכוח (5V) בעזרת חוט מגשר, ואת הקצה השני לעמודת המינוס בעזרת נגד 10K אוהם, בנוסף, נחבר חוט מגשר מהרגל של המינוס שלו אל הפין הדיגיטלי מס' 6. - -פין ה RS של המסך שולט על היכן התווים יצוגו (על גבי המסך). הפין R/W מכניס את המסך למצב פלט / קלט (נשתמש במצב פלט בפרויקט הזה). פין ה EN (או E) אומר למסך שהוא יקבל פקודה. פיני המידע (D0-D7) משמשים כדי לשלוח מידע למסך (נשתמש רק ב-4 מתוכם). ולבסוף נשתמש בפינים -LED ו +LED כדי לכוון את הניגודיות של המסך. - -ניעזר בספרייה [liquidCrystal](http://arduino.cc/en/Reference/LiquidCrystal) הניתנת לנו "חינם" עם ה Arduino ומפשטת את תהליך הכתיבה אל המסך והצגת התווים על גביו. אז נחבר את הפינים החיצוניים ביותר (Vss ו -LED) לאדמה (בעזרת חוט מגשר), וגם את הפין R/W (כדי שהוא יכניס את המסך למצב של write). את מקור הכוח של המסך (Vcc) נחבר ישירות לעמודת ה 5V בעזרת חוט מגשר, ואת פין ה +LED נחבר לעמודת ה 5V עם נגד 220 אוהם. - -כעת, נחבר את פיני המידע. נחבר את הפין הדיגיטלי מס' 2 של הארדואינו לפין D7 של המסך, את פין מס' 3 של הארדואינו לפין D6 של המסך, את פין מס' 4 של הארדואינו לפין D5 של המסך, ואת פין מס' 5 של הארדואינו לפין D4, בפינים אלה נשתמש כדי לשלוח את המידע אל המסך. - -לבסוף, נחבר את פין EN (או E) של המסך לפין הדיגיטלי מס' 11 של הארדואינו, ואת הפין RS של המסך לפין מס' 12 של הארדואינו (הפין יאפשר את הכתיבה למסך, בניגוד ל R/W שמכניס אותו למצב כתיבה או פיני המידע ששולחים את המידע). - -בנוסף, לא לשכוח לחבר את הפוטנציומטר ללוח המטריצה, רגל אחת לאדמה ואת השניה לכוח, כשהרגל האמצעית תתחבר ישירות ל V0 של המסך. -להלן סכמה ואיור להמחשה: - -
    - Wiring Sketch -
    - -  - -### הקוד - -תחילה נייבא את הספרייה של ה LCD עם הפקודה [include#](http://arduino.cc/en/Reference/Include) ובסוגריים משולשים את שם הספרייה. לאחר מכן נאתחל אותה ונכניס את מספרי הפינים שימשו לנו לתקשורת בין הארדואינו למסך. - -כעת נגדיר את המשתנים השונים שבהם ניעזר במהלך התוכנית, switchPin שישמור את המס' 6 (אליו מחובר מתג ההטיה, על מנת לראות האם הזיזו אותו) והוא יהיה קבוע. והמשתנים switchState ו prevSwitchState שבהם נשמור את המצב בו נמצא מתג ההטיה (כדי לראות אם הוא זז נצטרך לשמור גם את מצבו העכשוי וגם את מצבו הקודם), ומשתנה בשם reply (שבו נשמור את המס' הרנדומלי שנקבל כדי להגריל את התשובה שתודפס על המסך). - -  - -**בפוקנציית ה ()setup:** - -נתחיל את פעולת ה LCD ונכניס לתוך הפקודה את הפרמטרים של גודל המסך. ונכוון את פין מס' 6 - switchPin (המחובר למתג ההטיה) להיות קלט. נחזור ל LCD ונכתוב פקודה על המסך בעזרת הפונ' [()lcd.print](http://arduino.cc/en/Reference/LiquidCrystalPrint) המקבלת טקסט (כדי להגדיר את הכתוב כטקסט נכניסו בתוך גרשיים). ועכשיו כדי לכתוב בשורה השניה עוד טקסט, תחילה יש להזיז את ה cursor (סמן). נזיז אותו עם [()lcd.setCursor](http://arduino.cc/en/Reference/LiquidCrystalSetCursor) וכפרמטרים נכניס את העמודה 0 (הראשונה), ואת השורה 1 (השנייה). ושוב נכניס טקסט לשורה השניה. - -  - -**בפונקציית ה ()loop:** - -בתוך ה loop יש קודם כל לקרוא את הערך מפין מס' 6 (ממתג ההטיה) ולבדוק האם הוא זז (עם משפט [if](http://arduino.cc/en/Reference/If)), לאחר מכן לוודא האם הוא שווה ל LOW (עם משפט [if](http://arduino.cc/en/Reference/If) נוסף) (ז"א האם הוא זז, וכתוצאה מזה פתח את המעגל). במידה וכן נסיק כי המשתמש ניער / טלטל את הפרויקט ( / הכדור) ויש להחליף את הכתוב על המסך. - -דבר ראשון נגריל מספר (על מנת להגריל את התשובה), הפונ' [()random](http://arduino.cc/en/Reference/Random) מחזירה מספר בהתבסס על הפרמטר שהעברנו לה, בפרויקט שלנו נכניס לתוכה את המס' 8 , והיא תחזיר מספר בין 0 למספר אחד פחות ממה שהכנסו, ז"א נקבל מספר בין 0-7 (סה"כ 8 אפשרויות). - -ננקה את המסך בעזרת הפקודה [()lcd.clear](http://arduino.cc/en/Reference/LiquidCrystalClear), נזיז את הסמן להתחלה (שורה 0 עמודה 0). ונכתוב ש"הכדור אומר:" ונזיז את הסמן לשורה השניה (1) עמודה ראשונה (0) כדי להיות מוכנים לכתוב מה הוא אומר. כעת נעבור על כל האופציות שלנו (המספרים בין 0 ל-7), אך במקום לעבור עליהם עם משפטי if, נעבור עליהם עם [switch](http://arduino.cc/en/Reference/SwitchCase). - -switch לוקח מס' כלשהו (השמור במשתנה reply) ועובר על מספרים שלמים כדי לראות איזה מתאים, ז"א "case 0" יהיה אם reply=0. לאחר ה"case 0" נכתוב נקודותיים ואז מה יקרה במידה ומדובר על המקרה הזה (במקרה של 0 נגיד למסך להדפיס "yes", ונבצע את הפקודה [break](http://arduino.cc/en/Reference/Break), הפקודה תגיד ל Arduino היכן נגמר קטע הפקודות שעליו לבצע במידה ו reply=0, והוא ידלג על שאר הבדיקות ויקפוץ לסוף ה switch. - -לבסוף כמובן, לפני שניצא מהתוכנית נשמור את הערך של מתג ההטיה הנוכחי כערך הקודם (ממש לפני שאנחנו עוברים עליה שוב כדי לקרוא ערך הטייה חדש ולבדוק האם האם שווים או לא (האם הזיזו את הפרויקט / כדור או לא)). - - כך יראה הקוד הסופי: - -```c -#include -LiquidCrystal lcd(12, 11, 5, 4, 3, 2); -const int switchPin = 6; -int switchState = 0; -int prevSwitchState = 0; -int reply; - -void setup(){ - lcd.begin(16, 2); - pinMode(switchPin, INPUT); - lcd.print("Ask the"); - lcd.setCursor(0, 1); - lcd.print("Crystal Ball!"); -} - -void loop(){ - switchState = digitalRead(switchPin); - - if(switchState != prevSwitchState){ - if(switchState == LOW){ - reply = random(8); - lcd.clear(); - lcd.setCursor(0, 0); - lcd.print("The ball says:"); - lcd.setCursor(0, 1); - - swtich(reply){ - case 0: lcd.print("Yes"); - break; - case 1: lcd.print("Most likely"); - break; - case 2: lcd.print("Certainly"); - break; - case 3: lcd.print("Outlook good"); - break; - case 4: lcd.print("Unsure"); - break; - case 5: lcd.print("Ask again"); - break; - case 6: lcd.print("Doudtful"); - break; - case 7: lcd.print("No"); - break; - } - } - } - prevSwitchState = switchState; -} -``` - -  - -### לסיכום - -הפרויקט הזה לא היה מורכב מידי אך היה חשוב, שכן חזרנו קצת על שימוש במתג ההטייה ובפוטנציומטר, בייבוא ספריות (עשינו את זה גם בפרויקט הסרוו). למדנו על רכיב חדש ושימושי מאוד בחיינו – מסך LCD, והשתמשנו בפקודה חדשה בשם switch. - -> שימו לב לגבי כל החוטים המגשרים שעוברים בפרויקט, אם נתקלתם בבעיות כלשהן, סביר להניח שהן נובעות מחיבור לא נכון של החוטים (בהתחשב בכמות הגבוהה שיש בפרויקט הנל) - אז שימו לב. diff --git a/data/_oldPosts/2015-03-15-binary-tree.md b/data/_oldPosts/2015-03-15-binary-tree.md deleted file mode 100644 index 2721aeb..0000000 --- a/data/_oldPosts/2015-03-15-binary-tree.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: עץ בינארי (Binary Tree) -author: nirgn -layout: post -summary: "עץ בינארי הוא מבנה נתונים מופשט, הבנוי / מאורגן בצורת עץ, כשלכל קודקוד יש לכל היותר שני בנים (המתייחסים אליהם כ’בן ימיני’ ו’בן שמאלי’) ולכל קודקוד (פרט לראשון, הנקרא שורש) יש אב יחיד." -category: Data Structures ---- - -
    - First example of binary tree -
    - -עץ בינארי הוא מבנה נתונים מופשט, הבנוי / מאורגן בצורת עץ, כשלכל קודקוד יש לכל היותר שני בנים (המתייחסים אליהם כ'בן ימיני' ו'בן שמאלי') ולכל קודקוד (פרט לראשון, הנקרא שורש) יש אב יחיד. העץ הינו מכוון ז"א שישנו כיוון אחד (במקרה שלנו נראה כמו מלמעלה למטה, כאילו אנו יורדים במורד העץ), וזה מתבטא בכך שכל צומת שומר אך ורק את הבנים שלו ולא את האב. - - - -עץ הוא בעצם סוג של גרף (מבנה נתונים נוסף, עליו נדבר בעתיד), למי שכן קצת מכיר גרפים אז עץ הוא גרף קשיר ללא מעגלים. עץ בינארי לעומת זאת (מבנה נתונים ספציפי יותר) הוא עץ מכוון (ז"א שניתן ללכת בו בכיוון אחד בלבד, כך שאנו יודעים מי האב ומי הבן), לכל צומת יש יש לכל היותר שני צאצאים (צמתים), וקיים קודקוד אחד ויחיד (שיקרא שורש העץ). - -  - -אבות ובנים בעץ בינארי מוגדרים כאשר יש קשת מ A ל B. זה אומר ש A הוא אב של B ו B הוא בן של A. ניתן לראות בשתי התמונות למטה דוגמאות של עצים בינארים: הימינית עם אותיות, בה ניתן לראות ש A הוא השורש ו B ו C הם הבנים שלו (וכך הלאה), והשמאלית עם מספרים, בה ניתן לראות ש 1 הוא השורש ו 2 ו 3 הם הבנים שלו (וכך הלאה). - -
    - Second example of binary tree -
    - -  - -בנוסף, גם לעץ בינארי יש כמה סוגים (מבני נתונים ספציפיים יותר) להלן כמה מהם: - - * **עץ בינארי מלא –** עץ בו לכל צומת שאינו עלה יש שני בנים. - * **עץ בינארי מאוזן –** עץ בו ההפרש בין הגובה של שני תתי-עצים של אותה הצומת לעולם אינו גדול מאחד. לכן הגובה שלו יהיה חסום (מלמעלה) ע"י הערך (log2(n (כאשר n הוא מס' הצמתים בעץ). - * **עץ בינארי מנוון –** עץ בו לכל צומת שאינו עלה יש בן אחד בלבד. - * **עץ חיפוש בינארי –** בו לכל קודקוד שני בנים. הבן השמאלי (יחד עם כל צאצאיו) קודם לאביו ביחס הסדר, ואילו הבן השמאלי (יחד עם כל צאצאיו) נמצא אחרי אביו מבחינת הסדר. - * **עץ אדום שחור –** מבנה נתונים המשלב עץ חיפוש בינארי, עם עץ בינארי מאוזן. - -יש לציין כי הפעולות המתבצעות על עצים בינארים נעשות בזמן הנמצא ביחס ישיר לגבוהו של העץ. ובפוסט הזה אנו נתמקד בעץ חיפוש בינארי, ובעץ בינארי מאוזן – AVL בלבד. - -  - -### Binary Search Tree - עץ חיפוש בינארי - -עץ חיפוש בינארי הוא עץ הנתונים הפופלרי ביותר. כל צומת בעץ חיפוש בינארי מכיל את השדות left (הבן השמאלי), right (הבן הימני), p (האב של צומת זו), ואם אחד הבנים או האב חסר, השדה המתאים מכיל את הערך NIL (צומת השורש, הוא הצומת היחיד בעץ ששדה האב שלו מכיל NIL). - -על מנת שעץ בינארי יחשב לעץ חיפוש בינארי, על המפתחות בעץ להיות מאוחסנים תמיד באופן כזה שיקיים את תכונת עץ החיפוש הבינארי: - -> _יהי x צומת בעץ חיפוש בינארי. אם y הוא צומת בתת עץ השמאלי של x, אזי [key[y] <= key[x. אם y הוא צומת בתת עץ הימיני של x, אזי [key[x] <= key[y._ - -תכונה זו של עץ החיפוש הבינארי מאפשרת לנו להדפיס בסדר ממוין את כל המפתחות שעץ החיפוש הבינארי מכיל, באמצעות אלגוריתם רקורסיבי פשוט הנקרא סריקה תוכית של עץ (InOrder Tree Walk). שמו של האלגוריתם נגזר מכך שהמפתח של השורש של תת עץ מודפיס בין הערכים המופיעים בתת עץ השמאלי שלו לאלה המופיעים בתת עץ הימיני שלו (בצורה דומה לסריקה תוכית, ישנה גם סריקה תחילת של העץ (PreOrder Tree Walk) המדפיסה את השורש לפני הערכים המופיעים בכל אחד מהתת עצים שלו, וסריקה סופית של העץ (PostOrder Tree Walk) המדפיסה את השורש אחרי הערכים המופיעים בכל אחד מהתת עצים שלו). - -להלן Inorder Tree Walk המדפיסה את כל המפתחות בסדר ממוין, בעץ חיפוש בינארי. -קוד: - -```c -INORDER-TREE-WALK (x) -if (x != NIL) - INORDER-TREE-WALK (left[x]) - print key[x] - INORDER-TREE-WALK (right[x]) -``` - - לדוגמה, סריקה תוכית של העץ בתמונה למעלה (השמאלית) תדפיס: 6,3,8,5,7,1,4,2. הסריקה עצמה מתבצעת בזמן (O(n (לעץ בעל n צמתים), שכן לאחר הקריאה ההתחלתית, האלגוריתם נקרא באופן רקורסיבי בדיוק פעמיים עבור כל צומת בעת (פעם בנו השמאלי, ופעם בנו הימיני). - -  - -### שאילתות - -אחת הפעולות השכיחות על עץ חיפוש בינארי היא חיפוש מפתח המאוחסן בעץ. מלבד הפעולה Search, עץ חיפוש בינארי יכול לתמוך בשאילתות נוספות (כמו Minimum, Maximum, Successor ו Predecessor). לכן נממשן על עץ חיפוש בינארי בגובה h [בזמן (O(h]. כמו בכל פוסט, הקוד יכתב ב [פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode). - -**Tree-Search -** מחזיר מצביע לצומת בעל מפתח k, אם קיים כזה. אחרת מחזירה NIL. -קוד: - -```c -TREE-SEARCH (x, k) -if (x = NIL or k = key[x]) - return x -if (k < key[x]) - return TREE-SEARCH (left[x], k) -else return TREE-SEARCH (right[x], k) -``` - -האלגוריתם מתחיל את החיפוש בשורש העץ וסורק מסלול במוקד העץ. בכל צומת x כשהוא נתקל בו, הוא משווה את המפתח k עם [key[x. אם שני המפתחות שווים, החיפוש מסתיים. אם k קטן מ [key[x, החיפוש נמשך בתת עץ השמאלי של x (שכן מתכונת עץ החיפוש בינארי אנו יודעים ש k אינו יכול להימצא בתת עץ הימיני). בדומה, אם k גדול מ [key[x החיפוש נמשך בתת עץ הימיני. הצמתים הנבחנים (כל ה [key[x-ים הנבחנים במהלך הריצה של האלגו') יוצרים מעין מסלול במורד העץ, החל מהשורש שנבחן ראשון. ומכאן שזמן הריצה של האלגו' הוא (O(h, כאשר h הוא גובה העץ. - -  - -**Tree-Minimum -** מחזיר מצביע לאיבר המינימלי. -קוד: - -```c -TREE-MINIMUM (x) -while (left[x] != NIL) do - x <- left[x] -return x -``` - - אפשר תמיד למצוא את האיבר בעל המפתח המינימלי בעץ חיפוש בינארי על ידי מעקב אחר המצביעים left, החל משורש העץ ועד שנתקלים ב NIL. הרי תוכנת העץ הבינארי מבטיחה לנו כי הבן השמאלי תמיד יהיה קטן מהעלה הנוכחי ומהבן הימיני שלו (במידה וקיים). לכן נלך שמאלה עד שלא יהיו עוד עלים. אם לצומת אין תת עץ שמאלי, אז המפתח המינימלי בתת עץ המורש ב x הוא השורש עצמו, ז"א [key[x (לכן נחזיר x לא קשר לנעשה בלולאה). אך אם לצומת x יש תת עץ שמאלי, אז כמו שאמרנו לא יכול להיות מפתח בתת עץ הימיני שהוא קטן מ [key[x, וכל המפתחות בתת עץ השמאלי אינם גודלים מ [key[x, לכן המפתח המינימלי יימצא בתת עץ המורש ב [left[x. - -  - -**Tree-Maximum -** מחזיר מצביע לאיבר המקסימלי. -קוד: - -```c -TREE-MAXIMUM (x) -while (right[x] != NIL) do - x <- right[x] -return x -``` - - הקוד למציאת האיבר המקסימלי סימטרי לקוד המחזיר מצביע לאיבר המינימלי. הרי מאותה התכונה של עץ בינארי מובטח לנו כי האיבר בעל הערך הגדול תמיד ימצא בתת עץ הימיני (בתת עץ הנגזר מהבן הימיני), לכן נלך ימינה עד אשר נמצא את העלה האחרון (נקבל NIL ואז נדע שהעלה שלפניו הוא העלה האחרון). זמן הריצה של האלגוריתמים למציאת האיבר המינמלי או המקסימלי הוא (O(h, כאשר h הוא גובה העץ (שכן שתי האלגו' סורקים מסלולים במורד העץ). - -  - -**Tree-Successor -** מחזיר את העוקב (הצומת בעל המפתח הקטן ביותר הגדול מ [key[x) לצומת x, אם קיים כזה, ו NIL אם x הוא בעל המפתח הגדול ביותר בעץ. -קוד: - -```c -TREE-SUCCESSOR (x) -if (right[x] != NIL) - return TREE-MINMUM (right[x]) -y <- p[x] -while (y != NIL and x = right[y]) do - x <- y - y <- p[y] -return y -``` - -כמו שניתן לראות, הקוד מחולק ל-2 מקרים. אם התת עץ הימיני של צומת x אינו ריק, אז העוקב לx הוא פשוט הצומת השמאלי ביותר (עם הערך הקטן ביותר) בתת עץ הימיני, לכן קוראים ל Tree-Minimum על [right[x. אך במקרה השני בו תת העץ הימיני של צומת x ריק ול x יש עוקב (נקרא לו y). אז y הוא האב הקדמון הנמוך ביותר של x (ז"א הגבוה ביותר בעץ) אשר הבן השמאלי שלו גם הוא אב קדמון של x (שניתן להגיע ממנו ל x אך ורק ע"י ירידה במורד העץ). כדי למצוא את y נעלה בעץ החל מ x עד שנתקל בצומת שהוא הבן השמאלי של אביו (שמתבצע בשורות 4-8 באלגו'). - -האלגו' Tree-Successor מחזיר את הקודם לצומת x, והינו סימטרי לאגו' הזה. שתיהם רצים בזמן (O(h על עץ בגובה h. - -  - -**Tree-Insert -** כדי להכניס ערך חדש v, לעץ חיפוש בינארי T. -קוד: - -```c -TREE-INSERT (T, z) -y <- NIL -x <- root[T] -while (x != NIL) do - y <- x - if (key[z] <- key[x]) - x <- left[x] - else x <- right[x] -p[z] <- y -if (y = NIL) - root[T] <- z -else if (key[z] <- key[y]) - left[y] <- z -else right[y] <- z -``` - - האלגוריתם מקבל כפרמטר צומת z, שעבורו key[z] = v, והבן השמאלי והימיני שלו ריקים (right[z] = NIL ו left[z] = NIL). האלגו' משנה את T וחלק מהשדות של z באופן כזה ש z מוכנס למקומו המתאים בעץ. - -האלגו' מתחיל בשורש העץ וסורק מסלול כלפי מטה. המצביע x סורק את המסלול, ו y מצביע תמיד על האב של x (כדי לדעת אחרי איזה איבר להכניס את z). לאחר פעולת האתחול, לולאת ה while בשורות 4-8 גורמת לכך ששני המצביעים (x ו y) ירדו במורד העץ ויפנו שמאלה או ימינה בכל צומת, על פי תוצאת ההשוואה בין [key[z ל [key[x, עד ש x יקבל את הערך NIL ויצא מהלולאה. הערך NIL נמצא בדיוק במיקום בו אני רוצים להציב את איבר הקלט z, ובשורות 9-14 נקבעים ערכי המצביעים הגורמים להכנסתו של z לעץ. - -גם כאן, בדומה לפעולות הבסיסיות האחרות על עצי חיפוש בינאריים, האלגו' רץ בזמן (O(h על עץ בגובה h. - -  - -**Tree-Delete -** כדי למחוק צומת נתון z מעץ חיפוש בינארי (המתודה מקבלת מצביע ל z). -קוד: - -```c -TREE-DELETE (T. z) -if (left[z] = NIL or right[z] = NIL) - y <- z -else y <- TREE-SUCCESSOR(z) -if (left[y] != NIL) - x <- left[y] -else x <- right[y] -if (x != NIL) - p[x] <- [y] -if (p[y] = NIL) - root[t] <- x -else if (y = left[p[y]]) - left[p[y]] <- x - else right[p[y]] <- x -if (y != z) - key[z] <- key[y] - copy y-s satellite data into z -return y -``` - - פעולת המחיקה קצת יותר מסובכת מכיוון שהיא גורמת לשינוי בקבוצה הדינמית המיוצגת על ידי עץ החיפוש הבינארי. יש לשנות את מבנה הנתונים כך שישקף את השינוי הזה, ויש לעשות זאת בלי להפר את תכונות עץ החיפוש הבינארי. - -השגרה מטפלת ב-3 מקרים: אם ל z אין בנים, משנים את אביו [p[z כך שבנו יהיה NIL במקום z. אם לצומת יש רק בן אחד, מסירים את z ע"י יצרת קשר חדש בין אביו לבנו. ואם לצומת יש שני בנים, מסירים את y, העוקב של z אשר לו אין בן שמאלי והמפתח והנתונים הנלווים של z מוחלפים באלה של y. למטה  מצד שמאל, ניתן לראות דוגמה לשלושת המקרים (על פי הסדר שתיארנו כאן). - -
    - Delete from Tree -
    - -בשורות 2-4 האלגוריתם קובע איזה צומת y תוסר. הצומת y היא צומת הקלט z (אם ל z לכל היותר בן אחד) או העוקב של z (אם ל z שני בנים). לאחר מכן, בשורות 5-7, מציבים ב x מצביע לבנו של y שאינו NIL, אם יש כזה, ואם ל y אין בנים מציבים ב x את NIL. בשורות 8-14 מסירים את הצומת y באמצעות שינוי ערכי מצביעים ב [p[y וב x. הסרתו של y מסתבכת קצת עקב הצורך לטפל במקרי קצה בהם x=NIL או y הוא שורש העץ. ולבסוף, אם הצומת שהוסרה הייתה העוקב של z, מעבירים בשורות 15-17 את המפתח ואת הנתונים הנלווים של y אל z במקום המפתח והנתונים הנלווים הקודמים. בשורה 18 מחזירים את הצומת y למתודה הקוראת, כדי שזו תוכל למחזר אותו באמצעות רשימת הפנויים. - -זמן הריצה הוא (O(h עבור עץ בגובה h.  - -  - -### לסיכום - -אז הצגנו את תכונותיהם הבסיסיות של עצי חיפוש בינאריים, ולאחר מכן ראינו כיצד סורקים עץ חיפוש בינארי כדי להדפיס את ערכיו בסדר ממוין, כיצד מחפשים ערך בעץ חיפוש בינארי, כיצד מוצאים את איבר המינימום או המקסימום, כיצד מוצאים את האיבר העוקב לאיבר נתון (ובאופן סימטרי את האיבר הקודם לאיבר נתון), וכיצד מכניסים איבר לעץ חיפוש בינארי או מוחקים ממנו איבר. - -היתרון בעצי חיפוש בינאריים הוא האפשרות לחפש איבר מסוים או למיין את האיברים בזמן מהיר יחסית (לדוגמה ביחס למערך או רשימה מקושרת). הפעולות הבסיסיות שתיארנו יתבצעו במהירות אם עץ החיפוש הוא נמוך, אך אם הוא גבוה, הביצועים לא יהיו טובים יותר מאשר מימוש באמצעות רשימה מקושרת. לכן בפוסט הבא נדבר על עצי חיפוש מאוזנים, או AVL. diff --git a/data/_oldPosts/2015-04-19-arduino-12.md b/data/_oldPosts/2015-04-19-arduino-12.md deleted file mode 100644 index 9b712c0..0000000 --- a/data/_oldPosts/2015-04-19-arduino-12.md +++ /dev/null @@ -1,182 +0,0 @@ ---- -title: '12 - מנגנון נעילה' -author: nirgn -layout: post -summary: "בפרויקט הזה, נבנה מנגנון נעילה. אפשר לבנות את המעגל כשלעצמו, אך הרבה יותר כיף אם הוא באמת עושה משהו, לכן אם יש לכם קופסת קרטון, עץ או משהו דומה, חתכו אותה והשתמשו במנוע הסרוו על מנת לפתוח ולסגור אותה." -category: Arduino ---- -בפרויקט הזה, נבנה מנגנון נעילה. אפשר לבנות את המעגל כשלעצמו, אך הרבה יותר כיף אם הוא באמת עושה ההו, לכן אם יש לכם קופסת קרטון, עץ או משהו דומה, חתכו אותה והשתמשו במנוע הסרוו על מנת לפתוח ולסגור אותה. - - - -בפרויקטים הקודמים השתמשנו ברכיב ה Piezo בשביל להוציא פלט (תווים), אך אנחנו יכולים גם להשתמש בו כאמצעי קלט ע"י חיבור למקור כוח (5V, +), כדי החיישן של ה Piezo יהיה מסוגל לזהות תנודות שאותם אנו יכולים לקרוא עם הכניסה האנלוגית של ה Arduino (כניסה A0). כאשר רכיב ה Piezo מחובר למשטח מוצק שיכול לרטוט (כמו משטח עץ לדוגמה), הארדואינו יכול לחוש את אינטנסיביות הרטט, התזוהה של המשטח. ואנו יכולים לבדוק האם הדפיקה על העץ (knock) נמצאת בטווח כלשהו (עליו החלטנו מראש), ואף לעקוב אחר מספר הדפיקות ולראות אם כולן תואמות את ההגדרות שלנו. - -בנוסף, בפרויקט נעשה שימוש במתג שיאפשר לנו לנעול את המנוע במקום, ונוריות שיראו לנו באופן וויזואלי את המצב שלו: נורת ה LED האדומה תראה שהקופסא נעולה, נורה ירוקה תראה שהקופסא אינה נעולה, ונורה צהובה תראה לנו אם התקבלה דפיקה חוקית (בטווח שקבענו). - -בתכנות אחד מהערכים הראשונים במעלה הוא אינו לחזור על הקוד שכבר כתבנו (מסיבות של גודל ומסובכות הפרויקט, קושי בניפוי שגיאות וכ'ו), לכן בפרויקט הזה נבצע זאת (למרות שלא נצטרך לכתוב קוד כפול (אולי בעתיד), וזוהי תכונה חשובה בתכנות שצריך להכיר), ניצור פונקציה נפרדת בה ימצא הקוד, ונשתמש בה במקום לכתוב את הקוד עצמו כל פעם מחדש. פונקציות יכולות לקבל ערכים כלשהם (נקראים פרמטרים) ואף להחזיר ערך כלשהו. - -השתמשנו בהמון פונקציות מובנות עד כה (כאלה שקיבלנו "בחינם" כחלק מהספרייה המובנת של ה Arduino, ולכן לא היה לנו צורך לכתוב אותן, אלא רק להשתמש בהן), לדוג הפונקציות הראשיות ()void setup ו ()void loop, שאינן מחזירות אף ערך [לכן כתוב בתחילתן void – ריק, ולא את הערך שהן מחזירות (אם הן היו מחזירות מספר שלם היה כתוב שם int, לדוגמה)], ואינן מקבלות אף פרמטר (לכן אין אף פרמרטר בסוגריים). אך בנוסף השתמשנו בפונ' -[()pinMode](http://arduino.cc/en/Reference/pinMode) שכן מקבלת 2 ערכים (מס' פין, ואת המילה השמורה INPUT או OUTPU) אך לא מחזירה אף ערך, ובפונ' [()digitalRead](http://arduino.cc/en/Reference/digitalRead) שמקבלת פרמטר (את מס' הפין שממנו יש לקרוא את הערך), ומחזירה ערך (את הערך הנקרא מהפין שהיא קיבלה בפרמטר), וכ'ו. - -  - -### חיבור הרכיבים - -כמו תמיד, חברו ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). מקמו את המתג על גבי לוח המטריצה כך שיחובר מעל המחיצה של הלוח (שיחובר לשני צדדי לוח המטירצה), נחבר את הרגל העליונה של החלק הקרוב ל Arduino לכוח (5v, עמודת ה+), ואת הרגל התחתונה של אותו הצד לפין הדיגיטלי מס' 2. בחלק השני של לוח המטריצה נחבר נגד 10kilohm מעמודת האדמה (-) אל הרגל התחתונה של המתג. - -הצמידו את רכיב ה Piezo ללוח המטירצה [אם יש לו חוטים, חברו את האדום לכוח, 5V, או אם יש לו סימון + באחד הצדדים, חברו את הצד הזה לכוח. במידה ואין לו אף סימון המצביע על קוטביות, חברו אותו איך שתבחרו (אין זה משנה)]. את החיבור השני של ה Piezo חברו לעמודת המינוס (דרך נגד 1megohm) ולפין האנלוגי A0 (כמובן שהחיבור של הפין צריך להגיע לפני החיבור לאדמה – שאם תחברו הפוך, שהרי לא תקבלו כל ערך בעת הקריאה של הפין האנלוגי). - -חברו את שלושת נוריות ה LED אל לוח המטריצה, כשהקתודה (הרגל הקצרה) מחוברת לרקקע דרך חוט מגשר, והאנודה (הרגל הארוכה) מחוברת לנגד 200ohm ומשם לפינים הדיגטליים של ה Arduino (הנורה הצהובה לפין מס' 3, הנורה הירוקה לפין מס' 4, והנורה האדומה לפין מס' 5). - -חברו את הכוח (החוט האדום) והאדמה (החוט השחור) של מנוע הסרוו לעמודות ה+ וה- של החלק השני של לוח המטריצה. בנוסף, חברו לאותן עמודות חוטים מגשרים מעמודות ה+ וה- של החלק הראשון של לוח המטריצה (החלק הקרוב יותר ל Arduino, שאליו חיברתם בהתחלה את החוטים המגשרים כדי להעביר כוח ללוח המטריצה). את חוט המידע של מנוע הסרוו חברו לפין הדיגיטלי מס' 9, והניחו קבל 100uf בעמודת ה+ וה- שאליהם מחובר מנוע הסרוו. זוכרים מפרויקט 5, למה הקבל משמש? - -כאשר מנוע הסרוו מתחיל את התזוזה שלו, הוא צורך זרם גבוה מאשר כשהוא כבר בתזוזה. דבר כזה יגרום לשקע במתח על גבי הלוח. לכן נניח קבל 100uf בצמוד לכוח ולאדמה (החוטים אדום ושחור שיוצאים ממנוע הסרוו ומחוברים ללוח המטריצה) כדי שיאגור את המטען החשמלי שהסרוו אינו משתמש בו, הקבל "ישטח" כל שינוי מתח שיקרה. את הקבל חברו כך שהרגל הקצרה (קתודה, מסומנת על הקבל בפס שחור) תהיה מחוברת לאדמה (חוט מגשר שחור) והרגל הארוכה יותר (אנודה) תהיה מחוברת למקור הכוח (חוט מגשר אדום). -להלן סכמה ואיור להמחשה: - -
    - Wiring Sketch -
    - -  - -### הקוד - -נתחיל בלייבא את [ספריית ה Servo](http://arduino.cc/en/reference/servo), וליצור מופע של מחלקת הסרוו. בנוסף, ניצור משתנים קבועים ([const](http://arduino.cc/en/Reference/Const)) מסוג מספרים שלמים ([int](http://arduino.cc/en/Reference/Int)) שישמרו את מספרי הפינים שלנו: משתנה בשם piezo שישמור את הפין האנלוגי A0, משתנה בשם switchPin שישמור את הפין של המתג (מס' 2), משתנה בשם yellowLed שישמור את הערך 3 (פין מס' 3), greenLed שישמור את הערך 4, ו redLed שישמור ת הערך 5. - -נוסף לאלו נגדיר 2 משתני [int](http://arduino.cc/en/Reference/Int) בשם knockVal ו switchVal שישמרו לנו את הערכים שנקרא מהפין של המתג ומהפין של ה Piezo. עוד 2 משתנים קבועים ([const](http://arduino.cc/en/Reference/Const)) בשם quitKnock ו loudKnock שישמרו לנו ערכים קבועים אליהם נחליט מראש (כרגע 10, ו-100) שיקבעו את טווח הערכים לנקישה (נקישה שקטה מ-10 או חזקה מ-100 לא תתקבל, כי היא אינה בטווח), [משתנה בוליאני](http://arduino.cc/en/Reference/BooleanVariables) בשם locked שבו נשמור האם המנעול נעול או לא (כרגע נגדיר אותו ל"לא" – false), ומשתנה שיספור לנו את מס' הניסיונות, נקרא לו numberOfKnocks. - -  - -**בפוקנציית ה ()setup:** - -נבצע את כל ההגדרות של הפינים השונים: המופע myServo יתחבר לפין מס' 9 (באמצעות הפונ' שבספרייה שלו הנקראת [()attach](http://arduino.cc/en/Reference/ServoAttach). עם הפונ' [pinMode](http://arduino.cc/en/Reference/PinMode) נגדיר את הפינים של הלדים השונים (הצהוב, האדום, והירוק) להיות פלט (OUTPUT), הפין של המתג יהיה INPUT (כדי לקרוא ממנו את הערך ולבדוק האם הוא לחוץ או לא). - -בנוסף, נפתח חיבור בין ה Arduino למחשב (כדי שנוכל להדפיס את הערכים ולבדוק את התוכנית שלנו בזמן הריצה). נבצע זאת עם הפונ' [()Serial.begin](http://arduino.cc/en/Serial/Begin), ונכניס לתוכה את הפרמטר 9600 (זוהי המהירות בו ה Arduino יתקשר, 9600 ביטים לשניה). ולבסוף הפונ' נכתוב לנורה הירוקה להיות דולקת, למנוע הסרוו להיות במצב פתוח (0), ולנו, למחשב, נכתוב שהקופסא לא נעולה. - -  - -**בפונקציית ה ()loop:** - -בתוך ה [loop](http://arduino.cc/en/Reference/Loop) נבדוק קודם כל האם הקופסא לא נעולה, ע"י משפט [if](http://arduino.cc/en/Reference/If) והשוואה של משתנה ה locked ל false. זה ישפיע על מה שקורה בהמשך הפונ', אם הוא לא נעול נקרא את הערך שבמתג (switchVal), ונבדוק האם המתג לוחץ (ז"א המעגל נסגר ויש מתח, לכן האם הערך שווה ל HIGH): - - * ננעל את הקופסא (locked=true). - * נכבה את הנורה הירוקה. - * נדליק את הנורה האדומה. - * נסובב את מנוע הסרוו ל-90 מעלות. - * נדפיס הודעה לעצמנו (למחשב), שהקופסט נעולה. - * ונבצע דיילי (כדי שיהיה זמן למנוע לזוז). - -ונצא מה if של האם המתג לחוץ (כי אם הוא לא אין לנו מה לעשות, המצב לא משתנה, הקופסא עדיין נשארת פתוחה), ונצא מה if של האם הקופסא לא נעולה. כעת נבדוק שוב את הקופסא, אך הפעם האם היא נעולה (נשווה ל true), ניתן כמובן לעשות זאת עם else ל if של "האם הקופסא לא נעולה, הרי ערך בוליאני יכול להיות רק true או false, כך שאם הוא לא false הוא בטוח true. אך הפעם נכתוב את ה [if](http://arduino.cc/en/Reference/If) מחדש. - -אם הקופסא נעולה: - - * נקרא את הערך מרכיב ה piezo ונאחסן אותו במשתנה KnockVal. - * כדי להכיל רק נקישות "חוקיות", נבדוק (עם משפט [if](http://arduino.cc/en/Reference/If)) האם מס' הנקישות קטן מ-3 (הרי המקסימום הוא 3), והאם knockVal גדול מ-0 (האם התקבל ערך כלשהו). - * כדי לבדוק האם הנקישה עצמה חוקית נבדוק אותה ע"י העברת הנקישה לפונ' אחרת בשם `checkForKnock` שכרגע היא לא כתובה (נכתוב אותה בסוף התוכנית), ונבדוק האם התוצאה שתוחזר מהפונ' הזאת שווה ל true, אם כן נעלה את מס' הנקישות ב-1 (במקום לכתוב numberOfKnocks שווה לעצמו ועוד 1, ניתן בקיצור לכתוב `++numberOfKnocks`). - * ונרצה להדפיס את מס' הנקישות שנותרו {לא רק אם הנקישה הייתה חוקית, אלא כל פעם. לכן נכתוב זאת מחוץ ל if של הפונ' checkForKnock, ז"א בתוך ה if הנוכחי (נדפיס את מס' הנקישות שנותרו [3 פחות מס' הנקישות שהוקשו עד כה, וטקסט)]}, וסיימנו גם עם ה if של מס' הנקישות קטן מ-3, לכן נסגור גם אותו עם סוגריים מסולסלים. - * אך מה עם מס' הנקישות גדול מ-3? אז בכלל לא ניכנס לכל הבדיקה שעשינו עד כה, לכן נישאר ב [if](http://arduino.cc/en/Reference/If) של 'הקופסא נעולה' (לא סגרנו אותו עדיין), ונכתוב [if](http://arduino.cc/en/Reference/If) נוסף, בו נבדוק האם מס' הנקישות גדול מ-3, אם כן: - * נפתח את הקופסא (locked=false). - * נסובב את מנוע הסרוו ל-0 מעלות. - * נבצע דיילי (כדי לתת למנוע זמן לבצע את הסיבוב). - * נדליק את הנורה הירוקה. - * נכבה את הנורה האדומה. - * נדפיס לעצמנו (למחשב), שהקופסא פתוחה. - -לבסוף, נכתוב את פונ' הבדיקה של "האם הנקשיה חוקית", נקרא לה `checkForKnock`, ולפניה נכתוב `boolean` (אנחנו רוצים שהיא תחזיר משתנה בוליאני למי שקורא לה, ז"א את התשובה "כן" או "לא"), בנוסף, הפונ' תקבל פרמטר שהוא מס' שלם ([int](http://arduino.cc/en/Reference/Int)) ונקרא לו value (הוא יהיה קיים אך ורק בתוך הפונ', ונוכל להתייחס עליו כאל value, אך הערך שעובר אלינו לא צריך להיקרא באותו שם, אלא רק להיות מאותו סוג – int). - -נבדוק האם הנקישה חוקית ע"י בדיקה של האם הערך בין טווח הערכים quitKnock ל loudKnock, אם כן: - - * נדליק את הנורה הצהובה. - * נבצע דיילי. - * נכבה את הנורה הצהובה. - * נדפיס לעצמנו טקסט (שהנקישה תקינה, ואת הערך של הנקישה). - * ונחזיר `true`(ברגע שאנחנו מחזירים איזשהו ערך, ע"י `return`, הפונ' מסתיימת כאן, היא אינה תמשיך לבצע את עצמה). - -אם הנקישה אינה בין אותם ערכים, ז"א לא חוקית, נדפיס לעצמנו (למחשב) טקסט שהיא אינה חוקית, ואת ערך הנקישה עצמה, ונחזיר `false`. -כך יראה הקוד הסופי: - -```c -#include <Servo.h> -Servo myServo; - -const int pieso = A0; -const int switchPin = 2; -const int yellowLed = 3; -const int greenLed = 4; -const int redLed = 5; -int knockVal; -int switchVal; -const int quietKnock = 10; -const int loudKnock = 100; -boolean locked = false; -int numberOfKnocks = 0; - -void setup(){ - myServo.attach(9); - pinMode(yellowLed, OUTPUT); - pinMode(redLed, OUTPUT); - pinMode(greenLed, OUTPUT); - pinMode(switchPin, INPUT); - Serial.begin(9600); - digitalWrite(greenLed, HIGH); - myServo.write(0); - Serial.println("The box is unlocked!"); -} - -void loop(){ - if (locked == false){ - switchVal = digitalRead(switchPin); - if (switchVAL == high){ - locked = true; - digitalWrite(greenLed, LOW); - digitalWrite(redLed, HIGH); - myServo.write(90); - Serial.println("The box is locked!"); - dealy(1000); - } - } - if (locked ==true){ - knockVal = analogRead(piezo); - if (numberOfKnocks < 3 && knockVal > 0){ - if (checkForKnock(knockVal) == true){ - numberOfKnocks++; - } - Serial.print(3-numberOfKnocks); - Serial.print(" more knocks to go"); - } - if (numberOfKnocks >= 3){ - locked = false; - myServo.write(0); - dealy(20); - digitalWrite(greenLed, HIGH); - digitalWrite(redLed, LOW); - Serial.println("The box is unlocked!"); - } - } -} - -boolean checkForKnock(int value){ - if (value > quietKnock && value < loudKnock){ - digitalWrite(yellowLed, HIGH); - dealy(50); - digitalWrite(yellowLed, LOW); - Serial.print("Valid knock of value "); - Serial.print(value); - return true; - }else{ - Serial.print("Bad knock value "); - Serial.print(value); - return false; - } -} -``` - -  - -### לסיכום - -בפרויקט הזה תרגלנו שימוש נוסף ברכיב ה Piezo ובמנוע הסרוו, נזכרנו למה משמש הקבל, ייבאנו שוב ספריות, ולמדנו עקרון חדש (וחשוב) בתכנות – יצרנו פונ' נפרדת לגמרי ל-2 הפונ' הראשיות שבהם אנו משתמשים (והשתמשנו בה בהם, ע"י קריאה אליה). - -הפרויקט סוגר ופותח את הקופסא ע"י המתג, ופותח את הקופסא ע"י הנקישות. כתבתי את הפתיחה של הקופסה גם ע"י המתג רק לבקרה. בשביל לשחק עם הפרויקט, הורידו את השורות ששולטות על פתיחת הקופסא עם המתג, כך שהמתג ינעל רק את הקופסא, והנקישות יפתחו אותה. - -> שימו לב שנגד בעל ערך קטן יותר שיתחבר לרכיב ה Piezo יהיה רגיש יותר לתנודות - אז אם תצטרכו חברו נגד שמתנגד פחות. diff --git a/data/_oldPosts/2015-05-03-arduino-13.md b/data/_oldPosts/2015-05-03-arduino-13.md deleted file mode 100644 index 1ff30c3..0000000 --- a/data/_oldPosts/2015-05-03-arduino-13.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: '13 - מנורת LED' -author: nirgn -layout: post -summary: "בפרויקט הזה נבנה נבנה מנורת LED שתידלק כשנגע בחומר מוליך כלשהו. כמו בפרויקט ה Servo נשתמש בספרייה חיצונית, אך הפעם לא אחת המובנת ב IDE של ה Arduino, אלא בספרייה שבן אדם פרטי כתב, בחור בשם פול בדג’ר, ושמה CapacitiveSensor." -category: Arduino ---- -בפרויקט הזה נבנה נבנה מנורת LED שתידלק כשנגע בחומר מוליך כלשהו. כמו בפרויקט ה Servo נשתמש בספרייה חיצונית, אך הפעם לא אחת המובנת ב IDE של ה Arduino, אלא בספרייה שבן אדם פרטי כתב, בחור בשם פול בדג'ר, ושמה CapacitiveSensor. - - - -קיבלות ([Capacitance](http://en.wikipedia.org/wiki/Capacitance)) זה מדד של כמה מטען חשמלי משהו יכול לאחסן. הספרייה בודקת את הקיבולת בעזרת 2 פינים של ה Arduino (אחד משדר ואחד קולט) שיהיו מחוברים לאוביקט מתכת כלשהו (כמו נייר אלומינימום). היא מודדת את הזמן שלוקח להם להיות באותו המצב. ככל שאנו מתקרבים לאובייקט, הגוף שלנו יספוג חלק מהמטען החשמלי, מה שישפיע על הפינים ויקח להם יותר זמן להיות באותו המצב. - -  - -**הכנת הספרייה:** -נוריד את הספרייה [מכאן](http://playground.arduino.cc/Main/CapacitiveSensor), נפתח את קובץ ה zip ונלחץ את התקייה שנמצאת בתוכו לתיקיית ה IDE של הארדואינו. ב Ubuntu התקייה של ה Arduino נקראת `sketchbook` ובתוכה נמצאת תקייה בשם `libraries`, אליה נחלץ את תקיית הפרויקט. ב Windows, כברירת מחדל, תקיית ה Ardunio תיהיה בתוך `Documents`, ועליכם ליצור תקייה בשם `libraries`. - -לאחר שחילצתם את התקייה, הפעילו מחדש את ה IDE של ה Arduino. לחצו עם `File` (בתפריט העליון) > ואז על `Examples` > משם ל `CapacitiveSensor` > ול `libraries` > בחרו ב `CapacitiveSensor` > ולבסוף ב `CapacitiveSensorSkeatch`. יפתח לכם חלון חדש ובו דוגמה (Demo Sketch), קמפלו אותה (ע"י לחיצה על V, כמו שאתם עושים כדי לבדוק שאין שגיאות בפרויקט). ואם הקימפול עבר בהצלחה (ללא שגיאות), התקנתם אותה באופן תקין (במידה והייתה שגיאה קפצו לקרוא את הפסקה האחרונה בסוף המאמר). - -  - -### חיבור הרכיבים - -נחבר ללוח המטריצה חוט מגשר מעמודת ה- (מינוס) לפין ה GND שב Arduino (בפרויקט הזה אנחנו לא צריכים לחבר חוט מגשר ל 5V כי אנו נקבל אותו ישירות מפין מס' 4 של ה Arduino). נמקם על גבי לוח המטריצה נורת לד ונחבר את הקתודה (הרגל הקצרה) לאדמה בעזרת נגד 220Ω, ואת האנודה לפין הדיגיטלי מס' 12. - -נחבר 2 חוטים מגשרים לארדואינו, הראשון לפין הדיגיטלי מס' 2 והשני למס' 4, ואת הקצה השני שלהם נמקם על לוח המטריצה (במרחק אחד מהשני), בינהם נחבר נגד 1MΩ (ראשי תיבות: Megaohm). באותה השורה של החוט המגשר המגיע מפין מס' 2 נחבר עוד חוט מגשר (אחרי הנגד) שלא יתחבר לשום דבר בקצהו השני (הוא יהיה חיישן המגע שלנו). -להלן סכמה ואיור להמחשה: - -
    - Wiring Sketch -
    - -  - -### הקוד - -נתחיל בלייבא את ספריית ה CapacitiveSensor עם `include` וניצור מופע של מחלקה (בשם capSensor), כשאנו יוצרים את המופע של המחלקה אנו מעבירים לבנאי של הספריה את הפינים מהם הוא ישלח ויקבל את המידע, במקרה שלנו, פין מס' 4 שולח את האות, ופין מס' 2 קולט. - -בנוסף, ניצור משתנה מסוג מספר שלם ([int](http://arduino.cc/en/Reference/Int)) בשם `threshold` שישמור לנו את הסף שבו המנורה תידלק (נכניס אליו את הערך 1,000). ומשתנה קבוע ([const](http://arduino.cc/en/Reference/Const)) מסוג מספר שלם (int) שישמר את מספר הפין שאליו נורת ה LED מחוברת (במקרה שלנו פין מס' 12). - -**בפוקנציית ה ()setup:** - -נפתח חיבור למחשב, נבצע זאת עם הפונ' [()Serial.begin](http://arduino.cc/en/Serial/Begin), ונכניס לתוכה את הפרמטר 9600 (המהירות בו ה Arduino יתקשר, 9600 ביטים לשניה). לאחר מכן נגדיר את הפין שמחובר לנורת ה LED להיות במצב פלט. - -**בפונקציית ה ()loop:** - -בתוך ה loop ניצור משתנה בשם `sensorValue` מסוג [long](http://arduino.cc/en/Reference/Long), שישמור את הערך שנקלוט מהחיישן. נקרא לפקודה capacitiveSensor (ממשתנה המופע), ונכניס לתוכה את הערך 30 (שמציין את מספר הדגימות שאנו רוצים לקרוא, אם נקרא מספר קטן מידי יתכן ונראה הרבה שינויים בחיישן, אך אם נקרא יותר מידי דגימות, אנחנו יכולים לגרום ללאג עקב הזמן הדרוש לקריאה מהחיישן), ואת התוצאה שהיא מחזירה נשמור ב sensorValue שיצרנו קודם לכן. - -נדפיס לעצמנו את התוצאה ששמורה ב sensorValue. ונבדוק ע"י משפט [if / else](http://arduino.cc/en/Reference/Else) האם הערך שהתקבל מהחיישן גבוהה מהסף שקבענו בתחילת התוכנית, אם כן אז נדליק את הנורה, אם לא נכבה אותה. לבסוף, נוסיף דיילי קטן לפני שאנו מסיימים את פונ' ה loop כדי לתת כמה מאיות השניה מהקריאה הבאה (על מנת שנספיק לראות את האור נדלק אם המצב ישתנה ונצטרך לכבות אותו אח"כ). - -כך יראה הקוד הסופי: - -```c -#indluce <CapacitiveSensor.h> -CapacitiveSensor capSensor = CapacitiveSensor(4,2); -int threshold = 1000; -const int ledPin = 12; - -void setup(){ - Serial.begin(9600); - pinMode(ledPin, OUTPUT); -} - -void loop(){ - long sensorValue = capSensor.capacitiveSensor(30); - Serial.println(sensorValue); - if(sensorValue > threshold){ - digitalWrite(ledPin, HIGH); - }else{ - digitalWrite(ledPin, LOW); - } - delay(10); -} -``` - -  - -### לסיכום - -הפרויקט הזה היה קטן יחסית, בלי הרבה חיבורים או הרבה קוד, אך התמקדנו בדבר חדש והוא התקנה של ספריות חיצוניות. הדבר חשוב במיוחד מכיוון שאנו לא רוצים לבנות הכל בעצמנו ואם מישהו בנה כבר ספרייה כלשהי שאנו יכולים להשתמש בה לצרכינו, אין לנו כל סיבה להמציא את הגלגל מחדש. בנוסף, שימו לב שבפרויקט הזה השתמשנו בקצה השני של החוט המגשר על מנת לסגור מעגל (ניתן גם לגעת בו, וגופנו יסגור את המעגל), כל שעשינו זה לשדר אות, לסגור את המעגל ולקרוא אותו בפין הנוסף על מנת לראות האם הוא נסגר או לא (אם אנחנו מקבלים את האות ששלחנו או לא). - -במידה ונתקלתם בבעיה כלשהי בעת קימפול הספרייה, להלן המדריך המלאה מאתר Arduino להתקנה של ספריות: [http://arduino.cc/en/Guide/Libraries](http://arduino.cc/en/Guide/Libraries). בנוסף, שימו לב שכשאתם מחלצים את התיקייה מתוך ה zip היא מכילה תקייה ובתוכה ישנה כבר תיקייה בשם `libraries`, כנסו אליה וחלצו את 2 הפרויקטים משם אל תוך תקיית ה `libraries` הקיימת שלכם (שלא יהיה לכם מצב של תקייה בתוך תיקייה בתוך תקייה ורק אז הפרויקטים). diff --git a/data/_oldPosts/2015-05-17-arduino-14.md b/data/_oldPosts/2015-05-17-arduino-14.md deleted file mode 100644 index 752b06b..0000000 --- a/data/_oldPosts/2015-05-17-arduino-14.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: '14 - הארדואינו ותקשורת נתונים' -author: nirgn -layout: post -summary: "בפרויקט הזה, נשתמש ב Arduino על מנת לשלוט על תוכנית במחשב שלנו (באמצעות תקשורת טורית)." -category: Arduino ---- -בפרויקט הזה, נשתמש ב Arduino על מנת לשלוט על תוכנית במחשב שלנו (באמצעות תקשורת טורית). המעגל האלקטרוני יהיה פשוט מאוד הפעם, וכך גם הקוד של ה Arduino, נתמקד נטו בשליטה על התוכנית מחשב האחרת, באמצעות ה Arduino. - - - -נפתח חיבור בין ה Arduino למחשב שלנו, כמו שעשינו עד כה, אך הפעם נשתמש בחיבור זה כדי לשלוח ולקבל נתונים ליישומים אחרים. - -ל Arduino יש שבב הממיר את התקשורת של המחשב (המבוססת USB) לתקשורת טורית אותה ה Arduino מבין. תקשורת טורית אומרת ששני מחשבים, ה Arduino והמחשב האישי שלנו, מחליפים פיסות מידע באופן סידרתי, ז"א אחד לאחר השני מבחינת רצף הזמן. כאשר מחשבים משתמשים בתקשורת טורית הם צריכים להסכים על המהירות בה הם ידברו זה עם זה (בטח שמתם לב שכאשר השתמשנו בתקשורת טורית והזנו את המס' 9600 ביטים לשניה, אותו המספר הופיע גם בחלון התקשורת במחשב, בפינה הימינית התחתונה של החלון). המספר אותו אנו מזינים, 9600 ביטים לשניה, הוא המספר שאנו מכניסים כפרמטר לפונ' -[()Serial.begin](http://www.arduino.cc/en/Serial/Begin) והוא המהירות שבה ה Arduino והמחשב יחליפו נתונים (ביט – [bit](https://en.wikipedia.org/wiki/Bit) – סיבית, היא ספרה בינארית – יחידת הנתונים הקטנה ביותר שבה משתמש המחשב). - -כבר השתמשנו ב serial monitor כדי להסתכל על ערכים מהכניסות האנלוגיות. נשתמש בשיטה דומה כדי להכניס ערכים לתוכנית שנכתוב בסביבת תכנות בשם Processing. סביבת תכנות זו מבוססת על Java, וסביבת התכנות של ה Arduino מבוססת על זו של Processing, ככה שאנחנו צריכים להרגיש די בבית. לכן לפני שנתחיל לעבוד על הפרויקט, נוריד את הגרסה העדכנית ביותר של Processing [מכאן](https://www.processing.org/download/?processing). וכדאי אולי להציץ, לפני שאנו מתחילים לעבוד על הפרויקט, ב [מדריכים שבאתר](https://www.processing.org/tutorials/), רק כדי להרגיש נוח יותר. - -הדרך היעילה ביותר כדי לשלוח נתונים בין ה Arduino ו Processing היא עם הפונ' [()Serial.write](http://www.arduino.cc/en/Serial/Write) (בסביבת Arduino – הלא היא Sketch). זה דומה מאוד לפונ' שהשתמשנו עד כה, ()Serial.print, אך במקום לשלוח מידע קריא לבני אדם (כמו אותיות ומספרים), הפונ' הזו שולחת ערכים בין 0-255 כבתים (יחידת המידה מעל ביטים, bytes) של מידע גולמי. זה כמובן מגביל את המידע שה Arduino יכול לשלוח, אך מאפשר העברה מהירה יותר של מידע. - -בשני המחשבים (המחשב האישי שלנו וה Arduino) יש משהו שנקרא serial buffer (חוצץ סידורי) המחזיק את המידע עד שהוא נקרא ע"י התוכנית. את המידע שנשלח (בצורת bytes), נשלח אל ה serial buffer של Processing, ולאחר מכן Processing תקרא את המידע מה buffer. כשתוכנית כלשהי קוראת את המידע מה buffer הוא מתרוקן, מה שאמפשר לנו לשלוח אליו מידע חדש. בנוסף, בעת השימוש בתקשורת טורית בין מכשירים ותוכניות, חשוב ששני הצדדים לא רק ידעו כמה מהר התקשורת תיהיה אלא גם למה לצפות. - -  - -### חיבור הרכיבים - -נחבר ללוח המטריצה חוטים מגשרים מעמודות ה+ וה-, אל ה 5V וה GND (בהתאמה, כפי שעשינו עד כה). נמקם פוטנציומטר על גבי לוח המטריצה ונחבר רגל אחת שלו לאדמה (-) ואת הרגל השניה לכוח (+), ואת הרגל האמצעית לפין האנלוגי A0. -להלן סכמה ואיור להמחשה: - -
    - Wiring Sketch -
    - -  - -### הקוד - -**תחילה, נכתוב את התוכנית ל Arduino:** - -**בפוקנציית ה ()setup: **נפתח חיבור למחשב, נבצע זאת עם הפונ' ()Serial.begin, ונכניס לתוכה את הפרמטר 9600 (המהירות בו ה Arduino יתקשר, 9600 ביטים לשניה). אותו המספר (9600) יהיה כתוב בתוכנית Processing. - -**בפונקציית ה ()loop: **בתוך ה loop נשתמש בפקודת ה ()Serial.write כדי לשלוח מידע על גבי החיבור הטורי. פקודת ה ()Serial.write יכולה לשלוח ערך אך ורק בטווח 0-255, אך הפקודה [()analogRead](http://www.arduino.cc/en/Reference/AnalogRead) מקבלת ערכים בטווחים אחרים, גבוהים יותר. לכן נחלק את התוצאה שנקבל ב-4 על מנת להתאים את הערכים לאלה שאנו יכולים לשלוח. לאחר שליחת המידע, נחכה מילי-שניה אחת כדי לתת ל [ADC](https://en.wikipedia.org/wiki/Analog-to-digital_converter) לנוח לרגע. - -```c -void setup(){ - Serial.begin(9600); -} - -void loop(){ - Serial.write(analogRead(A0)/4); - dealy(1); -} -``` - -  - -
    - Processing Logo -
    - -**התוכנית ל Processing:** - -processing, שלא כמו ה Arduino, לא יודע כלום על יצאות טוריות באופן מובנה, כך שאנו צריכים לייבא ספרייה חיצונית הנקראת `*.processing.serial` שתתן לנו את האפשרות הזו (הכוכבית אומרת שאנו מייבאים את כל הפונקציות בספריית ה serial). לאחר מכן, ניצור אובייקט (נקרא לו myPort) בדיוק כמו שעשינו עם ספריית ה Servo ב Arduino. - -המטרה שלנו בתוכנית הזו היא לבצע שינויים על גבי תמונה. לכן ניצור עוד משתנה ונקרא לו `logo`, שיהיה מסוג `PImage` והוא יחזיק את התמונה. בנוסף, ניצור משתנה שיחזיק את ערך צבע הרקע, למשתנה הזה נקרא `bgcolor` והוא יהיה מסוג `int`. - -  - -**בפוקנציית ה ()setup:** - -בדיוק כמו ל Arduino גם ל Processing יש פונ' `setup`. כאן נפתח חיבור טורי ל Arduino, ונגדיר כמה פרמטרים שנשתמש בהם מאוחר יותר בתוכנית. בדרך כלל Processing עובדת בצבעים עם RGB, אך ניתן לשנות את הדרך שבה היא מעבדת את המידע של הצבעים. בפרויקט הזה נעבוד עם מוד צבע הנקרא [HSB](https://en.wikipedia.org/wiki/HSL_and_HSV) שמסמל גוון (Hue), רוויה (Saturation), ובהירות (Brightness). כשנזיז את הפונציומטר המחובר ל Arduino נשנה את הגוון (Hue) של צבע הרקע של תמונת ה PNG. - -דבר ראשון הוא לקבוע את ערך ההתחלה של צבע הרקע, עם הפונ' [()colorMode](https://processing.org/reference/colorMode_.html) שמקבלת 2 פרמטרים, הראשון הוא סוג המוד של הצבע, והשני הוא הערך המקסימלי שעליה לצפות לו. בנוסף, עלינו לטעון את התמונה לתוכנית שלנו. נטען אותה מהכתובת`http://arduino.cc/logo.png` בעזרת הפונ' [()loadImage](https://processing.org/reference/loadImage_.html) ונשמור אותה באוביקט שיצרנו במיוחד בשביל התמונה (logo). לאחר מכן עלינו להגיד ל Processing מה גודל החלון שעליו להציג, נעשה זאת עם הפונ' [()size](https://processing.org/reference/size_.html), ונספק לו את הרוחב והגובה של התמונה (באוביקט logo). - -ולבסוף ניצור אובייקט של החיבור הטורי ונכניס אותו לתוך myPort (היצירה של האובייקט מתבצעת ע"י כתיבת המילה השמורה new ולאחריה האובייקט (Serial) והפרמטרים שהבנאי שלו מקבל (הראשון הוא עם איזה יישום האובייקט ידבר, לכן אנו מכניסים this, השני הוא על איזה פורט סיריאלי הוא יבצע את התקשורת, במקרה שלנו אנו מבקשים את הרשימה עם [()Serial.list](https://processing.org/reference/libraries/serial/Serial_list_.html), הרשימה תוחזר בדמות של מערך ( -[Array](http://en.wikipedia.org/wiki/Array_data_structure)), ולכן אנו מבקשים את האיבר הראשון בתוך סוגרים מרובעים \[0\] (במחשבים האיבר הראשון הוא תמיד 0 ולא 1, והסוגריים המרובעים משמשים למיקום איבר במערך), ולבסוף באיזה מהירות הוא יתקשר עם היישום). - -  - -**בפונקציית ה ()draw:** -פונקציית ה draw היא המקבילה ל loop ב Arduino, בכך שהיא מתבצעת שוב ושוב עד אין סוף. כאן אנו מתארים את הדברים שיצטיירו על החלון של התוכנית. דבר ראשון שנעשה הוא לבדוק האם קיבלנו בכלל מידע מה Arduino ע"י משפט if. הפקודה [()available](https://processing.org/reference/libraries/serial/Serial_available_.html) של האוביקט myPort תחזיר לנו את גודל של ה serial buffer, אם הגודל שלו גדול מ-0, סימן שיש שם משהו. לכן נקרא את הבתים (bytes) לתוך משתנה הרקע (bgcolor) בעזרת הפקודה [()read](https://processing.org/reference/libraries/serial/Serial_read_.html) על האוביקט myPort, ולאחר מכן נדפיס לנו את הערך לחלון ה debug (רק כדי לוודא שהכל תקין). - -הפונקציה [()background](https://processing.org/reference/background_.html) קובעת את הצבע של החלון (הרקע של התמונה הוא שקוף, לכן הצבע של החלון יהיה צבע הרקע של התמונה). הפונ' מקבלת 3 פרמטרים: הראשון הוא הגוון (hue), השני הוא הבהירות (brightness) והשלישי הוא הרוויה (saturation). נשתמש בערך שקלטנו מה Arduino ושמרנו במשתנה bgcolor כדי לקבוע את הגוון (hue, הפרמטר הראשון). ואת הבהירות והרוויה נקבע לערך המקסימלי, הלא הוא 255, באופן קבוע. לבסוף אנו צריכים לצייר את הלוגו על המסך (אחרי שטענו אותו ושמרנו אותו במשתנה logo), ונעשה זאת עם הפונ' [()image](https://processing.org/reference/image_.html) המקבלת גם היא 3 פרמטרים: הראשון את התמונה (במקרה שלנו נכניס logo), והפרמטר השני והשלישי אלה נקודות הגובה והרוחב שבהם התמונה תמוקם. מכיוון שאנו רוצים אותה מתחילת המסך, נכניס 0 ו-0. - -```c -import processing.serial.*; -Serial myPort; -PImage logo; -int bgcolor = 0; - -void setup(){ - colorMode(HSB, 255); - logo = logoImage("http://arduino.cc/logo.png"); - size(logo.width, logo.height); - myPort = new Serial(this, Serial.list()[0], 9600); -} - -void draw(){ - if(myPort.available() > 0){ - bgcolor = myPort.read(); - println(bgcolor); - } - beckground(bgcolor, 255, 255); - image(logo, 0, 0); -} -``` - -  - -### לסיכום - -בפרויקט הזה התמקדנו בלמידת תוכנית חדשה בשם Processing, השפה דומה לזו שנו משתמשים ב Sketch (ה IDE של Arduino), אך מספיק שונה בשביל שנצטרך לדבר עליה ולהתנסות קצת. הפן הפיזי בפרויקט הזה היה קטן, כמו גם תכנות ה Arduino. אך התמקדנו בעיקר בתקשורת שבין התוכנות על מנת להשפיע בעזרת ה Arduino על תוכנית חדשה ושונה לגמרי שמבצעת דברים אחרים, במקרה הזה במחשב שלנו, אך את המידע ניתן להעביר גם על גבי האינטרנט ולהשפיע על תוכנית הנמצאת במחשב / בשרת מרוחק. וודאו שאתם מבינים כיצד בנינו וכתבנו את הפרויקט מכיוון שהוא מהווה קפיצת מדרגה משמועתית ובסיס לפרויקטים עתידים. כעת, נפתח בפנינו עולם חדש של אפשרויות לתקשר עם המכשירים שסביבנו ולשלוט בהם. diff --git a/data/_oldPosts/2015-06-14-bfs.md b/data/_oldPosts/2015-06-14-bfs.md deleted file mode 100644 index 42d1dfc..0000000 --- a/data/_oldPosts/2015-06-14-bfs.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: חיפוש לרוחב (BFS) -author: nirgn -layout: post -summary: 'BFS (ראשי תיבות של Breadth First Search) - חיפוש לרוחב, הוא אלגוריתם המשתמש במבנה נתונים תור (Queue) על מנת לעבור ולהדפיס את הצמתים של עץ בינארי בצורה רוחבית (על פי הייצוג בעץ).האלגוריתם, לרוב (לא בגרסה שכתבתי כאן) משמש על מנת לחפש צומת כלשהי בעץ. בעזרת שינויים קלים ניתן להשיג זאת גם באלגוריתם שכתבתי בפוסט.' -category: Algorithms ---- - -
    - BFS Algorithm -
    - -BFS (ראשי תיבות של Breadth First Search) - חיפוש לרוחב, הוא אלגוריתם המשתמש במבנה נתונים תור (Queue) על מנת לעבור ולהדפיס את הצמתים של עץ בינארי בצורה רוחבית (על פי הייצוג בעץ). - - - -האלגוריתם, לרוב (לא בגרסה שכתבתי כאן) משמש על מנת לחפש צומת כלשהי בעץ. בעזרת שינויים קלים ניתן להשיג זאת גם באלגוריתם שכתבתי למטה (שרק מדפיס את האיברים, בלי להשוות אותם למשהו). - -  - -### עקרון האלגוריתם: - - * נדחוף את הצומת הראשונה (השורש) לתור. - * כל עוד המערך לא ריק (עץ בינארי הינו ייצוג שונה של מבנה נתונים מסוג מערך) נוציא ונדפיס את הערך בתור. - * נבדוק האם הבן השמאלי והימני קיימים, במידה וכן נכניס אותם לתור. - -  - -### הקוד של האלגוריתם ([פסאודו קוד](https://en.wikipedia.org/wiki/Pseudocode)): - -```c -1. BFS (t) -2. enqueue(q, t) -3. while (notEmpty (q)) do -4. t <- dequeue(q) -5. print (t) -6. if (left(t) != NIL) -7. enqueue (q, left(t)) -8. if (right(t) != NIL) -9. enqueue (q, right(t)) -``` - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים: - -1. נקבל עץ בינארי: {a, b, c, d, e, f, g, h} לפי התמונה משמאל. -2. שורה 2: נוסיף לתור q את השורש t (שקיבלנו בעת הקריאה לפונקציה - אלגוריתם), ז"א את a. -3. שורה 3: כל עוד התור q אינו ריק (והוא אינו ריק מכיוון שיש לנו בו את a): - * שורה 4: נוציא את האיבר הראשון מהתור (השורש, a), ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א a. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL. במקרה שלנו זה נכון, הבן השמאלי הוא b, וניכנס ל if: - * שורה 7: נכניס את הבן השמאלי, b, לתור q. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL, במקרה שלנו הוא c, ולכן ניכנס ל if: - * שורה 9: נכניס את הבן הימני, c, לתור q. - * כעת התור, q, נראה: [b, c]. -4. שורה 3: התור עדיין לא ריק, ולכן נמשיך בלולאת ה while: - * שורה 4: נוציא את האיבר הראשון מהתור, b, ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א b. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL. והוא שווה ל d, לכן ניכנס ל if: - * שורה 7: נכניס את הבן השמאלי, d, לתור q. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL. והוא שווה ל e, לכן ניכנס ל if: - * שורה 9: נכניס את הבן הימני, e, לתור q. - * כעת התור q, נראה: [c, d, e]. -5. שורה 3: התור עדיין לא ריק, ולכן נמשיך בלולאת ה while: - * שורה 4: נוציא את האיבר הראשון מהתור, c, ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א c. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL, הוא f, לכן ניכנס ל if: - * שורה 7: נכניס את הבן השמאלי, f, לתור q. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL, הוא g, לכן ניכנס ל if: - * שורה 9: נכניס את הבן הימני, g, לתור q. - * כעת התור, q, נראה: [d, e, f, g]. -6. שורה 3: התור עדיין לא ריק, לכן נמשיך בלולאת ה while: - * שורה 4: נוציא את האיבר הראשון מהתור, d, ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א d. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * כעת התור, q, נראה: [e, f, g]. -7. שורה 3: התור עדיין לא ריק, לכן נמשיך בלולאת ה while: - * שורה 4: נוציא את האיבר הראשון מהתור, e, ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א e. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL, הוא h, ולכן ניכנס ל If: - * שורה 7: נכניס את הבן השמאלי, h, לתור q. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * כעת התור, q, נראה: [f, g, h]. -8. שורה 3: התור עדיין לא ריק, לכן נמשיך בלולאת ה while: - * שורה 4: נוציא את האיבר הראשון מהתור, f, ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א f. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * כעת התור, q, נראה: [g, h]. -9. שורה 3: התור עדיין לא ריק, לכן נמשיך בלולאת ה while: - * שורה 4: נוציא את האיבר הראשון מהתור, g, ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א g. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * כעת התור, q, נראה: [h]. -10. שורה 3: התור עדיין לא ריק, לכן נמשיך בלולאת ה while: - * שורה 4: נוציא את האיבר הראשון מהתור, h, ונכניס אותו למשתנה t. - * שורה 5: נדפיס את t, ז"א h. - * שורה 6: נבדוק האם הבן השמאלי של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * שורה 8: נבדוק האם הבן הימני של t שונה מ NIL, הוא לא שונה, ולכן לא ניכנס ל If. - * כעת התור, q, נראה: [ ]. -11. שורה 4: התור ריק, ולכן לא נמשיך בלולאת ה while. - -  - -**סיבוכיות זמן ריצה: (O(n**. -**סיבוכיות מקום: (O(1**. diff --git a/data/_oldPosts/2015-07-12-why-is-so-hard-to-be-a-new-developer.md b/data/_oldPosts/2015-07-12-why-is-so-hard-to-be-a-new-developer.md deleted file mode 100644 index 77d0c33..0000000 --- a/data/_oldPosts/2015-07-12-why-is-so-hard-to-be-a-new-developer.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: "Why it's so hard to be a new developer" -author: nirgn -layout: post -summary: 'פוסט זה הינו פוסט דעה אישי המתאר את המחשבות שלי על המפתח המתחיל וכמה קשה להיות אחד כזה, במיוחד כשהפרקטיקה והתאוריה אינם מתחברים.' -base-images-url: 'new-developers' -category: Stuff ---- - -
    - Software Developers Working -
    - -אתחיל בלהסביר שהפוסט הנל בא כתוצאה מקריאת הכתבה "[Computer science students are in demand and they know it](http://www.itworld.com/article/2945674/careers/computer-science-students-are-in-demand-and-they-know-it.html)" של ITWORLD. הפוסט מציין כי ישנו ביקוש הולך וגובר לבוגרי מדעי המחשב ותחומים דומים, והבוגרים מודעים לכך. ושללכת ללמוד מדעי המחשב זהו צעד חכם, במיוחד בהתחשב במחקרים המראים ביקוש הולך וגובר. - - - -הפוסט מציין כי 61% מבוגרי מדעי המחשב מצאו עבודה במשרה מלאה תוך שנה מסיום התואר, כשהממוצע של בוגרי תארים הוא 45%, ורק military science (אין לי מושג מהו התואר הזה) נמצא מעליהם עם 62%. בנוסף, לבוגרי מדעי המחשב המשכורת הממוצעת הגבוהה ביותר. ואף כי 53% מכלל הסטודנטים בסקר לקחו קורס כלשהו מתחום מדעי המחשב כחלק מהתואר (לפעמים רק כדי "לבלוט"), דבר המראה את הערך של סט הכלים מתחום מדעי המחשב בעיני סטודנטים מתחומים אחרים. - -והפוסט מסיים בזאת שללמוד מדעי המחשב זאת בקיצור בחירה נהדרת. - -  - -גם אם לא נתייחס לכתבה הזאת, הלך הרוח הכללי בחברה היום הוא שהאמא היהודייה רוצה שבנה ילמד מדעי המחשב, משפט שהיה שייך עד לא ממזמן לתחום הרפואה ועריכת הדין. ואני טוען שהציבור כלל אינו מבין את מקצוע מדעי המחשב, ואפילו אפשר להגיד שגם התעשייה לא. לפני שאמשיך אבצע disclaimer קטן, אני סטודנט למדעי המחשב ומנהל עסקים באונ' הפתוחה. - -  - -### אנחנו לא בוחרים ללמוד מדעי המחשב - -מחשבים וטכנולוגיה זהו תחום שכנראה לא בחרת ללמוד, אלא (אפשר להגיד) שהוא זה שבחר אותך. ניתן לחלק את הסטודנטים למדעי המחשב ל-2 קבוצות, אלה שאוהבים מחשבים מגיל קטן, למדו את זה בתיכון, אולי עסקו בזה במהלך שירותם הצבאי, ואף המשיכו ללימודים גבוהים בתחום. ואלה שהלכו ללמוד זאת מכיוון שיש בזה כסף / יוקרה / ביטחון תעסוקתי וכד'. - -בגיל קטן אפשר לראות את הילדים שיושבים מול המחשב, בוחרים ללכת למגמת מחשבים בתיכון ואלה (ברובם) הילדים שיאכלסו את התחום. מנגד, אפשר לראות את אלה שנבחרו לעסוק בתחום המחשבים בשירותם הצבאי בגלל הציונים הטובים בתיכון (ללא קשר לאם למדו מחשבים או אוהבים את התחום), ואלה שבחרו ללמוד אותו באונ' / מכללה בגלל גובה המשכורת (לדוג'), אלה לרוב יאכלסו את התחום בשנים הראשונות בקריירה שלהם ויפרשו בגלל 1001 סיבות או ישארו ולא יהנו מעבודתם (מה שיתבטא כנראה ברמת ביצוע נמוכה). - -מה שאני רוצה להגיד הוא שיש את האנשים שאוהבים מחשבים מגיל קטן ועוסקים בזה לבד (בלי קשר לאם הצליחו להתקדם לבד או היו צריכים דחיפה ממנטור כלשהו או מחוג מחשבים או ממגמת מחשבים בתיכון), ואלה שלא. ולרוב, אי אפשר להכריח בן אדם לעסוק 40 שנה במה שלא מעניין אותו באופן טבעי, זה פשוט מתכון לא נכון. ואם ננסה להכריח בכוח, מי שמפסיד מכך זאת החברה (אם זה בן אדם שהוכשר בצהל ע"י כספי המיסים שלנו, בן אדם שלמד לתואר על חשבון (בחלקו) מכספי המיסים שלנו, וכד'). - -לכן הגדרת הבחירה ללמוד מדעי המחשב כבחירה אינה נכונה. לרוב, לא תצפו בבן אדם שהחליט ללמוד לתואר מדפדף בעלון של האונ' לכל התארים וחושב מה הוא מעוניין, כנראה שכבר ידע מראש את התחום או כמה התחומים בהם הוא מתעניין. - -  - -### אהבה וסקרנות טבעית ינצחו! - -אני חושב שכולנו נסכים בכך שתואר במדעי המחשב הוא לא פשוט (קרי קשה), וגם נסכים בכך שלימוד מתוך הכרח, ולא מתוך סקרנות טבעית מובילה לתוצאות נמוכות. מכאן נובע שתואר במדעי המחשב מהסיבות הלא נכונות (כסף, יוקרה, מעמד, ביטחון תעסוקתי, אמא יהודייה, המלצה של חבר, וכ'ו) יוביל לביצועים נמוכים (קרי ממוצע ציונים נמוך), וזאת מעבר לציונים הנמוכים (יחסית) שיכולים להיות כתוצאה מהקושי לבדו. - -מעבר לציונים הנמוכים, מקצוע מדעי המחשב דורש למידה נוספת. אני נתקל בזה כרגע בעודי מחפש את העבודה הראשונה שלי בתחום, הידע המקנה תואר במדעי המחשב אינו מספיק כדי להתקבל לעבודת פיתוח במשרת junior. אני יודע 2 שפות מהתואר (C ו Java כאשר בג'אווה עסקנו יותר), הספריות בהם עסקנו ב Java ישנות (במקום ללמוד על Swing, למדנו על Applets במקום על Servlets, וכד'), לא דיברנו בכלל על כתיבת Unit Tests, לא למדנו על TDD, לא למדנו על REST, לא על ארכיטקטורת ענן או הקמת שרתים, למדנו קצת על SQL אבל רוב הקורס בנושא עסק בתורת הקבוצות שמאחורי השפה עצמה, ברשתות בקושי נגענו בשכבת האפליקציה (התעסקנו יותר בשכבות 2-3-4), לא דיברנו בכלל על הכלים הבסיסיים ותהליכי העבודה של המפתח (לדוג' git, או אלפי הספריות והכלים של השנים האחרונות בפיתוח ל Web), לא על JSON והתנהלות מול APIs, לא מכירים מה זה Regular Expressions, לא שמענו על מודל MVC, והרשימה עוד ארוכה. - -את רוב הדברים האלו השלמתי לבד במהלך השנה וחצי האחרונות מאתרים וספרים שונים. ההרגשה הייתה שלמדתי ל-2 תארים שונים במקביל, האחד באונ' ברמת אבסטרקציה גבוהה בו למדתי רעיונות מעניינים שפיתחו לי את החשיבה ואני מאמין שעוד אעזר בהם בעתיד (במיוחד ככל שנסיוני יגדל ואעסוק בדברים מתקדמים יותר), והשני hands-on, בו למדתי לקרוא API, לבקש משירות כלשהו מידע, לשמור אותו ב DB כדי להשתמש בו אח"כ באפליקציה, להתנהל עם מערכת לניהול גרסאות, וכד'. - -סטודנטים שלא אוהבים את התחום ואין להם סקרנות טבעית אליו, לא ילמדו זאת לבד, במיוחד כשהזמן והמאמץ הנדרש פוגעים בלימודים האוניברסיטאים. וסטודנט שהחליט ללמוד מדעי המחשב מהסיבות הלא נכונות (דבר המתאפיין, כמו שכבר אמרנו, בציונים נמוכים יותר יחסית), יתקשה למצוא עבודה בלי הידע הנל (גם אם בסופו של יום ציוניו עומדים בממוצע של חבריו לכיתה ואפילו אף עולים עליהם). - -  - -### התעשייה מצפה והאונ' בשלה - -נכתב על כך כבר רבות, לכן אמעיט בדברי בסעיף זה. התעשייה מצפה ל-1 והאונ' מספקת 2. האונ' מספקת בוגרים היכולים להמשיך לתואר שני במדעי המחשב, להיות חוקרים בתחום, ולהוציא מאמרים. התעשייה מצפה למפתחים היכולים להגיע לעבודה חדשה מחר בבוקר ולהשתלב תוך עקומת למידה מהירה יחסית. - -התעשייה מתקדמת מהר, והאונ' מפגרת בקצב. התעשייה מצפה ממך להכיר את הכלים והשיטות האחרונות, והאונ' לא. בסופו של דבר, מעסיקים מדברים על זה הרבה, בוגרי מדעי המחשב יצטרכו "להשתפשף" לא מעט עד שיניבו תוצאות והיו כלכליים למעסיק. מה שגורם לביקוש למפתחים לקפוץ, והופך את התואר לכדאי ללמידה. - -אך צריך לדייק, מעסיקים מחפשים מפתחים מנוסים (אפילו במקצת), כדי לרכך את עקומת הלמידה וההתשתלבות. מעסיקים תמיד יעדיפו מפתח ממוצע פלוס עם חצי שנה – שנה ניסיון על בוגר אונ' בעלת שם, בעל ממוצע ציונים גבוהה פלוס אך בלי ניסיון כלל. רבים כתבו ואמרו זאת לפני: בתחום הזה – הניסיון הוא כמעט הכל! - -מעבר ללימודים המכינים אתכם להיות חוקרים בתחום מדעי המחשב ולא מפתחים, ההתקדמות בתעשייה היא מהירה, וסביר להניח שגם מה שהתחלת ללמוד לבד בתחילת התואר לא יהיה הכי רלוונטי בסופו (בהתחשב בזה שתואר במדעי המחשב לוקח 4 שנים). לדוג' JavaScript שפרצה בשנים האחרונות, או אפילו grunt שמתחיל לאבד פופלריות לטובת gulp, וכד'. 4 שנים הם המון זמן בתחום הטכנולוגיה, צריך תמיד להישאר עם היד על הדופק, וסטודנט ללא סקרנות טבעית לא יקפיד על זה, וכשהאונ' אפילו לא מלמדת את הנושאים האלו אין ספק שהוא יהיה בעמדת נחיתות. - -יש לציין כי כדי למלא את הפער הזה קמו עשרות שירותים אינטרנטים כמו Codecademy, Code School, Udacity, Coursera, edx, Tuts, lynda.com, Khan academy, Threehouse וכ'ו. אך גם הם לפעמים לא מצליחים לעמוד בקצב, או לא קולעים לאותה מטרה (כמו Coursera ו edx שמציעים קורסים אוניברסיטאיים שלרוב עם חומרים תיאורטיים חשובים אך לוקים בחסר בפרקטיקה). - -  - -### משכורות מוצדקות (לרוב) - -המשכורות בתחום ההייטק (לרוב לפחות) מוצדקות, החברה למדו קשה, ואל תטעו, הם גם עובדים קשה! עבודה פיזית או רגשית לפעמים קלה יותר מעבודה אינטלקטואלית. אף אחד מאיתנו לא אוהב להרגיש טיפש, ולרוב אנחנו ננסה להימנע מהמצבים האלו ואף לא להגיע אליהם. אך מפתחים אוהבים את זה (אולי אוהבים זאת לא המילה הנכונה אך לא מצאתי אחרת), הם צריכים להרגיש "טיפשים" לא פעם אחת במהלך הקריירה שלהם כשהמידע משתנה מתחת לרגליהם וניהיה לא רלוונטי, הם תמיד ימשיכו ללמוד / לקרוא / לחקור (אחרת ישארו לא רלוונטים), ובקיצור הטיפשות אצל מהנדסים לא נמדדת ברמת הידע בו הבן אדם מחזיק, אלא בסט הכישורים שברשתו. - -אני לא חושב שמישהו יערער על כך שגם בשאר מקצועות ה STEM יש משכורות גבוהות, ואם לא אז מגיע להם. וזאת מכיוון שבניגוד לשאר התחומים, מקצועות ה STEM מראים את התרומה שלהם בצורה ברורה יותר משאר התחומים. כולם יודעים מה התרומה של מערכות ההפעלה, האינטרנט, הלווינים, הסמאטרפונים, וכ'ו לקידמה אותה אנו חווים. ולתרומה זו אין אבא ואמא יחידים, המהנדסים והמפתחים אינם אלה שגרמו לה, הם ישבו על כתפיהם של גדולים מהם והתבססו על פיתוחים וגילויים מקדימים בתחומי המדע המדוייק (מתמטיקה, ביולוגיה, כימיה, פיזיקה, וסליחה אם שכחתי תחום נוסף). - -אך סטודנט שלא יקפיד להישאר רלוונטי בתחום בו הוא עובד, ולפעמים אף מעודכן גם בשאר תחומי המדע המדוייק ימצא את עצמו לא עם המשכורת שציפה לה. - -  - -### חלק אישי - -בהתחלה ביצעתי disclaimer וכתבתי שאני סטודנט למדעי המחשב ומנהל עסקים. כבר מגיל קטן התעניינתי במחשבים ואף בתיכון הייתי במגמת מחשבים. אך החלטתי כי לימודים גבוהים לא נועדו רק להתמקצע אלא גם לפתוח אופקים והחלטתי ללכת לתואר דו-חוגי עם מנהל עסקים (מכיוון שזה תואר שיש בו קצת מהכל, וכך אוכל לקבל טעימה קטנה מעוד תחומים). - -מיותר לציין כי לא כך היה. רוב הקורסים במנהל עסקים פשוט שיעממו אותי, אני יכול לספור על יד אחת את הקורסים במנהל עסקים שבהם לא הייתי צריך קפה כבר לפני השיעור. וזה התבטא בציונים נמוכים (דבר שהוריד את הממוצע של התואר כולו), ובקושי תרם לי משהו באופן אישי. את הנושאים של הקורסים המעניינים למדתי עוד לפני, לבד, (קראתי ספרים, כתבות, וכ'ו) ויכולתי גם להשלים אותם באופן אישי לאחר התואר. - -עשיתי טעות של ילד, הוספתי על עצמי מעמסה (תואר דו חוגי עם מנהל עסקים) כתוצאה מרצון למשהו שגם ככה יכולתי לעשות (וכנראה שהייתי עושה) אותו לבד, וכתוצאה מכך הציונים שלי נפגעו ועברתי לא מעט שעות בהם לא נהנתי אך הכרחתי את עצמי לקרוא / ללמוד. נכון שלא כל מה שצריך ללמוד אוהבים, גם מתמטיקה לא באה לי בקלות, אך זהו תחום חובה למי שרוצה להיות מפתח טוב, ומנהל עסקים – ממש לא. עברתי על בשרי את חלק ממה שעוברים הסטודנטים למדעי המחשב שלא אוהבים מחשבים, לא ממליץ זאת לאף אחד. - -אני יודע שאני רוצה להמשיך לתואר שני, והפעם במדעי המחשב (בלבד!), אל תלכו ללמוד מה שלא הייתם לומדים לבד, זה פשוט לא משתלם, גם לא מבחינה כלכלית (הרי מפתח לא טוב, לא ירוויח טוב). - -  - -### לסיכום - -ההמלצה לבחור ללמוד מדעי המחשב אינה נכונה, וסביר להניח שמי שעד התואר לא התעניין במחשבים לא יתעניין בכך גם אחריו (ישנם יוצאים מהכלל כמו בכל דבר). מי שישלם על בוגרי תואר מדעי המחשב (או בוגרי יח' צהליות) שלא יעסקו בכך במהלך הקריירה שלהם (או גרוע מכך יעסקו בכך בצורה גרוע) היא החברה – כולנו (אנחנו משלמים על ההכשרה של הסטודנטים, הרי לימודים אוניברסיטאיים לא באמת עולים מה שהם עולים, המדינה משלימה על כל סטודנט וסטודנט). - -גם אם הסטודנטים התעניינו במחשבים כבר לפני וזה אכן המסלול הנכון להם, האונ' אינה מכשירה אותם בצורה נאותה למה שהתעשייה מצפה, ואיני יודע מי צודק, האונ' בהכשרתה או התעשייה בציפייתה. אני רק סטודנט לקראת סיום התואר שמרגיש את הפער ההולך וגדל בין הידע של בוגרי התואר למדעי המחשב והעבודה בפועל. - -ולמרות מספר הדרכים הגדול מאי פעם בהם אפשר ללמוד את התחום, הפער הזה (שלדעתי גדול כרגע מאי פעם!) הוא מה שהופך את הרצון להיות מפתח (או במילים אחרות, את המפתח המתחיל) לאתגר קשה במיוחד. diff --git a/data/_oldPosts/2015-08-09-pen-testing-introduction.md b/data/_oldPosts/2015-08-09-pen-testing-introduction.md deleted file mode 100644 index 9fd5487..0000000 --- a/data/_oldPosts/2015-08-09-pen-testing-introduction.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: 'Pen Testing - הקדמה' -author: nirgn -layout: post -summary: 'סדרת הפוסטים הקרובה תיהיה יומן מסע של תהליך הלמידה שלי את העולם הענק הנקרא בדיקות חדירה. החלק הזה יהיה הקדמה, תזכורת, ויישור קו. נעבור על מונחים בסיסיים, נתקין את סביבת העבודה, ונדבר קצת על אנונימיות (למה היא חשובה, וכיצד אפשר להתחיל ליישם שיטות לשמירת האנונימיות שלנו בזמן תהליך הלמידה).' -category: Pen Testing ---- -לא ממזמן חזרתי לנושא שעניין אותי עוד מהתקופה שלי בתור נער מתבגר - בדיקות חדירה (Pen Testing ראשי תיבות של Penetration Testing). באיזשהו שלב (לא זכור לי אפילו למה) פניתי לתחומים אחרים הקשורים למחשבים (בעיקר פיתוח), אך העניין האינסופי בתחום נשאר, ולאחרונה חזרתי להתעניין בנושא. סדרת הפוסטים הקרובה תיהיה יומן מסע של תהליך הלמידה שלי את העולם הענק הנקרא בדיקות חדירה. כמו תמיד אבצע disclaimer: אינני מתיימר לדעת הכל, וכל מה שאכתוב כאן הוא מלמידה אישית שלי דרך ספרים ואתרים שונים. אינני אחראי על השימוש שתבצעו בידע שיכתב בפוסטים אלו, ו**אני נגד שימוש לרעה בידע שתצברו כאן** (יש מספיק עבודות בהם תוכלו ליישם את הידע שלכם, כך שממש אין צורך לעבור על החוק). - -**תוכן עניינים:** - - 1. הכנות - 2. מונחים בסיסיים - 3. סביבת עבודה - 4. אנונימיות - -  - - - -### 1. הכנות - -מכיוון שאני רק מתחיל לחקור את העולם הזה ועדיין אין ברשותי את הידע לאן ללכת או מה לעשות, התחלתי בלהוריד ולהתקין הפצת לינוקס המגיעה עם מספר כלים לביצוע בדיקות חדירה (penetration testing) הנקראת Kali Linux (שמעתי עליה מראש, ואפשר גם [לקרוא עליה ב wikipedia](https://en.wikipedia.org/wiki/Kali_Linux)). - -  - -### 2. מונחים בסיסיים - -בזמן שהפצת Kali יורדת (3.1GB), הלכתי ל Google והתחלתי לקרוא על המושגים השונים ששמעתי במשך השנים: - -* **Footprinting -** זהו שם המייצג את תהליך איסוף המידע. מידע זה יכול להיות ווירטואלי כמו כתובת IP של השרת, או פיזי כמו לזהות עובדים באותה החברה או תדפיסים שנזרקו לפח וכד'. -* **DDoS -** (ראשי תיבות של Distributed Denial-of Service או בעברית התקפת מניעת שירות) היא התקפה המשביתה מערכת ע"י יצירת עומס חריג על משאביה (עד שאינה יכולה לשרת אף משתמש אחר). בדר"כ התקפה כזאת דורשת משאבים נוספים ולכן ההכנה שלה יכולה להיות מורכבת (במידה ואתם עושים זאת לבד ולא קונים את המשאבים, ודורשת השתלטות על מספר רב של מחשבים נוספים), אך ביצוע קל יחסית ולכן נחשבת לילדותית. לדוגמה אם אני זוכר נכון, לשרת [Apache](https://en.wikipedia.org/wiki/Apache_HTTP_Server) יש מגבלה (כברירת מחדל) של 10,00 בקשות, ואם אתם יכולים לשלוח 10,000 בקשות לשניה בעיקרון סתמתם את השרת, והוא לא ישרת אף חיבור אחר. -* **RAT -** (ראשי תיבות של  Remote Administration Tools) הוא מושג המתאר כלים המאפשרים למישהו לשלוט באופן במלא במכשירכם, מרוחק. הטריק עם הכלים האלו הוא לגרום להם להיות FUD (ראשי תיבות של Fully UnDetectable). -* **RootKit -** הוא כינוי לכלי המתקינים על מערכת ההפעלה, המסוגל להסתיר תהליכים הרצים ברקע מהמערכת עצמה (לדוג' כדי שהמשתמש לא יראה את התהליך רץ ב Task Manager). בה בעת, כמו כלי RAT, כלי זה מאפשר גישה מלאה למכשירכם. -* **Phishing -** הוא ניסיון גניבת מידע ע"י התחזות. ז"א כשמישהו משתמש בפיתיון כלשהו כדי להוליך אתכם שולל, ואתם "בולעים" אותו. לדוג' שליחת מייל עם לינק להורדת איזשהו קובץ, או שליחת לינק לאתר שנראה כמו האתר המקורי אך בפועל זה אתר שאתם הקמתם (וזאת על מנת לגנוב את שם המשתמש והסיסמה שלכם), וכד'. -* **SQL Injections -** זהו מקרה פרטי של קבוצת פרצות אבטחה הנגרמות עקב היכולת ל"הזריק קוד" לשירות (מדובר על היכולת ליצור קוד בזמן ריצה, כאשר תוכן הקוד אינו נוצר על ידי המתכנת ואינו נבדק על ידו). במקרה הזה מדובר על שליחת שאילתות SQL לבקשות HTTP (בדרך כלל דרך שדה קלט כלשהו), כאשר המבנה / תבנית של השאליתה אינו מסודר כמו שצריך בשרת הדבר מאפשר חשיפה של נתונים ממסד הנתונים. -* **VPN -** (ראשי תיבות של Virtual Private Network או בעברית רשת פרטית ווירטואלית), היא שיטה להעברת מידע פרטי על גבי רשת ציבורית. ארגונים רבים בעולם משתמשים בשיטה זו על מנת לחבר עובדים באופן מרוחק לרשת הארגונית שלהם. ומשתמשים רבים מבצעים שימוש בחברות המאפשרות להתחבר לרשת שלהם (בתמורה לסכום כספי כלשהו) על מנת שישמשו חוצץ אל מול התקשורת החיצונית (ז"א כדי שהמיקום שלך לא יוודע, אתה מתחבר ל VPN של אותה חברה וגולש דרכם כשהם מנתבים אלייך, דרך הרשת הפנימית שלהם, את המידע שמגיע אליהם מבחוץ (לאחר שעבר הצפנה). כך שמי ששלח את המידע אינו יודע שבפועל זאת הייתה הבקשה שלך). היישומים המפורסמים ביותר של רשתות VPN הם [OpenVPN](https://openvpn.net/) ו [IPsec](https://en.wikipedia.org/wiki/IPsec). - -
    - Proxy Concept -
    - -* **Proxy -** בדומה ל VPN, שרת פרוקסי מספק גישה למשאבים חיצוניים ברשת, ז"א שדרכו עוברים כל הבקשות (הנתונים נשלחים אליו והוא שולח אותם אל היעד, היעד מחזיר אליו את התשובה והוא שולח אותה אליכם). משמאל ניתן לראות תמונה המתארת (באופן מושפט למדי) את תהליך התקשורת מול השרת פרוקסי. השרת משמש כנקודת הפרדה בין רשת המחשבים הפנימית של הארגון ובין הרשת החיצונית, ומאפשר ניתוח של המידע לפני כניסתו לרשת הפנימית. Proxy נחשבת לשיטה פחות אמינה בכל הקשור לשמירה על פרטיות (אינני יודע עדיין למה, אך זה מה שעולה מהחפירה הקטנה שלי באינטרנט, ולכן ראיתי שלרוב מבצעים שרשור Proxy).  -* **Tor -** (ראשי תיבות של The Onion Router) זוהי תוכנת קוד פתוח הנועדה לאפשר גלישה אנונימית באינטרנט. התוכנה מנתבת את החבילות (Packets) דרך מחשבים אחרים המחוברים לרשת Tor עם התוכנה, עד שהחבילה יוצאת דרך אחד הצמתים (Nodes). כאשר החבילה מתחילה את דרכה, שכבת האפליקציה מוצפנת (ז"א המידע המקורי כולל כתובת ה IP של היעד מוצפן) כמה פעמים, והחבילה נשלחת "לטיול ווירטואלי" בין הצמתים (שנבחרו באופן אקראי) עד שיוצאת באחד מהם. כל אחד מהצמתים מפענח את השכבה הבאה המכילה את המידע לאן לשלוח את הבקשה הלאה, ושולח אותה מבלי לחשוף את כתובת המקור (ממנה הבקשה נשלחה). וכך גם מפחית את הסיכוי לחשיפה (גם אם מקור אחד יחשוף את היעד שלו, הבקשה עוברת דרך כמה צמתים עד שיוצאת, ובהסתמך על זה שאחד יקיים את ההסכם ולא יחשוף את המידע, הבקשה תיהיה אנונימית). יש לציין כי כבר הוכח בעבר שמפעלי הצמתים כן יכולים לנתח ולחשוף את המידע שעובר מהצומת האחרונה אל היעד במידה והתקשורת אינה משתמשת בפרוטקול [SSL (או TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security), דבר המאפשר לדלות מידע על מי המקור של הבקשה. ואף כי ישנם אתרים שחוסמים גישה דרך צמתי Tor ידועים (לדוג' לא ניתן לערוך ערכים בוויקיפדיה דרך Tor). -* **VPS -** (ראשי תיבות של Virtual Private Server) הוא מכונה ווירטואלית הנמכרת כשירות (ז"א חברה שבבעלותה מחשב גדול מחלקת אותו ומשכירה לך מפרט שלך עליו אתה יכול לעשות מה שאתה רוצה). מפתחים רבים משתמשים במכונות אלה בשביל להתקין סביבת פיתוח מרוחקת (או לפתח או לבצע בדיקות כנגד סביבה ספציפית). משתמשים בשירותים אלה גם כדי לאחסון שירותים שלא צריכים שרתים פיזיים אך גם שירותי אחסון כבר אינם מספיקים להם. -* **Key Loggers -** המונח מתאר כלים המאפשרים לחלץ מידע (הקשות מקלדת) ממקור כלשהו. ז"א להקליט את הקשות המקלדת במחשב כלשהו ושלוח אותם לאימייל ספציפי או לשרת FTP בשביל ניתוח והוצאת מידע בעל ערך. היום כלים אלה יכולים לעשות יותר מאשר להקליט הקשות מקלדת, כמו לנתר אחר תיקייה ספציפית, לקחת תמונות מסך, וכד'. -* **Terminal -** (או System Console) היא מעטפת גרפית ל Shell שהוא כלי שורת פקודה, המעבד את בקשות המשתמש, ואומר למערכת ההפעלה מה לעשות בהתאם. לכלים המבוססים על ה Terminal יש יתרונות רבים, בינהם פחות תלויות בספריות חיצוניות (בדר"כ ספריות GUI), קלים יותר מבחינת משקל בדיסק ומבחינת תקשורת באינטרנט (לשלוח שורת טקסט באינטרנט יהיה מהיר יותר משלוח צילום מסך, לדוג'), ועוד. -* **Firewall -** במקרה הזה אני מדבר על מערכת לניטור וחסימת תקשורת לא רצויה (לרשת המקומית או למחשב ספציפי), ולא Computer Firewall שהוא מחשב ייעודי המנתר את התקשורת.  -* **Virus -** היא תוכנה המסוגלת לבצע שכפול עצמי, ולרוב גם מסוגלת לבצע פעולות נוספות כגון מחיקת מידע, הצגת הודעה מעצבנת וכד'. -* **Reverse Shells -** הוא סוג של Shell בו המכונה המדובקת פותחת חיבור ומתקשרת חזרה עם המכונה התוקפת. - -כמובן שאין זאת רשימה מלאה או מייצגת, רק הפירוש שלי למושגים השונים שראיתי בכל מיני מקומות, כדי שאתחיל להבין מה אני קורא. - -  - -### 3. סביבת עבודה - -נתחיל בהתקנת Kali על [Virtual Box](https://www.virtualbox.org/). מכיוון שההתקנה זו דומה לכל התקנת מכונה ווירטואלית רגילה אני לא אעבור על כל התהליך, אך אציין כי כשאתם יוצרים מכונה ווירטואלית חדשה ה Type שלה כמובן צריך להיות Linux וב Version בחרו Debian (דביאן) (מכיוון שהיא מבוססת עליה) 64bit. הזיכרון המומלץ הוא 2GB, והאחסון המומלץ הוא 20GB. - -כשהתחלתם להתקין, תידרשו לבחור שפה, אזור זמן וכד' (שאר הדברים הרגילים בעת התקנת מערכת הפעלה). במהלך ההתקנה תגיעו למסך בו תתבקשו להכניס את שם ה host של המערכת שזה יהיה שם המחשב (תכתבו מה שבא לכם), לאחר מכן תתבקשו להכניס את ה domain לא אבצע בו שימוש אז מחקתי את ערך ברירת המחדל שהיה שם ולחצתי על continue (כמובן שהכל ניתן לשנות גם אח"כ מתוך המערכת), ולבסוף את הסיסמה של ה Root. ותמשיכו כמו כל התקנת Linux רגילה. באמצע תשאלו האם להשתמש ב Network Mirror אתם יכולים לסמן No, לאחר מכן תשאלו האם להתקין GRUB אני סמנתי Yes (ניתן לקרוא עליו  [כאן](https://en.wikipedia.org/wiki/GNU_GRUB)), ולבסוף מסך המודיע על סיום התקנה. - -אחרי שההתקנה הסתיימה ניכנס למערכת כאשר שם המשתמש שלנו הוא root והסיסמה היא זאת שבחרנו לפני כן (ההגיון בכינסה כ root הוא שאנחנו לא נכנסים ל Kali על מנת לצפות בסרטים, אלא כדי להשתמש בכלים שלרוב צריכים הרשאות root). הדבר הראשון שנעשה הוא לבדוק ולעדכן את החבילות המותקנות (במידה ויש עדכונים) בעזרת הפקודה `apt-get upgrade` ונמשיך עפ"י ההוראות. - -  - -**פקודות טרמינל** - -הרבה מהכלים בהם נשתמש יפעלו באופן בלעדי ב Terminal ולכן עלינו להכיר לפחות כמה פקודות בסיסיות על מנת שנוכל להתנהל דרכו. אז כעת אפרט על כמה פקודות בסיסיות שיעזרו לכם בהתנהלות היום – יומית שלכם בטרמינל (מכיוון שזה לא קשור לנושא המרכזי מוקדש לטרמינל רק חלק קטן, בעתיד ארחיב על נושא הפקודות / טרמינל / ו bash scripting יותר). - - * **cd -** (ראשי תיבות של change directory), תאפשר לנו להחליף להיכנס או לצאת מתיקייה כלשהי. אחרי המילה cd נכתבת שם התיקייה (או הנתיב המוביל אליה), וכדי לחזור לתיקיית האב (שמעלינו בעץ) נכתוב `cd ..`. - * **ls -** (ראשי תיבות של list directory), תדפיס לנו את תוכן התיקייה (קבצים, תיקיות, וכד' שנמצאים בתיקייה שאנו כעת). בנוסף ניתן לבקש את התוכן של תיקייה בה אנו לא נמצאים כעת אם נכתוב את הפקודה (ls) ואח"כ הנתיב המלא לתיקייה המבוקשת. לדוגמה: `ls /nirgn/home/Downloads` (שימו לב שמערכת הקבצים בלינוקס היא case sensitive). לפקודה ישנם דגלים (flags), ז"א דגלים שאנו יכולים "להרים" כדי להרחיב את הפקודה, כמו `ls -l` כדי לקבל את רשימה של תוכן התיקייה עם פירוט נרחב הכולל לדוגמה תאריך היצירה, הרשאות, קבוצה, וכד'. או הדגל `ls -a` (כדי להראות קבצים נסתרים). ואף אפשר לשלב בין הדגלים כך `ls -la`. - * **pwd -** (ראשי תיבות של print working directory), ידפיס לנו את הנתיב המלא של התיקייה בה אנו נמצאים. - * **cp -** (ראשי תיבות של copy), מאפשר לנו להעתיק קבצים ותיקיות. השימוש מתבצע ע"י כתיבת הפקודה (cp) ולאחריה הקובץ / תיקייה אותה אנו רוצים להעתיק, ואחריה הנתיב אליו אנו רוצים להעתיק (כשרווח מפריד בין הכל). לדוגמה: `cp path/item.txt /path2/someRandomDir`. כשנבצא את הפקודה, אם היא הצליחה לא נקבל פלט אישור חזרה. כדי לראות בדיוק מה קרה נשתמש בדגל v, כך: `cp -v path/item.txt /path2/someRandomDir`. - * **mv -** (ראשי תיבות של move), תגזור, תעביר את הקובץ / תיקייה ליעד המבוקש. בדיוק כמו cp, אנחנו כותבים את הפקודה (mv) ולאחריה את הקובץ / תיקייה אותה אנו רוצים להעביר / לגזור, ולאחר מכן את הנתיב אליו אנו רוצים להעביר / לגזור את הפריט המבוקש. לדוגמה: `mv item.txt /path/someRandomPath`. ניתן גם לשנות שם של קובץ עם הפקודה הנל, כך: `mv item.txt item2.txt` (כך הקובץ יועבר לאותו מקום עם שם שונה, ובעצם כל שעשינו הוא לשנות את שם הקובץ). - * **cat -** (ראשי תיבות של concatenate), מאפשר לנו להציג את תוכן הקובץ. לדוגמה: `cat item.txt` תציג לנו את התוכן הכתוב בתוך הקובץ item.txt בתוך הטרמינל. - * **echo -** תדפיס את הטקסט המתקבל אחריה, וכמובן של הטקסט להיות בין גרשיים, לדוגמה: `"echo "hi there`. ואנחנו יכולים להיעזר בסימן ה"גודל מ.." כדי להכניס את הטקסט לקובץ, לדוגמה: `echo "This text will be in the file" > testFile`. - * **touch -** היא דרך מהירה ליצור קבצים חדשים. כדי ליצור קובץ חדש נכתוב את הפקודה (touch) ואז את שם הקובץ. ניתן כמובן גם ליצור כמה קבצים באותה פקודה, ע"י רווח ואז לכתוב את שם הקובץ הבא, לדוגמה: `touch file1 file2`. - * **mkdir -** (ראשי תיבות של make directory), יצור לנו תיקייה חדשה. השימוש בפקודה מתבצע ע"י כתיבתה ואחריה השם שאנו רוצים לתת לתיקייה החדשה, לדוגמה: `mkdir placeToBe`. - * **rm -** (ראשי תיבות של remove), הפקודה תמחוק את הקובץ / תיקייה שתכתבו אחריה (צריכה להיות בתיקייה בה אתם נמצאים כעת, ואם לא נמצאת שם עליכם לפרט את הנתיב המלא). - * **help -** כמובן שלכל הפקודות יש עוד דגלים, ואנחנו גם לא צריכים לשנן את הדגלים, מספיק שנכתוב help- אחרי הפקודה (כך: `cp –help`) כדי לקבל את כל התיעוד והדגלים של פקודת ה cp. - * **clear -** מידי פעם, בעיקר אחרי שאנחנו כותבים הרבה פקודות, נרצה לנקות את המסך. אין צורך לפתור חלון טרמינל חדש, אפשר פשוט לכתוב את הפקודה `clear`. - -  - -### 4. אנונימיות - -יש כמה דרכים לנסות לשמור על אנונימיות ברשת. בראש ובראשונה, Proxy בה אנו מנתבים את התקשורת שלנו דרך כמה צמתים אחרים. שיטה זאת יכולה להיות מסוכנת כי איננו יודעים דבר אודות השרת בו החבילות שלנו (Packets) עוברות. שיטה אחרת היא להשתמש ב VPN ולהצפין את המידע העובר בינינו ובין ספק ה VPN. והשיטה בה נעסוק כרגע היא דרך Tor, המנתבת את הגלישה דרך צמתים שונים כאשר כל צומת מוסיף שכבת (המצפינה את החבילה ומוסיפה מידע נחוץ כגון להחזיר אליו את החבילה) עד שלבסוף החבילה יוצאת מאחד הצמתים אל רשת האינטרנט. - -
    - Tor Logo -
    - -תחילה נתקין את tor במשתמש root (אך לא את הדפדפן, כי לא נגלוש דרך המשתמש הזה) עם הפקודה `apt-get install tor -y`. לאחר מכן, כדי לגלוש ב Tor ניצור משתמש חדש עם הפקודה `adduser userName` (החליפו את userName בשם שתבחרו, הקלידו אח"כ את הסיסמה ואת שאר הפרטים אתם יכולים להשאיר ריקים). צעד זה אינו חובה, אך הגיוני מכיוון שאיננו רוצים להריץ את Tor עם הרשאות Root מהסיבה שאנו לא מכירים את הקוד שעומד לרוץ באתרים אליהם ניכנס, ואיננו רוצים ליצור מצב שקוד זדוני ירוץ (ועוד בלי שאנו יודעים זאת) עם הרשאות Root.  - -לאחר שיצרנו משתמש חדש, נצא מהמשתמש root וניכנס למשתמש שיצרנו (ע"י לחיצה על root בפינה הימנית עליונה -> Switch User), ומתוך המשתמש החדש ניכנס [לאתר הפרויקט של Tor](https://www.torproject.org/) ונוריד את הגרסה המתאימה (בפינה הימנית עליונה, מתחת לתפריט הניווט ישנו כפתור Download). הקובץ שירד לנו יהיה קובץ tar.xz וממנו נלחץ את התיקייה עם הפרויקט, כדי להפעיל את הדפדפן של Tor (ישנם 2 חלקים: הדפדפן שמבוסס Firefox והתוכנה עצמה) נלחץ על "Tor Browser" שנמצא בתוך התיקייה שחילצנו ובחלון שיפתח נלחץ על "Connect". - -בפשטות, מה שהדפדפן Tor נותן לנו הוא גישה לסיומות onion שאינם נגישים משאר הדפדפנים. נתחיל בלכתוב בשורת החיפוש "hiddenwiki url" שהוא בעצם אתר המהווה אינדקס של אתרים בעלי סיומות onion בכתובת. הסיבה שאנו מחפשים את האתר ולא כותבים כבר את הכתובת שלו היא שהכתובת שלו משתנה מעת לעת (בעיקר בגלל שהוא נפרץ). בזמן שכתבתי את הפוסט הזה הכתובת הייתה "http://kpvz7ki2v5agwt35.onion" אך יכול להיות שזה כבר השתנה. ב Hidden Wiki ניתן למצוא מגוון לינקים לאתרים שונים העוסקים בנושאים שונים (חלק מהאתרים לא יהיו זמינים), אחד האתרים שיצא לי לשמוע עליו ולחפור בו קצת הוא Intel Exchange שזה בעיקרון פורום עם שיחות במגוון נושאים מ"דיבורים" ל"מדע ומתמטיקה", "תוכנה", "חומרה", "בריאות פיזית ונפשית", וכד'. - -כבר עכשיו אציין שכמו שלא כדאי להאמין לכל מה שכתוב באינטרנט, כך לא כדאי להאמין לכל מה שכתוב גם באתרים האלו. ויש לציין כי Tor כמובן לא היחידי במשחק (למרות שהוא הגדול ביותר עקב עלייתו לכותרות בשנים האחרונות), קיימים עוד מערכות העובדות על אותו עקרון (פחות או יותר) כדוגמת I2P ו Freenet. בנוסף, בפוסט הבא נכיר עוד דרכים לשמירה על האנונמיות. - -  - -### סיכום - -הפוסט הזה היה יותר הקדמה ויישור קו עם עצמי מאשר למידה של משהו חדש. הכנו את הסביבה בה נבלה את רוב זמננו, פירשנו והבנו מושגים ששמענו בחצי אוזן (או נזכרנו והבהרנו מושגים אותם שמענו בעבר), למדנו (או חזרנו) על מספר פקודות Bash בסיסיות אותם נצטרך לעבודה היום - יומית במערכת Linux, ולבסוף נכנסו קצת לאתרים שלא נגישים בדרכים רגילות והבנו כיצד Tor עובד ושומר (או מנסה) על האנונימיות שלנו. בפוסט הבא נמשיך לדבר בהרחבה על נושא האנונמיות ונתחיל לדבר על איסוף מידע חיצוני, ולמה לבצע את זה בכלל. diff --git a/data/_oldPosts/2015-09-13-avl.md b/data/_oldPosts/2015-09-13-avl.md deleted file mode 100644 index c2627de..0000000 --- a/data/_oldPosts/2015-09-13-avl.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: עץ AVL -author: nirgn -layout: post -summary: "אפשר לממש כל אחת מהפעולות הבסיסיות בזמן (O(h כאשר h הוא גבוה העץ. מהירות זאת יכולה להיות נמוכה אם העץ נמוך אם העץ גבוה. על מנת לפתור את הבעיה הזאת קיימת גרסה אחרת של עץ חיפוש בינארי הנקראת עץ AVL." -category: Data Structures ---- -בפוסט הקודם במבני נתונים (על עצים בינארים בכלל ועץ חיפוש בינארי בפרט) ראינו שאפשר לממש כל אחת מהפעולות הבסיסיות בזמן (O(h כאשר h הוא גבוה העץ. מהירות זאת יכולה להיות נמוכה אם העץ נמוך, אך כמו שאמרנו, אם העץ גבוה אפשר שהביצועים לא יהיו טובים יותר מאשר במימוש באמצעות רשימה מקושרת. על מנת לפתור את הבעיה הזאת קיימת גרסה אחרת של עץ חיפוש בינארי הנקראת עץ AVL. ההבדל בין הגרסאות הוא שעץ AVL הוא עץ מאוזן. - - - -  - -### עקרון האיזון - -
    - AVL Example -
    - -עץ מאוזן אומר שגובה התת עץ השמאלי פחות גובה התת עץ הימיני הוא 0 או 1 או 1-. - -גבוהו של עץ בינארי T שווה לאורך המסלול הארוך ביותר מהשורש לאיזשהו עלה ב T. אם העץ ריק הגובה מוגדר כ-(1-). ואם העץ מכיל רק צומת יחיד, גבוהו מוגדר כ-0. לדוגמה: בתמונה משמאל, גורם האיזון של A הוא 1, וזאת משום שגובה התת עץ השמאלי  (2) פחות גובה התת עץ הימיני (1) הוא 1. גם גורם האיזון של B הוא 1, וגם של C. גורם האיזון של F, לדוגמה, הוא 1- (גורם האיזון של כל עלה בעץ הוא כמובן 0). - -נשים לב כי הדרישה שהעץ יהיה מאוזן (ז"א שהגבהים של שני תת העצים שלו אינם נבדלים ביותר מ-1) קיימת לכל צומת בעץ, ולא רק לשורש. לא אלאה אתכם בחישוב, אך ניתן להגיע בקלות (יחסית) לכך שהחסם העליון (במקרה הגרוע ביותר) של גבוה העץ הוא (lg(n [כאשר ה log נכתב כ lg מדובר על log בבסיס 2) לעץ בעל n צמתים.  - -  - -### ביצוע פעולות - -קודם כל, צריך להבחין בין שאילתות לבין פעולות שמשנות את מבנה העץ. כאשר אנו מדברים על שאילתה (כמו Search, Minimum, Maximum, Successor וכ'ו), הפעולה תתבצע בדיוק באותו אופן שבו היא מתבצעת על עץ חיפוש בינארי רגיל (לכן לא נרחיב על פעולות אלה בפוסט זה). בנוסף, מאחר שידוע לנו שגובהו של עץ AVL הוא מקסימום (lg(n מובטח לנו שפעולות אלה יתבצעו מהר, ולפעמים, אף, מהר יותר מאשר על עץ חיפוש בינארי. - -אך כאשר אנו מדברים על פעולות שמשנות את מבנה העץ (כמו Insert ו  Delete) המצב מסובך יותר, מכיוון שלאחר שנבצע את פעולת הכנסת איבר לעץ או מחיקת איבר מהעץ, העץ עלול להפוך להיות לא מאוזן. לדוגמה: אם נמחק את G מהעץ שלמעלה בצד שמאל, או שנכניס איבר כבן של E. - -  - -**רוטציה על עץ AVL** - -
    - Left Rotation -
    - -רוטציה (rotation) היא פעולה מקומית בעץ חיפוש בינארי, השומרת על הסדר התוכי של המפתחות. ישנם 2 סוגים של רוטציה: רוטציה שמאלית ורוטציה ימנית. כאשר מפעלים לדוגמה רוטציה, שמאלית על צומת x, שבנו הימיני הוא y, התת עץ שהיה מושרש ב x משתנה כך: - - * y הופך להיות השורש של התת עץ. - * x הופך להיות בנו השמאלי של y. - * התת עץ השמאלי של y הופך להיות התת עץ הימני של x. - -בתמונה משמאל ניתן לראות הדגמה של רוטציה שמאלית על עץ חיפוש בינארי. אם נבצע בעץ שקיבלנו בתמונה משמאל את הפעולה ההפוכה (כלומר, רוטציה ימנית על y) נקבל בחזרה את העץ המקורי. רוטציה כמובן אינה משנה את הסדר התוכי של המפתחות, ולכן אם העץ המקורי היה עץ חיפוש, אז גם לאחר ביצוע הרוטציה מובטח לנו כי העץ יהיה עץ חיפוש. להלן ה - -[פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) של הרוטציה השמאלית: - -```c -y <- right[x] -right[x] <- left[y] -if (left[y] != NIL) - then p[left[y]] <- x -p[y] <- p[x] -if (p[x] = NIL) - then root[T] <- y - else if (x == left[p[x]]) - then left[p[x]] <- y - else right[p[x]] <- y -left[y] <- x -p[x] <- y -``` - -**הסבר קצר:** בשורה 1 מציבים ב y את בנו הימיני של x (ההנחה היא שיש ל x בן ימני). בשורה 2 התת עץ השמאלי של y הופך להיות התת עץ הימני של x. אם תת עץ זה איננו ריק, אביו של שורש התת עץ יהיה כעת x (שורות 4-3). בשורה 5 מעדכנים את אביו של y (הוא יהיה אביו שהיה אביו של x). אם אביו של x היה NIL, אז y הוא כעת השורש החדש של העץ (שורות 6-7). אחרת, דואגים לכך שאביו של x יצביע כעת על y, בנו החדש (שורות 8-10). ולבסוף, בשורות 11-12, x הופך להיות בנו השמאלי של y. כמובן שהקוד עבור רוטציה ימנית דומה, וזמן הריצה של הרוטציות (ימנית / שמאלית) הוא (O(1. - -  - -**הכנסת איבר לעץ AVL (פעולת Insert)** - -תהליך ההכנסה מתחלק לשלושה שלבים: - - 1. מכניסים את k כעלה לעץ, בדומה להכנסה של צומת לעץ חיפוש בינארי רגיל. ההבדל הוא, שהפעם נדאג לשמור מצביע לאב הקדום הנמוך ביותר של k, שגורם האיזון שלו לפני ההכנסה היה 1 או 1-. נסמן צומת זו ב A. הצומת A היא הצומת הקריטי, מפני שהוא הצומת הראשון שגורם האיזון שלו עלול להפוך להיות 2 או 2- בעקבות הכנסת k לעץ. - 2. בודקים אם בעקבות הכנסת k לעץ, העץ הפך להיות לא מאוזן. הנקודה החשובה היא שמספיק לבדוק רק את צומת A: אם גורם האיזון של A היה 1 ו k הוכנס לתת עץ הימני של A, או שגורם האיזון של A היה 1- ו k הוכנס לתת עץ השמאלי של A, אז גורם האיזון של A ישתנה ל-0, ובמקרה זה העץ נשאר מאוזן. אם לעומת זאת, גורם האיזון של A היה 1 ו k הוכנס לתת עץ השמאלי של A, אז גורם האיזון של A הפך להיות 2 וצריך לאזן את העץ. באופן דומה, אם לנפי הכנסת k גורם האיזון של A היה 1- ו k הוכנס לתת עץ הימני של A, אז גורם האיזון של A הפך להיות 2- וצריך לאזן את העץ (איזון העץ יתבצע באמצעות רוטציה אחת או שתיים, כפי שנתאר בהמשך). - 3. כעת נותר רק לעדכן את גורמי האיזון של שאר הצמתים בעץ שהושפעו מהכנסת האיבר החדש. יש לעדכן את גורמי האיזון של האבות הקדמונים של k, שהחל מהצומת הראשון מתחת ל A שלא היה מעורבת ברוטציה ועד לאביו של k. (במקרה שלא הייתה צומת קריטי, מבצעים את העדכון החל מהשורש.) כדי לבצע את העדכון הולכים לשוב לאורך המסלול שבו הלכנו כשהכנסנו את k לעץ, ומשנים כל אחד מגורמי האיזון של הצמתים מ-0 ל-1 או ל-(1-) בהתאם לכיוון ההכנסה של k. - -**סיבוכיות זמן ריצה:** מאחר שגובה העץ הוא ((O(lg(n, ברור שהשלב הראשון (הכנסת k לעץ) והשלב השלישי (עדכון גורמי האיזון של האבות הקדומנים של k) מתבצעים בזמן ((O(lg(n. בשלב השני לעומת זאת מתבצעות לכל היותר שתי רוטציות ולכן זמן הריצה שלו הוא (O(1. ולכן כל תהליך ההכנסה מתבצע בזמן ((O(lg(n. - -**סיבוכיות מקום:** נשים לב שמספיק לזכור רק את הצומת הקריטי, ואין צורך לזכור את כל המסלול מהשורש ועד למיקום של הצומת החדש. כלומר, כמות הזיכרון הנדרשת היא (O(1. - -  - -**נבחין בין ארבעה מקרים אפשריים:** - - 1. k מוכנס לתת עץ השמאלי של A ולתת עץ השמאלי של B. - 2. k מוכנס לתת עץ השמאלי של A ולתת עץ הימני של B. - 3. k מוכנס לתת עץ המני של A ולתת עץ הימני של B. - 4. k מוכנס לתת עץ הימני של A ולתת עץ השמאלי של B. - -אך מכיוון שמקרים 3 ו-4 הם סימטריים למקרים 1 ו-2 נדון במקרים 1 ו-2 בלבד (המקרים שבהם גורם האיזון של A לפני הכנסת k היה 1 ובעקבות ההכנסה הוא השתנה ל-2). - -  - -**מקרה 1:** - -
    - Right Rotation On A -
    - -כדי לתאר את תהליך איזון העץ נשתמש בסימונים אלה: - - * B – בנו של A בכיוון ההכנסה של k. - * T1 ו T2 – שני התת עצים של B. - * T3 – התת עץ של A בכיוון הנגדי לכיוון ההכנסה של k. - -נסמן את גבוהו של T1 (התת עץ השמאלי של B) ב h. ומכאן ברור שגם גבוהו של T2 (התת עץ הימני של B) הוא h, כי האיזון של B לפני הכנסת k הוא 0. גבוהו של T3 (התת עץ הימני של A) הוא גם כן h, כי האיזון של A לפני ההכנסה הוא 1. הפעולה הנגדרשת היא רוטציה ימנית על A. - -כפי שניתן לראות באיור משמאל, גורמי האיזון של A ו B  לאחר ביצוע הרוטציה הם 0, ויש לדאוג לעדכן אותם בהתאם. בנוסף, נשים לב שלפני ההכנסה של k גובה התת עץ המושרש ב A (התת עץ שהשורש שלו הוא A) היה h+2. לאחר ההכנסה של k ואיזון העץ, גבוה העץ נשאר h+2 (לאחר האיזון, B הוא השורש החדש של התת עץ). כלומר, גורמי האיזון של כל הצמתים שהיו אבות קדומנים של A לא השתנו בעקבות הכנסת k לעץ (והצמתים שאינם אבות קדומנים של k כלל לא הושפעו מהכנסת k לעץ). - -  - -**מקרה 2:** - -
    - Two Rotations -
    -מקרה זה מסובך יותר מכיוון שדורש שתי רוטציות. לכן גם נשרטט את מקרה זה בצורה מפורטת יותר: - - * C – בנו של B בכיוון ההכנסה של k. - * T2 – התת עץ השמאלי של C. - * T3 – התת עץ הימני של C. - * T4 – התת עץ הימני של A. - * אם נסמן את גבוהם של T2 ושל T3 ב h, אז גבוהו של T1 הוא h+1 (משום שגורם האיזון של הצומת B לפני ההכנסה של k היא 0), וגבהו של T4 גם h+1 (משום שגורם האיזון של הצומת A לפני ההכנסה של K הוא 1). - -במקרה זה, יש 3 תת מקרים אפשריים: - - 1. k נכנס ל T2 (כמו באיור משמאל). - 2. k נכנס ל T3. - 3. הצומת B הוא עלה, ו k נכנס לעץ כבנו הימני של B. - -
    - Rotation left and right -
    -בכל שלושת התת מקרים האלו נדרשת אותה פעולה, צריך לבצע רוטציה שמאלית על B  ולאחר מכן רוטציה ימנית על A. גורם האיזון החדש של A הוא 1-, וגורמי האיזון של B ו C נשארים 0. - -בנוסף, נשים לב שלפני ההכנסה של K, גובה התת עץ המושרש ב A היה h+3, ולאחר ההכנסה והאיזון גובה התת עץ נשאר h+3 (לאחר האיזון C הוא השורש החדש של התת עץ). כלומר, גם הפעם גורמי האיזון של כל הצמתים שהיו אבות קדמונים של A לא השתנו בעקבות הכנסת k לעץ. - -
    - Delete AVL Example -
    - -  - -**מחיקת איבר מעץ AVL (פעולת Delete)** - -כדי למחוק איבר מעץ AVL, מפעילים קודם כל את כל האלגוריתם למחיקת איבר מעץ חיפוש בינארי רגיל (נזכיר: אם הצומת הוא עלה – פשוט נמחק אותו. אם לצומת יש בן אחד – מוחקים את הצומת ומציבים את בנו במקומו. אם לצומת יש 2 בנים – מציבים במקום הצומת את העוקב לו בסדר תוכי ומוחקים את העוקב  בסדר תוכי), ולאחר ביצוע המחיקה, משתנה גורם האיזון של אביו של הצומת שנמחק. - -ז"א שישנם 3 מקרים אפשריים: שינוי בגורם האיזון מ-0 ל-(1+/-), שינוי מ-(1+/-) ל-0, או שינוי מ-(1+/-) ל-(2+/-). נדגים את שלושת המקרים באמצעות מחיקת איבר מהעץ שמשמאל. - -  - -
    - Case A -
    - -**מקרה א** - -גורם האיזון של האב היה 0 והוא משתנה ל-(1+/-). במקרה זה גובהו של התת עץ המושרש באב לא משתנה, ולכן צריך רק לעדכן את גורם האיזון של האב. זה המקרה הפשוט ביותר, מאחר שלשינוי בגורם האיזון של האב אין השפעה על צמתים אחרים בעץ. - -גורם האיזון של D משתנה מ-0 ל-(1-), ובכך האלגוריתם מסתיים. - -  - -**מקרה ב** - -
    - Case B -
    - -גורם האיזון של האב היה 1+/- והוא משתנה ל-0. במקרה זה גובהו של התת עץ המושרש באב קטן ב-1, ולכן יש השפעה כל גורם האיזון של הסבא. לכן, צריך לעדכן את גורם האיזון של הסבא, ולהמשיך בהתאם לסוג השינוי בגורם האיזון של הסבא (שינוי מ-0 ל-(1+/-), שינוי מ-(1+/-) ל-0, או שינוי מ-(1+/-) ל-(2+/-). - -אביו של הצומת שנמחק הוא P, וגורם האיזון של P משתנה מ-1 ל-0. בעקבות זאת יש לשנות גם את גורמי האיזון של הבאות הקדמונים של P, שהם כעת R ו-M. גורם האיזון של הסבא, R, משתנה מ-1 ל-0, וגורם האיזון של M, אביו של הסבא, משתנה מ-1 ל-0. - -  - -**מקרה ג** - -
    - Case C -
    - -גורם האיזון של האב היה 1+/-, והוא משתנה ל-(2+/-). במקרה זה יש צורך לבצע רוטציה על האב כדי לאזן את העץ. לאחר ביצוע הרוטציה, גובה התת עץ המושרש באב עלול לקטון ב-1. וכמו שאמרנו, יש לכך הפשעה על גורם האיזון של הסבא, וצריך לפעול כמו שפעלנו במקרה ב. - -אביו של הצומת שנמחק הוא R, וגורם האיזון שלו משתנה מ-1 ל-2. לאחר ביצוע רוטציה על R, גובהו של התת עץ ש R היה השורש שלו קטן ב-1, ויש לשנות את גורם האיזון של F מ-(1-) ל-0. - -  - -לסיכום, כאשר גורם האיזון של האב הוא 1+/- הוא משתנה ל-0 או ל-(2+/-). (כאשר הוא משתנה ל-(2+/-) צריך לבצע רוטציה). בעקבות השינוי בגורם האיזון של האב, משתנה גם גורם האיזון של הסבא, ויש לחזור על תהליך האיזון, כשהפעם בוחנים את האפקט שיש לשינוי בגורם האיזון של הסבא. במקרה הגרוע, יהיה צורך לבצע רוטציה בכל צומת לאורך המסלול מהצומת שנמחק ועד לשורש. - -  - -### לסיכום - -בפוסט זה למדנו על נגזרת של עצי חיפוש בינארים הנקראת עצי חיפוש בינארים מאוזנים. הבנו כיצד מבצעים פעולת הכנסה (4 אפשרויות שונות) ומחיקה (3 אפשרויות שונות) לעצים כאלו תוך שמירה על האיזון שלהם (איזון גבוה העץ). על מנת לשמור על איזון העץ למדנו כיצד לבצע רוטציה על העץ (לשנות את סדר המפתחות התוכי של העץ).  - -עצי חיפוש בינארי **מאוזנים** מאפשרים לנו לבצע את פעולות המילון (הכנסה ומחיקה) בזמן (O(lgn (מה שאינו מובטח אם משתמשים בעצי חיפוש בינארי רגילים). לכן השימוש בעצי AVL כ"קופסה שחורה" יכול להועיל כאשר אנו מתכננים מבני נתונים שתומכים או בפעולות המילון או בפעולות פשוטות ושימושיות אחרות שנגזרות מהן. diff --git a/data/_oldPosts/2015-10-11-priority-queue.md b/data/_oldPosts/2015-10-11-priority-queue.md deleted file mode 100644 index 0945b36..0000000 --- a/data/_oldPosts/2015-10-11-priority-queue.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: תור קדימויות (Priority Queue) -author: nirgn -layout: post -summary: "" -category: Data Structures ---- diff --git a/data/_oldPosts/2015-11-01-operating-system-part-1.md b/data/_oldPosts/2015-11-01-operating-system-part-1.md deleted file mode 100644 index fa4486e..0000000 --- a/data/_oldPosts/2015-11-01-operating-system-part-1.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: 'מערכות הפעלה - חלק 1 (הקדמה)' -author: nirgn -layout: post -summary: פוסט זה הוא הראשון בסדרת פוסטים על מערכות הפעלה, ומהווה הקדמה ויישור קו תיאורטי של הנושא. -base-images-url: 'operating-system-part-1' -category: Operating Systems ---- -פוסט זה הוא הראשון בסדרת פוסטים על מערכות הפעלה, ומהווה הקדמה ויישור קו תיאורטי של הנושא. אציין מראש כי הפוסטים בסדרה יהיו כבדים (בעלי מלל רב) וטכניים. הפוסטים נועדו למי שולמד מערכות הפעלה כחלק מתואר במדעי המחשב ו/או למי שמעוניין ללמוד לבד ו/או לאנשים שרק רוצים להיזכר (בראש כל פוסט יהיה תוכן עניינים).  - - 1. מהי מערכת ההפעלה - 2. ההיסטוריה של מערכות ההפעלה - 3. גן החיות של מערכות ההפעלה - 4. מושגים בסיסיים - 5. קריאות מערכת - 6. המבנה של מערכות הפעלה - - - -  - -### 1. מהי מערכת הפעלה - -OS Stack - -מערכת הפעלה היא תוכנה שמנהלת את חומרת המחשב. מערכות הפעלה גם מספקות בסיס להרצת אפליקציות שונות ומשמשות תווך בין משתמשי המחשב לבין החומרה (תמונה משמאל). למרות שמערכת ההפעלה משמשת כתווך, אין זה אומר שכל פעולה שאפליקציה או שירות מסוים יבצעו עוברת דרך מערכת ההפעלה (לכן ישנו קו בצד שמאל שמקשר בין האפליקציה ישירות לחומרה). חשבו מה היה קורה אילו כל הוראה של תוכנית משתמש הייתה מצריכה פנייה לממשק המשתמש ומשם לגרעין מערכת ההפעלה (kernel), איזה דיילי ועל כמה משאבים מבוזבזים מדובר. ובמקרים מסויימים, אין צורך אפילו בפנייה לחומרה (לדוג' כאשר תוכנית מסויימת מבקשת לבצע הוראה הדורשת קיום הרשאה מיוחדת, ההרשאה תיתן ע"י מערכת ההפעלה, ללא קשר לחומרה). - -החץ מהחומרה אל גרעין המערכת (Kernel) מתייחס למקרים בהן אין צורך בפנייה לחומרה, אך ישנו צורך בפנייה אל ה kernel (כמו שניתן לשים לב, אין חץ ישיר ממלבן האפליקציות אל גרעין המערכת). כאשר הוראות כאלו מגיעות (מכונות גם הוראות מיוחסות) המעבד עובר למצב המכונה מצב מיוחס (kernel mode או supervisor mode), בעוד הוראות שאינן מיוחסות מתבצעות במצב משתמש (user mode), ז"א שהמעבד מספק תמיכה כדי שמערכת ההפעלה תוכל להגן על משאביה. ההגנה מיועדת לחסום את אפשרות ההתערבות של המשתמשים בפעולתה של המערכת עצמה (בפועל, ההבחנה בין מצב מיוחס למצב משתמש נעשית ע"י מידור של קבוצת פקודות מכונה מיוחסות שאינן עומדות לעולם לרשות המשתמש הרגיל). - -  - -**על מערכת ההפעלה ניתן להסתכל מ-2 כיוונים:** - - 1. **מלמעלה למטה –** מכיוון זה, מערכת ההפעלה נראת כמכונה מדומה (או מכונה מורחבת), והינה שכבת תוכנה שנמצאת מעל התוכנה ומתחת ליישומי תוכנה אחרים, ומספקת למשתמש ממשק שמאפשר שימוש בחומרה. בדרך כלל, שכבת תוכנה זו מספקת למשתמש ממשק לחומרה שהינו נוח וקל לתכנות, ובכך מסתירה מהמשתמש את מורכבות הפעולה האמיתית של החומרה. - 2. **מלמטה למעלה –** מחשב מורכב מרכיבים רבים ושונים. ומנהל המשאבים (כחלק ממערכת ההפעלה כולה) הוא תוכנה שמנהלת את הקצאת המשאבים האלה לתהליכים שרצים במערכות שמעל מערכת ההפעלה. - -  - -### 2. ההיסטוריה של מערכות ההפעלה - -
    - Punched Cards Programming -
    - -במחשבים הראשונים, ללא מערכות ההפעלה, כל תוכנית הייתה צריכה מפרט מלא של החומרה כדי לפעול כראוי ולבצע משימות סטנדרטיות. והמורכבות ההולכת וגדלה של החומרה ושל התוכניות (האפליקציות) הפכו בסופו של דבר את מערכות ההפעלה להכרח. מערכת ההפעלה מספקת סט של פונקציות נחוצות המשמשת את רוב תוכניות המחשב (האפליקציות), ולינקים הדרושים כדי לשלוט ולסנכרן את חומרת המחשב. - -המחשבים הראשונים היו מחשבי mainframe (מחשבים מרכזיים חסרי כל צורה של מערכת הפעלה). לכל משתמש היה שימוש בלעדי של המכונה לתקופה קצובה של זמן, והיה מגיע עם התוכנית והנתונים מראש (על [כרטיסי נייר מנוקבים](https://en.wikipedia.org/wiki/Punched_card) וסרטים מגנטיים). התוכנית הייתה נטענת למכונה, והמכונה הייתה מוגדרת לעבוד עד שהתוכנית הושלמה או התרסקה (ניתן היה לדבג, Debugging, באמצעות לוח בקרה עם מתגים ונוריות). עם הזמן חל שינוי משמעותי של ממשק מערכות ההפעלה ובדיוק כמו מכוניות ישנות שהיו חסרות מהירות האצה, מכשיר רדיו, מזגן, וכד' שהפכו אח"כ לסטנדרטיים, כך יותר ויותר מהתוכנות האופציונליות (עורכי טקסט, מנהלי קבצים, דפדפן, וכד') הפכו לסטנדרט בכל חבילה של מערכת הפעלה. אך הצאצא האמיתי של מערכות ההפעלה המוקדמות הוא מה שנקרא היום ליבה / גרעין (kernel). - -**מושגים שיש להכיר:** - - * **מערכות אצווה ([Batch System](https://en.wikipedia.org/wiki/Batch_processing)) –** מערכת שיכולה לבצע באופן רצוף סדרה של משימות שהוכנה מראש. במערכת כזו כל משימה תתבצע מתחילתה ועד סופה (מבלי לשתף את המעבד עם תהליכים אחרים, כפי שנעשה במערכות עם timesharing). - * **ריבוי תוכניות ([Multiprogramming](https://en.wikipedia.org/wiki/Computer_multitasking#Multiprogramming)) –** שיטה שבה מס' תהליכים יכולים להימצא בזיכרון הראשון בו זמנית. שיטה זו מייעלת את ניצול המעבד ע"י הקצאתו לתהליך שממתין לו, בזמן שהתהליך שהתבצע קודם ממתין לאירוע כלשהו (למשל קבלת קלט מהאינטרנט). - * **חלוקת זמן ([Timesharing](https://en.wikipedia.org/wiki/Time-sharing)) –** שיטה שבה המערכת מאפשרת למספר משתמשים אינטרקטיביים לעבוד בו זמנית, כל אחד מהמסוף שלו (Terminal). בשיטה זו כל משתמש מקבל את הקצאת המעבד לפרק זמן מוגבל כדי לבצע עבודות, וכשהזמן מסתיים ההקצאה עוברת למשתמש אחר. העבודות של המשתמש שממנו נלקח המעבד ממשיכות לרוץ כאשר המשתמש מקבל את המעבד בפעם הבאה. - -  - -### 3. גן החיות של מערכות ההפעלה - -במהלך השנים התפתחו סוגים רבים ושונים של מערכות הפעלה, שלכל אחת ייעוד מרכזי משלה. בשנים האחרונות הרבה מסוגים אלו מתמזגים ומתאחדים, בעיקר בגלל ההתקדמות במחשוב האישי. למרות זאת בפסקה זו אציג בקצרה את הסוגים העיקריים של מערכות ההפעלה, גם אם כבר אינן איתנו. להלן הסוגים העיקריים: - - * **מערכות הפעלה למחשב מרכזי (mainframe operating system) –** מחשב מרכזי הוא מחשב בעל עוצמה חישובית גדולה, המשמש ארגונים גדולים (כגון מוסדות ממשלתיים, חברות מסחריות גדולות, בנקים, אוניברסיטאות וכ'ו) להפעלת יישומים רבים באמצעות עיבוד נתונים רחב היקף (לדוג' מרשם תושבים, תזמון טיסות מטוסים, ביצוע פעולות כספיות, וכל זה תוך כדי שירות משתמשים רבים). מערכות הפעלה למחשבים מרכזיים תוכננו לנצל בצורה יעילה את משאבי המחשב המרכזי, ולספק אמינות ואבטחת מידע גבוהים. הרבה מהרעיונות של מערכות ההפעלה למחשבים מרכזיים מצאו את דרכן, עם הזמן, למערכות הפעלה המשמשות מחשבים אחרים. - * **מערכות הפעלה לשרתים ([server operating system](http://www.webopedia.com/TERM/S/server_operating_system.html)) –** שרת מתאפיין בהפעלת מס' רב של תוכניות ותהליכים במקביל. כל תכנית או תהליך משרתים בדרך כלל מספר משתמשי קצה במחשבים המחוברת לשרת אשר ניגשים אל השרת באמצעות רשת האינטרנט. מערכות הפעלה לשרתים שמות דגש על זמינות ושרידות (למשל בשרתי אינטרנט כל נפילה או תקלה בתהליך או ביישום על גבי השרת פירושה השבתת שירות, וזו עלולה לגרום לניתוק ולאי הצגה של אתרי אינטרנט המאוחסנים על השרת). לכן שרתי אינטרנט מסופקים עם רכבי חומרה עודפים שמערכת ההפעלה יכולה לעבוד איתם במקביל, ובמקרה שהרכיב יוצא מכלל פעולה, המערכת תעבור לעבוד במתכונת חירום עם הרכיב העודף. בנוסף, במערכת הפעלה מסוג זה ניתן, לרוב, גם להחליף רכיבים "on the fly". - * **מערכות הפעלה מקביליות (multiprocessor operating system) –** מחשב מקבילי הוא מחשב המצויד ביותר ממעבד אחד. המעבדים במחשב מקבילי בדרך כלל חולקים זיכרון ושעון, והתקשורת נעשית לרוב דרך הזיכרון המשותף (ארכיטקטורה כזאת מכונה tightly coupled processors). ניתן להבחין בין 2 סוגים: הראשון עם מעבדים סימטריים (מערכות הפעלה הרצות על מעבדים מסוג זה משתמשות בטכניקה המכונה [Symmetric Multi Processing](https://en.wikipedia.org/wiki/Symmetric_multiprocessing) או בקיצור SMP והן יכולות לרוץ על כל אחד מהמעבדים, תהליכים יכולים להיות מתוזמנים גם על כל אחד מהמעבדים. ומחשבים ביתיים בימנו, שמצוידים ביותר ממעבד אחד, עושים, לרוב, שימוש בטכניקה זו). והשני עם מעבדים אסימטריים (בסוג זה מערכת ההפעלה רצה על מעבד אחד, הנקרא master. שאר המעבדים מכונים slaves ומערכת ההפעלה מקצה להם משימות. מערכות הפעלה מסוג זה נפוצות במחשבים גדולים יותר). - * **מערכות הפעלה מבוזרות ([distributed operating system](https://en.wikipedia.org/wiki/Distributed_operating_system)) –** במערכות אלו החישוב מבוזר בין מספר מעבדים כאשר לכל אחד מהמעבדים זיכרון ושעון משלו. מעבדים אלה מכונים loosely coupled processors. המעבדים מתקשרים בינהם דרך קווי תקשורת מסוגים שונים, כמו אפיקים ([buses](https://en.wikipedia.org/wiki/Bus_(computing))) או בתקשורת על גבי רשת לוקאלית. מערכות הפעלה מסוג זה שמות דגש על שיתוף משאבים, אמינות, ביזור עומסים ומאפשרות חישוב מהיר יותר. - * **מערכות הפעלה למחשבים ביתיים (personal computer operating system) –** תפקיד מערכות ההפעלה מהסוג הזה הוא לשרת את המשתמש הבודד. לכן מערכת הפעלה כזו משותתת על עקורונות של נוחות למשתמש וזמן תגובה מהיר. בשנים האחרונות התעצמה המגמה של ריבוי מעבדים במחשבים ביתיים, ולכן הגבול בין מערכות הפעלה מקביליות למערכות הפעלה למחשבים ביתיים הולך ומיטשטש. - * **מערכות הפעלה זמן אמת (real-time operating system) –** במערכת זמן אמת הדגש הוא על זמן הביצועים. ניתן להבחין בין 2 סוגי מערכות זמן אמת: מערכות שמציבות אילוצים נוקשים על זמני ביצוע (hard real time) ומערכות שהאילוצים גמישים יותר (soft real time). למערכות מהסוג הראשון ניתן לשייך מערכות במטוסים ומכוניות. ולסוג השני אפשר לשייך, לדוג', מערכות מוטלימדיה (בהן אי עמידה בזמנים יכול להיות נסבל במידה מסוימת). - * **מערכות הפעלה למערכות משובצות ([embedded operating system](https://en.wikipedia.org/wiki/Embedded_operating_system)) –** מערכות הפעלה אלו מיועדות לשימוש בסמארטפונים, ב smartcards וכד'. מערכות משובצות מתאפיינות בהצבת דרישות מחמירות מאוד על שימוש במשאבי המערכת. - -  - -### 4. מושגים בסיסיים - -Ubuntu Terminal - -במהלך הפוסטים הבאים נעמיק יותר בנושאים הבאים, אך כדי כבר להכירם היכרות ראשונית ולהבין באופן כללי את משמעותם נעבור עליהם באופן מהיר: - -* **תהליך (process) –** תכנית ריצה (executable) בביצוע. באופן בסיסי, תהליך מכיל את התכנית עצמה (code), את התונים שהיא יוצרת ומשתמשת בהם (data), מצביע למחסנית, מונה פקודות, ואוגרים אחרים שמכילים מידע על הסטטוס הנוכחי של הביצוע (התהליך גם מכיל מידע על הקבצים שהוא משתמש בהם, ונתונים רבים נוספים, אך על זה נרחיב בהמשך). -* **מצב קיפאון (deadlock) –** קבוצה של תהליכים נמצאת במצב קיפאון אם כל אחד מהתהליכים אינו יכול להתקדם אלא לאחר שיקרה אירוע אשר יכול להיגרם אך ורק על ידי תהליך אחר בקבוצה. תופעת הקיפאון בצורתה הפשוטה ביותר מתרחשת כאשר קיימים מינימום של שני תהליכים, שכל אחד מחזיק ברשותו משאב בלעדי הנחוץ לתהליך השני. במצב זה אף אחד מהתהליכים אינו יכול להתקדם. -* **ניהול זיכרון (memory management) –** בהמשך נדבר על שיטות ניהול זיכרון המאפשרות לשכן בו זמנית מספר תהליכים בזיכרון, ואף בחלק מהמקרים להריץ תוכניות שמשתמשות בכמות של זיכרון גדולה יותר מהזיכרון הפיזי. -* **קלט / פלט (input / output) –** התקן קלט / פלט הוא רכיב חומרה אשר נועד לאחסן ו/או להעברת מידע. לדוג' דיסק קשיח, דיסק און קיי, כרטיס רשת וכ'ו. ישנם התקני קלט / פלט אשר משמשים כהתקני קלט בלבד (לדוג' עכבר ומקלדת), או כהתקני פלט בלבד (לדוג' מדפסת ומסך). אחד התפקידים החשובים ביותר של מערכת ההפעלה הוא הניהול של התקנים אלו. -* **קבצים (files) –** קובץ הוא יחידת מידע לוגית לאחסון במדיה חיצונית. כיוון שקבצים הם מבנים לוגיים, מימושים נעשה בתוכנה ולא בחומרה. מערכת ניהול הקבצים (שהיא חלק ממערכת ההפעלה) אחראית למימוש הקבצים. -* **מעבד פקודות סדרתי (shell) –** תכנית המהווה ממשק אינטראקטיבי למערכת ההפעלה. ה shell מקבל פקודות שמוקלדות ע"י המשתמש ומבצע אותן על ידי שימוש בשירותי מערכת ההפעלה. - -  - -### 5. קריאות מערכת - -מערכת ההפעלה לא רק מנהלת את החומרה, אלא גם צריכה להגן על משאבי המערכת (לדוג', מפני הרצה של קוד זדוני במעבד). הגנה כזאת איננה יכולה להיות תוכנתית, מכיוון שאם מערכת ההפעלה תקבל כל פקודה ופקודה ותצטרך לנתח אותה (ואולי גם בהתאם לפקודות הקודמות שקיבלה מאותה תוכנית) לפני העברתה למעבד הדבר ישפיע בצורה קריטית על משאבי המערכת (בהנחה וזה בכלל אפשרי, הרי שורת קוד אחת לבדה יכולה להיות תמימה, אך בצירוף כמה שורות נוספות יהיה מדובר כבר על קוד זדוני שיכול להסב למערכת נזק). - -לכן, המסקנה היא שההגנה צריכה להיות חומרתית, ז"א ביט דלוק (1) או מכובה (0) שמייצג מצב מיוחס (kernel mode) או מצב משתמש (user mode). כאשר תוכנה מסויימת מבקשת את השירותים של המעבד, כדי לבצע חישוב כלשהו, המערכת תעביר את הביט במעבד למצב user mode ותעביר את השליטה לאותה תוכנה כדי לבצע את חישוביה. מכאן ישנן 2 אפשרויות: - -* הראשון הוא שהתוכנה תסיים את פעולותיה ותחזיר את המעבד למערכת ההפעלה, אך נזכור שכרגע המעבד במצב user mode ואי אפשר לבצע איתו פעולות מסויימות, כמו לדוג' להדליק את הביט ולהעביר את המעבד למצב kernel mode. אז נשארנו נעולים ב user mode, עד מתי? עד איזה time out? (אז מי מבטיח שהתוכנה תחזיר את משאבי המעבד למערכת ההפעלה לפני ה time out ולא תשאיר אותו אצלה גם אחרי שיקרה ה time out והמעבד יחזור למצב kernel mode?). -* האפשרות השניה היא שהתוכנה תשאיר אצלה את המעבד עד אין סוף, ולא תחזיר את המשאבים למערכת ההפעלה, ובקיצור תתקע את המחשב.  - -מה שמכריח את התוכנה להחזיר את משאבי המעבד חזרה למערכת ההפעלה הוא system call. ישנן מספר פעולות שאינן יכולות להתבצע ב user mode, אלא אך ורק ב kernel mode. כשהתוכנה רוצה לבצע את אחת מהפעולות הללו (לדוג', להתחיל תהליך חדש, או לקרוא ולכתוב אל מערכת הקבצים) היא מבצעת system call כדי לבקש ממערכת ההפעלה לעשות זאת בשבילה. בעת ביצוע ה system call מורמת פסיקה (Interrupt) שנתפסת ע"י בקר הפסיקות (PIC – ראשי תיבות של Programmable Interrupt Controller. בקר הפסיקות הינו רכיב פיזי, לדוג' [Intel 8259](https://en.wikipedia.org/wiki/Intel_8259)), והוא זה שמעביר את השליטה למערכת ההפעלה ומדליק את הביט במעבד כדי להעבירו למצב מיוחס (kernel mode). - -הבקר פסיקות, מרים בנוסף פסיקות כל זמן מסוים, רק כדי לוודא שגם האפשרות השניה (בה התוכנה אינה תשחרר את משאבי המעבד לעולם) לא תקרה. גם כאשר מדובר על פסיקות המורמות כל זמן מסוים (time out) (וגם כאשר מורמות פסיקות כתוצאה מ system call) הפסיקה מתקבלת אצל המעבד בהפתעה גמורה, הוא אינו מודע לכך שהיא אמורה לקרות. - -בתחילת הפוסט ראינו כי ביצוע של הוראות מיוחסות מתאפשר רק במצב מיוחס (kernel mode), ולמשתמש רגיל לא ניתנת אפשרות כזאת. אך, כמו שאמרנו, לרשות המשתמש עומד ממשק מיוחד של קריאות מערכת (system call) שדרכו הוא יכול לבקש ממערכת הפעלה שירותים אשר דורשים הרשאות מיוחדות. השירותים שמערכת ההפעלה מספקת יכולים להתבקש ע"י תכנית הכתובה בשפה עילית בצורה של פונקציות. כל קריאת מערכת מוציאה את השליטה מידי תכנית המשתמש ומעבירה אותה באופן זמני למערכת ההפעלה (מי שמבצע זאת בפועל זה בקר הפסיקות). התוצאה של הפעולה איננה ודאית, ולכן עבור כל קריאת מערכת, מערכת ההפעלה מחזירה אינדיקציה על תוצאת הביצוע (וחייבת להתבצע בדיקה של הערך שהפונ' מחזירה).  - -כדי להבין כיצד עוברת השליטה למערכת ההפעלה בעת הקריאה פונקציות אשר מכילות קריאת מערכת, להלן תוכנית בשפת C המדפיסה "hello world" על המסך, ומשתמשת בפונ' write אשר מכילה קריאה לשירות של מערכת ההפעלה. - -```c -#include <unistd.h> -#include <string.h> -#define STDOUT 1 - -int main(){ - char *msg[] = "Hello wold\n\0"; - if (write(STDOUT, msg, strlen(msg)) < 0) - exit(1); - return(0); -} -``` - -להלן התוכנית בשפת assembly שמבצעת את המשימה: - -```c -.data # Data section - -msg: .asciz "Hello world\n" # The string to print - len = . - msg - 1 # The length of the string - -.text # Code section -.global _start - -_start: # Entry point - push1 $len # Arg 3 to write: length of string - push1 $msg # Arg 2: pointer to string - push1 $1 # Arg 1: file descriptor -mov1 $4, %eax # Write - call do_syscall - add1 $12, %esp # Clean stack - - push1 $0 # Exit status -mov1 $1, %eax # Exit - call do_syscall - -do_syscall: - int $0x80 # Call kernel - ret -``` - -בשורות 10-12 מתבצעת העברת שלושה פרמטרים המכילים אינדיקציה של יעד הפלט (STDOUT), מצביע להודעה הנפלטת, ומספר התווים שבהודעת. בשורה 13 מועבר מספר השירות המסופק על ידי מערכת ההפעלה (במקרה שלנו write). ובשורה 22 מתבצעת הוראת TRAP שמעבירה את המעבד למצב מיוחס וגורמת למעבר השליטה למערכת ההפעלה. - -מערכת ההפעלה, תבדוק את הפרמטרים שהועברו בשורות 10-13, ואם הכל נמצא תקין היא תספק למשתמש את השירות המבוקש (במקרה שלנו תבצע הדפסה של הודעה על למסך). - -להלן הרשימה של הקריאות מערכת (system calls) במערכות UNIX: - -| UNIX | WIN32 | Description | -| :---------:|:-----:|:----:| -| fork | CreateProcess | Create a new process | -| waitpid | WaitForSingleObject | Can wait for a process to exit | -| execve | (none) | CreateProcess = fork + execve | -| exit | ExitProcess | Terminate execution | -| open | CreateFile | Create a file or open an existing file | -| close | CloseHandle | Close a file | -| read | ReadFile | Read data from a file | -| write | WriteFile | Write data to a file | -| lseek | SetFilePointer | Move the file pointer | -| stat | GetFileAtterbutesEx | Get various file attributes | -| mkdir | CreateDirectory | Create a new directory | -| rmdir | RemoveDirectory | Remove an empty directory | -| link | (none) | Win32 does not support links | -| unlink | DeleteFile | Destroy an existing file | -| mount | (none) | Win32 does not support mount | -| umount | (none) | Win32 does not support mount | -| chdir | SetCurrentDirectory | Change the current working directory | -| chmod | (none) | Win32 does not support securiry (although NT does) | -| kill | (none) | Win32 does not support signals | -| time | GetLocalTime | Get the current time | - -Monolithic Systems - -  - -### 6. המבנה של מערכות הפעלה - -מערכות הפעלה הן מערכות גדולות, המכילות, לרוב, עשרות ולפעמים מאות אלפי שורות קוד. אך כדי שכל האופרציה הזאת תפעל כשורה דרוש עיצוב כללי כלשהו, ולכל מערכת יש רעיון עיצובי משלה: - -* מערכות מונוליתיות (monolithic systems) - מערכת מונוליתית היא למעשה אוסף גדול של פונקציות שונות. -* מערכות מרובדות (layered systems) - אלו הן מערכות שמרכיביהן מאורגנים ברבדים הנמצאים ביחס היררכי. לכל רובד מוגדר ממשק שדרכו הרבדים הסמוכים בהיררכיה יכולים לתקשר בינהם. - -| Function | Layer| -|:----:|:--------:| -| The operator | 5 | -| User programs | 4 | -| input/output management | 3 | -| Operator-process communication | 2 | -| Memory and drum management | 1 | -| Processor allocation and multiprogramming | 0 | - -* מכונה מדומה (virtual machine) – בחלק הראשון ראינו שאחד התפקידים של מערכת ההפעלה הוא אספקה של שירותים של המכונה המורחבת ושל המכונה המדומה. ניתן לראות את מערכת ההפעלה כשכבת תוכנה המספקת לשכבות שמעליה מס' העתקים של החומרה עם כמות משאבים פחותה מזו שבחומרה הפיזית בפועל (במובן מסוים זו אינה מערכת הפעלה רגילה, שכן על כל מכונה מדומה יכולה לרוץ מערכת הפעלה חדשה). התוכונות הפופלריות בשוק כדי ליצור ולהפעיל מכונות מדומות הן [virtualbox](https://www.virtualbox.org/wiki/Downloads) של חברת oracle ו [vmware](http://www.vmware.com/il). -* מערכות Exokernel – במערכות אלה השירותים המסורתיים כגון מערכת קבצים, ניהול זיכרון, תזמון תהליכים ותקשורת הוצאו אל מחוץ לגרעין של מערכת ההפעלה. ההחלטה הזאת נובעת מכך שמערכת ההפעלה איננה כופה על המשתמש את צורת השימוש במשאבים (אלא רק דואגת להגנה על המשאבים וניהולם). -* מערכות שרת לקוח (client – server systems) – מערכות שרת לקוח מבוססות על הרעיון של גרעין מנינימליסטי (micro kernel), ז"א גרעיון מערכת ההפעלה מתפקד כדוור המריץ בקשות של לקוחות (תהליכים) אל שרתים עצמאיים (גם תהליכים), המפוזרים במערכת, כגון שרתי מערכת הקבצים, מנהל הזיכרון, תכנית התקשורת, תכנית המסך (מנהל חלונות), וכ'ו. כאשר מתקבלות תשובות מהשרתים, הגרעין מחזיר את התשובה להתליך המבקש. בשיטה זו התוכנה מורכבת מיחידות עצמאיות, שכל אחת מהן ממלאת תפקיד מוגדר. שיטה זו מצמצת מאוד את התלות בחומרה. - -  - -### סיכום - -בחלק זה למדנו את שני התפקידים של מערכת ההפעלה, ראינו מהן קריאות מערכת, ביצענו יישור קו לגבי הסוגים השונים של המבנה של מערכות הפעלה, ועברנו גם על מושגים יסודיים בתחום (קבצים, תהליכים, ניהול זיכרון, וכד'). חלק זה הינו תיאורטי (ברובו) ואנו עדין לא צוללים אל עומק הדברים, למרות זאת הבסיס הוא חשוב להבנה לפני שממשיכים לפן הטכני של הנושא (כדי שלא נאבד את הידיים והרגליים). diff --git a/data/_oldPosts/2015-12-13-operating-system-part-2.md b/data/_oldPosts/2015-12-13-operating-system-part-2.md deleted file mode 100644 index fdd2b5b..0000000 --- a/data/_oldPosts/2015-12-13-operating-system-part-2.md +++ /dev/null @@ -1,731 +0,0 @@ ---- -title: 'מערכות הפעלה - חלק 2' -author: nirgn -layout: post -summary: הפוסט השני בנושא מערכות הפעלה יתמקד בעיקר בתהליכים ותהליכונים, והבעיות השונות שמגיעות איתן. -base-images-url: 'operating-system-part-2' -category: Operating Systems ---- -הגענו לפוסט השני בסדרת פוסטים על מערכות הפעלה. הפוסט הזה יתמקד בתהליכים ותהליכונים והבעיות השונות שמגיעות איתן. שוב, אציין מראש כי הפוסטים יהיו כבדים (בעלי מלל רב) וטכניים. הפוסטים נועדו למי שולמד מערכות הפעלה כחלק מתואר במדעי המחשב ו/או למי שמעוניין ללמוד לבד ו/או לאנשים שרק רוצים להיזכר (בראש כל פוסט יהיה תוכן עניינים).  - - 1. תהליכים (Processes) - 2. תהליכונים (Threads) - 3. תקשורת בין תהליכים - 4. תזמון תהליכים - 5. בעיות IPC קלאסיות - 6. סיכום - - - -  - -### 1. תהליכים (Processes) - -אחת המשימות העיקריות של כל מערכת הפעלה היא ניהול תהליכים. מערכת ההפעלה דואגת לעקוב אחר המצבים השונים בהם התהליכים נמצאים ולאכוף במידת הצורך את הגישה של התהליכים הרצים בה למשאבי המערכת. לצורך כך היא מתחזקת מבני נתונים המשמשים לניהול התהליכים. - -תהליך כלשהו יכול להיות אך ורק באחד משלושת המצבים: 'מצב חסום', 'מצב מוכן לריצה', מצב ריצה'. ובמצב ריצה יכול להיות רק תהליך אחד בכל זמן נתון. - -  - -**מבנה המעבד בקצרה:** - -
    - Interrupt Processor -
    - -[אוגרים](https://en.wikipedia.org/wiki/Processor_register) מהווים סוג של זיכרון קטן, אך מהיר, המשמש לצמצום מספר הפניות לזיכרון הראשי ולצורך בקרה על פעולות המעבד. בין אוגרי הזיכרון נמצאים data registers (היכולים לשמש מתכנתים למטרות שונות. לדוג', בשפת C אפשר להציע למהדר ([compiler](https://en.wikipedia.org/wiki/Compiler)) לשמור משתנה באוגר (במקום בזיכרון הרגיל) על ידי המילה השמורה register בזמן הצהרת המשתנה), ו address registers (שומרים כתובת של הוראות מכונה או של data). לקבוצה של אוגרי הבקרה שייכים בין השאר PC (ראשי תיבות: program counter), ה IR (ראשי תיבות: instruction register), וה PSW (ראשי תיבות: program status word). - -הכתובת של ההוראה הבאה מחזקת באוגר בשם program counter, לאחר ביצוע ההוראה הנוכחית, המעבד מעדכן את ה program counter ומורה לו להצביע לכתובת של ההוראה הבאה (הבאה שאחריו). לאחר מכן, המעבד שולף את ההוראה ומאכסן אותה באוגר בשם instruction register (שם הוא מחזיק את ההוראה הנוכחית, שמתבצעת). ולבסוף המעבד מפרש את ההוראה (לפי קוד ההוראה) ומבצע אותה. - -> באוגר PSW מוחזקת סיבית המידע המציינת אם המעבד נמצא במצב מיוחס (kernel mode) או במצב משתמש (user mode), ובמעבדים מסויימים יש יותר מסיבית אחת המשמשת למטרה זו (כדי לאפשר יותר רמות אבטחה שונות). - -  - -פסיקות חומרה נועדו, בעיקר, להגדיל את ניצולת ה CPU. למשל, בעת ביצוע I/O. תוכנית שמבקשת לבצע I/O, קריאה או כתיבה, מושהית ע"י מערכת ההפעלה עד לסיום פעולת ה I/O. בזמן ההשהיה תתבצע תכנית אחרת ב CPU. כאשר ההתקן שעליו התבצעה פעולת ה I/O יסיים את המשימה, יישלח סיגנל (signal) בקשה לפסיקה ל CPU. עם קבלת הסיגנל, המעבד משהה מיד את הביצוע של ההוראות שהוא מבצע כעת, ומפעיל שגרה מיוחדת הנקראת 'שגרה לטיפול בפסיקות' (או interrupt handler routine). השגרה לטיפול בפסיקות היא בדרך כלל חלק ממערכת ההפעלה. לאחר סיום השגרה לטיפול בפסיקות, ה CPU יכול לחזור לביצוע של התכנית המקורית שביצע לפי שקיבל את הסיגנל (למרות שייתכן והעניינים יתנהלו לפי תסריט אחר. השגרה לטיפול בפסיקות יכולה להורות להפעיל מתזמן תהליכים שיכול "לתת" את ה CPU לתכנית אחרת). - -המעבר הזה, לביצוע של השגרה לטיפול בפסיקות, יוצר תקורה, מכיוון שצריך לבצע שמירת תוכן של התהליך על מנת לאפשר שחזור של ביצוע התוכנית מהנקודה שבה הופסקה. שמירת התוכן מתבצעת ע"י החומרה ותלויה במעבד (שלב 6 באיור משמאל). שמירת ה PSW וה PC מתבצעת גם ע"י המעבד עצמו (שלב 4) אשר קורא לשגרה לטיפול בפסיקות (בשלב 5). תהליך השמירה עצמו מתואר בצורה סכמתית באיור משמאל (בעקבות ריבוי הארכיטקטורות השונות של המעבד, ייתכנו גם אפשרויות נוספות). - -  - -אך מה קורה כאשר מתקיים מצב של ריבוי פסיקות? ז"א בעת הטיפול בפסיקה אחת מגיע סיגנל חדש לבקשת פסיקה? ישנן 2 גישות לטיפול במצב הזה: - - * בגישה הראשונה ייחסמו כל הסיגנלים כאשר מתבצע טיפול בפסיקה. עם סיום הטיפול בפסיקה, המעבד יבטל את החסימה ויבדוק אם הגיעו סיגנלים לפסיקות חדשות בזמן שטיפל בפסיקה הקודמת. לפשטותה של הגישה יש חיסרון משמעותי המחייב טיפול מהיר מאוד בפסיקות. אם, למשל, תגיע פסיקה המבקשת קריאה מדויקת של שעון, לא סביר לצפות שתמתין לסיומה של הפסיקה הקודמת. - * לכן, ברובם המכריע של המעבדים יש אפשרות לקבוע סדר קדימויות של טיפול בפסיקות. בגישה זו, פסיקות בעלות עדיפות גבוהה יכולות לגרום להשהיית הטיפול בפסיקות בעלות עדיפות נמוכה. התוכן של הפסיקה המושהית x, שהיא בעלת עדיפות נמוכה, נשמר ומתבצע טיפול בפסיקה בעלת העדיפות הגבוהה y. לאחר הטיפול ב y משוחזר התוכן של x. בגישה הזאת יתבצע טיפול בפסיקה רק כאשר לא ממתינות פסיקות בעלות עדיפות גבוהה יותר (ולביצוע התוכנית עצמה תיהיה העדיפות הנמוכה ביותר). - -  - -**מבוא לתהליכים:** - -תהליך הוא ישות מופשטת שמערכת ההפעלה מספקת לייצוג של תוכנית בריצה. תהליכים משקפים את המצב הנוכחי של ריצת התוכנית ואת המשאבים השייכים לה (חלק מהמשאבים של המערכת יכולים להיות משותפים למספר תהליכים). שיתוף של המעבד המרכזי (CPU) מאפשר ליצור אשליה של ריצה בו זמנית של מס' אפליקציות במחשב עם CPU אחד (אשליה זו מושגת ע"י חילוף מהיר של תהליכים שרצים על המעבד). לחילופין, אם קיימים מס' מעבדים במערכת, ניתן להקצות אותם למס' זהה של תהליכים בו זמנית. - -לכל התוכנות שרצות במחשב, ובינהן לעיתים גם למערכת ההפעלה, מתאימים תהליכים. קונספטואלית, כל תהליך רץ על מעבד וירטואלי, כאשר באופן מעשי המעבד הפיזי (או מספר המעבדים, אם קיימים) עומד לרשות התהליך לזמן קצוב. בתום זמן זה, התהליך הפעיל מתחלף, והמעבד עובר לרשותו של תהליך אחר. כך נוצרת _מקבילויות מדומה_ שמאפשרת ריבוי תהליכים ([Multiprogramming](https://en.wikipedia.org/wiki/Computer_multitasking#Multiprogramming)) במספר מצומצם של מעבדים (להבדיל מ_מקבילויות אמיתית_, אשר בה לפחות שני תהליכים מתקדמים בו זמנית במעבדים מקביליים). - -ההבחנה בין תוכנית (Program) לבין תהליך (Process) הינה חיונית להבנת המודל לפיו פועלים תהליכים. ומשל העוגה המפורסם מבהיר זאת היטב: באנלוגיה זו, המתכון לאפיית העוגה הוא קוד התוכנית, האופה הוא המעבד, מרכיבי העוגה הם הקלט של התוכנית, והעוגה עצמה היא הפלט. התהליך של אפיית העוגה מורכב מקריאת המתכון, הכנת המרכיבים, פיקוח על תוצאת הביניים ולבסוף הגשת התוצאה הסופית. בחלק מהמתכונים אפשר לקטוע את רציפות תהליך האפייה לצורך ביצוע של משימות אחרות (למשל, ניתן להפסיק ללוש בצק ולענות לשיחת טלפון, ובתום שיחת הטלפון אפשר להמשיך ללוש את הבצק, כאשר דבר לא יפגע בתוצאה הסופית). האופה רק צריך לזכור באיזה שלב של ביצוע המתכון היה כדי להמשיך מאותו השלב. - -  - -בכל מערכת הפעלה קיימים מספר מקרים שבהם אפשר או צריך ליצור תהליכים חדשים: - - 1. **בעת האתחול של מערכת ההפעלה** נוצרים תהליכים שמטרתם לבצע משימות עבור מערכת ההפעלה. תהליכי רקע (daemons) כגון שרת web או spooler של מדפסת. - 2. **תהליכים קיימים יכולים ליצור תהליכים חדשים**. המטרה יכולה להיות שיפור המודולריות של תוכנית או ניצול של ריבוי מעבדים לשיפור המקביליות. - 3. **עבודות אצווה -** מערכת ההפעלה מקבלת דרך ה batch control stream את ההוראות ויוצרת תהליכים חדשים לפיהם. ניתן לראות צורה זו של יצירת תהליכים במחשבי Mainframe כאשר משתמשים רבים מגישים עבודות אצווה כגון indexing של בסיסי נתונים. - -כפי שאמרנו, תהליכים הם ישויות במודל התהליכים של מערכת ההפעלה, ולכן הם מהויים משאבים של המערכת ודינם ככל משאב אחר. כמות המשאבים במערכת מוגבלת, ולכן כאשר תוכנית מסתיימת, גם התהליך המתאים צריך להסתיים. נבדיל בין כמה סוגים של סיום תהליכים: - - 1. **סיום רגיל -** תהליך שמסתיים בעקבות סיום של תוכנית ומפה את המשאבים שתפס. - 2. **סיום בעקבות שגיאה -** סיום מתוכנן של תהליך בעקבות שגיאה במהלך ריצה. - 3. **סיום בעקבות שגיאטה פטאלית -** תהליך שמסתיים בעקבות שגיאה שלא נצפתה מראש ולא היה קיים מענה לתרחיש בעייתי בקוד התוכנית. סיום מסוג זה גורם לקריסה של התוכנית (crash). - 4. **סיום בעקבות הריגת תהליך -** תהליך שמתסיים בעקבות הבקשה המפורשת ממערכת ההפעלה לסיים את ריצתו. מערכת ההפעלה שמקבלת בקשה כזאת בוחנת את הרשאות המבקש (המבקש יכול להיות תהליך אחר, ובפרט תהליך של מערכת ההפעלה עצמה), ואם קיימות הרשאות מתאימות, היא מסיימת את ריצתו של התהליך המבוקש. - -
    - Finite-state Machine -
    - -מודל התהליכים מתאפיין בהגדרה של מבנה היררכי בין תהליכי מערכת ההפעלה. אחד המרכיבים החשובים ביותר של מודל התהליכים הוא **מכונת מצבים**, המתארת את תקופת חייו של התהליך. - - 1. התהליך חסום לקלט. - 2. המתזמן בוחר תהליך אחר. - 3. המתזמן בוחר את התהליך הזה. - 4. הקלט הופך לזמין. - -המעבר ממצב Running למצב Blocked מתבצע כאשר התהליך אינו יכול עוד להתקדם. תהליך במצב חסום יחכה לאירוע חיצוני שיגרום לו להשתחרר מהחסימה (לדוג' תהליך שמבקש לקרוא קובץ מהדיסק הקשיח - I/O, יכול להיחסם ע"י מערכת ההפעלה עד אשר תתבצע קריאת הקובץ. עם קריאת הקובץ, ישלח בקר הדיסק הקשיח בקשה לפסיקה אשר תביא לשחרור התהליך ממצב Blocked). - -המעבר ממצב Blocked למצב Ready יתבצע כאשר מתרחש האירוע החיצוני אשר בגללו התהליך מחכה במצב Blocked. (לדוג' כאשר בקר הדיסק הקשיח ישלח בקשה לפסיקה, הפסיקה מטופלת ע"י מערכת ההפעלה שגורמת לשינוי של מצב התהליך והפעלת מתזמן המערכת). המעברים ממצב Running למצב Ready ולהיפך מתרחשים כתוצאה מהחלטת מתזמן המערכת להפקיע את ה CPU מתהליך רץ ולהקצותו לאחד התהליכים הממתין לו במצב Ready. - -> המעברים במצב Ready ו Blocked מוחזקים בתורים (queues) נפרדים. מכונת המצבים המתוארת לעיל הינה הפשטה של מודל מכונת המצבים, מכונת המצבים במערכת UNIX הינה שונה ומורכבת יותר, ולפעמים אף משתנה בין גרסה לגרסה. - -  - -**המבנים הדרושים למימוש המודל** - -מערכת ההפעלה מנהלת טבלה המכונה _טבלת תהליכים_ וכל רשומה בטבלה מכילה מידע המתייחס לתהליך באופן חח"ע ([חד חד ערכי](https://he.wikipedia.org/wiki/%D7%A4%D7%95%D7%A0%D7%A7%D7%A6%D7%99%D7%94_%D7%97%D7%93-%D7%97%D7%93-%D7%A2%D7%A8%D7%9B%D7%99%D7%AA)). הרשומה יכולה להכיל מידע ישיר או מצביעים למבנים נוספים (בהתאם למימוש), אך באופן כללי המידע השמור ברשומה משקף במלואו את מצב התהליך ואת המשאבים המוקצים לו. באמצעות המידע הזה ניתן לשחזר תהליך, וכדי שהשחזור יהיה אפשרי – מערכת ההפעלה צריכה לדאוג לעדכון עקבי של מבני הנתונים המתייחסים לתהליך. - -כל מערכת הפעלה מנהלת מבני נתונים רבים כדי לאפשר החלפת תהליכים וכדי לאפשר קיום מעברים בין מצב משתמש (user mode) למצב מיוחס (kernel mode). אז כיצד מתבצע הקוד של מערכת ההפעלה? (האם המערכת היא אוסף של תהליכים? או אולי היא חלק מתהליכי המשתמש?) השאלות האלו מגדירות גישות שונות (גישת השרת – לקוח עליה דיברנו בפוסט הראשון ממומשת כאוסף של תהליכים. לעומת זאת מערכות הפעלה במחשבים ביתיים רצות במרחב הכתובות של תהליכי המשתמש). - -
    - CPU Utilization -
    - -כמו שאמרנו, העלאת רמת המקביליות של המערכת מביאה לניצול טוב יותר של המשאבים. נניח שתהליך מבלה חלק מזמנו בפעולת קלט / פלט (ז"א 0 < p וגם 1 > p). כאשר n תהליכים נמצאים בזיכרון בבת אחת, ההסתברות לכך שכל התהליכים מבצעים פעולת קלט / פלט היא p^n (בהנחה שהתהליכים אינם תלויים זה בזה). בתנאים אלה, ההסתברות לכך שהמעבד פעיל היא 1 פחות p^n (וזאת הנוסחה לחישוב הניצולת של המעבד). - -באיור משמאל ניתן לראות את גרף הניצולת כפונקציה של מספר התהליכים במערכת, אשר גם נקרא הדרגה של ריבוי התוכנית (ציר x מראה את כמות התהליכים בזיכרון, וציר y את אחוז ניצולת ה CPU). נציין בנוסף, כי במציאות הניצולת תגדל בצורה לינארית עד לנק' מסויימת ומשם תיהיה האטה בגידול הניצולת עם הגדלת רמת המקביליות. ולאחר מכן, בשלב מסוים, הגדלת רמת המקביליות לא רק שלא תגרום לגידול הניצולת אלא יתרחיש תהליך הפוך. המערכת תעבוד תחת עומס כבד, וככל שהעומס יגבר, כך תפחת יעילותה של המערכת (תארו לכם מצב קיצוני בו משאבי המעבד עוברים מתהליך אחד לשני לפני שהראשון הספיק בכלל לבצע חישוב כלשהו). בנקודה זאת המערכת חייבת להוציא תהליכים מהזיכרון הראשי אל הדיסק (הקשיח). - -  - -### 2. תהליכונים (Threads) - -ניתן לומר שלכל תהליך יש חוט (תהליכון, thread) אחד, אך קורה שאנו צריכים יותר מחוט יחיד במרחב הכתובות של כל תהליך. למשל, חוטים נפרדים עבור פרוצדורות שרצות במקביל. בניגוד להתהליכים, כל התהליכונים של תהליך יחיד חולקים את אותו מרחב כתובות. לתהליך יש שני היבטים שונים: האחד, הוא היבט הבקרה של ביצוע סדרתי של תוכנית, והשני הוא ניהול המשאבים של המערכת. התהליך מתאפיין כמשאב בקבוצת המשאבים, אולם התהליכונים מאופיינים כישויות הניתנות לתזמון. מערכות הפעלה אשר תומכות בתהליכונים נקראות [Multithreading Operating System](https://en.wikipedia.org/wiki/Multithreading_(computer_architecture)). - -במערכת הפעלה שתומכת בתהליכונים, יש לכל תהליך במערכת מרחב זיכרון מדומה משלו, וכל תהליך כזה מחזיק במשאבים שהוקצו לו ע"י מערכת ההפעלה. בכל תהליך יכולים להימצא מס' תהליכונים, ולכל אחד מהם יש את המאפיינים: - - * מצב התהליכון (Running, Ready, Blocked). - * מצב הרגיסטרים ([Registers](https://en.wikipedia.org/wiki/Processor_register)) של המעבד. - * מחסנית (Stack) נפרדת עבור כל תהליכון. - * אפשרות גישה לזיכרון ולמשאבים המשותפים בתוך התהליך. - -מצב התהליכון, הרגיסטרים, והמחסנית יוצרים ביחד את המידע שישמש לשחזור ה Thread (תהליכון). נדגיש כי תהליכונים שרצים במרחב כתובות של תהליך מארח משתפים גישה למרחב הזיכרון שלו (כך למשל, אפשר ליצור תהליכונים בתוך תהליך אחד, ואז הם יכולים לגשת לכל המשאבים שהוקצו להתהליך. שינוי של משתנה גלובאלי ע"י תהליכון אחד בתהליך מארח יגרום לכך שכל שאר התהליכונים של אותו תהליך יראו את השינוי. דוגמה נוספת היא שאם אחד התהליכונים פותח קובץ עם הרשאות קריאה, שאר התהליכונים של התהליך המארח יכולים גם לקרוא מאותו הקובץ). - -בסופו של דבר, מודל התהליכונים הינו הרחבה של מודל התהליכים. היתרונות שמספק המודל מורחב הם: - - * יצירת תהליך חדש מצריכה משאבים רבים יחסית לדרישות של תהליכון (לדוג' יצירת תהליכון אינה דורשת יצירה של מפת זיכרון, ולכן זמן היצירה של תהליכונים קטן בהרבה מזמן יצירתם של תהליכים חדשים). - * זמן ההשמדה של תהליכונים, בתנאי שאין מדובר בתהליכון האחרון בתהליך המארח, קטן בהרבה מזמן ההשמדה של תהליכים. - * החלפת תהליכים ותהליכונים מצריכה שמירת תוכן לשם שחזור עתידי. אך בשל דרישות המשאבים הנמוכות יותר, ההחלפה תיהיה מהירה יותר מהחלפת תהליכים. - * תקשורת בין תהליכים דורשת מעורבות של גרעין מערכת ההפעלה (Kernel). לעומת זאת, תקשורת בין תהליכונים בתוך תהליך מארח יכולה להתבצע ללא התערבותו של גרעין מערכת ההפעלה, מכיוון שהתהליכונים משתפים זיכרון, קבצים וכ'ו. - -מודל זה מאפשר לשנות את הגישה התכנותית, ומאפשר חלוקת התוכנית למודלים שונים, כאשר כל מודל כזה מבצע משימה ייחודית לו. באופן כללי, כדאי לשקול את השימוש בתהליכונים במקרה של אפליקציות שנותנות מענה למספר רב של אירועים לא סינכורניים (לכל מאורע לא סינכרוני אפשר ליצור תהליכון שייתן מענה מתאים). - -בנוסף, נשים לב כי ישנו פוטנציאל לקבוצת בעיות הנקראות "בעיות מירוץ" אותן נפתור בהמשך. הבעיות בקבוצה זו דומות ומדברות על מירוץ בין תהליכונים, לדוג': נניח שתהליך מסוים מכיל מס' תהליכונים המבצעים משימה משותפת הדורשת הקצאת זיכרון. מכיוון שלא ידוע מראש איזה מהתהליכונים יהיה מתוזמן, כל אחד מהם מבצע בדיקה אם יש מספיק זיכרון לביצוע המשימה. ייתכן שהתהליכון שיבצע בדיקה יוחלף בדיוק לפני הקצאת הזיכרון וירוץ תהליכון אחר שיבצע גם הוא את הבדיקה. במקרה כזה יכול להיות ששני התהלכוינים יגרמו להקצאת זיכרון, ואז הזיכרון יוקצה פעמיים. - -  - -**מימוש תהליכונים** - -מודל התהליכונים יכול להיות מוממש ברמת המשתמש או בגרעין המערכת, ולכל אחת מהשיטות ישנם יתרונות וחסרונות. כמו תמיד, השאיפה להשיג בו זמנית את היתרונות של שתי השיטות הביאה להתפתחות השיטות המעורבות. - -בשיטה הראשונה, ניהול התהליכונים מתבצע במרחב של התהליך המארח וגרעין המערכת כלל אינו מודע לקיום התהליכונים. מימוש אפשרי של השיטה הוא באמצעות ספריית פונקציות שמספקת ממשק ליצירה, השמדה, ותזמון של תהליכונים, ומספקת מנגנוני תקשורת בינהם. באחריותה של הספרייה לדאוג לניהולה של טבלת התהליכונים המכילה מאפיינים של כל התהליכונים הנמצאים בתהליך המארח. צריך לזכור שכל הפעולות שמבצעת הספרייה מתבצעות במצב משתמש, וגרעין המערכת איננו מודע כלל לקיום התהליכונים. - -**יתרונות השיטה:** - - * החלפת תהליכונים ברמת המשתמש איננה דורשת מעבר למצב ראשוני, כפי שנדרש בהחלפת תהליכים. להבדיל מהחלפת תהליכים שדורשת את הפעלת המתזמן (scheduler) של מערכת ההפעלה, בעוד החלפת תהליכונים מתבצעת ע"י המתזמן שנמצא במרחב הזיכרון של התהליך המארח. - * שימוש ברמת משתמש מאפשר את התאמת אלוגריתם התזמון של ספריית התהליכונים לצרכים של כל יישום בנפרד. - * חבילת תוכנה שממשת תהליכונים ברמת המשתמש יכולה לרוץ ללא שום תמיכה מצד גרעין המערכת (kernel), ולכן זה נותן אפשרות לממש אפליקציות העושות שימוש בתהליכונים גם במערכת הפעלה שאינן תומכות בתהליכונים. - -_החסרון העקרי של השיטה הוא_ קריאות רבות במערכת ההפעלה יכולות לגרום לכך שהתהליך שביצע קריאה עובר למצב חסום. אם אחד התהליכונים בתהליך המארח מבצע קריאה שגורמת לחסימת התהליך, אז מערכת ההפעלה תשהה את התהליך ואתו יושהו גם כל התהליכונים שלו (וזה למרות שייתכן שבתהליך המארח היו תהליכונים שהיו מוכנים לריצה). ז"א שגרעין מערכת ההפעלה יכול להקצות מעבד לתהליך המארח, אך אינו יכול להקצות מעבדים לתהליכונים נפרדים מכיוון שאינו מודע לקיומם. - -בשיטה השניה מימוש התהליכונים הינו בגרעין המערכת ואין ולו שורת קוד אחת המיועדת לניהול התהליכונים ברמת האפליקציה (האפליקציה משתמשת רק בקריאות מערכת המפעילות את מנגון ניהול התהליכים). גרעין המערכת אחראי לתחזק את תוכן תהליכי המערכת ואת תוכן התהליכונים אשר רצים תחת התהליכים האלו (והוא גם מבצע את התזמון הנדרש). - -כפי שניתן לראות, שיטה זו מתגברת בקלות על הבעיות העיקריות של הגישה הראשונה: הגרעין יכול לתזמן את התהליכונים השייכים לאותו התהליך על מעבדים שונים, וגם אם אחד מהם עובר למצב חסום, אין מניעה לתזמן תהליכון אחר השייך לתהליך המארח. ויתרון נוסף וגדול מאוד של השיטה הזו הוא שפרוצדורות של גרעין המערכת עצמו יכולות להיות ממומשות בעזרת תהליכונים. כמובן שהחסרון העיקרי של מימוש זה הוא בזבוז הזמן הכרוך במעבר ממצב משתמש למצב מיוחס. - -  - -### 3. תקשורת בין תהליכים - -תקשורת בין תהליכים הינה פועל יוצא מהצורף בשיתוף פעולה בין תהליכים. לשיתוף פעולה זה 2 היבטים: הראשון הוא שתהליכים צריכים להחליף מידע. והשני הוא קבוצת תהליכים אשר חייבת לשתף פעולה ולפעול תוך התחשבות בקיומם של תהליכים אחרים בקבוצה, וזאת מכיוון שתהליכים עלולים לבצע פעילויות שיכולות להשפיע על תקינות התוצאה של תהליכים אחרים. (באופן עקרוני הנושאים שקשורים בשיתוף פעולה בין תהליכים תקפים גם לגבי תהליכונים, לכן, למרות שבסעיף זה אדבר על תהליכים, הדברים נכונים גם לגבי תהליכונים). - -  - -**מירוץ קריטי** - -נניח ששני תהליכונים שרצים במרחב כתובות משותף מנסים לעדכן רשימה משורשרת. התהליכונים משתמשים בשגרות (פרוצדורות) של ספרייה שמספקת ממשק לניהול רשימות משורשרות. להלן הפרוצדורה ()deleteFirst: - -```c -deleteFirst(){ - //TmpNodePtr is a local variable, ListHeadPtr is global - Node * TmpNodePtr=ListHeadPtr; - ListHeadPtr=TmpHeadPtr->next; - delete(TmpNodePtr(; -} -``` - -
    - Critical Race -
    - -התוצאה הרצויה היא ששני התהליכונים ימחקו מראש הרשימה שני איברים ראשונים. אך נניח שבתור ישנם ארבעה עצמים. תהליכון 1 מגיע לפרוצדורה ()deleteFirst ומבצע את השורה הראשונה. לאחר ביצוע השורה, מתרחשת החלפת תהליכונים ותהליכון 2 מגיע לפונ' ()deleteFirst שלו ומבצע גם כן את השורה הראשונה. נניח שהתלהיכונים ממשיכים להתחלף כל שורה. באיור משמאל (חלק b) ניתן לראות מה מתרחש בתור לאחר שהתהליכונים ביצעו את השורה השנייה. ובחלק האחרון, c, ניתן לראות כי לאחר שהתהליכונים סיימו לבצע (כל אחד את העותק שלו של ()deleteFirst. הרי לכל תהליכון יש מחסנית נפרדת, ולכן עותקים נפרדים של הפרוצדורה רצים במקביל, המשתנה TmpNodePtr הוא משתנה מקומי ולכן בתמונה משמאל אנו רואים 2 כאלו -עותקים נפרדים שלו יפיעו בכל מחסנית. המשתנה ListNodePtr הוא משתנה גלובלי בספרייה ולכן הוא משותף לשני התהליכונים), רק איבר אחד נמחק מהרשימה. - -ברור שבלעדי ההחלפה התדירה הדברים היו קורים באופן תקין. אך במציאות, ההסתברות לתרחישים מהסוג הזה היא ניכרת. מצבים כאלה, בהם התוצאה הסופית תלויה בתזמונם של תהליכים או תהליכונים, מכונים _מצבי מירוץ_. - -הבעיה שתוארה לעיל הייתה נמענת אילו שני התהליכונים לא היו ניגשים לעדכון הרשימה המשורשרת בו זמנית. קטע קוד כזה (קטע קוד עם משאב משותף לשני תהליכים או יותר ובו מתבצע עדכון כלשהו) מכונה קטע קריטי. והוא עצמו הפך להיות מושא למירוץ בין התהליכונים. שיתוף הפעולה אשר היה מונע זאת נקרא _מניעה הדדית_ ומסוגל למנוע מתהליכון לבצע עדכון של קטע קריטי כל עוד התהליכון השני לא סיים את אותו קטע. - -שיתוף פעולה מסוג מניעה הדדית אינו מספיק (הוא מהווה תנאי הכרחי לפתרון סביר של בעיית המירוץ), ישנם ארבעה תנאים הדרושים להשגת פתרון סביר: - -* שני תהליכים לא ישהו בו זמנית בתוך קטע קריטי. -* הפתרון לא יסתמך על השערות הקשורות למהירות או למס' מעבדים. -* תהליך מחוץ לקטע קריטי לא ימנע מתהליך אחר להיכנס לקטע קריטי. -* תהליך לא ימתין לנצח כדי להיכנס לקטע קריטי (בעיית הרעבה). - -  - -**מניעת הפסיקות** - -מניעת הפסיקות לפני כניסת תהליך לקטע קריטי היא הדרך הפשוטה ביותר להשיג מניעה הדדית. הפסיקות מופעלות שוב רק לאחר היציאה מהקטע הקריטי. מניעת הפסיקות גורמת לכך שהמעבד לא עובר מתהליך לתהליך ולכן אין חשש שתהליך אחר יכול להימצא בקטע הקריטי. - -אך לשיטה יש כמה חסרונות מהותיים: - - * לא סביר לתת לתהליך משתמש אפשרות למנוע פסיקות.  תהליכי משתמש יהיו יכולים למנוע מתהליכים אחרים לקבל זמן מעבד עקב שגיאות תכנות, או גרוע מכך, קוד זדוני של תהליך יכול לגרום לכך בכוונה. - * חסימת הפסיקות לפרק זמן ארוך יכולה להביא לתופעות לא נעימות. ירידה ברמת המקביליות של מערכת ההפעלה יכולה לגרום למשל הצפה של שידור בכרטיס תקשורת או תגובה איטית של המקלדת. - * חסימה של פסיקות תקפה לגבי מעבד אחד בלבד (בסביבה של מס' מעבדים, חסימת פסיקות תידרש בכל מעבד, וזה יביא להורדה דרמטית של רמת המקביליות). - -לכן, נראה שלא סביר להשתמש בשיטה זו עבור תהליכי משתמש. - -  - -**משתני נעילה – Lock Variables** - -נניח שיש לנו משתנה משותף, lock, מאותחל ל 0. והפתרון המוצע הוא כזה: - -```c -while(true){ - ... // non critical section - while (lock == 1) - ; // loop - lock = 1; - CriticalSection(); - lock = 0; - ... // non critical section -} -``` - -כאשר תהליך מנסה להיכנס לקטע הקריטי הוא בודק תחילה האם המשתנה lock, המשותף, שווה ל-1 ז"א נעול. אם המנעול הוא 0 (ז"א לא נעול) הוא משנה אותו ל-1 ונכנס לקטע הקריטי. ואם הוא כבר נעול (ז"א 1) התהליך ימתין עד אשר ערך המנעול ישתנה חזרה ל-0. - -למרות שפתרון זה נראה הגיוני הוא אינו סביר, וזאת מכיוון שעדיין גורם לבעיית מירוץ. נניח שתהליך 1 קורא את ערך המנעול ורואה שערכו 0. ולפני שהוא נועל את המנעול, בדיוק מתבצעת החלפת תהליכים. תהליך 2 רואה שערך המנעול 0 ונכנס לקטע הקריטי. כעת אם שוב תתבצע החלפת תהליכים גם תהליך 1 וגם תהליך 2 יהיו במירוץ. - -  - -**פתרון התור** - -כמו שאמרנו, הבעיה עם משתני הנעילה מהסעיף למעלה היא שהבדיקה והעדכון של משתנה הנעילה הופך לקטע הקריטי בעצמו. לכן ניתן לכתוב לכל תהליך קוד אחר, כך שלעולם הם לא יהיו ביחד בקטg הקריטי. הקוד להתליך 0: - -```c -while(true){ - ... // non critical section - while (turn != 0) - ; // loop - CriticalSection_0(); - turn = 1; - ... // non critical section -} -``` - -הקוד לתהליך 1: - -```c -while(true){ - ... // non critical section - while (turn != 1) - ; // loop - CriticalSection_1(); - turn = 0; - ... // non critical section -} -``` - -אך פתרון זה אינוו פתרון סביר מכיוון שהוא מפר את אחד מארבעת התנאים שהזכרנו למעלה ("תהליך מחוץ לקטע קריטי לא ימנע מהתליך אחר להיכנס לקטע הקריטי"). כי כמו שניתן לראות, המשתנה המשותף, turn, מאותחל ל-0 בהתחלה וערכו משקף את מס' התהליך שתורו להיכנס לקטע הקריטי. בהתחלה תהליך 0 בודק את turn ונכנס לקטע קריטי. תהליך 1 בודק את turn ומכיוון שהוא שונה מ-1 הוא נכנס לולאה עד שהערך של turn משתנה ל-1. תהליך 1 בנתיים נמצאה במצב המכונה המתנה פעילה ([Busy Waiting](https://en.wikipedia.org/wiki/Busy_waiting)), מצב בו תהליך מקבל את המעבד ומנצל את מלוא הזמן המוקצב לו, איך איננו מתקדם כלל. אם ההמתנה נמשכת זמן רב נוצרת תופעת ההרעבה (Starvation), בה התהליך השני אינו מקבל זמן מעבד. - -אם נחזור לדוג', כאשר תהליך 0 עוזב את הקטע הקריטי ומשנה את turn ל-1, נשים לב שעכשיו תהליך 0 אינו יכול להיכנס שוב לקטע הקריטי עד שתהליך 1 לא יאפשר זאת ע"י שינוי ערכו של turn (תנאי 3). - -  - -**הפתרוונת של דקר ופטרסון** - -ב 1965 הציע המתמטיקאי דקר ([Dekker](https://en.wikipedia.org/wiki/Dekker%27s_algorithm)) פתרון ששילב במובן מסוים את פתרון התור והפתרון באמצעות משתנה נעילה. הפתרון דורש 2 משתני נעילה ומשתנה תור אחד, כאשר כולם משותפים לשני התהליכים. אך ב 1981 הוצע ע"י פטרסון ([Peterson](https://en.wikipedia.org/wiki/Peterson%27s_algorithm)) פתרון קצת יותר אלגנטי ופשוט, שגם דורש 3 משתנים משותפים. להלן הפתרון של פטרסון: - -המשתנים: - -```c -boolean interested[2]; -in turn; -interested[0] = interested[1] = FALSE; -turn = 1; -``` - -הקוד של תהליך 0: - -``` -while (TRUE){ - ... // non critical section - interested[0] = TRUE; - turn = 0; - while(interested[1] == TRUE && turn == 0){ - ; // loop - } - CriticalSection_0(); - interested[0] = FALSE; - ... // non critical section -} -``` - -הקוד של תהליך 1: - -```c -while (TRUE){ - ... // non critical section - interested[1] = TRUE; - turn = 1; - while(interested[0] == TRUE && turn == 1){ - ; // loop - } - CriticalSection_1(); - interested[1] = FALSE; - ... // non critical section -} -``` - -התהליכים מצהירים, ע"י שינוי התא במערך interested בשורה 3, על רצונם להיכנס לקטע הקריטי. הבדיקה בשורה 5 בודקת האם התהליך השני מעוניין להיכנס והאם זה תורו של התהליך הנוכחי (turn), ואם התהליך השני מעוניין להיכנס אז התהליך הנוכחי נכנס ללולאה. לכן פתרון זה נקרא גם הפתרון הנדיב, מכיוון שאם התהליך השני הצהיר כי הוא מעוניין להיכנס לקטע הקריטי, התהליך הנוכחי יתנדב להמתין. - -  - -**TSL** - -ניזכר כי בסעיף של מניעת פסיקות, השימוש בביטול הפסיקות היה תקף רק למעבד אחד, כשיש מס' מעבדים המעבד חייב להציע מספר הוראות שחייבות להיות אטומיות (הוראה המתבצעת כצעד אחד שלא ניתן להפרידו לשלבים, על מנת שהמערכת לא תוכל להעביר את משאבי המעבד באמצע ההוראה). דוגמה להוראה כזאת היא TSL (ראשי תיבות של Test and Set Lock). נציין בנוסף, כי ביצוע של הוראת TSL נועל את ערוץ הזיכרון (memory bus) למשך זמן הביצוע של ההוראה, מה שפותר את בעית המירוץ במחשבים אלו. - -הקוד של תהליך 0: - -```c -while(TRUE){ - ... // non critical section - while (TSL (lock) != 0) - ; // loop - CriticalSection_0(); - lock = 0; - ... // non critical section -} -``` - -הקוד של תהליך 1: - -```c -while(TRUE){ - ... // non critical section - while (TSL (lock) != 0) - ; // loop - CriticalSection_1(); - lock = 0; - ... // non critical section -} -``` - -נשים לב רק שהפתרון באמצעות הוראת TSL משתמש במשתנה זיכרון משותף בשם lock. - -הפסאודו קוד של הוראת TSL נראה כך: - -```c -int TSL (int lock){ - if (lock == 0){ - lock = 1; - return 0; - } - return lock; -} -``` - -אם שני תהליכים מעוניינים להיכנס לקטע הקריטי, אז הראשון שייכנס יהיה זה שקרא ראשון ל TSL. לאחר סיום של קטע קריטי התהליך פשוט מציב ב lock ערך 0 ובכך משחרר את המנעול. במקרה של 2 תהליכים הפתרון עובד, אך הפתרון הנל אינו מסדיר את אופן הכניסה של תהליכים שרצו להיכנס לקטע הקריטי ולא יכלו לעשות זאת מכיוון שהקטע היה תפוס. אותם תהליכים מטופלים ע"י המתזמן תהליכים כתהליכים מהשורה והמתזמן אינו יודע על רצונם להיכנס לקטע הקריטי. לכן יכול לקרות מצב שבו תהליך יורעב – כלומר לא יצליח להיכנס לקטע הקריטי במשך פרק זמן ארוך. - -  - -**הרדמה והערה** - -החסרון המובהק של כל הפתרונות מהסעיפים לעיל הוא בזבוז זמן עיבוד, ואף יכולות להיות לה תוצאות בלתי צפיות (כמו במקרה בו תהליך בעדיפות נמוכה, L, נכנס לקטע קריטי, ובדיוק באותו הזמן נוצר תהליך בעדיפות גבוהה H. המתזמן של מערכת ההפעלה אינו מאפשר לתהליך עם העדיפות הנמוכה לרוץ על המעבד כל עוד קיים תהליך בעל עדיפות גבוהה יותר. H מתחיל לרוץ ומנסה להיכנס גם לקטע הקריטי, איך אינו מצליח מכיוון שתהליך L נועל אותו.  כמובן ש L לעולם לא יצא מהקטע הקריטי מכיוון שהמתזמן של מערכת ההפעלה לא יתן לו לרוץ על המעבד. מצב זה, כאשר 2 תהליכים ממתינים אחד לשני בגלל אילוצים כלשהם נקרא _קיפאון_ והיפוך עדיפויות לזמן קצר היה עוזר לצאת ממנו. - -לסוגי הפתרונות הבאים נשתמש בשני פרימיטיבים (primitives), קריאות מערכת בשם SLEEP ו WAKEUP. ונניח כי תהליך יכול להשות את עצמו ע"י קריאת המערכת SLEEP ולהתעורר כאשר תהליך אחרי מבצע קריאת מערכת WAKEUP עם המזהה של התהליך שצריך להעיר. תהליכים שמבצעים קראית מערכת SLEEP, עוברים למצב חסום. ומערכת הפעלה מנהלת תור של תהליכים רדומים וכך יכולה להסדיר את אופן כניסתם של תהליכים שרוצים להיכנס לקטע קריטי. - -  - -**בעיית היצרן – צרכן** - -נניח שנתונים שני תהליכים, האחד קרוי יצרן והוא מכניס פרמטרים למאגר, והשני קרוי צרכן והוא נוהג להוציא את הפריטים מהמאגר. מכיוון שגודל המאגר חסום (הנחה כדי להקשות את הבעיה), מתעוררת בעיה כאשר היצרן רוצה להכניס פריט למאגר מלא. הפתרון כמובן הוא שהיצרן ירדים את עצמו, ויתעורר רק כאשר הצרכן הוציא לפחות פריט אחד. ומה קורה כאשר המאגר ריק? אם הצרכן רוצה להוציא פריט והמאגר ריק, הוא מרדים את עצמו עד שהיצרן יכניס פריט ויעיר אותו. - -```c -#define N 100 /* number of slots in the buffer */ -int count = 0; /* number of items in the buffer */ - -void producer(void) -{ - int item; - - while (TRUE) { /* repeat forever */ - item = produce_item(); /* generate next item */ - if (count == N) sleep(); /* if buffer is full, go to sleep */ - insert_item(item); /* put item in buffer */ - count = count + 1; /* increment count of item in buffer */ - if (count == 1) wakeup(consumer); /* was buffer empty? */ - } -} - -void consumer(void) -{ - int item; - - while (TRUE) { /* repeat forever */ - if (count == 0) sleep(); /* if buffer is empty, go to sleep */ - item = remove_item(); /* take item out of buffer */ - count = count - 1; /* decrement count of items in buffer */ - if (count == N -1) wakeup(producer); /* was buffer full? */ - consume_item(item); /* print item */ - } -} -``` - -כדי לעקוב אחר מס' הפריטים במאגר נשתמש בתמונה, count. ונניח שהמאגר יכול להכיל N פריטים. היצרן בודק האם count שווה ל N, ואם זה המצב הוא הולך לישון, אחרת הוא מאחסן פריט ומגדיל את המונה בהתאם. היצרן גם דואג לקרוא ל WAKEUP כדי להעיר את הצרכן כאשר הוא מאחסן את הפריט הראשון, כי במקרה שהמאגר היה ריק והיצרן אכסן פריט חדש, הוא צריך לגרום לצרכן להתעורר על מנת לאפשר מחדש עבודה במקביל. - -הצרכן מצדו הולך לישון כאשר הוא מגלה ש count שווה ל 0. אחרת הוא מפנה פריטים מהמאגר ודואג להעיר את היצרן אם יש מקום פנוי במאגר. הפרימיטיבם SLEEP ו WAKEUP אכן מונעים את בעיית ההמתנה הפעילה. אך הפתרון בכל זאת סובל מבעיית מירוץ (מצב זה יכול לקרות מכיוון שהגישה למשתנה של המונה אינה מבוקרת ולכן עקב המרוץ שנוצר על המשתנה, יתכן שאחת מהקריאות של WAKEUP תאבד). - -  - -**Semaphores** - -בשנת 1965 הציע דייקסטרה ([Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)) להשתמש במשתנה מיוחד, s, שישמש כמונה של מספר כלשהו של WAKEUP וגם יבדוק אם תהליך אחד התעורר. הוא הציע שתי פעולות, up ו down (אשר מהוות הכללה של SLEEP ו WAKEUP שתיארנו למעלה), הפעולות על המשתנה המיוחד שמסוגל למנות את מספר ה WAKEUPS: - -```c -down(s){ - if (s == 0) - // place the process on the semaphore queue and move it to the block state; - if (s > 0) - s--; -} - -up(s){ - if (there is at least one process sleeping in the semaphore queue){ - wake him up; - return; - } - s++; -} -``` - -המשתנה המיוחד s  מכונה סמפור (באנגלית: [Semaphore](https://en.wikipedia.org/wiki/Semaphore_(programming))). סמפור איננו משתנה רגיל אלא מנגנון מיוחד המסופק ע"י מערכת הפעלה או שפת תכנות. המנגנון משתמש בתור (queue) המנהל את התהליכים הממתינים על הסמפור במצב רדום (כך ניתן לדעת אם תהליך שאמור היה להתעורר אכן עשה זאת). נשים לב כי ערך אתחול הסמפור משמש לקביעה של מספר התהליכים שיכולים להיות ערים באותו הסמפור. ונציין גם כי פעולות ה up וה down חייבות להיות אטומיות (אחרת, יכולים להיווצר מצבי מירוץ בעת עדכון התור של תהליכים הממתינים על הסמפור). להלן הקוד שפותר את בעיית המניעה ההדדית ע"י שימוש פשוט ביותר בסמפור (נאתחל סמפור S בעל ערך 1). - -תהליך 0: - -```c -while (TRUE) { - ... // non critical section; - down(S); - critical_section_0(); - up(S); - ... // non critical section; -} -``` - -תהליך 1: - -```c -while (TRUE) { - ... // non critical section; - down(S); - critical_section_1(); - up(S); - ... // non critical section; -} -``` - -סמפורים המאותחלים תמיד בערך 1 נקראים סמפורים בינאריים והם מספקים מניעה הדדית למספר שרירותי של תהליכים שרצים במעבד אחד (סמפורים שמאותחלים לערך שונה מ 1 מכונים לעיתים סמפורים כלליים). - -אם נשתמש ב-3 סמפורים (שניים מהם משמשים לסנכרון, והשלישי משמש להגנה על קטע קריטי), נפתור את בעיית היצרן-צרכן. סמפור בשם full ימנה את מס' המקומות במאגר שכבר תפוסים ע"י הפריטים, סמפור empty מונה את מס' המקומות הפנויים במאגר, וסמפור בינארי mutex משמש למניעה הדדית כדי שהיצרן והצרכן לא יכנסו למירוץ בעץ העדכון של המאגר ושאר הנתונים המשותפים (סמפור full יאותחל ל 0, סמפור empty יאותחל ל N – מס' המקומות הפנויים במאגר, והסמפור הבינארי mutex יאותחל ל 1). - -  - -**מנעולים** - -מנעול הוא משתנה במרחב זיכרון משותף המשמש לניהול הגישה לקטע הקריטי, למשל עבור תהליכונים או עבור תהליכים שמשתפים אזור בזיכרון. בדומה לסמפור בינארי עליו דיברנו למעלה, יש למנעול שני מצבים "נעול" ו"לא נעול". בניגוד לסמפור בינארי, השימוש במנעולים יעיל יותר (במקרים שאפשר להשתמש בו), מכיוון שלא נדרש עבורו מעבר בין רמת המשתמש לרמת הגרעין. - -  - -**מבני פיקוח – Monitors** - -סמפורים (Semaphore) הם כלים חזקים, אך הבעיה בשימוש בהם היא שמספר רב של סמפורים המפוזרים על פני תוכנית כלשהי הופכים אותה לקשה לניפוי שגיאות (debugging). יתכן מצב בו תתבצע טעות שאינה ניתנת לשחזור מדויק (דבר שמקשה על העבודה), כמו במקרה של תלויות בסדר של חילופי התהליכים, דבר שיגרום למצב קיפאון. - -מכאן נולדה השאיפה להעביר את הטיפול במניעה הדדית אל מנגנונים משוכללים יותר, שיהיו חסינים מפי שגיאות כאלו. כך נולד הרעיון להעביר את האחריות אל המהדר (Compiler). כל מה שהמפתח צריך לעשות במקרה זה הוא להגדיר קטע קוד כקטע קריטי, ויובטח לו כי לעולם לא ישהה בקטע זה יותר מתהליך אחד. המבנה של שפת התכנות שהוצע לטיפול במניעה הדדית נקרא _מבנה פיקוח_ (Monitor). מבנה זה הוא ספרייה של פרוצדורות, משתנים, ומבני נתונים המוגדרים יחדיו במבנה של שפת תכנות, ושפת התכנות היא המבטיחה שהתהליכים הקוראים לפרוצדורות המוגדרות במבנה פיקוח מממשים מניעה הדדית. - -המוניטור מספק דרך נוחה להשגת מניעה הדדית, אך עדיין אינו יכול להיות שווה עוצמה לסמפורים כל עוד איננו מספק מנגנון לסנכרון בין תהליכים. הפתרון לבעיות סנכרון שמוצע הוא האפשרות להגדרה של משתנים מיוחדים הנקראים condition variables, וניתן לשלוט על המשתנים האללו באמצעות שתי פעולות: - - * פעולת (signal(c מעירה אחד מהתהליכים שהיה חסום ע"י מבנה פיקוח על התנאי c. - * פעולת (wait(c גורמת להשהיית תהליך כל עוד התנאי c לא יתקיים. מבנה פיקוח מבטיח שלאחר הקריאה ל wait אחד מהתהליכים שהיה חסום על קטע קריטי יוכל להיכנס אליו. - -לדוג' בבעית היצרן-צרכן נשתמש בשני מתשנים בשם full ו empty כדי לבצע סנכרון. המשתנה full יסמל כי המאגר מלא, והמשתנה empty מסמל כי המאגר ריק. הפונ' insert  שמופעלת ע"י היצרן מבצעת קריאה ל (wait(full כאשר מתגלה שאין עוד מקום לאכסון פריטים והדבר משהה כמובן את תהליך היצרן (השימוש במבנה פיקוח פוטר אותנו מהצורך לשחרר את הנעילה על הקטע הקריטי). - -הפונ' (signal(empty מופעלת ע"י היצרן לאחר שיצר פריט והכניסו למחסן אשר היה ריק לפני כן. הפעלת הפונ' מעירה את הצרכן שהיה רדום עקב המחסור בפריטים במחסן (שימו לב כי היצרן יעיר את תהליך הצרכן רק כאשר (בשורה בקוד) סיים לעדכן את המאגר ונמצא בסיומו של הקטע הקריטי). - -כדי להימנע משני תהליכים פעילים בתוך מבנה פיקוח, אפשר לנקוט בגישות האלה: - - * לתת לתהליך ש (signal(c העיר אותו לרוץ, תוך כדי השהיה של תהליך שקרא ל signal. - * לתת לתהליך שקרא ל (signal(c לסיים את הפונ' של מבנה הפיקוח ורק אז להעיר את אחד התהליכים שממתינים על c. - * לדרוש, ברמת התחביר של שפת התכנות, שהקריאה ל (signal(c תתבצע רק בסוף הפונ' של מבנה הפיקוח. - -* יש לציין כי להבדיל מסמפורים שמשמים כמונים. condition variables אינם זוכרים את כמות הפעמים שנקרא signal עליהם. בנוסף, נזכור שמבני פיקוח, בדיוק כמו סמפורים, הם מנגנונים שפועלים בארכיטקטורה של מעבד אחד עם זיכרון אחד, או מס' מעבדים בעלי זיכרון משותף. - -  - -**העברת הודעות (Message Passing)** - -שיטת העברת הודעות מספקת שני פרימיטיבים, send ו receive, המשמשים לשליחה וקבלה של הודעות. - - * הפונ' (send(destination, &message שולחת את ההודעה message ליעד נתון. - * הפונ' (receive(source, &message מקבלת הודעה ממקור נתון. - -השליחה של הודעות יכולה להיות שליחה שחוסמת את התהליך השולח או כזו שאיננה חוסמת (בדומה לכתיבה חוסמת או לא חוסמת לקובץ), וכך גם לגבי קבלת הודעות. היעדים יכולים להיות ישירים או עקיפים: - - * מיעון ישיר מחייב להעביר כ destination מזהה של תהליך. לסוג זה של העברת הודעות קוראים גם בשם שיטת המפגש (rendezvous), מכיוון שהתהליכים מקיימים בינהם מעין שיח בעת המפגש. - * מיעון עקיף לעומת זאת משתמש בתחנת ביניים שאליה מועברות הודעות וממנה מתבצעת משיכתן. לעיתים מכנים את תחנת הביניים הזו תיבת דואר (mailbox).  - -להלן פתרון של בעיית המניעה ההדדית באמצעות העברת הודעות בשיטת מיעון עקיף: - -תהליך 0: - -```c -meesage msg; -while (true){ - ... // non critical section - receive(message_box, msg); - CriticalSection_0(); - send(message_box, msg); - ... // non critical section -} -``` - -תהליך 1: - -```c -meesage msg; -while (true){ - ... // non critical section - receive(message_box, msg); - CriticalSection_1(); - send(message_box, msg); - ... // non critical section -} -``` - -מבנה ראשי: - -```c -main(){ - message token; - SetUpMessageBox(message_box); // create mailbox named message_box - PutMessage(message_boxm token); // send token to message_box - CreateAndShedulePeocesses(P1, P2); -} -``` - -הפתרון משתמש בתיבת דואר שבה מכניסים הודעה שתשמש כאסימון, כל אחד מהתהליכים (p1 ו p2) ינסה למשוך הודעה מהתיבה, התהליך שמצליח מקבל לידו אסימון שמאפשר את כניסתו לקטע הקריטי. מכיוון שמלכתחילה שידרנו לתיבה רק אסימון אחד, משיכת הודעה ע"י תהליך אחר תגרום לחסימתו וכך תתממש מניעה הדדית. - -  - -### 4. תזמון תהליכים - -תזמון תהליכים הוא נושא מורכב מאוד ויש לו השפעה על כל מרכיבי המערכת (ניהול זיכרון, מערכת קבצים וכ'ו). במהלך הסעיף הנל נתמקד באלוגריתמים לתזמון תהליכים שנמצאים במצב מוכן לריצה (ז"א בהינתן קבוצה של תהליכים מוכנים לריצה, המשימה תיהיה לבחור מתוכה איזה מן התהליכים יהיה התהליך הבא שמקבל זמן CPU ומתי תהליך שרץ ב CPU עובר למצב מוכן, ז"א במעברים בין מצב Ready למצב Running). אלוגריתמים אלה נקראים _אלוגריתמי תזמון לטווח קצר _(Short-time Scheduling Algorithms) ונראה בהמשך כיצד הם משתלבים במנגון התזמון שלוקח החלטות תזמון לטווח ארוך. - -  - -**קריטריונים להערכה של אלוגריתמי תזמון לזמן קצר** - -כדי קבוע מדד לטיב התזמון לטווח קצר, הונהגו הקריטריונים האלה בכל סוגי המערכות: - - * **הגינות (Fairness) –** דאגה לכך שכל תהליך יקבל אותו זמן CPU. - * **אכיפת מדיניות (Policy Enforcement) –** אפשרות לקבוע מדיניות לקבוצות שונות של תהליכים שנמצאים במצב מוכן לריצה (פעמים רבות קיימת קבוצה של תהליכים שחשוב להריץ אותם לפני תהליכים אחרים). - * **איזון (Balance) –** איזון עומסים בין מעבדים. - -בנוסף, לכל מערכת ישנם קריטריונים נוספים המיוחדים רק לה. במערכות לעיבוד באצווה ([Batch Processing](https://en.wikipedia.org/wiki/Batch_processing)): - - * **קצב עבודה (Throughput) – **כמות התהליכים שמסיימים ביחידת זמן (חשוב לבחור באלוג' תזמון בעל קצב עבודה גבוה). - * **זמן השהייה (Turnaround Time) – **הזמן שחלף מהרגע שהתהליך התקבל למערכת ועד הרגע שסיים לרוץ (אלוג' תזמון טוב ממזער את זמן השהייה הממוצע של התהליכים). - * **ניצולת המעבד (CPU Utilization) – **האלוג' צריך לדאוג לכך שהמעבד יהיה עסוק רוב הזמן. - -במערכות אינטראקטיביות: - - * **זמן תגובה (Response Time) – **ממוצע הזמנים שחלפו מרגע מתן הפקודה (כגון לחיצת כפתור העכבר או הקלדה במקלדת) ועד לקבלת התגובה הראשונה (האלוג' צריך לשאוף להביא את זמן התגובה למינימום). - * **יחסיות (Proportionality) – **ההגדרה של זמן תגובה טוב הינו יחסי בין משימות אינטראקטיביות שונות. - -במערכות בזמן אמת: - - * **עמידה בזמנים (Meeting Deadlines) – **במערכות זמן אמת זהו אחד הקריטריונים החשובים ביותר (לדוג' מערכת מחשב במטוס קרב שצריכה לבצע תמרון נגד יירוט). - * **ניתנות לחיזוי (Predictability) – **מדד למשימות זמן אמת עם אילוצים פחות נוקשים מהדוג' למעלה. למשל, בשיחת סקייפ חשוב להשיג העברה רציפה של האודיו גם על חשבון משימת ההעברה הרציפה של הווידיאו (קפיצה של פריים אחד בווידיאו אינה קריטית כמו קפיצה של האודיו). - -  - -**תזמון במערכות אצווה (Batch)** - -האלוגריתם הראשון לתזמון לזמן קצר במערכות אצווה נקרא FCFS (ראשי תיבות של First-Come First-Served), ומכונה לעיתים FIFO (ראשי תיבות של First In First Out). המתזמן מנהל תור של תהליכים מוכנים לריצה. כאשר תהליך שרץ ב CPU מבצע קריאת מערכת שגורמת לחסימה, המתזמן מקצה את ה CPU להתליך הבא בתור. כאשר התהליך חוזר ממצב רדום, הוא מוכנס לסוף התור. היתרון של האלוגריתם הוא כמובן בפשטות המימוש שלו. אך החיסרון שלו הוא זמן השהייה הארוך שלו בתהליכים עתירי קלט / פלט, אם במערכת קיימים הרבה תהליכים עתירי חישוב. - -האלוגריתם השני נקרא SJF (ראשי תיבות של Shortest Job First), והוא יכול להתגבר על החיסרון של FSFC בתנאי שזמני הריצה של התהליכים ידועים מראש ושמפעילים אותו על קבוצה של תהליכים שנקבעו מראש. האלוג' בוחר לתת זמן CPU לתהליך בעל זמן הריצה הקצר ביותר ומריץ אותו עד לסיום.  - -נחשב את 2 האלוגריתמים: נניח שהמחשב שלנו מקבל 4 תהליכים, כאשר תהליך A דורש 8 יחידות זמן, תהליך B דורש 4 יח' זמן, תהליך C דורש 4 יח' זמן, ותהליך D דורש 4 יח' זמן. ומנגד נניח שהמחשב שלנו שוב מקבל 4 תהליכים, כאשר הפעם הסדר שבו הוא מקבל אותם שונה – קודם תהליך B, תהליך C, תהליך D, ורק בסוף תהליך A (שדורש הכי הרבה יח' זמן – 8). - -להלן החישוב לאגוריתם FSFC: - - -| תזמון | תהליך | זמן הגעה | CPU | התחלה | סיום | זמן שהייה | זמן שהייה ממוצע -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| 1 | A | | 8 | | 8 | 8 | 56 / 4 = 14 | -| 2 | B | | 4 | 8 | 12 | 12 | 14 | -| 3 | C | | 4 | 12 | 16 | 16 | 14 | -| 4 | D | | 4 | 16 | 20 | 20 | 14 | - -להלן החישוב לאגוריתם SJF: - -| תזמון | תהליך | זמן הגעה | CPU | התחלה | סיום | זמן שהייה | זמן שהייה ממוצע -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| 4 | A | | 8 | 12 | 20 | 20 | 44 / 4 = 11 | -| 1 | B | | 4 | | 4 | 4 | 11 | -| 2 | C | | 4 | 4 | 8 | 8 | 11 | -| 3 | D | | 4 | 8 | 12 | 12 | 11 | - -נשים לב כי אכן SJF מהיר יותר, אך בנוסף נשים לב כי אנחנו מניחים שהזמן המצטבר שהתהליכים בילו בפעולות קלט / פלט היה זהה לכל תהליך. וגם כאשר זמן ההגעה שלהם אינו אחיד, עדיין SJF מהיר יותר: - -| תזמון | תהליך | זמן הגעה | CPU | התחלה | סיום | זמן שהייה | זמן שהייה ממוצע -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| 1 | A | | 2 | | 2 | 2 | 17 / 4 = 4.25 | -| 2 | B | | 4 | 2 | 6 | 6 | 4.25 | -| 3 | C | 3 | 1 | 6 | 7 | 4 | 4.25 | -| 4 | D | 3 | 1 | 7 | 8 | 5 | 4.25 | - - -| תזמון | תהליך | זמן הגעה | CPU | התחלה | סיום | זמן שהייה | זמן שהייה ממוצע -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| 1 | A | | 2 | | 2 | 2 | 14 / 4 = 3.5 | -| 4 | B | | 4 | 5 | 9 | 9 | 3.5 | -| 2 | C | 3 | 1 | 3 | 4 | 1 | 3.5 | -| 3 | D | 3 | 1 | 4 | 5 | 2 | 3.5 | - -  - -האלוגריתם השלישי הינו שינוי על אלוג' SJF ונקרא SRTN (רשי תיבות של Shortest Remaining Time Next), והוא מבטיח שאם זמני הריצה של תהליכים ידועים מראש וקבוצות התהליכים שהאלוגריתם פועל עליה היא קבועה, אזי זמן השהייה יהיה מזערי, ללא הנחות על זמני קלט / פלט. - -באלוג' זה מתזמן המערכת מבצע בדיקה ב-3 מקרים שונים ובוחר לריצה את התהליך בעל הזמן הקטן ביותר שנותר. 3 המקרים הללו הם: אם תהליך שהיה במצב חסום הופך להיות מוכן, אם מגיע תהליך חדש שמוכן לריצה בזיכרון, אם תהליך רץ מבצע קריאת מערכת שגורמת להרדמתו. להלן הדוג' מלמעלה על אלוג' SRTN: - -| תזמון | תהליך | זמן הגעה | CPU | התחלה | סיום | זמן שהייה | זמן שהייה ממוצע -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| 1 | A | | 2 | | 2 | 2 | 13 / 4 = 3.25 | -| 4 | B | | 4 | 2 | 8 | 8 | 3.25 | -| 2 | C | 3 | 1 | 3 | 4 | 1 | 3.25 | -| 3 | D | 3 | 1 | 4 | 5 | 2 | 3.25 | - -  - -ברמת ה CPU Scheduler מתבצע תזמון לטווח קצר. תזמון ברמה הזו גורם למעברים בין מצב Ready למצב Running (ולהפך). החלטות תזמון ברמה הזו מתבצעת בכפוף למדיניות המתזמן, והמקרים בהם בדר"כ תתבצע הפעלת מתזמן CPU הם כאשר תהליך רץ הקורא לפונקציית מערכת שגורמת להרדמתו, או תהליך שהיה במצב רדום חוזר למצב מוכן בזיכרון, או תהליך מוכן לריצה המגיע לזיכרון הראשי (בשאר המקרים הפעלת המתזמן תלויה במדיניותו). - -ברמת ה Memory Scheduler מתבצעות החלטות תזמון שבעקבותיהן תהליכים עוברים ממצב מכונות לריצה בזיכרון למצב מוכנות לריצה בדיסק (ולהפך), או ממצב רדום בזיכרון למצב רדום בדיסק (ולהפך). התזמון ברמה הזו נקרא גם "תזמון לטווח בינוני". החלטות התזמון ברמה הזו נועדו לשפר את הניצולת של מרכיבי המערכת, ומובן שהמידע אשר יכול לשפר את הניצולת של מרכיבי המערכת אינו מצוי בדרך כלל בידי המערכת בתחילת ריצתם של התהליכים. לכן, החלטות תזמון ברמה זו מתבצעות בהסתמך על עברם של התהליכים, כך שבסופו של דבר התוצאה מביאה, לרוב, לשיפור בניצולת. - -ברמת ה Admission Scheduler מתבצעות החלטות תזמון גסות, והתזמון ברמה זו מכונה לעיתים "תזמון לטווח ארוך". רמה זו מאפיינת רק מערכות אצווה, מכיוון שבמערכות אלה העבודות צריכות להצהיר כל כמות משאבי המערכת שדרושה להם. ומתוך הידע הזה המערכת בונה תכנון ארוך טווח לניצול משאביה ויכולה להחליט אם לקבל עבודה חדשה. - -  - -**תזמון במערכות אינטראקטיביות** - -להבדיל ממערכות אצווה, מנגנון התזמון של מערכות אינטראקטיביות אינו כולל מתזמן לטווח ארוך, ולכן כל העבודות מתקבלות למערכת ותהליכים חדשים נוצרים עבורן. כל האלוגריתימים עליהם נעבור כעת מתייחסים לתזמון לטווח קצר (את השיקולים לתזמון לטווח בינוני נבחן בהמשך). - -האלוג' הראשון נקרא **RR (ראשי תיבות של Round Robin)**, והרעיון שעומד ביסודו הוא פשוט: מחלקים את זמן ה CPU לאינטרוולים שווים ולכל תהליך שמוכן לריצה מקצים את ה CPU לפרק זמן קצוב (אינטרוול אחד). פרק זמן זה מכונה time quantum ולאחר סיום אותו quantum מפקיעים את ה CPU ונותנים אותו לתהליך אחר. התהליכים מנוהלים בתור מעגלי (ומכאן שם האלוג') וחלוקת זמן ה CPU לאינטרוולים שווים נקראת time slicing. - -כמובן שיכול להיות מצב בו תהליכים לא ינצלו את זמן ה quantum שלהם עד סופו עקב קריאה לפונ' מערכת הגורמת להרדמתו של אותו תהליך. במקרה כזה, התהליך הרדום מוצא מהתור המעגלי של RR ומשאבי המעבד עוברים לתהליך הבא בתור. כאשר התהליך חזר להיות מוכן, הוא מוכנס לסוף התור (כלומר, במקום שלפני התהליך המבוצע כעת). - -מכיוון שהחלפת תהליכים דורשת זמן, קביעת אורך ה quantum הוא נושא חשוב מאוד. קביעת "פרוסת זמן" קצרה גורמת לתקורה גבוהה עקב הזמן המתבזבז על החלפת תהליכים. מנגד, קביעת פרוסת זמן ארוכה יכולה להביא לזמן תגובה ארוך, דבר הפוגע אנושות בזמן התגובה של תהליכים אינטראקטיביים. לכן נהוג, ככלל אצבע, לקבוע את ה quantum למשך הזמן של ה CPU burst (משך הזמן שלוקח לפעולה אינטראקטיבית להסתיים). אך עבור פעולות אינטראקטיביות שונות, משך הזמן הזה יכול להיות שונה, ולכן גם נשתמש בריבוי תורים (נרחיב על כך בהמשך). - -  - -האלוגריתם השני נקרא **תזמון עם עדיפויות (קדימויות)**. באלוגריתם זה נמצא הרעיון הבסיסי שכל התהליכים המוכנים לריצה בזיכרון מדורגים לפי עדיפויות. תהליך בעל עדיפות גבוהה רץ על ה CPU כל עוד עדיפותו גבוהה מעדיפותם של שאר התהליכים שמוכנים לריצה. אם התהליך הרץ מבצע קריאת מערכת שגורמת להרדמתו, ה CPU עובר להתהליך בעל העדיפות גבוהה ביותר שיימצא מוכן לריצה. החלטת תזמון דומה מתבצעת כאשר תהליך שהיה במצב רדום או בדיסק חוזר להיות במצב מוכן בזיכרון. - -שינוי עדיפויות מתבצע בצורה דינמאית (אם מתן העדיפות היה קבוע, תהליך בעל עדיפות גבוהה שאיננה משתנה היה מקבל את הCPU לתקופה בלתי מוגדרת ושאר התהליכים היו מורעבים). לדוג', אלוג' התזמון יכול להפקיע את ה CPU כעבור פרק זמן (quantum) מסוים כדי למנוע הרעבה, כאשר עדיפותו של תהליך תיקבע לפי החלק היחסי של ה quantum שנוצל על ידו (ככל שהחלק המנוצל גדול יותר, כך עדיפותו תיהיה קטנה יותר). - -הבעיה בשיטה זו היא שקשה מאוד להתאים אותה לקשת הרחבה של סוגי השירות שתהליכים דורשים. וגם אם הצלחנו לעשות זאת, ההתנהגות של התהליכים יכולה להשתנות עם הזמן כתוצאה ממעבר לוגי מתקופת חיים (קטע קוד) אחד לתקופת חיים בעלת אופי שונה. - -ריבוי תורים (כמו שהזכרנו ב RR) משמש פתרון לדיפרנציאציה בין קבוצות תהליכים שונות, כאשר כל התהליכים בקבוצה מצפים לאותו סוג שירות (בקיצור שילוב של RR ותזמון עדיפויות). לכל תור משוייכת עדיפות וסוג השירות שהתהליכים הנמצאים בתור מצפים להם נגזר כתוצאה ממנו, ולכן כל התהלכים הנמצאים באותו תור הם בעלי עדיפות שווה. תהליכים יכולים לעבור בין התורים כתוצאה מהחלטת המתזמן, וכל אחד מהתורים יכול להיות מנוהל לפי מדיניות שונה. - -  - -במערכות אצווה ראינו כי אלוג' SRTN מביא למזעור של זמן השהייה הכולל בתנאי שאנו יודעים את זמן הריצה הצפוי. זאת כמובן אינה דרישה סבירה במערכת אינטרקטיבית מכיוון שהיא מונחת אירועים (Event Driven) וזמן החישוב דרוש כדי להגיב על אירוע כלשהו (כמו הקלדת תו במקלדת) ולכן קשה לצפות מראש מה יהיה משך הזמן שיידרש לביצוע הפעולה. אחת הגישות בהן ניתן להשתמש כדי לנבות את הזמן הדרוש לפעולה הבאה היא להסתמך על ההיסטוריה של התהליך: - - * נסמן ב (T(i את זמן הפעולה האינטראקטיבית ה-Iית שלקח לבצע בפועל. - * נסמן ב (E(i את הניחוש לזמן הפעולה האינטראקטיבית ה-Iית. - * והניחוש ההתחלתי למשך הזמן של הפעולה האינטראקטיבית הראשונה צריך להיות נתון, והוא (E(1. - -לכן, הניבוי לזמן הפעולה האינטראקטיבית הבאה מחושב לפי הנוסחה: (E(i+1) = a T(i) + (1-a) E(i, כאשר a גדול מ-0 וגם קטן מ-1. ובעצם הנוסחה מבצעת שקלול של זמני הפעולה שהיו בעבר. - -ע"י בחירת ערכו של a אפשר לייחס חשיבות רבה יותר (או פחותה) להיסטוריה. למשל, ע"י בחירת a = 0.5, נקבל את סדרת הניבויים: - -``` -E(1) - -E(2) = 0.5T(1) + 0.5E(1) - -E(3) = 0.5T(2) + 0.25T(1) + 0.25E(1) - -E(4) = 0.5T(3) + 0.25T(2) + 0.125T(1) + 0.125E(1) -``` - -כלומר, חשיבותם של הזמנים בעבר יורדת בצורה מעריכית. שיטה זו, הנקראת גם **[SPN](https://en.wikipedia.org/wiki/Shortest_job_next)**, מנסה לספק זמן תגובה מזערי. אך גם יכולה לגרום להרעבה של תהליכים שהפעולה האינטראקטיבית שלהם ארוכה ממוצע של משך זמן הפעולה האינטראקטיבית במערכת. - -גישה אחרת לתזמון תהליכים נקראת _תזמון מובטח_ והיא אומרת להבטיח הבטחה לגבי אופי השירות. לדוג', בהינן מס' משתמשים במערכת, אפשר להבטיח להם שיקבלו כמות שווה של זמן CPU או אפשר לתת הבטחה כזאת ברמה של תהליכים. באלוג' זה מערכת ההפעלה מנהלת בטבלת תהליכים רישום של משך הזמן שה CPU עמד לרשות כל אחד מהתהליכים במערכת, בהינתן הבטחה לספק חלוקת זמנים שווה, ובהינתן המידע כמה זמן קיבל כל תהליך ביחס לזמן שהובטח לו, אלוג' התזמון יבחר את התהליך בעל היחס הנמוך ביותר ויריץ אותו ב CPU עד שהיחס יעלה על היחס של תהליך אחר במערכת (או עד שהתהליך הרץ יבצע קריאת מערכת שתגרום להרדמתו). - -החסרון בשיטה זו היא שהיא מוסיפה תקורה די גדולה. למשל, במקרה של ההבטחה על חלוקה שווה של זמני CPU, צריך לחשב מחדש את היחס לכל תהליכי המערכת כאשר מגיע למערכת תהליך חדש או כאשר אחד מהתהליכים עוזב את המערכת. - -ב_שיטת ההגרלה (Lottery Scheduling)_ המתזמן יתן לכל תהליך חדש שנכנס למערכת כרטיס הגרלה המזכה בנתח כלשהו של זמן CPU. החלטות התזמון מתבצעות בפרקי זמן שמשכם נגזר מכמות הכרטיסים המשתתפים בהגרלה או מקריאת מערכת והגעת תהליך חדש. בעת החלטת תזמון מתבצעת הגרלה שבעקבותיה נבחר תהליך שיקבל את ה CPU. כך, לאורך זמן, השיטה משיגה חלוקה שווה למדי של זמני העיבוד. - -נשים לב כי בשיטה זו קל לתת ביטוי לחשיבותו של תהליך (תהליכים חשובים יכולים לקבל מספר כרטיסי זכייה ובכך להגדיל באופן סטטיסטי את זמן ה CPU המוקצה להם). ובנוסף, תהליכים שמשתפים פעולה בינהם יכולים להעביר כרטיסים זה לזה, והדבר מאפשר פתרונות נוספים לבעיות כמו יצרן-צרכן באמצעות מנגנונים לתקשורת בין תהליכים. - - - -### 5. בעיות IPC קלאסיות - -ניזכר כי בסעיף בו דיברנו על סמאפורים הבנו שהפרוטוקול לפתרון בעיית הקטע הקריטי לזוג תהליכים בעזרת סמפור בינארי כולל 3 כללים: קיים סמפור בינארי S המאותחל למצב S=1, תהליך הנכנס לקטע קריטי מבצע (DOWN(S, תהליך היוצא מקטע קריטי מבצע (UP(S. ושלושת כללים אלה יוצרים את הפרוטוקול המבוקש. - -  - -**בעיית הפילוסופים הסועדים** - -
    - Dining Philosophers -
    - -[הבעיה המפורסמת ביותר](https://en.wikipedia.org/wiki/Dining_philosophers_problem) בהקשר זה, והפתרון שלה משמש כמודל שבאמצעותו בוחנים יעילות של מנגנונים חדשים לתקשורת בין תהליכים בסביבה בעלת מספר מוגבל של משאבים (כמו התקני קלט / פלט). - -להלן תיאור הבעיה: מספר פילוסופים יושבים מסביב לשולחן עגול ולפני כל אחד מהם מונחת צלחת ספגטי. בין כל שתי צלחות מונח מזלג. כדי לאכול פילוסוף צירך לאחוז בשני מזלגות בו זמנית. חייו של פילוסוף מתחלקים לתקופות שבהן הוא חושב (אינו רעב), רעב אך אין ברשותו 2 מזלגות, ואוכל (וברשותו, כמובן, 2 מזלגות). כאשר פילוסוף הופך לרעב, הוא מנסה לקחת את 2 המזלגות. אם הוא מצליח לקבל את 2 המזגלות, הוא אוכל. כשהוא מסיים לאכול הוא מניח את המזלגות בחזרה בשני הצדדים של הצלחת שלו וחוזר להרהר בבעיות החשובות בעולם. המטרה היא למצוא פרוטוקול שמבטיח שאף פילוסוף לא יגווע ברעב. - -הפתרון הראשון שבד"כ עולה לראש הוא שכל פילוסוף יקח קודם את המזלג השמאלי ואחריו את המזלג הימני (הסדר לא באמת משנה). אם המזלג שהוא מנסה לקחת אינו פנוי (ז"א פילוסוף אחר כבר לקח אותו), הפילוסוף ממשיך בעקשנות לנסות להשיג את המזלג. אך אם כל הפילוסופים לקחו את המזלג השמאלי, אף אחד מהם לא יצליח להשיג את המזלג הימני, ומכיוון שהם משחררים את המזלג רק כשהם מסיימים לאכול – כל אחד מהם יחכה לשכן שמימינו, וכך כולם יגוועו ברעב. מצב זה נקרא מצב קיפאון. - -אם הפילוסופים היו משחררים את המזלג השמאלי בכל פעם שלא הצליחו להשיג מזלג ימני, המצב היה משתפר פלאים. אך גם התרחיש בו הפילוסופים לוקחים בזה אחר זה המזלג השמאלי, אפשרי. במצב כזה הם מנסים, כל אחד בתורו (בזמן ה CPU שהוא מקבל) לקחת את המזלג הימני. הם כמובן נכשלים ובזה אחר זה משחררים את המזלגות שברשותם. לאחר מכן, הסבב יחזור על עצמו, ותיאורטית הסבבים יכולים להימשך כך לנצח ללא התקדמות אמיתית. מצב כזה נקרא הרעבה, ומצב כזה יכול להימשך (תיאורטית) זמן בלתי מוגבל. נבדיל בין הרעבה לקיפאון בכך שבקיפאון התהליכים ממתינים לאירוע מאחד מתהליכי הקבוצה, ולעומת זאת בהרעבה הם אינם מקבלים משאב כלשהו (בלי קשר לקבוצה נתונה) לאורך תקופת זמן שיכולה תיאורטית להימשך לנצח וכתוצאה מכך הם אינם מסוגלים להתקדם. אחת הדרכים לפתור את מצב ההרעבה, במקרה שלנו, היא שהזמנים שבהם הפילוסופים יבקשו לאכול יהיו מקריים, ההסתברות לכך שהדבר יקרה שוב היא אפסית, ולכן, הגרלה מקרית של זמני הארוחות האישיות מהווה פתרון הסתברותי לבעיה. - -  - -### לסיכום - -שלושת הנושאים החשובים ביותר בחלק זה היו בעיית המירוץ הקריטי, תיאום ושיתוף פעולה בין תהליכים או תהליכונים שוים, ותזמון תהליכים ותהליכונים. אך דיברנו על עוד דברים כמו כיצד תהליכים ותהליכונים נוצרים וכיצד הם מסתיימים, הכרנו את היררכיה שלהם, המימוש בקרנל, תקשורת בינהם והבעיות שמגיעות איתם (מירוץ קריטי ומגוון הפתרונות שלו), דיברנו על סמפורים, מנעולים, ומבני פיקוח, ולבסוף על תזמון התהליכים במערכות השונות והבעייה הקלאסית של הפילוסופים הסועדים. diff --git a/data/_oldPosts/2016-03-06-heap.md b/data/_oldPosts/2016-03-06-heap.md deleted file mode 100644 index 958f87e..0000000 --- a/data/_oldPosts/2016-03-06-heap.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: ערמה (Heap) -author: nirgn -layout: post -summary: "" -category: Data Structures ---- diff --git a/data/_oldPosts/2016-03-20-graph.md b/data/_oldPosts/2016-03-20-graph.md deleted file mode 100644 index efa77a4..0000000 --- a/data/_oldPosts/2016-03-20-graph.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: גרף (Graph) -author: nirgn -layout: post -summary: "" -category: Data Structures ---- diff --git a/data/_oldPosts/2016-04-03-hash-table.md b/data/_oldPosts/2016-04-03-hash-table.md deleted file mode 100644 index bdbd92f..0000000 --- a/data/_oldPosts/2016-04-03-hash-table.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: טבלת גיבוב (Hash Table) -author: nirgn -layout: post -summary: "" -category: Data Structures ---- diff --git a/data/_oldPosts/2016-04-17-dfs.md b/data/_oldPosts/2016-04-17-dfs.md deleted file mode 100644 index 6db7758..0000000 --- a/data/_oldPosts/2016-04-17-dfs.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: חיפוש לעומק (DFS) -author: nirgn -layout: post -summary: "" -category: Algorithms ---- -DFS (ראשי תיבות של Depth-First Search) או במילים אחרות חיפוש לעומק משמש לסריקה לעומק של עץ בינארי, ו/או הדפסת האיברים בו. האלגוריתם רקורסיבי, ובגרסה שאני כתבתי מדפיס את כל הצמתים בעץ לפי עומק העץ. - - - -עקרון האלגוריתם: - -גכע -גכע - - -הקוד של האגוריתם (בפסאודו קוד): - -DFS (t) -dir <- L -while (t != NIL) do - switch (dir) - L: if (left(t) != NIL) - t <- left(t) - else - dir <- R - R: if (right(t) != NIL) - t <- right(t) - dir <- L - else - dir <- U - U: if (parent(t) != NIL and t = left(parent(t)) - dir <- R - t <- parent(t) - - - -סיבוכיות זמן ריצה: (O(n. -סיבוכיות מקום: (O(1. diff --git a/data/_oldPosts/2016-05-01-heap-sort.md b/data/_oldPosts/2016-05-01-heap-sort.md deleted file mode 100644 index 08c2ee2..0000000 --- a/data/_oldPosts/2016-05-01-heap-sort.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: מיון בעזרת תור קדימויות (Heap Sort) -author: nirgn -layout: post -summary: "" -category: Algorithms ---- - -מיון ערמה משתמש במבנה נתונים מופשט הנקרא ערמה. -במבנה נתונים זה, הנתונים מאוחסנים במערך רגיל, אך נקבעים יחסים מסוימים בין האינדקסים המעניקים למערך יכולת ייצוג כערמה של עץ בינרי כמעט שלם. קיימים 2 סוגים של ערמות עליהם דנו בתחילת הפוסט (תחת מבני נתונים - ערמות): ערמת מקסימום וערימת מינימום. - -באנימציה בצד שמאל, ניתן לראות את התהליך של מיון ערמה. -תחילה נקבל מערך (בצבע תכלת), ונבנה ממנו את הערמה (בשלב זה המערך הופך לצהוב), על ידי כך שנפעיל את שגרת BUILD-MAX-HEAP, השגרה הזאת מבצעת את MAX-HEAPIFY (שתפקידה להחליק איברים, במורד הערמה, למקומם הנכון לפי תכונות הערמה - עץ בינרי), על חצי מהמערך (מכיוון שזהו גובה הערמה - מתכונות עץ בינרי). - -לאחר מכן האלגוריתם יתחיל להוציא את האיברים (כאן המערך הופך לירוק), ע"י לולאה יורדת - מהאינדקס האחרון ועד לאינדקס ה-2, בכך שיוציא את איבר השורש של הערמה (איבר המקסימום - מתכונות הערמה) ומחליף במקומו את העלה האחרון בערמה ומפעיל עליו MAX-HEAPIFY (על מנת לוודא כי תכונות הערמה לא נפגעו, ובמידה ונפגעו - לתקנם). -כמו שהוזכר האלגוריתם יבצע זאת בלולאה עד שיוציא את כל הערכים (יוציא - החלפת מיקומם במערך), וכשישאר האיבר האחרון הוא כבר יהיה במקומו (כאיבר המינימלי במערך, מקומו באינדקס הראשון). -ולבסוף נקבל מערך ממוין מהערך הקטן לערך הגדול. - -שימו לב: ישנן בעיות בסיסיות שערמה אינה מאפשרת לנו לפתור ביעילות. לדוגמה בעיית החיפוש: אם נתבקש לברר אם ערך נתון כלשהו מצוי בערמה, ייתכן שניאלץ לעבור על כל הערכים המאוחסנים בה על מנת להשיב על שאלה זו, והדבר אינו יעיל. - -  - -### הקוד של האלגוריתם ב [פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -(ה ~ נועד לסמן עיגול כלפי מטה) -```c -PARENT (i) -return ~i/2~ - -LEFT (i) -return 2*i - -RIGHT (i) -return 2*i + 1 - -MAX-HEAPIFY (A, i) -l <- Left(i) -r <- Right (i) -if (l <= heap-size[A] and A[l] > A[I] ) - largest <- l -else largest <- i -if (r <= heap-size[A] and A[r] > A[largest]) - largest <- r -if (largest != r) - exchange A[I] <-> A[largest] - MAX-HEAPIFY (A, largest) - -BUILD-MAX-HEAP (A) -heap-size[A] <- length[A] -for (i <- ~length[A]/2~ downto 1) - MAX-HEAPIFY (A, i) - -HEAPSORT (A) -BUILD-MAX-HEAP(A) -for (i <- length[A] downto 2) do - exchange A[1] <-> A[i] - heap-size[A] <- heap-size[A] -1 - MAX-HEAPIFY (A, 1) -``` - -  - -### הסבר מופשט: - -* בונים ערמה ממערך של איברים. -* מוציאים מהערמה את השורש ומכניסים אותו למיקום הפנוי הגדול ביותר במערך. -* מוציאים את האיבר האחרון בערמה ומציבים אותו כשורש הערמה (במקום השורש שהוצאנו). -* מצבעים את Heapify (שמתקנת את מבנה הערמה, על מנת לשמור על תכונות הערמה). -* חוזרים שוב על תהליך הוצאת השורש עד שהערמה מגיעה לגודל של איבר אחד. - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים: - -משהו.. - -  - -**סיבוכיות זמן ריצה: ((O(n*lg(n.** -> שימו לב למרות שבמקרה הגרוע מיון זה מתבצע באותה מהירות כמו הזמן הממוצע של Quick Sort, המשתנים הקבועים שלו גדולים ולכן, לרוב, זמן הריצה במקרה הגרוע של Heap Sort יהיה גדול יותר מזמן הריצה ממוצע של Quick Sort (אך רק בקבועים ולא בסדר גודל). - -**סיבוכיות מקום: (O(n.** diff --git a/data/_oldPosts/2016-05-15-radix-sort.md b/data/_oldPosts/2016-05-15-radix-sort.md deleted file mode 100644 index 79d69d6..0000000 --- a/data/_oldPosts/2016-05-15-radix-sort.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: מיון בסיס (Radix Sort) -author: nirgn -layout: post -summary: "Radix Sort - מיון בסיס, הוא האלגוריתם ששימש את ממיינות הכרטיסים, מכונות שניתן לראותן כיום רק במוזיאונים למחשבים. הכרטיסים מחולקים ל 80 עמודות, ובכל אחת מהן ניתן לנקב חור באחד מ 12 מקומות. עבור ספרות עשרוניות יש צורך ב 10 מקומות בלבד בכל עמודה (שני המקומות הנוספים משמשים לקידוד תווים שאינם ספרות). מספר בן d ספרות יתפוס שדה בן d עמודות. ומכיוון שהממיינת יכולה לבחון בכל פעם רק עמודה אחת, הרי שלפתרון בעיית מיונם של n כרטיסים, שמקודדים בהם מספרים בני d ספרות, נדרש אלגוריתם מיון." -category: Algorithms ---- -Radix Sort - מיון בסיס, הוא האלגוריתם ששימש את ממיינות הכרטיסים, מכונות שניתן לראותן כיום רק במוזיאונים למחשבים. הכרטיסים מחולקים ל 80 עמודות, ובכל אחת מהן ניתן לנקב חור באחד מ 12 מקומות. עבור ספרות עשרוניות יש צורך ב 10 מקומות בלבד בכל עמודה (שני המקומות הנוספים משמשים לקידוד תווים שאינם ספרות). מספר בן d ספרות יתפוס שדה בן d עמודות. ומכיוון שהממיינת יכולה לבחון בכל פעם רק עמודה אחת, הרי שלפתרון בעיית מיונם של n כרטיסים, שמקודדים בהם מספרים בני d ספרות, נדרש אלגוריתם מיון. - - - -הגישה האינטואיטיבית היא למיין את המספרים על פי הספרה המשמעותית ביותר שלהם, למיין באופן רקורסיבי כל אחד מהתאים המתקבלים, ואז לצרף את החבילות על פי סדרן. אולם כדי למיין כל תא, יש להניח בצד את תכולתם של 9 מתוך 10 התאים, ולכן תהליך זה מחייב ניהול של חבילות ביניים רבות של כרטיסים. - -מיון בסיס (Radix Sort) פותר את בעיית מיון הכרטיסים באופן הנוגד את האינטואיציה שהזכרנו למעלה. תחילה הוא ממיין על פי הספרה האחרונה (הכי פחות משמעותית). אז הוא מצרף את הכרטיסים לחבילה אחת, אשר בה הכרטיסים מתא 0 מונחים מעל לכרטיסים מתא 1, שמונחים מעל לכרטיסים מתא 2, וכך הלאה. לאחר מכן הוא ממיין שוב את החבילה כולה על פי הספרה שלפני האחרונה, ומצרף את הכרטיסים כמו קודם. תהליך זה נמשך עד שהוא גומר למיין את הכרטיסים על פי כל d הספרות. באופן מפתיע, בשלב זה הכרטיסים כולם ממוינים על פי המספר בן d הספרות. תהליך מיון זה סורק את חבילת הכרטיסים d פעמים. - -> שימו לב, באלגוריתם זה המיונים על פי הספרות השונות חייבים להיות יציבים. - -
    - Radix Sort Algorithm -
    - -במחשב אופייני, מיון בסיס משמש לעתים למיון רשומות מידע שהמפתחות שלהן מורכבים מכמה שדות. לדוגמה, נניח שרוצים למיין תאריכים על פי שלושה מפתחות: שנה, חודש, ויום. ניתן להריץ אלגוריתם מיון המפעיל את פונקציית ההשוואה הבאה: בהינתן שני תאריכים, היא משווה תחילה את השנים. אם הן שוות, היא משווה את החודשים. ואם גם הן שווים, היא משווה את הימים. (לחלופין, ניתן למיין את המידע מיון יציב שלוש פעמים: תחילה על פי היום, אחר כך על פי החודש, ולבסוף על פי השנה). - -  - -### הקוד של האלגוריתם ב [פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -```c -RADIX-SORT(A, d) -for i <- 1 to d - use a stable sort to sort array A on digit i -``` - -הקוד עבור מיון בסיס הוא פשוט ומיידי, הפונ' למעלה מניחה שכל איבר במערך A שגודלו n הוא בן d ספרות, כאשר הספרה שמספרה הסידורי 1 היא הספרה הכי פחות משמעותית והספרה שמספרה הסידורי d היא המשמעותית ביותר. - -  - -**הסבר מופשט:** -תנאי הכרחי לא - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים: - -* כמו שציינתי בעבר, במדעי המח - - 1. נקבל מערך: { 30, 10, 9, 6, 5, 4, 3, 1 }. A זהו מצביע למערך, p זה מצביע לתחילת המערך (תא מס' 0), r מצביע לסוף המערך (תא מס' 7), ו x זהו הערך שאנחנו מחפשים, בואו ניקח לדוגמה את 10. - 2. שורה 2: אם r < p אז.., מכיוון - -**סיבוכיות זמן ריצה: ((O(n*d** בהינתן n מספרים בני d ספרות. - -**סיבוכיות מקום: תלויה במיון היציב בו אנו משתמשים**. diff --git a/data/_oldPosts/2016-06-03-backet-sort.md b/data/_oldPosts/2016-06-03-backet-sort.md deleted file mode 100644 index fa67fb1..0000000 --- a/data/_oldPosts/2016-06-03-backet-sort.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: מיון דלי (Bucket Sort) -author: nirgn -layout: post -summary: "." -category: Algorithms ---- -בדומה למיון בסיס, גם מיון דלי (Bucket Sort) מהיר משום שהוא מניח משהו על הקלט. מיון דלי מניח שהקלט נוצר ע"י תהליך אקראי המפזר את האיברים באופן אחיד ובלתי תלוי בקטע (1 ,0] ([התפלגות אחידה](https://he.wikipedia.org/wiki/%D7%94%D7%AA%D7%A4%D7%9C%D7%92%D7%95%D7%AA_%D7%90%D7%97%D7%99%D7%93%D7%94)). - - - -מיון דלי מבוסס על חלוקת הקטע (1 ,0] ל n תת קטעים (או דליים, buckets), שווים בגודלם, ופיזור n מספרי הקלט בין הדליים השונים. מכיון שהקלטים מתפלגים באופן אחיד ובלתי תלוי בקטע (1 ,0], איננו מצפים למצוא מספר רב של מספרי קלט בכל דלי. כדי לקבל את הפלט, עלינו פשוט למיין את המספרים בכל דלי, ואז לעבור על כל הדליים על פי הסדר, ולרשום את האיברים בכל אחד מהם. - -  - -### הקוד של האלגוריתם ב [פסאודו קוד](http://en.wikipedia.org/wiki/Pseudocode) - -```c -BUCKET-SORT(A) - n <- length[A] - for i <- 1 to n - insert A[i] into list B[⌊nA[i]⌋] - for i <- 0 to n-1 - sort list B[i] with insertion sort - concatenate the lists B[0], B[1], .., B[n-1] together in order -``` - -להלן פעולתו של מיון דלי על מערך בן 10 מספרים - -
    - Bucket Sort Algorithm -
    - -הקוד מניח שהקלט הוא מערך A בן n איברים, ושכל איבר [A[i במערך מקיים `1 > [A[i => 0` הקוד דורש מערך עזר [B[0..n-1 של רשימות מקושרות (דליים), ומניח שקיים מנגון לטיפול ברשימות כאלה. - -  - -**הסבר מופשט:** -תנאי הכרחי לא - -  - -### הרצה של הקוד לשם המחשה של השלבים המתבצעים: - -* כמו שציינתי בעבר, במדעי המח - - 1. נקבל מערך: { 30, 10, 9, 6, 5, 4, 3, 1 }. A זהו מצביע למערך, p זה מצביע לתחילת המערך (תא מס' 0), r מצביע לסוף המערך (תא מס' 7), ו x זהו הערך שאנחנו מחפשים, בואו ניקח לדוגמה את 10. - 2. שורה 2: אם r < p אז.., מכיוון - -**סיבוכיות זמן ריצה: ((O(n*d** רץ בתחולת זמן לינארית אם מקורו של הקלט בהתפלגות אחידה. -**סיבוכיות מקום: תלויה במיון היציב בו אנו משתמשים**. diff --git a/data/_oldPosts/2016-06-17-red-black-tree.md b/data/_oldPosts/2016-06-17-red-black-tree.md deleted file mode 100644 index 75e08d9..0000000 --- a/data/_oldPosts/2016-06-17-red-black-tree.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: עצים אדומים-שחורים (Red-Black Trees) -author: nirgn -layout: post -summary: "" -category: Data Structures ---- diff --git a/data/_oldPosts/2016-07-03-data-link-layer.md b/data/_oldPosts/2016-07-03-data-link-layer.md deleted file mode 100644 index 22b859d..0000000 --- a/data/_oldPosts/2016-07-03-data-link-layer.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: The Data Link Layer - שכבת הערוץ -author: nirgn -layout: post -summary: "" -category: Computer Networks ---- -Zero And Onesפוסט זה מתמקד בשכבה השניה במודל, לאחר שדיברנו על השכבה הראשונה, הפיזית (לרוב, השכבה הקשה ביותר להבנה לאנשי מדעי המחשב), אנו ממשיכים לשכבה השנייה (מלמטה), הלא היא שכבת הערוץ. -בפוסט אבצע סקירה מלאה על השכבה ואפרט את הנושאים הבאים: - -נושאים בתיכון שכבת הערוץ. -קודים לגילוי שגיאות ותיקונן. -פרוטוקולים בסיסיים לשכבת הערוץ. -פרוטוקולי חלון-הזזה. -דוגמאות לשכבת הערוץ ברשתות שונות. - - -אז לפני שאנחנו מתחילים, מהי שכבת הערוץ? - -שכבת הערוץ עוסקת, באופן כללי, באלגוריתמים להשגת תקשורת אמינה ויעילה של יחידות מידע שלמות הנקראות "מסגרות" (במקום ביטים בודדים כמו בשכבה הפיסית). - - - -1. נושאים בתיכון שכבת הערוץ - -לשכבה זו יש כמה מטרות עקריות: - -לספק ממשק לשירות שכבת הרשת. -להתמודד עם שגיאות שידור. -לווסת את זרימת הנתונים כך שמקלטים איטיים אינם יוצפו ע"י שולחים מהירים. -כדי להשיג את מטרות אלה, שכבת הערוץ לוקחת את הפאקטות (packets) שהיא מקבלת משכבת הרשת (השכבה שמעליה, השלישית במספר) ועוטפת אותם (מבצעת עליהם אינקפסולציה - כימוס) למסגרות (frames) לשידור. כל מסגרת מכילה Header (כותרת), Payload field (שדה להחזקת המנות), ו Trailer (גורר). - - - -השירות הניתן לשכבת הרשת -המטרה של שכבת הערוץ היא לספק שירותים לשכבת הרשת (השכבה שמעליה, עליה עדיין לא דיברנו). השירות העיקרי הוא העברת נתונים משכבת הרשת במכונת המקור אל שכבת הרשת במכונת היעד. במכונת המקור ישנה ישות כלשהי, נחשוב עליה כעל תהליך, הנמצא בשכבת הרשת שמספקת לשכבת הערוץ חתיכות מידע לשם העברתם למכונת היעד, כדי שיוכלו להימסר לשכבת הרשת שם. בפועל שכבת הערוץ מעבירה את חתיכות המידע האלו דרך השכבה הפיזית אל מכונת היעד, אך קל יותר לחשוב (וזו תיהיה הדרך בה אנו נשתמש מכאן והלאה) כעל שני תהליכי תהליכים בשכבת הערוץ המתקשרים בינהם ישירות (ז"א משכבת הערוץ במכונת המקור לשכבת הערוץ במכונת היעד, ללא השכבה הפיזית שבפועל מתווכת בינהם). - -* דרך מחשבה זו מפשטת את מבנה ארכיטקטורת הרשת כולו, ומכיוון שבמאמר הקודם דיברנו על תפקיד השכבה הפיזית, כיצד היא פועלת, הבעיות והפתרונות שהממומשים בה, וכ'ו. אין לנו עוד צורך להתמקד בה, אנו יודעים שהיא תספק את השירות אותו היא אמורה לספק, וכל שאנו אמורים זה להעביר אליה את המידע שאנו רוצים לשדר בצורה עליה הסכמנו מראש (על כל אלה דיברנו במאמר הקודם, מי שלא קרא, מומלץ בחום לקרוא אותו לפני שאתם ממשיכים). - -שכבת הערוץ נועדה לספק מגוון שירותים שונים, בפועל, השירותים יכולים להשתנות מפרוטוקול לפרוטוקול, שלוש אפשרויות סבירות שנשקול הן: - -שירות ללא חיבור שלא מאושר. -שירות ללא חיבור מאושר. -שירות מכוון קשר מאושר. -שירות ללא חיבור שלא מאושר - מורכב ממכונת מקור המשדרת מסגרות עצמאיות אל מכונת היעד מבלי שמכונת היעד מכירה בהן. אתרנט (Ethernet) הוא דוגמה טובה לפרוטורול בעל שכבת ערוץ המספקת סוג כזה של שירות. אם מסגרת הולכת לאיבוד בשל רעש על הקו, לא נעשה כל ניסיון לזהות את האובדן או להתאושש ממנו בשכבת הערץ. שירות כזה מתאים כאשר שיעור השגיאות הוא נמוך מאוד, ולכן ההתאוששות נשמרת לשכבות גבוהות יותר. כמו כן הוא מתאים גם לתעבורה בזמן אמת כגון שידור קול, שבו מידע שמאחר להגיע גרוע יותר ממידע שהגיע משובש (או לא הגיע בכלל), שכן בתקשורת בזמן אמת עדיף לנו לחוות ירידה של פריים או קטיעה קטנה של התקשורת (גליץ) מאשר להשהות אותה כדי לשלוח אישור שהמסגרת לא הגיע ולחכות שתישלח שוב. - -שירות ללא חיבור מאושר - כל מסגרת הנשלחת מאושרת באופן נפרד. בדרך זו השולח יודע אם המסגרת הגיע בצורה נכונה אל יעדה ואף אם אבדה בדרך. אם המסגרת לא הגיע תוך פרק הזמן שסוכם מראש ניתן לשלוח אותה שוב. שירות כזה שימושי בערוצים לא אמינים כגון מערכות אלחוטיות, תקן 802.11 (WiFi) הוא דוגמה טובה לערוץ כזה. - -שירות מכוון קשר מאושר - בשירות זה מכונת המקור ומכונת היעד יוצרות חיבור עוד לפני תחילת העברת הנתונים. כל מסגרת הנשלחת דרך חיבור זה ממוספרת, ושכבת הערוץ מבטיחה כי כל מסגרת הנשלחת אכן מתקבלת, ואפילו יותר מכך, היא מבטיחה כי כל מסגרת התקבלה בדיוק פעם אחת, ושכל המסגרות התקבלו בדיוק בסדר הנכון. שירות שכזה מתאים בשידורים ארוכים ולא אמינים כמו ערוצי לווין או מעגלי טלפונים למרחקים ארוכים. כמובן שכמו "שירות ללא חיבור מאושר" אם מסגרת לא הגיעה אל יעדה או אבדה בדרך היא תישלח שוב, ואף אם הטיימר פקע ועדיין לא התקבל אישור שהמסגרת הגיע ליעדה, מכונת היעד תשלח את המסגרת פעם נוספת, מה שיגרום למס' מסגרות זהות שיגיעו אל היעד (ומכונת היעד פשוט "תזרוק" אותן) דבר הגורם לבזבוז רוחב הפס. לשירות זה יש 3 שלבים: הראשון הוא הקמת החיבור ע"י כך ששני הצדדים מאתחלים את המשתנים והמונים הדרושים כדי לעקוב אחר המסגרות והאישורים. בשלב השני מסגרת אחת או יותר מעוברת למכונת היעד. ובשלב השלישי והאחרון הקשר משוחרר, והמשאבים (משתנים, חוצצים - Buffers, וכ'ו) משתחררים. - - - -Unacknowledged connectionless service. - -2. Acknowledged connectionless service. - -3. Acknowledged connection-oriented service. - -מסגור - -כעי diff --git a/data/_oldPosts/2016-07-17-sub-layer-mac.md b/data/_oldPosts/2016-07-17-sub-layer-mac.md deleted file mode 100644 index 9a179fb..0000000 --- a/data/_oldPosts/2016-07-17-sub-layer-mac.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: תת שכבת MAC -author: nirgn -layout: post -summary: "" -category: Computer Networks ---- -תת שכבת MAC: -בעיית הקצאת הערוץ. -פרוטוקולי גישה מרובה (Multiple Access Protocols). -Ethernet. -רשתות מקומיות אלחוטיות. -תקן 802.16. -Bluetooth. -RFID. -גשרים. diff --git a/data/_oldPosts/2016-08-07-introduction-and-information-theory.md b/data/_oldPosts/2016-08-07-introduction-and-information-theory.md deleted file mode 100644 index b48ad5a..0000000 --- a/data/_oldPosts/2016-08-07-introduction-and-information-theory.md +++ /dev/null @@ -1,230 +0,0 @@ ---- -title: מבוא ותורת המידע -author: nirgn -layout: post -summary: "" -category: Data Mining ---- -בכל סמסטר בו אני לומד איזשהו קורס, כחלק מהלימוד עצמו אני קורא ספרים, פותר תרגילים, מכין סיכומים וכד'. ולאחרונה התחלתי ללמוד כריית מידע (Data Mining), אז כמו בחלק מהקורסים הקודמים, החלטתי לכתוב סדרת פוסטים המהווה יומן מסע ותכיל את הסיכומים של חומרי הלימוד כפי שאני לומד ומכין אותם. הספר עליו אני מתבסס הוא Data Mining Concepts and Techniques (מהדורה שלישית) והוא זמין גם כקובץ PDF. - -בפוסט זה נדבר על: - -למה לכרות מידע? -מהי כריית מידע? -מודלים ואלגוריתמים -מחסן נתונים מול מסד נתונים -תורת האניפורמציה -תקשורת -הגישות השונות לכריית מידע - - -1. למה לכרות מידע? - -אנחנו חיים בעולם עם כמויות עצומות של מידע הנאסף מידי יום, וניתוח של המידע הוא פעולה חשובה. נראה כיצד פעולת כריית המידע עונה על צורך זה בעזרת סיפוק כלים לחשיפת הידע מהמידע, ונראה כיצד פעולת כריית מידע ניראת אבולוציה טבעית לתוצאה של מידע טכנולוגי. - -"אנחנו חיים בעידן המידע" היא אמרה פופולרית, אך האמת היא שאנחנו חיים בעידן הנתונים. טאראה בייטים ואפילו פטאבייטים של מידע נשפכים לרשתות המחשבים שלנו, לאינטרנט (WWW), ומרכזי אחסון נתונים שונים בכל יום מהעסקים השונים, מהחברה באופן כללי, מתחום המדע, ההנדסה, הרפואה, ובקיצור כמעט מכל אספקט של חיי היום יום שלנו. הפיצוץ האדיר הקיים בשנים האחרונות של נתונים נובע ממהפכת המחשוב שהחברה שלנו עוברת והפיתוח המהיר של כלים חזקים לאיסוף ואחסון נתונים. - -מכאן נולד הצורך לכלים חזקים ורב תכליתיים שבאופן אוטומטי יחשפו מידע יקר מהררי המידע הזמינים, ואף יהפכו אותו לידע מאורגן. הצורך הזה הוביל להולדת התחום הנקרא כריית מידע. תחום צעיר, דינמי, ומבטיח המתיימר להביא אותנו מעידן הנתונים אל עידן המידע. - -דוגמה: כריית מידע הופכת אוסף גדול של נתונים לידע. מנוע חיפוש (דוגמת Google) מקבל מאות מליוני שאילתות בכל יום, כל שאילתה מתארת את הצורך / המידע שהמשתמש מבקש. באופן מעניין נמצאו תבניות בשאילתות החיפוש של המשתמשים. לדוגמה, הצליחה גוגל למצוא קשר ישיר בין מס' האנשים שחיפשו על מידע הקשור לשפעת ומספר האנשים בפועל שהיה להם סימפטומים של שפעת. בעזרת איסוף המידע, גוגל מצליחה להעריך פעילות של שפעת באזור מסוים עד לשבועיים מהר יותר (לפני) מערכות מסורתיות. - - - -2. מהי כריית מידע? - -כריית מידע יכולה להיות מוגדרת במגוון דרכים שונות, ולמרות שאולי לא מייצגת כהלכה את המשמעות, כרייה היא תהליך של מציאת דבר מה יקר, קטן, ממידה רבה של חומר גלם כלשהו. מושג פופולרי נוסף, ואולי אף מדויק יותר הוא Knowledge Discovery in Databases (חשיפת / גילוי מידע במסדי נתונים או KDD). המושג מתייחס לתהליך הלא טריוואלי של זיהוי דפוסי מידע תקפים / שעשויים להיות שימושיים / מובנים / חדשים. - -כריית מידה יכולה להיות מיושמת לכל סוג של נתונים. הצורה הבסיסית ביותר של יישום כריית המידע היא לנתונים במסדי נתונים, במחסני נתונים, ונתוני עסקאות (טרנזקציות). אך כריית מידע יכולה להיות מיושמת גם על צורות אחרות של נתונים, כמו זרמי נתונים, נתוני רשת, נתוני גרף, נתונים מרחביים, נתוני טקסט, נתוני מולטימדיה, וגם ה WWW. - -תחומי יישום KDD: - -CRM (ניהול קשרי לקוחות) - תחום העוסק בשירות לקוחות, הבנה וניתוח צרכיהם. המערכות מתיימרות לזהות את המאפיינים של הלקוח, דפוסי הצריכה, העדפות, מידת שביעות רצונו, ואף חיזוי סיכויי הנטישה של הלקוח. -פיננסים - זיהוי זיופים ע"י הרגלי צריכה בכרטיס אשראי, דירוג קרדיט בנקאי, אישור הלוואות והתאמת ריביות, חיזוי מניות ושערי מטבעות, וכד'. -שיווק ומסחר - פניות באמצעות דואר או אימייל לרכישת מוצרים, חיתוך קהלי יעד, חיזוי המידע שבו המשתמש מעוניין, וכ'ו. -פריצות למערכות מחשבים - זיהוי פריצה ע"י הרגילה שימוש וכד' (תחום שעדיין בחיתולים יחסית). -רפואה - שיפור הבחנות הרפואיות, זיהוי טיפולים אופטימליים לסוג מסוים של חולים, וכ'ו. -ביטחון - זיהוי קשרים לארגונים או מבוקשים מסויימים, הפקת מידע לשימוש ארגוני ביון וכד'. - Data Mining Process - -תהליך חשיפת המידע הוא תהליך איטרטיבי של הצעדים הבאים: - -מטרות - זיהוי מטרות התהליך, מדוע אנחנו רוצים לבצע בכלל את פעולת כריית המידע (להפעיל אלגוריתמים לכריית מידע על הנתונים). -בחירת נתונים - בחירת הנתונים ממסד נתונים קיים, יצירת הנתונים (במידת הצורך) ע"י בחירת מדגם, וכ'ו -ניקוי המידע - בדרך כלל כשמדובר על נתונים אמיתיים יש צורך לנקות אותם, ז"א כוליים מידע לא מדויק, חלק מהנתונים שגויים, לא רלוונטים. במצב כזה נשאלת השאלה כיצד מזהים נתונים שגויים? וכיצד מתמודדים במצב שחסרים לנו נתונים? -שילוב נתונים - שילוב כל כמה מקומות מידע למחסן נתונים אחד (צעד זה אינו הכרחי). -בחירת ושינוי הנתונים - בחירת הנתונים / ערכים הרלוונטים ביותר, ולפעמים גם הגדרת משתנים חדשים (ע"י חישוב מהנתונים הקיימים). -כריית מידע - נפנה לאלגוריתמים לכריית מידע ונריץ אותם על סט הנתונים שבחרנו. במידה וקיים צורך להתאמת הנתונים לכרייה על פי האלגוריתמים שבחרנו. -הערכת דפוסים / תבניות - זיהוי התבניות, יישום טכניקות הצגת המידע (ויזואליזציה) למשתמשים, שחזור מטה-נתונים (Metadata) כדי להבין את המשמעות של התבניות והדפוסים שנחשפו, הפקת התבניות בעזרת שיטות סטטיסטיות כמו מובהקות סטטיסטית, מעוניינות, חשיבות, רלוונטיות, אפשרות פעולה, וכ'ו. -לעיתים קרובות, לאחר הערכת התבניות נגלה שהמטרה לא הושגה ואנו לא מרוצים מהתוצאות, לכן יש צורך לחזור על חלק מהשלבים. לדוגמה לחזור על שלבי הכנת הנתונים (1-4) ולהכין אותם בצורה שונה, לחזור על שלב 5 ולבחור סט נתונים קצת שונה, הרצת אלגוריתם אחר או עוד אחד, או שינוי הפרמטרים שלו (שלב 6), ועוד. - - - -3. מודלים ואלגוריתמים - -המודלים בתחום כריית המידע נחלקים ל-3 קטגוריות: - -מודלי קופסא לבנה - מודלים מוכרים בהם אנו לא זקוקים לנתונים חדשים על מנת ללמוד את המודלים האלו. המודלים ידועים והתגלו בעבר, וכל שאנו עושים (באמצעות הנתונים) הוא לאושש את אותם מודלים (לדוגמה מודלים המאששים חוקים פיזקליים, המודלים מגיעים מתוך נתונים שהגיעו מעריכת ניסויי מעבדה). -מודלי קופסא אפורה - אנו כן יודעים את הצורה הכללית של המודל (לדוגמה מודל לרגרסיה לינארית, Y = ax + b). אך אנחנו לא בטוחים לגבי הפרמטרים השונים של המודל. גם מודלים אלה יחסית קלים לחישוב, ולכן רוב הזמן כשנדבר על אלגוריתמים לכריית מידע נתכוון להפקה של המודלים השחורים. -מודלי קופסא שחורה - מודלים מורכבים לדוגמה מודל של רשת נויירונים (ANN, ראשי תיבות: Artificial Neural Network). מודלים שקשה להבינם, מורכבים מעשרות או מאות אלמנטים שונים. - - -חשוב לציין כי תחום כריית המידע צמח מתחומים קיימים כמו זיהוי תבניות (הכולל זיהוי תווים, אובייקטים, פנים וכד'), Machine Learning (למידה מניסיון, וההנחה שככל שנצבור יותר ניסיון, יהיו יותר נתונים, נפיק יותר ידע לגבי התהליך הנחקר), סטטיסטיקה והסתברות (למידה מידע לא מושלם, רועש), אלגוריתמים ותאוריות חישוב מורכבות, תורת הבקרה (איזון של התהליך מתוך פידבק חוזר), תאוריית האינפורמציה, ועוד. - -בכנס ICDM שנערך בדצמבר 2006 (אחד מהכנסים הראשיים לכריית מידע), נערכה הצעה לאלגוריתמים השימושיים ביותר בתחום. ולהלן הטבלה למטה (בצירוף הבעיה הנפתרת ע"י כל אחד מהאלגוריתמים): - -סוג הבעיה שהאלגוריתם פותר Algorithm Rank -עצי החלטה C4.5 1 -ניתוח אשכולות K-Means 2 -סיווג ורגרסיה SVM 3 -חוקי הקשר Apriori 4 -ניתוח אשכולות EM 5 -כרייה באינטרנט PageRank 6 -Ensemble learning AdaBoost 7 -למידה מבוססת תצפיות Knn 8 -למידה בייסיאנית Naive Bayes 9 -עצי החלטה CART 10 - - - - - - - Decision Tree - -ישנן כמה שיטות לכריית מידע, אחת משיטות הסיווג המצויות בשימוש היא עץ החלטה. כדי לקבל מושג קל, נציג עץ החלטה כזה ונסביר את המונחים הקשורים אליו. עץ הוא מבנה אבסטרקטי המתאר היררכיה בין אובייקטים. בעץ ישנם קודקודים (צמתים) עם קשר אב-בן, דוגמה לעץ כזה היא אילן יוחסין. קיימים אלגוריתמים שונים לבניית עצי החלטה (נדבר עליהם בעתיד). אך על עץ החלטה יכיל את המבנה הבא: - -שורש - קודקוד (צומת) ללא אב. בדוגמה משמאל זהו A. -בן - קודקוד G הוא בן של קודקוד C אם יש קשת מ C ל G. -אב - קודקוד C הוא אב של קודקוד G, אם יש קשת מ C ל G. -עלה - קודקוד ללא בנים. לדוגמה G. -קודקוד פנימי - קודקוד שאינו עלה ושהוא אינו שורש, כלומר יש לו אב ולפחות בן אחד. לדוגמה C, F, B. -צאצא - קודקוד I הוא צאצא של B, אם יש מסלול אבות-בנים מ B ל I. -אב קדמון - קודקוד B הוא אב קדמון של J, אם יש מסלול של אבות-בנים מ B ל J. -תת עץ - תת עץ המורש מ B, זהו עץ ש B הוא שורש שלו, ומכיל את כל הקודקודים ש B הוא אב קדמון שלהם ואת הקשתות ביניהם בעץ המקורי. -את העץ נקבל כתוצאה משימוש באלגוריתמים לבניית עצי החלטה (לא נציין אותם כרגע). כל קודקוד בעץ הוא שאלה שאנו צריכים לענות עליה ולפיה ללכת לבן המתאים, וכל עלה הוא תוצאה אפשרית (חיזוי). - -ישנם מודלים נוספים של כריית מידע כמו אשכול (Cluster). אשכול הוא קבוצה של רשומות בעלות מאפיינים דומים. ניתוח אשכולות הוא פילוח רשומות בבסיס נתונים לאשכולות, כך שבכל אשכול נמצאים רשומות בעלות מאפיינים דומים. לדוגמה, ניתן לפלח את הסטודנטים לפי ההישגים שלהם (מצטיינים, טובים, בינוניים, וחלשים) באו"פ. דוגמה נוספת יכולה להיות פילוח הסטודנטים לפי אזורי מגורים. ישנו גם מודל רגרסיה (Regression). שהיא שיטה סטטיסטית המשמשת לבדיקה ולניבוי של קשרים בין שני משתנים (או יותר) (שיטה זו מצויה בשימוש נרחב במחקרים כמותיים בתחומי הדע השונים. הרגרסיה הפשוטה ביותר היא רגרסיה לינארית עם שני משתנים: משתנה מסביר ומשתנה מוסבר). - - - -4. מחסן נתונים מול מסד נתונים - -מערכת מסד נתונים (נקראת גם Database Management System או DBMS) מכילה אוסף של נתונים הקשורים זה לזה, הידועים גם כ"מסד נתונים", וסט של כלים / תוכנות לניהול וגישה לנתונים. התוכנות מספקות מנגנונים להגדרת מבנה ואחסון מסד הנתונים, לציון וניהול בו זמני, שיתוף או גישה מבוזרת לנתונים, והבטחת עקביות וביטחון של הנתונים המאוחסנים על אף קריסות מערכת או ניסיונות גישה לא מורשים. DBMS כזה נקרא גם בסיס נתונים תפעולי, ומשמש לביצוע ותיעוד הפעילות השוטפת של הארגון. העיבוד בו מכונה עיבוד תפעולי מקוון או OLTP (ראשי תיבות: Online Transactional Processing). - -לעומתו, קיים סוג נוסף של בסיס נתונים המשמש לעיבוד ולניתוח נתונים שהצטברו במערכות קיימות, ובדרך כלל מדובר במערכות תפעוליות. בבסיסי הנתונים האלו מתבצעת אינטגרציה של נתונים ממערכות שונות (תוך כדי טיפול בשמות שונים של אותם משתנים, יחידות מידנה שונות, מפתחות שונים וכד'). נתונים אלו מאוחסנים בצורה סיכומית ובחתכים המקלים על תהליכי העיבוד והניתוח, והנתונים יציבים יחסית ומעודנים בתידורת שנקבעת מראש (הנתונים נשמרים לפרקי זמן ארוכים יותר מב DBMS, ואינם מתעדכנים באותה תדירות, ובטח שלא בזמן אמת, כמו ה DBMS). בסיס נתונים זה נקרא מחסן נתונים או DW (ראשי תיבות: Data Warehouse), והעיבוד המבוצע ע"י DBA, כדוגמת עיבוד שאילתות והפקת דוחות, מכונה עיבוד אנליטי מקוון או OLAP (ראשי תיבות: Online Analytical Processing). - -bill inmon (אחד מהאבות של התחום) מגדיר את מחסן הנתונים כמאגר נתונים המוכוון לנושא מסויים, ומשלב נתונים ממוקורות שונים. הנתונים הינם תלויי זמן ובלתי נדיפים (אינם ניתנים למחיקה). המטרה של מחסן נתונים שכזה הוא לתמוך בתהליך קבלת ההחלטות של ההנהלה. ולרוב מקושר לנושא מסויים (שיווק, רכישה, ייצור, בקרת איכות וכ'ו). - - - -קוביית מידע - - Data Cubeמודל הנתונים עבור OLAP הוא מודל רב מימדי. כלומר, מסתכלים על המידע מנקודת המבט של מדד כמותי אחד שמעניין את המשתמש לפי ממדים - חתכים שונים. במחסן הנתונים עשויים להיות מספר מדדים שמעניינים את המשתמש, ולכל אחד מהם כמה מדדים. עיבוד נתוני מחסן הנתונים מתבצע על ידי משתמש הקצה באמצעות כלי OLAP, כשהנפוץ בינהם הוא קוביית מידע (Data Cube). בצד שמאל ישנה דוגמה לקוביית מידע בה אנו מתארים את נפחי המכירות בחברה Sony כפונקציה של מוצרים (טלוויזיות, מחשבים וכד'), רבעונים, וארצות (ארה"ב, קנדה, ומקסיקו). ממדי הנתונים מוגדרים באופן הבא: מיקום, מכירה, זמן. - -* אציין כי ניתן ליצור קוביות מידע בעלות יותר מ-3 ממדים, אך כמובן שלא נוכל לתאר אותן באופן וויזואלי כמו שאנו ממחישים בצד שמאל קובייה בעלת שלושה מימדים. - - - -ניתן לבצע מגוון פעולות על הנתונים שבמחסן המידע. נראה את הפעולות, ונייצג אותן באמצעות קוביית המידע: - -Roll up (או Drill up) - פעולה המיועדת לסיכום הנתונים, ז"א סיכום הנתונים ברמה גבוהה יותר (לדוגמה: במקום ברבעונים, בשנים). -Roll down (או Drill down) - פעולה הפוכה המיועדת לעבור מרמת סיכום גבוהה לרמת סיכום נמוכה (לדוגמה: מרמת רבעונים לרמת חודשים, או מרמה של קטגוריות מוצרים לדגמים ספציפיים). -Slice and Dice - פעולה בה אנו מחפשים שילוב בין ערכים של שני מימדים שונים. ב Slice אנו מגבילים את עצמנו לערכים של מימד אחד, וב Dice אנו משלבים לפחות 2 מימדים. -Pivot (או Rotate) - בפעולה זו אנו רק משנים את ההצגה של הנתונים (מסובבים את הטבלה ב-90 מעלות, על מנת להקהל על המשתמש). -Drill Across - כאשר אנו עוברים מטבלת עובדות אחת לטבלת עובדות נוספת (נרחיב על טבלת עובדות בהמשך). -Drill Through - כאשר אנו מגיעים לרמה הנמוכה ביותר של הנתונים הגולמיים. - - -5. תורת האינפורמציה - -קלוד שאנון אבי תורת האינפורמציה פרסם את המאמר "The mathematical theory of communication" ב-1949 שהיווה את היסוד לתורה זו, ובו הנחיל את המושגים הבסיסיים שאנו משתמשים בהם עד היום. תורת האינפורמציה פותחה במטרה לטפל בהעברת מידע במערכות תקשורת. המרכיבים העיקריים שלה הם קידוד מקור וקידוד ערוץ עבור משתנים מקריים בדידים. - -העברה יעילה של מידע דיגיטלי דרך ערוץ רועש ומבובש מבוצעת ב-2 שלבים עיקריים: 1. קידוד מקור - נדחס את המידע הגולמי המיועד להעברה ע"י ניצול התכונות הסטטיסטיות שקיימות בו, ונקודד אותו. 2. קידוד ערוץ - נוסיף למידע המועבר אינפרמציה יתירה, כך שמקבל המידע בצד השני של הערוץ הרועש יוכל לנקותו מרעשים. - -תורת האינפורמציה מספקת לנו מסגרת פורמלית כדי למצוא ולהעריך תבניות (שזהו המטרה העקרית שלנו בכריית מידע, למצוא תבניות ובעזרת קריטריונים אובייקטים להעריך אותם כדי למצוא את התבניות האינפורמטיביות ביותר, ולהעריך את מידת האינפורמטיביות שלהם ביחס לתבניות אחרות שמצאנו / שנמצאו בעבר). באמצעות תורת האינפורמציה ניתן להגדיר מדדים לשימושיות ולנצילות של טכניקות ומודלים שונים בכריית מידע. לדוגמה, בעת בניית עץ החלטה (נושא שנרחיב עליו בהמשך) נסתייע במדד האנטרופיה לקביעה מהי התכונה המפצלת בעץ ההחלטה. - - - -מדידת חוסר ודאות - -חוסר ודאות זה מושג הקיים בכל עסק. המטרה של כריית המידע היא לספק מידע שיפחית את חוסר הוודאות הקיים בקבלת ההחלטות בארגון. לדוגמה אם התבצעה פעולה בכרטיס אשראי, כיצד חברת האשראי יכולה לקבוע האם הפעולה חוקית או לא? זהו מצב של חוסר ודאות. ונשאלת השאלה כיצד ניתן למדוד חוסר ודאות? האם יש איזשהו מדד שמבחין בין אירועים עם אי ודאות גבוהה לאי וודאות נמוכה? נתחיל בכך שאם אנו יכולים לחזות את התוצאה בודאות של 100% ברור לנו שחוסר הודאות שווה ל-0. בנוסף, אי הודאות עולה כאשר מספר האופציות האפשריות עולות. ולבסוף, לאותו מס' תוצאות אפשריות, אי הודאות היא מקסימלית אם קיים אותו סיכוי (אותה הסתברות) לכל תוצאה אפשרית. - - - -אנטרופיה - -מדד האנטרופיה עוזר לנו להעריך את אי הודאות של משתנה מקרי כלשהו (X) (משתמשים במושג זה גם בפיזיקה, בתרמודינמיקה). האנטרופיה נחשבת מדד לאי ודאות על קבוצת מצבים אפשריים, והיא אינה תלויה בערכים שהמשתנה מקבל אלא רק בפונקצית ההתפלגות שלו. האנטרופיה של משתנה מקרי בדיד מקבלת ערך מינימלי יחיד כאשר אי הודאות מינימלית, וערך מקסימלי עבור אי ודאות מקסימלית. אנטרופיה של התפלגות כלשהי מהווה מדד למרחק סטטיסטי שבין התפלגות נתונה לבין התפלגות אחידה. יש לציין כי אנטרופיה היא בעלת ערכים חיובים בלבד ונמדדת ביחידות nats (כאשר משתמשים בבסיס הטבעי של הלוגריתם) או bits (כאשר משתמשים בבסיס 2). - -האנטרופיה מוגדרת כ- (H(X) = Σ-p(x)logp(x. נציין כמה תכונות של הנוסחה: - -המינוס נמצא שם כדי לספק תוצאה חיובית (הסתברות היא תמיד בין 1-0 ולוגריתם של מס' בטווח הזה יתן מס' 0 או שלילי). -התוצאה של האנטרופיה, (H(X, תיהיה שווה ל-0 אם"ם (אם ורק אם) האירוע וודאי (אירוע בעל תוצאה אפשרית אחת בלבד). -הערך המקסימלי שאנטרופיה יכולה להגיע אליו שווה לוגריתם של מס' התוצאות האפשריות. -אם לכל התוצאות יש את אותה הסתברות, האנטרופיה הוא פונ' מונוטונית עולה של מס' התוצאות. -Entropy Exampleבדוגמה לחישוב אנטרופיה בתמונה משמאל אנו מחשבים את האנטרופיה לבדיקה רפואית, אנו רואים בטבלה הראשונה שלנבדק אחד יצאה תוצאה שלילית ובכל זאת חלה, ל-3 יצאה תוצאה שלילית בבדיקה ואכן אינם חלו, ל-4 יצאה תוצאה חיובית ואכן חלו, ול-2 יצאה תוצאה חיובית אך לא חלו. בטבלה השניה אנו מחשבים את האנטרופיה של הבדיקה, ז"א 6 חלו ו-4 לא, לכן האנטרופיה של הבדיקה היא 0.971. בניגוד לכך, בטבלה השלישית אנו מחשבים את האנטרופיה של המחלה, בה 5 אנשים חלו, ו-5 אנשים לא. מצב כזה (שבו לכל תוצאה יש אותה הסתברות) מביא אותנו לאנטרופיה המקסימלית (במקרה הזה 1). - - - -אנטרופיה מותנית - -אנטרופיה מותנית (Conditional Entropy) היא מדד לאי ודאות של Y בהינתן X, ז"א אנו משתמשים במשתנה אחר (X) על מנת לצמצם את אי הודאות שיש לנו במשתנה Y. לדוגמה, אם אנו רוצים למדוד האם הפעולה הנוכחית בכרטיס אשראי היא חוקית או לא, אנו יכולים להיעזר במיקום הפעולה הקודמת של הלקוח כדי לקבוע האם הפעולה הנוכחית היא חוקית או לא. האנטרופיה המותנית מוגדרת כ- (H(Y/X) = -∑p(x,y)*logp(y/x. כאשר (p(x,y היא הסתברות משותפת (ההסתברות ששתי אירועים יקרו ביחד. לדוגמה גם שהתוצאה של הבדיקה תצא שלילית וגם שלבן אדם אין מחלה), ו (p(y/x היא הסתברות מותנת (ההסתברות שיקרה אירוע y, בהינתן x. לדוגמה ההסתברות להיות חולה בהינתן תוצאה שלילית). - -Conditional Entropy Example Oneחשוב לציין כי לא ניתן לעלות את אי הודאות, ז"א שאם, לדוגמה, אנו רוצים לחזות את ממוצע הציונים של סטודנט באונ', ומספקים לנו נתון של מידת הנעלים של הסטודנט, די ברור שמידת הנעלים לא קשורה לציון הממוצע של הסטודנט באונ'. אך נתון זה לא יעלה את אי הודאות (רוב הסיכויים שהיא תישאר אותו הדבר). במצב שאין השפעה של המשתנה (קיימת אי תלות בין המשתנים), האנטרופיה המותנית שווה ל-0 (שווה לאנטרופיה של Y). - -בתמונה משמאל ניתן לראות דוגמה לאנטרופיה מותנית. השתמשנו באותם נתונים מהדוגמה הקודמת (הטבלה הראשונה זהה), בטבלה השניה אנו מחשבים את ההסתברות המשותפת, בטבלה השלישית את ההסתברות המותנת (ליד כל תוצאה יש הסבר כיצד היא חושבה), ובטבלה הרביעית אנו מחשבים את האנטרופיה המותנית (המשוואה כולה), ומקבלים את התוצאה 0.875. - -לעומת זאת אם היינו מחשבים את ההסתברות המותנת של הבדיקה בהינתן המחלה (ולא כפי שעשינו מקודם, בתמונה משמאל), הטבלה הראשונה והשניה היו נשארות זהות, אך בטבלה השלישית והרביעית הינו מקבלים ערכים שונים. בסופו של דבר במקום 0.875 (כתוצאה סופית) היינו מקבלים 0.846. כשהתוצאה גבוהה יותר זה אומר שהגורם שבחרנו כגרום מסביר משפיע פחות על המשתנה התלוי. - -בכריית מידע אנו בוחרים באיזשהו משתנה תלוי (שאנו רוצים לחזות אותו) ולאחר מכן אנו מנסים למצוא אלגוריתם שיבנה את המודל הטוב ביותר, שיביא למינימום את האנטרופיה המותנית של המשתנה התלוי. אם למשל היינו רוצים, עפ"י הנתונים למעלה לבנות מודל שנותן חיזוי לגבי מחלה של אדם מסוים לפי תוצאות של בדיקה בודדת, ככל שהיינו מקבלים אנטרופיה מותנית נמוכה יותר כך היינו יודעים שהמודל שמצאנו הוא טוב יותר. - - - -אינפורמציה הדדית - -כמו שאמרנו בסעיף למעלה, ככל שאנו יודעים יותר על המשתנה התלוי כך האנטרופיה של אותו משתנה תפחת. ההפרש בין האנטרופיה הבלתי מותנית (שלרוב גבוהה יותר) לאנטרופיה המותנית מודד את הצמצום באי הודאות של משתנה מסוים (המשתנה התלוי) כתוצאה מהידע שלנו על משתנה נוסף, וההפרש הזה נקרא אינפורמציה הדדית (המכונה לעיתים גם אינפורמציה משותפת או Mutual Information). - -הנוסחה של האינפורמציה ההדדית היא [(I(X;Y) = H(Y) - H(Y/X) = ∑p(x,y)*log[p(y/x)] / [p(y. אם שני המשתנים (x ו y) אינם תלויים אחד בשני נקבל אינפורמציה הדדית ששוה ל-0, לעומת זאת כשהמידע שלנו ב x מעלה את ההסתברות של y נקבל תוצאה גדולה מ-1, וכמובן יכול להיות מצב הפוך בו נקבל תוצאה נמוכה מ-1 (לדוגמה, כאשר בדיקה מורידה את הסיכוי לחלות במחלה כלשהי). - - - -אינפורמציה הדדית מותנית - -המטרה של אינפורמציה הדדית מותנית הוא לחשב את הירידה באי ודאות של משתנה כלשהו x כתוצאה מהידע שלנו לגבי משתנה y, כאשר נתון משתנה נוסף, z. הנוסחה של מושג זה מוגדרת כ {[(I(X;Y/Z) = H(X/Z) - H(X/Y,Z) = ∑p(x,y,z)*log{[p(x,y/z)]/[p(x/z)*p(y/z. דוגמה לאינפורמציה הדדית מותנית יכולה להיות כאשר x היא איזשהי מחלה, y ו z הן תוצאות של בדיקות רפואיות כלשהן. יש לנו תוצאה של בדיקה אחת, z, ונשאלת השאלה האם בדיקה נוספת, בדיקה y, תעזור לנו, ז"א תוריד את רמת האי ודאות לגבי המחלה. - - - -6. תקשורת - -בחלק זה נדבר על ההקבלה של בעיות מתחום התקשורת ובעיות בתחום כריית המידע, אותן בעיות שבגללן שנון פיתוח את תורת האינפורמציה. המטרה של תקשורת נתונים היא לשחזר ביעד את ההודעה שנבחרה (או נוצרה) בנק' המוצא, באופן מדויק (או מקרוב). התקשורת מתבצעת באמצעות קידוד המידע, ז"א מיפוי סדרת סימנים לסימני קוד של המחשב. המטרות העקריות של הקידוד הן: - -דחיסת המידע (על מנת להקטין את נפחי האחסון ומשאבי התקשורת). -חסינות מפני רעשים. -הצפנה. -תרגום המידע לקוד מחשב. -בעיית דחיסת המידע היא אחת הבעיות העיקריות בתקשורת נתונים. שנון הגיע למסקנה שעל מנת לצמצם את מס' הספרות הבינאריות הדרושות לקידוד של הודעה אקראית למינימום צריך להשתמש ב (log(pi- (כאשר i היא ההודעה, ו pi הוא ההסתברות של ההודעה i) ביטים על מנת לשדר אותה (נקצה קודים קצרים יותר להודעות הנשלחות בצורה תקופה יותר, ולהפך). כך שהממוצע של הודעה אקראית יהיה (H(X) = ∑-p(xi)*log p(xi (שימו לב כי זאת הנוסחה של האנטרופיה), וזהו מס' הביטים המינימלי הממוצע הדרוש לנו כדי לשדר הודעות אקראיות ממקור המידע ליעד כלשהו. - - - -העברת מידע בערוץ רועש - -חסינות המידע לרעשים בסביבה מתאפשרת ע"י הוספת מידע יתיר (redundant) המאפשר לבצע שחזור של הההודעה המקורית למרות הרעשים שנלוו אליה. מנגד, הוספת המידע היתיר מאט את קבצ העברת המידע. על מנת להביא לאופטימום את קצב העברת המידע, יש להתאים את כמות המידע היתיר לרעש. באופן דומה, נניח שהתקבל מידע (תצפיות) ממקור רועש. גודל המדגם (מס' התצפיות) הוא סופי, וברצוננו למצוא פונ' או מודל שיתאר את התפלגות המידע שממנו נוצרו התצפיות ולא את התצפיות המסוימות שקיבלו. - -עבור כל מודל שנבנה, נבחין בין השגיאה על התצפיות שהתקבלו (נקראת שגיאת אימון) לבין השגיאה הממוצעת על כל התצפיות שיכולנו לקבל (שגיאה הכללה). התאמת יתר (over fitting) היא מצב שבו משיגים שגיאת אמון קטנה על חשבון שגיאת הכללה. בהתאמת יתר נפגמת יכולת החיזוי של המודל (המודל ישגה יותר בעת קבלת דוגמאות חדשות מההתפלגות המקורית). ומכאן שיש למצוא את שביל הביניים בין מודל מורכב ומסובך המתאר את המידע הנתון בדיוק רב ביותר, לבין מודל פשוט בעל יכולת הכללה גדולה יותר. - - - -7. הגישות השונות של כריית מידע - -ישנן כמה גישות לכריית מידע, כולן מבוססות באופן ישיר על תורת האינפורמציה. - -גישת אי הוודאות - ההנחה היא שכריית המידע מצמצמת את אי הוודאות לגבי משתנים מסויימים (משתני מטרה / חזויים). אחת הדרכים לייצג את אי הוודאות היא ע"י האנטרופיה (ז"א לפתח אלגוריתמים המביאים למינימום את האנטרופיה של המשתנה התלוי, או למקסימום את האינפורמציה ההדדית בין המודל למשתנה התלוי). קיימים לא מעט אלגוריתמים בכריית מידע המיועדים למזער את האנטרופיה כמו ID3 (לבניית עצי החלטה) או C4.5 (גם הוא לבניית עצי החלטה), IFN (לבניית רשתות אינפו-עמומות), ועוד (בהמשך נרחיב עליהם). -דחיסת מידע - בגישה זו אנו מניחים שמודלים קטנים יותר של כריית מידע מובנים יותר למשתמש, למשל עץ החלטה של 10 קודקודים הינו שימושי ומובן יותר מאשר עץ החלטה של 100 או 200 קודקודים. עפ"י גישה זו, המטרה של כריית מידע היא לדחוס את הנתונים ע"י מציאת מודל מסויים שמייצג את הנתונים (אלגוריתמים של כריית מידע אמורים לבחור בהשערה שיש לה אורך תיאור מנימלי, ז"א לבחור בהשערה (או במודל) המצומצם / קטן יותר - נוסחה קצרה יותר, עץ החלטה עם פחות קודקודים, רשת עם פחות שכבות, וכד'). עקרון זה נקרא גם MDL ומשתמשים בו, למשל, באלגוריתמים המבוססים על חוק בייס. -עקרון ה MDL מייצג את היחס בין סיבוכיות המודל למס' השגיאות שהמודל יעשה בנתוני האימון (ככל שהמודל יהיה מורכב יותר, כך הוא יתאים יותר לנתונים ויהיו בו פחות שגיאות, ומנגד יכול להיות שיהיה לנו מודל פשוט מאוד אך שלא יתאים לנתונים ולא יהיה מדוייק). - - - -לסיכום - -אז דיברנו בכלל על למה לכרות מידע, על הסיבה בגינה אנו מחפשים ידע (תבניות / דפוסים) בבסיסי נתונים. הבנו פחות או יותר מהי כריית מידע, ואת התהליכים שצריך לעבור כדי לבצע את התהליך כולו, כשהחשוב בינהם הוא תהליך ה KDD (תהליך גילוי הידע עצמו - השלב בו אנו מפעלים את האלגורימים על הנתונים הנבחרים). הבנו מהו מחסן נתונים (ואת ההבדל של מושג זה מול מושג ה DBMS). ראינו שלמרות שתחום כריית המידע הינו תחום עצמאי, הוא התפתח כתחום כזה מאמצע שנות ה-90, ומבוסס ברובו על דיסציפלינות אחרות, וותיקות יותר, כשהעקרית בינהם היא תורת האינמפורמציה. - -הזכרנו מושגים בסיסיים וחשובים בתורת האינפורמציה והבנו כיצד הם מתקשרים לכריית מידע (במיוחד בהיבט של צמצום אי הודאות). דיברנו בקצרה על כיצד מתבצעת תקשורת דיגיטלית ואת הבעיתיות של רעש בערוץ תקשורת. ולבסוף דיברנו על 2 הגישות העקריות והשונות בכריית מידע. בפוסט הבא נתחיל להתעמק בתהליכי כריית המידע עצמם. diff --git a/data/_oldPosts/2016-08-21-data-preparation.md b/data/_oldPosts/2016-08-21-data-preparation.md deleted file mode 100644 index 177bc3d..0000000 --- a/data/_oldPosts/2016-08-21-data-preparation.md +++ /dev/null @@ -1,270 +0,0 @@ ---- -title: הכנת הנתונים -author: nirgn -layout: post -summary: "" -category: Data Mining ---- -בפוסט הזה נדבר על בעיות באיכות נתונים, נסקור כמה שיטות לתצוגה גרפית של נתונים, נדבר על שיטות כמותיות לניקוי נתונים, נעבור לשילוב והמרה של נתונים המגיעים ממקורות שונים, נתייחס בקצרה לבעיות של הכנת נתונים תלויי זמן, ולבסוף נעבור על שיטות סיווג וחיזוי, נעריך את הדיוק והשגיאה שלהן ונראה כיצד להשוות בין שיטות שונות שלהן. - -בפוסט הזה נדבר על הנושאים: - -בעיות באיכות נתונים -ייצוג גרפי של נתונים -ניקוי נתונים -שילוב והמרות של נתונים -סיווג vs וחיזוי -מדדים להערכת דיוק ושגיאה -שיטות חיזוי (מודלים של רגרסיה) -השוואה בין מסווגים - - -1. בעיות באיכות נתונים - -כשהנתונים מגיעים מהעולם האמיתי הם לא תמיד "מושלמים", ואנחנו צריכים להתאים אותם למה שהכלים של כריית מידע זקוקים / מבקשים. ז"א לעמוד בתנאים שהכלים מציבים לנו, על מנת שאלה ידעו מה לעשות עם המידע, ויצלחו להפיק ממנו ידע. אז מה הכלים של כריית מידע צרכים? - -דבר ראשון, שהמידע יהיה זמין, כמובן שאם אנו לא יכולים לספק להם את המידע (בצורה שהם מכירים, כמו לדוגמה כ csv או כ arff). -בנוסף, אנו זקוקים לכל המידע בטבלה אחת, ז"א שאם המידע מגיע מכמה מקורות, יש לאחד בין טבלאות המידע. -אנחנו (איש כריית המידע) צריך להבין את המשמעות של כל משתנה (כדי שנוכל לקבוע מראש האם גורם מסויים הוא משתנה מסביר אפשרי או שמדובר במשתנה תלוי - כזה שאנו מעוניינים לנבא). -תחום ההגדרה של כל משתנה צריך להיות מוגדר וידוע מראש (אם מדובר במשתנה קטגורי, אז מדובר על סט ערכים ידוע מראש, לדוגמה ימים בשבוע. או אם מדובר על משתנה רציף, אז מדובר על קטע בין ערך מינימום למקסימום, לדוגמה ציונים ניתנים בתחום של 0-100). -על כל הערכים של המשתנים (בכל אחד מהתצפיות) להיות ידועים מראש, על הנתונים להיות אמינים (המידע יהיה נכון / אמיתי. אנחנו לא מצפים למצוא שגיאות בתוך הנתונים שלנו כשאנו מריצים את האלגו' לכריית מידע), ולבסוף, אין להכיל מידע כפול. - - -מדוע הנתונים ב"עולם האמיתי" "מלוכלכים"? - -במקרים מסויימים נגלה שלפעמים חסרים ערכים מסויימים ברשומות כלשהן. מצב זה קורה כשלא ניתן להשיג את הערך של אותו משתנה בזמן שהנתונים נאספו, כמו לדוגמה שאין לנו את הציון של הסטודנט כל עוד אינו סיים ללמוד את הקורס, וכד'. הבעיות האלו יכולות לנבוע גם מבעיות טכניות (בעיות אנוש, חומרה, תוכנה). בעיות נוספות בנתונים יכולים לנבוע מרעש הנוצר כתוצאה מבעיות טכניות הקיימות בציוד (במידה והנתונים נאספים באופן אוטומטי), ואז בעיה בציוד יכולה לגרום לנו לאסוף נתונים שגויים. כמובן שגם כאן יכולות להתבצע טעויות אנוש (אם זה נתונים המוקלדים למחשב, לדוגמה). לבסוף, הסיבה האחרונה ל"לכלוך" הנתונים היא קיום של מספר מקורות מידע, שיכולים להביל למידע לא אחיד. - -לאור כל זה, לאחר שראינו שהנתונים יכולים להיות חסרים ו/או מלוכלכים (שגויים, לא מדוייקים, וכ'ו). אנו מבינים כי ישנה חשיבות להכנה מוקדמת של הנתונים. הרי שאם אין לנו נתונים איכותיים, קשה לנו לצפות לתוצאות איכותיות מהתליך כריית המידע. תהליך הכנת המידע כולל: ניקוי הנתונים, שילוב נתונים מטבלאות שונות, המרות של נתונים, וצמצום טבלת הנתונים (במידת האפשר). - - - -Histogram2. ייצוג גרפי של נתונים - -לאחר איסוף הנתונים, נציג אותם בצורה גרפית באמצעות היסטוגרמה, תרשים פיזור, ועוד, במטרה לזהות נתונים שיש לנקותם כדוגמת נתונים שמחוץ לתחום או לא עקביים. - -היסטוגרמה -מטרת ההיסטוגרמה (Histogram) היא לעזור לנו לזהות את הערכים בעלי השכיחות הגבוהה ביותר, ערכים נדירים, וערכים הנופלים בתחום שאינו סביר. תרשים ההיסטוגרמיה מתייחס תמיד למשתנה אחד, ובדרך כלל, נבנה אותה עבור משתנה רציף, כאשר התחום מחולק למספר קטעים (בעלי רוחב שווה). בצד שמאל, ניתן לראות דוגמה לניתוח היסטוגרמה. - -נבנה את ההיסטוגרמה עפ"י השלבים הבאים: 1. נסדר את הערכים בסדר עולה. 2. נחלק את תחום הנתונים למרווחים (יש להקפיד שהמרווחים לא יהיו רחבים מידי או צרים מידי, כדי שמצד אחד לא נאבד מידע אך מצד שני שההיסטוגרמה לא תיהיה חלקה. כלל אצבע הוא לקבוע את מספר קבוצות המרווחים כבערך שורש גודל הדגימה). 3. נקבע עבור כל מרווח את התדירות ונבנה את טבלת התדירות הכוללת את המרווח. 4. נשרטט את התפלגות התדירות (ציר x יציין את המרווחים וציר y את התדירויות). - -scatter plotתרשים פיזור -תרשים פיזור (Scatter plot) או תרשים XY מציג את קשרי הגומלין בין הערכים המספריים במספר סדרות נתונים, או שהוא מתווה שתי קבוצות מספרים כסדרה אחת של קואורדינטות XY. בעזרת תרשים פיזור אנו יכולים להסיק מהר מאוד מסקנה כללית לגבי אופי המתאם בין 2 משתנים, אך אנו גם יכולים למצוא ביטוי ע"י נוסחה סטטיסטית בעזרת החלקה של הפיזור. - -לעקומה (או במקרה שלנו, בתמונה משמאל, לקו הישר) קוראים Loess (ראשי תיבות של Local Regression) או בעברית "רגרסיה מקומית". במקרה של רגרסיה לינארית, ניתן לבטא באופן כמותי את הקשר (המתאם) בין שני המשתנים X,Y בעזרת השונות המשותפת (Covariance) שתסומן כ (COV(X,Y. השונות המשותפת היא (COV(X,Y) = E(X,Y) - E(X) * E(Y כאשר E מציין תוחלת (הערכים המתקבלים יכולים להיות בין מינוס אינסוף לאינסוף). כאשר COV(X,Y)=0 המשמעות היא שהמשתנים האקראיים X ו Y בלתי מותאמים. - -מכיוון שהשונות המשותפת תלויה ביחידות המדידה, נגדיר את מקדם המתאם (קורלציה) שיסומן ב p ומהווה סטנדרטיזציה של השונות המשותפת. מקדם המתאם הוא [p(X,Y) = [COV(X,Y)]/[σx*σy כאשר σx ו σy הן סטיות התקן של x ו y (ערכו של מקדם המתאם הוא בין 1- ל 1+). - - - -3. ניקוי נתונים - -בחלק זה אנו מתמקדים בשאלה "כיצד ניתן לשפר את איכות הנתונים?" ונבצע מספר פעולות עקריות על מנת להשיג את מטרה זו: - -נשלים ערכים חסרים - כיצד ניתן להתמודד עם ברשומה מסוימת ישנם מספר משתנים עם ערך לא ידוע? הדבר הקל ביותר הוא להתעלם מאותה רשומה, אך זה אינו מומלץ כי אנו נאבד את כל המידע הקשור אליה. אך לפעמים לא תיהיה לנו ברירה וניהיה חייבים לבצע זאת (לדוגמה, במקרה בו אנו מסווגים את הנתונים, וחסר לנו הנתון לפיו אנו מסווגים את הרשומות). מנגד, אפשר לנסות ולהשלים את הנתון באופן ידני, אך אם מדובר על בסיס נתונים גדול אופציה זו אינה פרקטית כאשר אחוז הנתונים החסרים גדול מידי (או שהנתונים הוזנו לפני זמן רב עד כדי שלא מתאפשר לנו להשלים אותם). לבסוף, אם אין בידנו ברירה אחרת, נשלים את הנתונים באופן אוטומטי - נשתמש בקבוע המייצג את הנתון החסר, או נשלים את הערך החסר באמצעות הערך הממוצע של המשתנים, או אפילו להשלים את הערך החסר באמצעות הערך הממוצע של המשתנים מאותו הסיווג. -נזהה ערכים חריגים ונחליק נתונים רועשים - השיטה המקובלת ביותר להתמודדות עם צמצום השונות בתוך הנתונים היא Binning או חלוקה לקטעים - תיבות. נחלק את התצפיות לתיבות שיהיו בעלי שכיחות שווה, ואז ניתן להחליק את כל התצפיות באותה תיבה לפי הממוצע של התיבה / על פי החציון של התיבה / או הגבולות של אותה התיבה (כל ערך מוחלף בגבול העליון או התחתון של התיבה). ישנן שיטות נוספות להחלקה של ערכים, כמו באמעות מודל של רגריסה בו אנו נבצע שימוש אם יש קשר לינארי בין 2 משתנים, או ב Clustering - חלוקה אשכולות, אם מדובר בנתונים רב מימדיים (נזהה ונסלק תצפיות חריגות). -נסלק רשומות כפולות - נמחק רשומות כפולות, כאלו שנוצרו כתוצאה משילוב של נתונים ממקורות שונים. - - -אוסף הנתונים עשויים להיות רשומה, וקטור, תבנית, מאורע, דגימה, תצפית, ישות ועוד. הנתונים מותארים על ידי מספר תכונות כדוגמת מאפיין, משתנה, שדה, מימד ועוד. - -מקובל להבחין בין תכונות איכותיות המכונות תכונות קטגוריאליות (ארצות, מגדר, שביעות רצון {גבוהה, בינונית, נמוכה}, לבין תכונות כמותיות המכונות תכונות נומריות (ציונים בקורס, גובה, משקל, גיל). כמו כן, מקובל גם להבחין בין תכונות בדידות בעלות אוסף סט סופי ובר מנייה של ערכים (מס' סטודנטים הרשומים בקורס), בין תכונות רציפות בעלות ערכים מספריים ממשיים (משקל), לבין תכונות בינריות שהן מקרה פרטי של של תכונות בדידות, והן בעלות שני ערכים (0 או 1, זכר או נקבה, נכון או לא נכון). - - - -דוגמה ל Bining - חלוקה לקטעים -ל Bining יש 2 גישות. הגישה הראשונה היא 'רוחב שווה' ז"א אותה רוחב לכל קטע/תיבה (ע"י [ערך המקסימום-ערך המינמום] / מס' הערכים הכולל). אך לגישה זו יש חסרון מהותי, שכן אם ערך המקסימום או המינימום יושפעו כתוצאה מערך חריג (הנגרם מרעש), אותו ערך חריג ישפיע על הממוצע השייך לכל הערכים באותו קטע. כדי להתגבר על הבעיה הזו, בגישה השניה, הנקראת 'עומק שווה', אנו לא מחוייבים לאותו מס' של ערכים בכל קטע/תיבה (אך אנו בכל זאת מקפידים פחות או יותר על מספר שווה). - -ערכים לדוגמה: 4,8,9,15,21,21,24,25,26,28,29,34. - -נחלק את הערכים לקטעים/תיבות: - -תיבה 1: 4, 8, 9, 15 -תיבה 2: 21, 21, 24, 25 -תיבה 3: 26, 28, 29, 34 -אם נבצע Bining על פי הגישה השניה (עומק שווה): - -תיבה 1: 9, 9, 9, 9 -תיבה 2: 23, 23, 23, 23 -תיבה 3: 29, 29, 29, 29 -Bining על פי הגישה הראשונה (רוחב שווה): - -תיבה 1: 4, 4, 4, 15 -תיבה 2: 21, 21, 25, 25 -תיבה 3: 26, 26, 26, 34 - - -4. שילוב והמרות של נתונים - - כדי לשפר את היעילות, נעביר את הנתונים לתבנית המיועדת לכריית מידע. תבנית זאת תיהיה קטנה יותר ומייצגת, וקיימות מגוון שיטות לבצע זאת: - -החלקת הנתונים - הסרת רעשים, -קיבוץ הנתונים - לדוגמה, אם אנו מעוניינים בהיקף הרשמות חודשיות לקורסים באונ'. אז נקבץ את נתוני ההרשמות היומיות לנתון מסכם חודשי. -הכללת הנתונים. -מימדים - הפחתה בתכונות. -דחיסת נתונים. -דיסקרטיזציה - העברת נתונים נומריים (רציפים) לערכים קטגוריאליים. אפשר להשתמש בנירמול שבין min ל max, בעזרת הנוסחה הבאה: v' ={[v - minA] / [maxA - minA]} * (new_maxA - new_minA) + new_minA (כאשר new_minA ו new_maxA הם ערכי ה max וה min החדשים). או בשימוש בנירמול המבוסס על ההתפלגות הנורמלית (z-score), בעזרת הנוסחה: v' = (v - uA) / σA (כאשר u הוא הממוצע-תוחלת, ו σ הוא סטיית התקן). - - - 5. סיווג vs וחיזוי - -בבעיית הסיווג (classification) אנו מעוניינים לנבא משתנים קטגוריים (בדידים או נומינליים). הדוגמה הפשוטה ביותר למשתנה כזה היא משתנה בינארי (בעל 2 אפשרויות בלבד), לדוגמה הצלחה בקורס לעומת כישלון בקורס, זכר או נקבה, נכון או לא נכון וכד'. אך משתנים קטגוריים יכולים להיות בעלי יותר מ-2 משתנים. לעומתה בבעיית החיזוי (prediction) אנו מעוניינים לנבא ערכים של משתנים רציפים (כמו ציון של סטודנט בקורס, שער של מטבע וכד'). בעיות טיפוסיות של סיווג יכולות להיות אישור מתן אשראי (אושר / נדחה), אבחון רפואי (צהבת B / צהבת C) וכד', ומנגד בעיות טיפוסיות של חיזוי הן, לדוגמה, חיזוי תוחלת החיים בביטוח רפואי, חיזוי ממוצע ציוני הסטודנט בקבלה לאונ' וכד'. - - - -תהליך הסיווג -תהליך הסיווג מורכב מ-2 שלבים, בשלב בהראשון אנחנו בונים את המודל שאמור לספק תיאור למספר סיווגים שידועים לנו מראש. בשלב בניית המודל אנו משתמשים בתצפיות אימון (ז"א שאנו מחלקים את מאגר המידע שלנו ל-3, כאשר אנו יודעים את הסיווג של 2 החלקים הראשונים. נשתמש בחלק הראשון לבניית המודל, ובחלק השני (שאנו יודעים את הסיווג שלו) לבחינת המודל שבנינו. במידה והמודל תקין וקיבלנו אותו, נשתמש בו על החלק השלישי כדי לנבא (את הסיווג של החלק השלישי אנו לא יודעים, וזה מה שאנו מנבאים)). את המודל ניתן לייצג באמצעות חוקי סיווג, עצי החלטה, או איזשהן נוסחאות מתמטיות. - -התנאי הבסיסי לקבלת המודל סיווג שבנינו הוא שיהיה מדוייק יותר מחוק הרוב (לדוגמה, נניח שאנו רוצים לקבל תחזית האם מחר ירד או לא גשם, נניח גם שב-90% מהמקרים לא יורד גשם. מכאן אנו יכולים לבנות מודל פשוט האומר שמחר לא ירד גשם, וזאת עפ"י ההנחה שרק ב-10% מהמקרים יורד גשם. לכן מודל כזה, שנבא את מזג האוויר ללא קשר, יהיה מדוייק ב-90% מהמקרים). - - דוגמה לבניית מודל הסיווג: נניח שקיבלנו את ה Training Data (החלק הראשון של המאגר, ממנו אנו בונים את המודל) הבא: - -Tenured Years Rank Name -no 3 Assistant Prof Mike -yes 7 Assistant Prof Mary -yes 2 Professor Bill -yes 7 Associate Prof Jim -no 6 Assistant Prof Dave -no 3 Associate Prof Anne -ואנו רוצים לנבא את הערך Tenured, ז"א לנבא אם לפרופ' יש קביעות. ניתן לראות שחוק הרוב במקרה הזה הוא 50% (3 אנשים yes ו-3 no). נרחיב בעתיד כיצד אנו מגיעים למודל, אך מהר מאוד ניתן לראות שחוק כמו 'IF rank = 'professor' OR years > 6 THEN tenured = 'yes יתן לנו דיוק של 100% על תצפיות האימון (כל התצפיות מקיימות אותו). אך זה שהמודל נותן לנו 100% דיוק על תצפיות האימון אין זה אומר שזהו המודל שאנו רוצים מכיוון שאין זה אומר שהוא יתן לנו 100% דיוק על תצפיות המבחן (החלק ה-2 במאגר המידע, שאנו יודעים את הסיווג של התצפיות אך משתמשים בהם לבחינת המודל). אם מתקיים מצב כזה (בו המודל מתאים ב-100% לתצפיות האימון אך לא לתצפיות המבחן מתקיימת בעיית הנקראת המתאמת יתר (Overfitting) עליה נרחיב בהמשך. - -בשלב ה-2 של תהליך הסיווג אנו משתמשים בחלק ה-2 של מאגר התצפיות, ה Testing Data, להלן התצפיות: - -Tenured Years Rank Name -no 2 Assistant Prof Tom -no 7 Associate Prof Merlisa -yes 5 Professor George -yes 7 Assistant Prof Joseph -נפעיל את החוק, ונראה כי החוק אינו מקיים את התצפיות הראשונה (של Tom), מקיים את התצפית השנייה (של Merlisa) בגלל שהוותק שלה גדול מ-6, וזאת הרי טעות (כפי שניתן לראות אין לה קביעות). את התצפית השלישית (של George) והרביעית (של Joseph) החוק מקיים, ואכן יש להם קביעות. לכן, מצאנו חוק שפחות מדויק על נתוני המבחן מאשר על נתוני האימון, אך יותר מדויק מחוק הרוב (המודל שלנו מדוייק ב-75%). ולכן אפשר לשאול האם ההבדל הוא מובהק (מבחינה סטטיסטית) או הבדל שהתקבל באופן מקרי מתוך הנתונים? נחזור לשאלה זאת בהמשך. - -נציין כי עבור בסיס נתונים גדול מקובל לחלק את הנתונים כך ש-2/3 יהוו נתוני אימון, ו-1/3 יהיו נתוני מבחן. עבור בסיס נתונים בינוני, מקובל לחלק את הנתונים ל-k תת דגימות, כאשר (k-1) תת דגימות יהוו נתוני אימון ותת דגימה אחת תהווה נתוני מבחן. ועבור בסיס נתונים קטן, מקובל להשתמש בגישת Bootstrap עליה לא נרחיב. - - - -6. מדדים להערכת דיוק ושגיאה - -בשלב זה, לאחר שבנינו את מודל הסיווג, המטרה שלנו היא להעריך את אחוז הדיוק של המודל, ונעריך אותו תוך התייחסות לנושאים כגון דיוק הסיווג, מהירות וסקלביליות (יכולת המסווג להתמודד עם כמות גדולה של נתונים), שרידות ועמידות (טיפול בנתונים רועשים וערכים חסרים), יכולת אינטרפרטציה, וכ'ו. - -ניקח לדוג' את בסיס הנתונים לרכישת מחשב, לאחר שהפעלנו עליו מודל סיווג, ונייצג את הנתונים באמצעות מטריצת הצלבה (confusion matrix) (השורה הראשונה היא החיזוי של המודל שלנו על נתוני המבחן, והעמודה הראשונה היא התוצאות האמיתיות של נתוני המבחן): - -(%) recognition total buy_computer = no buy_computer = yes -Predicted class - -Actual class - -99.34 7000 46 6954 buy_computer = yes -86.27 3000 2588 412 buy_computer = no -95.42 10000 2634 7366 total -אחוז השגיאה (Error rate) של המודל, הוא 1 פחות גובה הדיוק [(acc(M] (כלומר, במקרה שלנו 412+46 מתוך 10,000 נגיע לאחוז השגיאה של המודל). - -בנוסף למדד אחוז השגיאה ולגובה הדיוק, ישנם מדדים נוספים: - -מדד הרגישות (sensitivity) - המחושב ע"י TP/P (ראשי תיבות של True_Positive ז"א אלה שהמודל צפה שיקנו מחשב ובאמת קנו מחשב, חלקי Positive ז"א כל אלה שבאמת רכשו מחשב). במקרה שלנו אנו נחשב 6954/7000 ונקבל 99.34%. -מדד הייחודיות (specificity) - המחשוב ע"י TN/N (ראשי תיבות של True_Negative ז"א אלה שהמודל צפה שלא יקנו מחשב ובאמת לא קנו מחשב, חלקי Negative ז"א כל אלה שבאמת לא קנו מחשב). במקרה שלנו אנו נחשב 2588/3000 ונקבל 86.27%. -מדד המדויקות (precision) - המחשוב ע"י (TP/(TP+FP (ראשי תיבות של True_Positive, חלקי True_Positive ועוד False_Positive - אלה שהמודל שלנו צפה שיקנו מחשב אך לא באמת קנו מחשב). במקרה שלנו אנו נחשב (6954+412)/6954 ונקבל 94.41%. -מדד הדיוק (accuracy) - המחשוב ע"י (TP+TN)/(P+N), ז"א True_Positive ועוד True_Negative חלקי כל ה Positive ועוד כל ה Negative. במקרה שלנו אנו נחשב (10000)/(6954+2588) ונקבל 95.42%. - - -עקומת ROC -ROC CurvesROC אלה ראשי תיבות של Receiver Operating Characteristics (עקומות מאפייני קליטה והפעלה), ונשתמש בהם על מנת לבצע השוואה וויזואלית בין מודלים שונים לסיווג. כמו שניתן לראות בתמונה משמאל, העקומה מציגה את הקשר / תמורה בין אחוז ה True Positive ל False Positive. - -כדי לבנות את העקומה אנו לוקחים את תצפיות המבחן ומדרגים אותם עפ"י סדר יורד של ההסתברות להשתייך לסיווג החיובי. כלומר, אם נסתכל על ציר ה x של עקומת ה ROC אנו נראה בצד שמאל (של ציר ה x) את התצפיות בעלות הסיכוי הגבוהה יותר להיות תצפיות חיוביות עפ"י המודל. במקרה הטוב ביותר נקבל עקומה הקרובה מאוד לזווית ישירה, ושטח של 1 (מתחת לעקומה), אך אם המודל אינו משפר את הדיוק (מודל אקראי - אין קשר בינו לבין המציאות) נקבל את כל התצפיות על קו האמצע (קו 45 מעלות), ובמקרה זה אין הבדל באחוז השגיאה לגבי תצפיות בעלות סיכוי גבוהה להשתייך לסיווג החיובי לעומת תצפיות שיש להן סיכוי נמוך להשתייך לאותו סיווג. - - ככל שהעקומת ה ROC שלנו תעלה מעל קו 45 מעלות ותתקרב לזווית הישרה, כך נקבל שטח גדול יותר (מתחת לקו), וזה אומר שהמודל שלנו יהיה מדוייק יותר. - - - -מדדים להערכת החיזוי -בבעיות חיזוי אנו מנסים לנבא ערך של משתנה רציף, ובדרך כלל הערך החזוי יהיה שונה מהערך בפועל, ואז אנו בודקים את המרחק (או ההפרש) בין שתי הערכים. קיימות 2 פונקציות הפסד: הראשונה היא 'שגיאה אבסולוטית' (Absolute Error) ומחושבת כ |'yi - yi| (כאשר yi הוא הערך בפועל, ו 'yi הוא הערך החזוי), והפונ' השניה היא 'שגיאה ריבועית' ומחושבת כ 2^('yi - yi). שימו לב כי 2 הפונ' מבטלות ערכים שליליים, ז"א שאין הבדל אם הערך החזוי קטן מהערך בפועל או להפך. להלן דוגמה לחישוב מודל חיזוי הנבא היקף מכירות בפועל כתלות בהשקעה בפרסומות: - -השקעה בפרסומת היקף מכירות בפועל היקף מכירות חזוי Abs. Error Sq. Error -1 5 5.6 0.6 0.36 -2 8 7.2 0.8 0.64 -3 9 8.8 0.2 0.04 -4 10 10.4 0.4 0.16 - - -בהינתן מאגר תצפיות מסויים, נשאלת השאלה כיצד נעריך את הדיוק של המסווג או של מודל החיזוי? - -הגישה הפשוטה ביותר לביצוע הערכה כזאת נקראת Holdout method, ובה יש לקחת את כל התצפיות העומדות לרשותנו (אלה שאנו כן יודעים את הסיווג או את הערך של משתנה המטרה) ומחלקים ל-2 קבוצות. קבוצה ראשונה היא קבוצת האימון (לדוג' לקחת 2/3 מהתצפיות לקב' האימון ולהשתמש בהם על מנת לבנות את המודל) יתר התצפיות ישמשו כקבוצת המבחן (לדוג' אם לקחנו 2/3 לקב' האימון, ניקח את ה1/3 הנותרים כקבוצת המבחן ונעריך את דיוק המודל על פיהם) (כמובן שהחלוקה צריכה להיות אקראית). - -שיטה מתקדמת יותר (וגם מקובלת יותר) נקראת Cross Validation (או k-fold), ובה לוקחים את כל התצפיות ומחלקים אותם ל k קבוצות שונות (כשה k המקובל הוא 10), פחות או יותר שוות. לאחר החלוקה, מריצים את האלגוריתם k פעמים, כאשר בכל איטרציה, i, קבוצה מס' i משמשת כקבוצת המבחן, ושאר התצפיות הנמצאות ביתר הקבוצות משמשות כקבוצת האימון. שיטה זה מדוייקת יותר מ Holdout ולכן גם מקובלת יותר. - - - -Linear Regression7. שיטות חיזוי (מודלים של רגרסיה) - -רגרסיה לינארית -המטרה של המודל היא לחזות ערכים של משתנה y על סמך של משתנה אחר (x) (כאשר הוא מניח ש-2 המשתנים רציפים). המודל הינו מסוג Yi = a + bXi + ei (כאשר e היא טעות אקראית), להלן דוגמה: Y=5 + 2x +e. בתמונה משמאל ניתן לראות דוגמה לשימוש במודל רגרסיה לינארית פשוטה, כאשר הקו מייצג את הפולינום והנק' מייצגות את הנתונים האמיתיים. - -המרכיבים של המודל הם: - -X ו Y - כש X הוא המשתנה הבלתי תלוי, הגורם שאנו מניחים שמשפיע על המשתנה התלוי, Y. -a - השיפוע (קבוע). -b - מקדם הרגרסיה. -e - השגיאה אקראית (אנו מניחים שישנם גורמים נוספים - לא ידועים לנו, ואנו מביאים אותם לידי ביטוי בשגיאה האקראית). -Least Squares Approachברגרסיה, כאמור, יש לנו את Yi שהוא הערך האמיתי, ואת 'Yi שאותו אנו מחשבים כפי שאמרנו [Yi = a + bXi]. ומטרתנו היא להעריך את הפרמטרים של קו הרגרסיה, a ו b. הגישה המקובלת ביותר לחישוב מקדמי הרגרסיה נקראת גישת הריבועים הפחותים (Least Squares Approach) וניתן לראות את 2 הנוסחאות שלה בתמונה משמאל. עפ"י גישה זו אנו רוצים להביא למינימום את סכום ריבועי השגיאה בין הרגרסיה לנקודות בפועל. רוב התוכנות הסטטיסטיות היום (כולל Excel) יודעות כבר לבצע את החישובים האלו, כך שלא נצטרך לבצע את העבודה השחורה בעצמנו. - -Multiple Linear Regressionאת מודל הרגרסיה הלינארית ניתן להרחיב לכמה משתנים (נקרא גם רגרסיה לינארית רבת משתנים - Multiple Linear Regression), במודל זה השיפוע a נשאר יחיד, אך כל אחד מהמשתנים x1, x2 ועד xk מקבל מקדם b משלו (ז"א b1, b2 עד bk), וגם השגיאה האקראית (בעלת ההתפלגות הנורמלית) נשארת (יחידה). - -בנוסף לרגרסיה לינארית פשוטה ורגרסיה לינארית רבת משתנים, ישנם גם מודלים לרגרסיה לא לינארית, וזאת מכיוון שלפעמים צורת הנתונים אינה מתאימה למודל לינארי כזה או אחר, אלא לדוג' למודל פולינומי הנראה כך: y = w0 + w1*x + w2*x^2 + w3*x^3 ואנו מחשבים אותה ע"י הפיכה של x במעלה למשתנה בפני עצמו (ז"א x2 = x^2). - - - -דוגמה לרגרסיה לינארית - -ניקח לדוגמה את הטבלה של ציוני הקורס "מבוא למדעי המחשב" המרוכבת מציון משוקלל של המטלות ומציון הבחינה. - -I Xi ציון מטלות משוקלל Yi ציון בחינה -1 88 87 -2 63 37 -3 47 53 -4 93 78 -5 73 61 -6 56 62 -7 42 29 -8 82 91 -9 59 68 -10 65 52 -נחשב עפ"י הנוסחאות של רגרסיה לינארית (למעלה בתמונות משמאל) את b גג: 2607.6 / 2446.6 שיהיה שווה ל 0.938. ולאחר מכן נציב בנוסחה השניה כדי למצוא את a גג: 66.8*0.938 - 61.8 ששווה ל 0.858-. - -לאחר מכן נתאר את קו הריבועים הפחותים (קו הרגריסה), ז"א Y גג. Ý = -0.858 + 0.938X. - -ובשלב השלישי נחשב את טעות הניבוי: נתבונן בציון המטלות המשוקלל של הסטודנט הראשון. אזי ציון הבחינה המנובא על סמך קו הריבועים הפחותים שמצאנו בשלב 2 יהיה 88*Ý1 = -0.858 + 0.938X ז"א 81.686. לכן טעות הניבוי היא ê1 = 87 - 81.686 = 5.314. - - - -Wekaדוגמה נוספת: - -בדוגמה השניה אנו לוקחים קובץ DB קטן (מכאן) בו ישנם נתוני עדשות מגע. מכיוון שאנו עובדים עם תוכנת ה Weka והקובץ אינו בדיוק מוכן בשבילה, סידרתי אותו ושמרתי ב csv, תוכלו להוריד אותו מכאן (את Weka ניתן להוריד מכאן). נפתח את תוכנת ה Weka ויפתח לנו חלון קטן (כמו בתמונה מצד שמאל) בו נלחץ על Explorer ונראה את החלון הגדול הבא: - -Weka Explorer - -לאחר שנטען את הקובץ נעבור לחוצץ Classify ונלחץ על Choose כדי לבחור את המודל, בחלון שיפתח לנו נבחר בתייקיה functions ובפונ' SimpleLinearRegression. לאחר מכן תחת Test Options נבחר ב Cross-validation Folds ונכתוב בתיבה 10 (בשיטה זו כל התצפיות מחולקות ל k קבוצות שונות, במקרה שלנו בחרנו 10, כשכל תצפית שייכת אך ורק לקבוצה אחת מתוך ה k. ומריצים את האלגו' k פעמים, כאשר בהרצה מספר i, תת קבוצה Di משמשת כקבוצת המבחן והשאר כקבוצות האימון). ונלחץ על Start: - -Simple Linear Regression - -ניתן לראות (סימנתי בתמונה בריבוע אדום) שקחבךנן את קו הריבועים הפחותים (קו הרגריסה). - - - -8. השוואה בין מסווגים - -בהינתן נתונים עם תוויות של סיווג, אנחנו יכולים להריץ אלגו' שונים ולקבל מגוון תוצאות של דיוק. נשאלת השאלה איך מחליטים שאלגו' מסויים הוא טוב יותר מהשני (מספק דיוק גבוהה יותר, או לחילופין שגיאה נמוכה יותר). - -רווח בר סמך (Confidence Intervals) מספק את התחום המשוער של הערכים שבו, קרוב לוודאי, נמצא פרמטר לא ידוע של האוכלוסיה. למשל כאשר ישנו רווח בר סמך ברמת מובהקות של 95% אנו יודעים שאם נבנה הרבה מאוד אינטרוולים כאלה, 95% מהם יכילו את הפרמטר הלא ידוע של האוכלוסיה. נציין גם שניתן לבנות הרבה מאוד סוגים של רווחי בר סמך ברמות מובהקות שונות, אך מקובל לבנות ב 90%, 95%, ו 99%. - -ErrTestעל מנת לבנות רווח בר סמך עבור השגיאה, נפעיל את המודל על תצפיות השגיאה ונקבל שגיאה משוערת (נקרא גם Err Test (מלשון Error)). לאחר מכן אנו מניחים שהתפלגות השגיאה היא בינומית, ובמידה ויש לנו יותר מ-30 תצפיות (שקיבלנו באופן מקרי ובלתי תלוי מהאוכלוסיה) אנו מקרבים אותה להתפלגות הנורמלית. במידה ואנו נשתמש בקירוב להתפלגות הנורמלית נשתמש בנוסחה שבתמונה מצד שמאל (כאשר Z אלפא הוא מספר סטיות התקן של ההתפלגות הנורמלית). - - - -Difference between Classifiers Exampleבטבלה משמאל ניתן לראות דוגמה לחישוב הרווח בר סמך. כאשר למודל הראשון יש שגיאה של 0.2 (Error1) כשגודל קב' המבחן הוא 30 תצפיות, ולמודל השני יש שגיאה של 0.4 (Error2) כשגודל קב' המבחן הוא 40 תצפיות. נחשב את רווח הבר סמך עבור ערכים שונים של alpha (הראשון 0.01 ז"א רמת מובהקות של , השני 0.05, והשלישי 0.1). - -נשים לב שעבור ה alpha ששווה ל-0.01 אנחנו מקבלים רווח בר סמך שהגבול התחתון שלו נמצא מתחת לאפס, וזה אומר שעבור אותו ערך של אלפא אנחנו לא בטוחים מי מבין המסווגים מדוויק יותר. עבור ערכי אלפא האחרים ניתן בהחלט לטעון כי המסווג השני הוא טוב יותר מהראשון (כי השגיאה שלו נמוכה יותר מהשגיאה של המסווג הראשון באופן מובהק). - - - -סיכום - -בפוסט הזה דיברנו על נושא חשוב הנקרא עיבוד מוקדם של נתונים (תהליך חשוב במיוחד עבור האלגוריתמים של כריית מידע). ראינו גם ייצוג גרפי של נתונים העוזר לנו להבין את הקשרים בין הנתונים, וללמוד על ההתפלגות שלהם. הפעולות העקריות של עיבוד הנתונים כוללות: ניקוי ושילוב הנתונים, בחירת משתנים, וחלוקה ל Binים (תיבות). בנוסף, דיברנו על בעיות סיווג ובעיות חיזוי וכיצד נעריך את הדיוק והשגיאה של מודלים אלו, הסברנו מהי עקומת ROC ומה השימוש שלה, ודיברנו על סוגים שונים של רגרסיה (לינאראית, רבת משתנים, לא לינארית) למרות שלא נצטרך לחשב אותה לבד. ולבסוף הראנו כיצד להשוות בין מסווגים שונים (בעזרת רווח בר סמך). - -אני שמח להגיד שעד כאן נגמר החלק ה"משעמם" ומתחיל החלק המעניין יותר, מפה והלאה לא רק נציג ונסביר מושגים ושיטות אלה נבנה אלגו' לכריית מידע, ונבין כיצד הם פועלים. האלגו' הראשון עליו נדבר כבר בפוסט הבא הוא "עצי החלטה". diff --git a/data/_oldPosts/2016-09-04-building-decision-trees.md b/data/_oldPosts/2016-09-04-building-decision-trees.md deleted file mode 100644 index 091c4b9..0000000 --- a/data/_oldPosts/2016-09-04-building-decision-trees.md +++ /dev/null @@ -1,256 +0,0 @@ ---- -title: בניית עצי החלטה -author: nirgn -layout: post -summary: "" -category: Data Mining ---- -בפוסט הזה נבצע סקירה כללית של עצי החלטה ובנייתם, נדבר על האלגוריתם הבסיסי לבניית עצי החלטה (הנקרא ID3), נדבר על שיטות למניעת בעיית התאמת יתר (overfitting), נראה כיצד להפיק חוקים בתוך עצי החלטה, ונתייחס לשיטות דיסקרטיזציה חלוקה למרווחים של משתנים רציפים (תוך כדי בניה של עצי החלטה). - -סקירה של בניית עצי החלטה -אלגוריתם לבניית עצי החלטה - ID3 -התאמת יתר (Overfitting) -הפקת חוקים מעץ החלטה וחלוקה למרווחים -דשכג - - -1. סקירה של בניית עצי החלטה - -עצי החלטה היא טכניקת סיווג. נזכיר כי סיווג היא מתודולוגיה שמטרתה לחזות תוויות סיווג קטגוריות עבור נתונים חדשים, אותם תוויות סיווג קטגוריות יכולות להיות במקרה של סיווג ביטחוני עבר / נכשל, במקרה של נטישת לקוחות (תחום שמעניין במיוחד חברות סלולר) עובר חברה / נשאר, במקרה של תחזית מזג האוויר שמשי / מעונן / גשום וכד'. את הנושאים השונים בפוסט נראה על דוגמה קבועה בה אנו מתבקשים לקבוע קבלה של סטודנטים לאונ'. אנו נסתמך על נתונים קודמים כדי לקבוע את ממוצע התואר של הסטודנטים המבקשים להתקבל. להלן הנתונים ההיסטורים: - -GPA Graduation Year Test Grade Admission Year Place of Birth Date of Birth Gender Last Name First Name ID -93.5 2006 730 2002 USA 18/12/1979 M Cohen David 543406619 -87.5 2006 680 2002 Israel 11/07/1980 M Levy Ophir 951984264 -94.3 2006 640 2002 Israel 19/05/1981 F Grosman Sharon 683168092 -85.8 2006 585 2002 Russia 11/02/1980 F Liberman Diana 100900927 -78.7 2006 570 2002 Israel 03/02/1982 F Klein Anat 516120403 -ולהלן הנתונים של הסטודנטים המבקשים להתקבל: - -GPA Graduation Year Test Grade Admission Year Place of Birth Date of Birth Gender Last Name First Name ID -? 2011 580 2007 Israel 22/09/1985 M Bazak Boaz 537793401 -? 2011 650 2007 Israel 10/02/1985 M Levy Ophir 808943728 -? 2011 720 2007 Ukraine 03/12/1987 F Neuman Maria 537362102 -כמו שניתן לראות ה GPA אינו ידוע (זה מה שאנו צריכים לחזות), ותתעלמו מהשנים, נניח כי אנחנו בתחילת שנת 2007 ואלו הנתונים של הסטודנטים המבקשים להיכנס לאונ' בשנת הלימודים הבאה. - - - -לפני שנתחיל להפעיל אלגוריתם כזה או אחר של כריית מידע, נבצע ניקוי של נתונים שאינם רלוונטים לתהליך החיזוי (בדיוק כמו שדיברנו בפוסט הראשון). נתחיל בלהוציא את מספר תעודת הזהות, ברור לנו שלת.ז. אין השפעה להצלחה בלימודים. לאחר מכן נתעלם מהשם הפרטי והמשפחה, מכיוון שגם זה לא עוזר לנו בחיזוי ההצלחה בלימודים. לאחר מכן ניפטר גם מתאריך הלידה, קודם במסד נתונים גדול יהיו הרבה מאוד ערכים אפשריים, דבר שמקשה על החיזוי ובעצם יפרק לנו את העץ ליותר מידי עלים, לאחר מכן ישנה הטענה כי אם אנו בכלל לא מאמינים באסטרולוגיה תאריך הלידה לא משפיע על ההצלחה בלימודים, ומכיוון שאני לא מאמין באסטרולוגיה נסיר את העמודה. ולבסוף, גם את עמודת שנת הקבלה ושנת הסיום אפשר להסיר מכיוון שאינם עמודות משמעותיות ואף זהות לכל התצפיות במקרה שלנו. - -נשארנו עם טבלה מצומצת המכילה 3 עמודות בלבד (GPA לא נחשב, זהו משתנה המטרה שלנו): - -GPA Test Grade Place of Birth Gender -93.5 730 USA M -87.5 680 Israel M -94.3 640 Israel F -85.8 585 Russia F -78.7 570 Israel F -לאחר שזיהנו את המשתנים הפוטנציאלים ואת משתנה המטרה, נשאלת השאלה כיצד נמצא את המודל הטוב ביותר לחיזוי ממוצע הציונים (GPA)? וכיצד נקבע אם מודל מסויים הוא טוב יותר או פחות ממודל אחר? כרגע, לצורך המשך הדיון, נניח כי המודל הטוב ביותר הוא המודל המדויק ביותר (זה שמאפשר לנו לחזות בדיוק המריבי מה יהיה הציון הממוצע בסיום לימודיו). - - - -Test Grade Line Fit Plotהדבר הראשון שניתן לעשות הוא לנסות לחזות באמצעות רגרסיה לינארית פשוטה או רבת משתנים, במקרה הזה ננסה עם רגרסיה לינארית פשוטה עם משתנה הפסיכומטרי (Test Grade) ונראה (בתמונה משמאל) כי רוב המשתנים במציאות די רחוקים מקו הרגרסיה שהתקבל. אנו גם יכולים להעריך את איכות המודל הזה בדרך יותר פורמלית, תוך שימוש במקדם המתאם R^2 (דיברנו עליו בפוסט הקודם, מדד שמקבל ערכים בין 0 [אין קשר בין המשתנים] ל-1 [יש קשר מוחלט בין המשתנים]) ויוצא במקרה הזה כי R^2 = 0.547 שזה מקדם מתאם יחסית נמוך, כלומר אם נשתמש ברגריסה לינארית פשוטה על מנת לנבא ציון ממוצע באונ' נקבל מודל בעל דיוק לא גבוהה. מכאן אנו מסיקים כי הקשר בין המשתנים לממוצע הציונים אינו קשר לינארי פשוט, אלא קשר מורכב יותר. - - - -נשים לב לעוד בעיה בבנושא ניקוי הנתונים, והיא ריבוי ערכים. במקרה שלנו אנו רואים שהבעיה הזאת קיימת במקום לידה (Place of Birth), נתון זה יכול לקבל הרבה מאוד ערכים אפשריים, מצב שאינו טוב לעצי החלטה (מסיבות שעליהם נדבר בהמשך), ולכן נחליף את הערכים האפשריים בעמודה ל-2 בלבד: Israel ו Abroad. משתנה נוסף שנצמצם את מספר הערכים שלו (נבצע לו דיסקרטיזציה) הוא ציון הפסיכומטרי (Test Grade), נקבע באופן שרירותי (כרגע) 3 מרווחים (אינטרוולים): ציונים בין 0 ל-600, ציונים בין 600 ל-700, וציונים מעל 700 (בהמשך נדבר על שיטות למציאה של מספר מרווחים והגבולות שלהם בצורה האופטימלית ביותר). ולבסוף, נבצע דיסקרטיזציה גם למשתנה המטרה, גם כאן באופן שרירותי ל-3 מרווחים: Low שיהיה 0-79, Meduim שיהיה בין 80-89, ו Hight שיהיה 90-100. - -לפעולת הדיסקרטיזציה יש משמעות מיוחדת - אנו מניחים מראש שיהיה לנו קשה מאוד למצוא מודל שמצליח לחזות באופן מדויק את הממוצע של כל מועמד (ואף להניח שאין לנו צורך במודל כזה, שכן לצורך קבלה לאונ' סביר להניח שיש להניח בחיזוי מקורב יותר - כזה שמדבר על מרווחים ולא על ציונים מדוייקים). לאחר שביצענו את כל פעולות ההכנה כך נראת טבלת הנתונים: - -GPA Test Grade Place of Birth Date of Birth Gender Last Name First Name -High Over 700 Abroad 18/12/1979 M Cohen David -Medium 600-700 Israel 11/07/1980 M Levy Ophir -High 600-700 Israel 19/05/1981 F Grosman Sharon -Medium 0-600 Abroad 11/02/1980 F Liberman Diana -Low 0-600 Israel 03/02/1982 F Klein Anat -Target Input Input Input Input Use: -Predict GPA Treeכעת (עוד לפני שדיברנו על איזשהו אלגו' לבניית עצי החלטה) ננסה לבנות בעצמנו עץ החלטה, בעזרת אחד מהמשתנים המנבים. ניקח את ציון הפסיכומטרי - Test Grade, ואנו יודעים שיש לו 3 ערכים אפשריים ועל פיהם נשייך את התצפיות לענפים המתאימים. העץ שנקבל נמצא בתמונה משמאל. - -נשים לב שאם נבצע חיזוי עבור כל אחד משלושת הענפים, לגבי הענף השמאלי אין לנו החלטה חד משמעית (יש לנו שם תוצאה של Low וגם של Medium ז"א 50% שנקבל כל אחת מהתוצאות האלו), גם בענף האמצעי אנחנו לא יכולים להגיע להחלטה חד משמעית, ורק בענף הימני (Over 700) אנחנו יכולים להגיע להחלטה חד משמעית בה החיזוי יהיה ציון ממוצע של High. מכאן הדיוק הממוצע של העץ הוא 60% [מחשבים אותו כך: 100%*(1/5) + 50%*(2/5) + 50%*(2/5)]. - -Predict GPA Tree by Gender - - - -כמובן שלא חייבים להשתמש במשתנה ציון פסיכומטרי, ניתן להשתמש גם באחרים, לדוג' בתמונה משמאל ישנו עץ החלטה שנבנה עפ"י המשתנה מין (Gender). בענף השמאלי אין לנו החלטה חד משמעית, ודיוק של הענף הוא 33% בלבד, בעוד בענף הימני הדיוק 50%. מכאן שהדיוק הממוצע של העץ הוא 40% בלבד [מחושב: 50%*(2/5) + 33%*(3/5)]. - -Predict GPA Tree by Place of Birth - - - -ישנו משתנה נוסף לפיו אנו יכולים להרכיב עץ החלטה והוא מקום לידה. עפ"י משתנה זה, עבור אלה שנולדו בארץ (הענף השמאלי - Israel) יש לנו דיוק של 33%, ועבור אלה שנולדו בחול (הענף הימני - Abroad) יש לנו דיוק של 50%. ולכן גם כאן אנחנו מגיעים לדיוק ממוצע של 40%. - - - -אחרי שבנינו 3 עצים אפשריים, אנחנו מתלבטים באיזה משתנה להשתמש בשורש העץ? לפני שנתאר את האלגוריתם שיעזור לנו לענות על השאלה הזאת, נעשה יישור קו קטן ונעבור על כמה מושגים הקשורים למבנה העץ. - -קודקוד (Nodes) - יכול להיות קודקוד השורש, אך גם להופיע באחת הרמות הבאות של עץ ההחלטה. המאפיין שלו הוא שהוא מתייחס לבדיקת הערכים של אחד המשתנים. -ענף (Branch) - כל אחד מהערכים של אותו משתנה הנבדק בקודקוד יוצר איזשהו ענף של העץ. -עלה (Leaf) - כאשר אנו מגיעים לעלה אנו מפסיקים לפצל את העלה למשתנים אחרים ונותנים תחזית, ניבוי לסיווג של משתנה המטרה. -מסלול (Path) - המסלול מחבר בין קודקוד השורש לאחד העלים. כפי שנראה בהמשך, כל מסלול כזה מייצג חוק חיזוי. ונשים לב כי מס' המסלולים בעץ ההחלטה יהיה תמיד שווה למס' העלים. -סוגי תכונות ואופי הפיצול המתאימים להם: - -תכונות בינאריות (Binary Attributes) - יפוצלו פיצול בינארי בלבד (כן / לא). -תכונות נומינליות (Nominal Attributes) - לכל תכונה יש מספר קטן וסופי של ערכים אפשריים. ניתן לפצל תכונות נומינליות לפיצול מרובה (multiway split) וכפיצול בינארי (binary split) (בפיצול בינארי יש לקבל יחד כמה ערכי תכונה). לדוגמה: סטטוס סטודנט עשוי להיות סטודנט פעיל / שהפסיק את לימודיו / סטודנט חדש. פיצול מרובה יהיה פיצול ל-3 התכונות, בעוד פיצול בינארי יכול להיות {הפסיק לימודיו} / {פעיל, חדש} או {פעיל, הפסיק לימודיו} / {חדש} או {חדש, הפסיק לימודיו} / פעיל. -תכונות סידוריות (Ordinal Attributes) - ניתן לצל לפיצול מרובה ולפיצול בינארי. לדוגמה ממוצע ציוני סטודנט בתואר יכול להיות: נמוך / בינוני / גבוהה / מצטיין. -תכונות רציפות (Continuous Attributes) - לדוגמה התכונה ציון בקורס X ניתן לפצל כפיצול בינארי מעל 90 / מתחת ל-90, או כפיצול מרובה {מעל 90} / {80 עד 90} / {70 עד 80} / {60 עד 70} / {מתחת ל-60}. - - -בעיות המתאימות לעצי החלטה - -לא כל בעיה מתאימה לחיזוי באמצעות עצי החלטה, לכן נוודא כי המאפיינים של הבעיה שלנו אכן מתאימים לחיזוי זה. - -נדרוש שכל תצפית תיוצג ע"י סט קבוע של משתנים [במקרה שלנו: מין (Gender), מקום לידה (Place of Birth), ציון פסיכומטרי (Test Grade)]. -כל משתנה מנבא יקבל מספר קטן של ערכים אפשריים שונים [במקרה שלנו לא רצינו להשתמש בכל הערכים האפשריים של ארץ לידה (Place of Birth) מכיוון שמס' הערכים האפשריים הוא גבוהה, לכן צמצמנו את הערכים האפשריים, והפכנו את המשתנה למשתנה בינארי]. -מניחים שפונ' המטרה מקבלת ערכים בדידים כאשר כל ערך בודד מתייחס לאיזשהי מחלקה [במקרה שלנו חילקנו את משתנה המטרה - ציון ממוצע באונ' (GPA) ל-3 מרווחים]. -אנו מצפים לקבל מעץ ההחלטה סט חוקים נפרדים [לדוגמה if (Test < 600 Then GPA = Low ו if (Test >= 600) Then GPA = Medium or High]. -הנחה כי נתוני האימון יכולים להכיל רעש, טעויות. ובנוסף, כי ערכים יכולים להיות חסרים (ישנם אלגוריתמים שיודעים לטפל בערכים חסרים, אבל בנתיים נניח כי כל הערכים ידועים). - - -2. אלגוריתם לבניית עצי החלטה - ID3 - -אלגוריתם ID3 הומצא ע"י רוס קווינלן בשנת 1986 והינו אלגוריתם חמדני, ז"א שאנו לא מחפשים מודל אופטימלי באופן כללי, אלא בונים את המודל באמצעות כלל אצבע לפיו אנו מסתכלים אך ורק על הצעד הבא (בלי הצעדים שאחריו) ובוחרים את האפשרות הטובה ביותר לגביו (ניתן להשוות את הרעיון לפתרון בעיית מבוך בה אנו מסתכלים אך ורק על הצעד הבא לפי מה שמקדם אותנו לכיוון היציאה, בלי להסתכל על כל המבוך באופן כללי ולראות כי אולי הצעד הבא מקדם אותנו יותר לכיוון היציאה אך באופן כללי הוא מקדם אותנו לפינה סגורה ממנה לא ניתן לצאת. בעוד הצעד שהיה מוציא אותנו מהמבוך נראה לנו באותו שלב כצעד שלוקח אותנו אחורה, או פחות מקדם אותנו). - -העץ נבנה מלמעלה למטה (מהשורש לעלים), כאשר בכל שלב אנו מבצעים חלוקה של תצפיות האימון לקבוצות באופן רקורסיבי. תחילה יש לנו קבוצה אחת, ז"א כל תצפיות האימון שייכות לאותה קבוצה והינה שורש העץ. בנוסף, אנו מניחים שכל המשתנים הינם מסוג קטגורי (ז"א מספר הערכים שהמשתנה יכול לקבל הינו מוגבל, סופי), לכן אם ישנו משתנה רציף אנו נבצע לו מראש דיסקרטיזציה. אז כאמור נתחיל מקדקוד השורש ונבצע חלוקה רקורסיבית עפ"י משתנים הנבחרים ע"י האלגוריתם, את המשתנה המנבא בכל שלב נבחר באמצעות כלל קבוע או משתנה סטטיסטי כלשהו. - -מכיוון שהחלוקה הרקורסיבית יכולה להימשך עד אינסוף, ישנם כמה תנאי עצירה. בראש ובראשונה נעצור אם כל התצפיות בענף מסויים שייכות לאותו סיווג מכיוון שאין טעם לחלק אותן לקבוצות קטנות יותר. נעצור גם כאשר לא נשארו לנו משתנים כדי לבצע פיצול נוסף (כלומר, השתמשנו כבר בכל המשתנים האפשריים ברמות גבוהות יותר), במקרה כזה נסווג את העלה עפ"י הצבעת הרוב, ז"א הערך השכיח ביותר באותה קבוצת תצפיות (זאת מכיוון שאנו נדרשים לקבל חיזוי מוחלט, ז"א החלטה, לא מצב של 50% אופציה א ו 50% אופציה ב). כאשר מספר התצפיות בעלה ירד מתחת לאיזשהו סף עליו החלטנו מראש (לדוג' כאשר ישנם פחות מ-10 תצפיות נעצור את הבנייה ונסווג את העלה עפ"י השיטה של הצבעת הרוב). - -בשלב הראשון באלגו' אנו יוצרים את צומת השורש, בודקים האם לכל התצפיות יש אותו ערך מטרה, במידה וכן האלגו' מחזיר עץ בעל קודקוד אחד המסווג עפ"י הערך של כל התצפיות. במידה ואין לכל התצפיות אותו ערך מטרה מפצלים את הקודקוד. כדי לפצל אותו אנו בוחרים במשתנה שמסוגל לפצל את הקודקוד בצורה הטובה ביותר (נדבר כיצד לעשות זאת בהמשך, כרגע נניח שיש לנו מדד כזה, השתמשנו בו, וכך בחרנו במשתנה המפצל). ברגע שבחרנו במשתנה A אנו מוסיפים לעץ ענף עבור כל משתנה של A. אם בקודקוד אין לנו תצפיות עבור משתנה מסויים, אנו יוצרים קודקוד עלה עבור אותו משתנה (ואותו קודקוד עלה יסווג עפ"י השכיח ביותר - הצבעת הרוב), אחרת (אם יש לנו תצפיות עבור המשתנה) ניצור תת עץ עפ"י האלגוריתם שתיארנו (בצורה רקורסיבית). - - - -Information Gain -רווח אינפורמטיבי (Information Gain) היא השיטה הפשוטה ביותר לבחירת משתנה פיצול בעץ. בשיטה זאת אנו בוחרים את המשתנה בעל Information Gain הגבוהה ביותר. את הרווח האינפורמטיבי של משתנה A נחשב כהפרש בין האנטרופיה של התצפיות לפני הפיצול [(Info(D] להאנטרופיה של התצפיות אחרי הפיצול [(InfoA(D], ז"א (Gain(A) = Info(D) - InfoA(D. - -נניח ש Pi היא הסתברות של תצפית כלשהי בקובץ האימון ושייכת לסיווג Ci, אנו יכולים להעריך את אותה הסתברות ע"י חלוקה של כל התצפיות בעלות הסיווג Ci בכלל התצפיות בקובץ האימון. בעזרת ההגדרה הזו נחשב את האנטרופיה, ז"א (Info(D) = -ΣPi*log2(Pi (הנוסחה המוכרת מחישוב האנטרופיה בפוסט הראשון). לאחר מכן נפצל את המשתנה A ל v הערכים השונים שלו, ונחשב את האנטרופיה עפ"י שיקלול של מספר התצפיות השייכות לכל אחד מהענפים ונכפיל את אותו אחוז תצפיות באנטרופיה של הענף המתאים., ז"א (InfoA(D) = Σ|Dj|/|D| * Info(Dj {כאשר Dj הוא מספר התצפיות השייכות לענף הנוכחי). - -Info(D)ואתו המשתנה (A) שיהיה בעל ה (Gain(A המקסימלי, הוא המשתנה בו נשתמש על מנת לפצל את העץ. - - - -נחשב את הנוסחאות על הדוגמה שלנו לקבלת סטודנטים לאונ' למשתנה ציון פסיכומטרי (Test Grade): - -יש תצפית Low אחת, ולכן ההסתברות שלו היא 0.2 (1 מתוך 5 תצפיות), מינוס log2 של 0.2 זה 2.322. -ל Medium יש 2 תצפיות ולכן ההסתברות שלו היא 0.4, מינוס log2 של 0.4 זה 1.322. -גם ל High יש 2 תצפיות ולכן ההסתברות שלו היא 0.4, מינוס log2 של 0.4 זה 1.322. -לכן שיקלול של 2.322 + 1.322 + 1.322 = 1.522 וזהו ה (Info(D. - - - -כדי לחשב את (InfoA(D ניצור את הטבלה הבאה ונסתכל על העמודות שלה (0-600, 600-700, ו Over 700). יש תצפית 1 ל Low ב 0-600, ותצפית אחת ל Medium ב 0-600, InfoA(D)ואף תצפית ל High באותו הסיווג, ולכן המשקל של כל אחת יהיה 0.5. ה מינוס log2 של 0.5 זה 1. נחשב את האנטרופיה של 0-600 ע"י הנוסחה של האנטרופיה הרגילה, (Info(D, ע"י p כפול (log2(p- של Low ועוד p כפול (log2(p- של Medium ונקבל 1. ונבצע אותו הדבר לסיווג 600-700 (האנטרופיה תצא 1) ולסיווג Over 700 (האנטרופיה תצא 0). - -אחרי שיש לנו את האנטרופיה של כל סיווג בנפרד, נבצע את האנטרופיה הכללית של החלוקה, ז"א (InfoA(D ע"י שיקלול האנטרופיה של כל סיווג במשקל היחסי שלו (ז"א ב 0-600 יש לנו 2 תצפיות מתוך 5 אז המשקל יהיה 0.4). והאנטרופיה הכללית תצא 0.8. כעת כדי לחשב את ה Gain נחסיר את (InfoA(D שחישבו עכשיו מ (Info(D שחישבו בפסקה למעלה, ונקבל שה Gain שווה ל 0.722. בטבלאות למטה נחשב את (InfoA(D גם למשתנים מין (Gender) ומקום לידה (Place of Birth). - -Information Gain GenderInformation Gain Place of Birth - - - - - - - - - - - - - - - - - - - - - - - - - -Decistion Treeוכשנעשה 1.522 [שזה (Info(D] פחות 1.351 [שזה מה שיצא לנו ה (InfoA(D של 2 המשתנים] נקבל 0.171. ז"א שה Gain של המשתנה פסיכומטרי (Test Grade) יצא הגבוהה ביותר ולכן נשתמש במשתנה הזה כדי לפצל את העץ. לאחר שנרכיב עץ החלטה כשהשורש שלו הוא המשתנה Test Grade ויוצאים ממנו 3 ענפים של 600>, 600-700, Over 700 נבדוק את התצפיות ששייכות לכל ענף ובמידה וישנו רק ערך אחד נסווג על פיו, במידה וישנם כמה ערכים נבצע Information Gain גם לתצפיות האלו (עם המשתנים שנשארו, שהם Gender ו Place of Birth) ונבדוק עם איזה משתנה כדאי לפצל אותם, אם נקבל תצפיות שלכולן יש אותו ערך נסווג על פיו, אם לא נעשה שוב Information Gain, אם אין לנו יותר משתנים נסווג את העלה על פי הערך של רוב התצפיות. בתמונה משמאל ניתן לראות את עץ ההחלטה כפי שהוא צריך להיראות בסוף. - - - -3. התאמת יתר (Overfitting) - -Overfittingיתכן מצב בו העץ שבנינו עפ"י אחד האלגוריתמים (לדוג' ID3 שדיברנו עליו כבר) מתאים מצוין לנתוני האימון אך לא מדויק מספיק על נתוני המבחן (נתונים חדשים). מצב זה יכול לקרות כאשר אנו בונים עץ גדול מידי עם יותר מידי צמתים, יכול להיות שחלק מהענפים יתאימו באופן מדויק לנתוני האימון אך הם לא מייצגים איזשהי תבנית שחוזרת על עצמה אלא תופעות מקריות או אפילו תופעות אנומליות המתרחשות בנתוני האימון. - -ניזכר שבסעיף הראשון בדקנו את הדיוק הממוצע של העץ לפי המשתנה Test Grade ומצאנו כי הדיוק הממוצע שלו הוא 60%, ז"א לחילופין הוא טועה ב-40% מהמקרים, לכן שגיאת האימון שלו error train = 40% (ונשלים את הענפים של העץ עפ"י הרוב או באופן אקראי, ניתן לראות בתמונה משמאל את ההשלמה שלי לעץ). אם ניקח את העץ הסופי שבנינו בסוף הסעיף השני, נראה כי הוא מתאים במדויק לנתוני האימון, ז"א שהדיוק הממוצע שלו הוא 100%, ושגיאת האימון שלו (error train) היא 0%. כעת, אם ניקח תצפיות חדשות (לדוג' את התצפיות בתמונה משמאל), ונניח שהן מייצגות את כלל האוכלוסיה, נבדוק אותן אל מול העץ הראשון (שהתקבל מ Test Grade עם שגיאת אימון של 40%) ונראה כי השגיאה שלו נתוני המבחן היא 0%, ז"א שהוא מדייק בכולן. לעומת זאת אם נקבל החלטה עפ"י העץ השני שבנינו (זה עם שגיאת האימון של 0%) נראה כי השגיאה שלו על נתוני המבחן היא 33%. - - - -וקיבלנו מקרה קלאסי של התאמת יתר. לכן כעת נשאלת השאלה כיצד אפשר למנוע אותה? בראש ובראשונה אנחנו יכולים להניח שישנו איזשהו גודל אופטימלי של עץ החלטה. - -כשהעץ קטן מאוד, ככל שמוסיפים לו יותר קודקודים (וכתוצאה מכך גם ענפים) דיוק האימון של עולה וגם דיוק המבחן, אך בשלב מסויים בעוד דיוק האימון ממשיך לעלות (כי את הקודקודים אנו קובעים עפ"י נתוני האימון אז ככל שיהיו יותר תתי מקרים כך העץ יתאים לאותם הנתונים טוב יותר), דיוק המבחן לעומתו נשאר אותו הדבר, ולאחר מכן אף מתחיל לרדת. מכך אנו מסיקים את הטענה שמעבר למס' קודקודים אין טעם להמשיך לפצל את העץ. - -קיימת 2 גישות שונות בבניית עצי החלטה המונעות מצב זה: - -גיזום מוקדם (Prepruning) - בגישה זו אנו מפסיקים לבנות את העץ מספיק מוקדם, ז"א לא נפצל איזשהו קודקוד, במידה והפיצול מביאה לירידה במדד איכות מסויים שבסופו של דבר יביא אותנו לקבל עץ שלא מספיק מדויק על נתוני המבחן. נציין כי הקושי בגישה זו הוא לבחור בסף המתאים כדי לעצור את הבניה של העץ. -גיזום מאוחר (Postpruning) - גישה זו הוכיחה את עצמה יותר מהגישה הקודמת, ובה אנחנו קודם כל בונים את העץ המלא (עם מס' מקסימלי של קודקודים) ואז, באופן הדרגתי, מנסים לצמצם את הענפים בעץ. אנו משתמשים בקובץ נפרד המכיל נתוני מבחן כדי לבדוק את העץ ולדעת לבחור (בעזרתם) את העץ המדויק ביותר (ז"א מתי להפסיק לגזום אותו). -דוגמה ל Postpruning ניתן לראות בדוגמה למעלה, היינו יכולים לקחת את העץ המלא שהגענו אליו בסוף סעיף 2, לגזום את המשתנים Place of Birth ו Gender ולהגיע לעץ Tree 1 בתמונה משמאל למעלה. - - - -קביעת הגודל האופטימלי של העץ החלטה - -קיימות כמה שיטות / גישות לקביעת הגודל האופטימלי של עץ החלטה. אחת מגישות, הנפוצה מבינהם היא גישה עליה דיברנו כבר, והיא אומרת לחלק את התצפיות (באופן אקראי) ל-2 קבוצות, כאשר 2/3 מהתצפיות יהיו בקבוצת האימון ממנה אנו בונים את העץ, ו-1/3 יהיו בקבוצת המבחן איתה אנו נבחן את המודלים השונים של העצים, ובעצם עם קבוצה זו נקבע מהו העץ שיבחר (מתוך העצים האפשריים). - -שיטה נוספת, שכבר דיברנו עליה בפוסט הקודם, נקראת Cross Validation. אפשר להשתמש בשיטה זו גם כאן (כדי לקבוע את הגודל האופטימלי של העץ). נזכיר כי בשיטה זו נבחר מס' (לדוג' 10) שיקבע את מספר המודלים שנבנה, כאשר נחלק באופן אקראי את התצפיות ל-10 קבוצות, וכל פעם 9/10 קבוצות יהיו בקבוצת האימון שתבנה את מודל העץ, והקבוצה שנשארה (1/10) תשמש כקבוצת המבחן. ונעשה זאת 10 פעמים, כך שכל הקבוצות ישמשו פעם אחת כקבוצת המבחן. - -גישה נוספת מבוססת על תורת האינפורמציה ונקראת אורך תיאור מינמלי (MDL). בשיטה זו אנו מפסיקים לבנות את העץ כאשר מביאים למינימום את אורך הקידוד הכולל של העץ וגם של השגיאות שלו. - -ולבסוף, הגישה האחרונה (עליה נרחיב יותר) אומרת כי אין לנו צורך בקבוצת מבחן ואנו משתמשים בכל התצפיות בקבוצת האימון. וניעזר במשתנה סטטיסטי כלשהו (לדוג' חי בריבוע) על מנת להעריך האם כדאי לנו לפצל קודקוד מסויים על מנת לשפר את הדיוק של העץ. - - - -גישת חי בריבוע (Chi-Square) מבוססת על המבחן הסטטיסטי הידוע הנקרא באותו שם. להלן הסימונים של המבחן: - -A - המשתנה עליו אנו מעוניינים לבצע את הפיצול. -v - מסמנים את גודל התחום של אותו משתנה (מספר הערכים האפשריים של המשתנה). -Ci - זאת תת קבוצה של תצפיות המתייחסות לערך i של משתנה A. -c - מספר הסיווגים שיש לנו בתצפיות. -ej - מספר התצפיות ששיכות לסיווג j בבסיס הנתנוים C. -oij - מספר התצפיות ששייכות לסיווג j בתוך תת קבוצה Ci (אותה תת קבוצה שמתייחסת לערך i של המשתנה המפוצל A). -α (אלפא) - רמת מובהקות במבחן חי בריבוע. -השערות המבחן הן: השערת ה-0 (ההשערה אותה אנו מנסים לבחון באמצעות מבחן חי בריבוע) היא: המשתנה A אינו רלוונטי לסיווג של התצפיות בבסיס הנתונים C (כלומר אם נפצל את התצפיות, עפ"י הערכים של A אנחנו לא נוכל לשפר את דיוק החיזוי). וההשערה האלטרנטיבית היא: שלמשתנה A כן יש השפעה על התפלגות הסיווג בבסיס הנתונים C. במבחן זה משתמשים בסטטיסטיקה על מנת להשוות בין 2 התפלגויות כל אוכלוסיה נתונה, אך במקרה של בניית עץ, נשאלת השאלה האם התפלגות של משתנה המטרה מושפעת כתוצאה מפיצול עפ"י ערכים של איזשהו משתנה A. - -על מנת לחשב את הסטטיסטי של המבחן נחשב קודם את המספר החזוי של תצפיות השייכות לסיווג j בקבוצה Ci: ניקח את אחוז התצפיות השייכות לסיווג j בכלל בסיס הנתונים ונכפיל במספר התצפיות הנמצאות בקבוצה Ci. לאחר מכן נחשב את הסטטיסטי של המבחן ע"י לקיחת ההפרש שבין מס' התצפיות הצפוי (עפ"י השערת ה-0) למס' התצפיות בפועל, ומחלקים במס' התצפיות הצפוי. בתמונה משמאל ניתן לראות את הנוסחאות (הראשונה לחישוב המספר החזוי של התצפיות, והשנייה לחישוב הסטטיסטי) (ואת מס' דרגות החופש של הסטטיסטי מחשבים ע"י מס' הערכים של המשתנה A פחות 1, כפול מס' הסיווגים פחות 1). - -כלומר, אם השערת ה-0 נכונה, אנו מצפים שהערך של הסטטיסטי שלנו יהיה נמוך יותר מהערף הקריטי של חי בריבוע, לעומת זאת אם הערך גבוהה יותר מהערך הקריטי אז נדחה את השערת ה-0, ונפצל את הקודקוד. - - - -דוגמה לחי בריבוע - -ניזכר שלפני הפיצול החלוקה הייתה: סטודנט אחד = Low, שתי סטודנטים = Medium, ו-2 סטודנטים = High. וכעת אנו רוצים לדעת האם כדאי לנו לפצל עפ"י המשתנה Test Grade (הציון הפסיכומטרי). - -עבור ערכים מתחת ל-600 (ז"א Test < 600) יש לנו 2 ערכים, אחד עם ממוצע Medium והשני עם ממוצע Low. נחשב את מס' התצפיות הצפוי (מכל סוג) עפ"י השערת ה-0: כיוון שיש לנו 2 תצפיות עם ערכים "מתחת ל-600" נכפיל את האחוז ב-2, ז"א e'low = (1/5)*2 = 0.4, ו e'medium = (2/5)*2 = 0.8, ו e'high = (2/5)*2 = 0.8. ז"א שבהינתן השערת ה-0, אנו מצפים לקבל 0.4 תצפיות בסיווג low, ו-0.8 תצפיות בסיווג medium, ו-0.8 תצפיות בסיווג high. -נלך לענף השני, Test בין 600 ל-700, ונראה שיש לנו שם 2 ערכים, אחד עם ממוצע Medium והשני עם ממוצע High. נעשה את אותו החישוב ונקבל את אותם התוצאות כמו בענף הראשון: ז"א e'low = (1/5)*2 = 0.4, ו e'medium = (2/5)*2 = 0.8, ו e'high = (2/5)*2 = 0.8. -נלך לענף השלישי, Test > 700, ונראה שיש לנו שם ערך אחד עם ממוצע High. נעשה את החישוב: e'low = (1/5)*1 = 0.2, ו e'medium = (2/5)*1 = 0.4, ו e'high = (2/5)*1 = 0.4. -בעזרת כל החישובים האלו נחשב לבסוף את הסטטיסטי (שיהיה שווה ל-3.75) וכאשר החי בריבוע ברמת מובהקות של 0.05 ועבור 4 דרגות חופש הוא שווה ל x²0.05(4) = 9.49. הגענו ל-4 דרגות חופש מכיוון שלמשתנה Test ha 3 ערכים 3-1 שווה ל-2, וגם לתצפיות עצמן יש 3 סיווגים אפשריים (Low, Medium, ן High) ו 3-1 זה שוב 2, וכשנכפיל 2*2 נקבל 4. - -מכיוון שקיבלנו סטטיסטי נמוך יותר מהערך הקריטי של חי בריבוע לא נדחה את השערת ה-0, והמסקנה היא שעפ"י מבחן זה לא כדאי לפצל את הקודקוד עפ"י המשתנה של הציון הפסיכומטרי. - - - -4. הפקת חוקים מעץ החלטה וחלוקה למרווחים - -Decistion Treeלהלן (בצד שמאל) העץ שבנינו בסוף סעיף 2. בעץ הזה אנו רואים 5 עלים, וכל עלה כזה ניתן לנסח כחוק חיזוי. למשל: If (Test < 600) and (Place of Birth = Israel) Then Grade = Low וכך הלאה לכל העלים. אין הרבה מה להרחיב על הפקת החוקים, כל צומת בעץ היא תנאי של ה If שצריך להתקיים (and) ולבסוף הצומת הראשונה ממנה יצאנו תיהיה שווה לערך של העלה. - -דסקרטיזציה (חלוקה למרווחים) של משתנים רציפים תוך כדי בנייה של עץ החלטה. נזכיר, כי עד כה הנחנו שכל משתנה שיש לנו בעץ הוא משתנה קטגורי, משתנה בדיד. וראינו גם שאם היה לנו דוגמאות שאם היה לנו איזשהוא משתנה רציף היה אפשר לחלק אותו מראש למרווחים. הגישה הפשוטה ביותר לחלוקה למרווחים מכונה דיסקרטיזציה בלתי מודרכת (Unsupervised Discretiztion) ודיברנו עליה בפוסט הקודם. בקצרה, בגישה זו מחלקים את המשתנה הרציף למרווחים בעלי רוחב זהה או בעלי תדירות זהה (bins). שיטה זו היא סטטית, מאחר שהשיטה קובעת את אופן החלוקה לכל משתנה במודל הסיווג. - -מנגד, כדי לשפר את יעילות הסיווג פותחו כמה שיטות לדיסקרטיזציה סטטית מודרכת (Supervised Discretiztion Static) המבוססת על ערכי משתנה המטרה בכל רשומת אימון. הדוגמה הפופלרית לאלגוריתם הממש שיטה זו היא אלגו' לדיסקרטיזציה בינארית המבוסס על מינמיזציה של אנתרופיית משתנה המטרה. הלאגוריתם מתחיל בפיצול של מרווח יחיד. ולאחר מכן, כל תת מרווח מפוצל רקורסיבית. וקריטריון העצירה הוא עקרון ה MDL (עליו דיברנו בפוסט הקודם). - -Supervised Discretzation Staticכדי להחליט על הפיצוללמרווחים נחשב את הרווח האינפורמטיבי (ההפרש בין האנתרופיה של לפני ואחרי הפיצול), ונבחר את הנק' עם הרווח המקסימלי (כמובן שנעשה זאת לכל נק' פיצול עד שנגיע לאחד מהקריטריונים לעצירה). בצד שמאל ניתן לראות את הנוסחה לחישוב, ולמטה מקרא שלה. - -S - הסט הכולל של התצפיות. -A - המשתנה הרציף שאנו מעוניינים לפצל. -T - נק' הפיצול (הגבול בין 2 המרווחים). -S1 - כל התצפיות הנמצאות מתחת לנק' הפיצול. -S2 - כל התצפיות הנמצאות מעל לנק' הפיצול. - - - - -לסיכום - -ראינו שעצי החלטה היא אחת הטכניקות הפופלריות ביותר לסיווג של תצפיות, את האלגוריתם הבסיסי לבניית עצי החלטה, ניתן לבחור את המשתנה הטוב ביותר לפיצול באמצעות מדדים שונים (כאשר האלגו' ID3 בוחר עפ"י הרווח האינפורמטיבי, Information gain, כלומר אותו משתנה שמביא אותו למקסימום). כאשר העץ גדול מידי ומתאים מידי לנתוני האימון יכולה להתעורר בעיה של התאמת יתר (Overfitting) וראינו את שיטת גיזום מוקדם ע"י עצירת בניית העץ ואת גיזום מאוחר המשמשות למנוע את התופעה. diff --git a/data/_oldPosts/2016-09-18-pen-testing-2.md b/data/_oldPosts/2016-09-18-pen-testing-2.md deleted file mode 100644 index 26663bc..0000000 --- a/data/_oldPosts/2016-09-18-pen-testing-2.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: חלק 2 -author: nirgn -layout: post -summary: "" -category: Pen Testing ---- -בפוסט נמשיך ללמוד על נושא האנונימיות לעומק. בנוסף, אציין כי החלק הזה הינו המשך ישיר לחלק הקודם, נמשיך מאותו המקום, עם אותן דוגמאות וכד'. הסדרה מהווה סוג של יומן מסע המתעד את תהליך הלמידה שלי את עולם ה Pen Testing ממקום שאינו פורמלי ומתבצע דרך חיפוש באינטרנט, קריאת ספרים ומאמרים, צפייה ב Youtube, וחקירה אישית. - -תוכן עיניינים: - -Proxy Chain -VPN -שלוש -ארבע -חמש - - -Proxy Chain - -שרשרת פרוקסי (Proxy Chain) היא הפעולה של הגדרת התעבורה דרך מספר שרתי פרוקסי, וזאת על מנת לחזק את האנונימיות שלנו (הרי אף פעם לא ניהיה אנונימיים ב 100%, ואסור לנו לסמוך על כך. לכן עלינו להפוך את פעולת האיתור לקשה יותר במידה ומישהו ינסה לבצע זאת). לכן כעת נגדיר שרשרת פרוקסי (Proxy Chain) שתעבוד ביחד עם Tor. יש לציין כי נגדיר את המערכת כך שכל התעבורה תעבור דרך שרשרת הפרוקסי ולא רק התעבורה של הדפדפן (Browser) שלנו. - -proxychains-confנבצע את שרשור הפרוקסים עם תוכנה בשם Proxifier המגיעה כבר עם Kali, וכדי לעשות זאת נערוך את קובץ ההגדרות שלה, הנקרא proxychains ע"י כתיבת הפקודה 'sudo nano /etc/proxychains.conf' בטרמינל (Terminal) עם עורך טקסט בשם Nano (המגיע גם הוא מותקן עם Kali, והאמת שעם רוב הפצות ה Linux) (בגלל שכתבנו sudo לפני הפקודה תידרשו להכניס את הסיסמה שלכם ורק אז יפתח הקובץ, עשינו זאת בשביל לקבל הרשאות Root כדי שנוכל לערוך את הקובץ). התוכנה יכולה לבצע את התקשורת עם פרוטוקול HTTP, SOCKS4, SOCKS5 ומומלץ להשתמש ב SOCKS5 בלבד. HTTP זה הפרוטוקול המוכר לכולם (אם לא, Wikipedia is your friend) ומיועד לתעבורת HTTP, פרוטוקול SOCKS מבצע תעבורה של חבילות מידע בין שרת ללקוח דרך שרת פרוקסי, גרסה 5 של אותו פרוטוקול מוסיפה את האפשרות לאימות, ל IPv6, ול QDP (ולכן נשתמש בגרסה זו). - -אחרי שכתבנו את הפקודה, נפתח לנו הטקסט (של הקובץ) בטרמינל ואנו יכולים לערוך אותו (תמונה משמאל). למי שחדש בנושא: (בקצרה) כל שורה המתחילה ב # (סולמית) הינה הערה (comment) והמערכת אינה מפרשת אותה. בין חלקי הטקסט (הערות) נראה מילים / משפטים המתארים פקודות שיקבעו כיצד אנו רוצים שהתעבורה שלנו תנותב, הראשון הוא dynamic_chain ומתחתיו ישנו תיאור של הפקודה. - -מעל dynamic_chain אנו רואים שישנו טקסט שאומר לנו כי האופציות מתחתיו יתארו כיצד שרשרת הפרוקסי מתנהגת, ורק אופציה אחת יכולה להיות מופעלת (ז"א לא בהערה). ז"א ששרשרת הפרוקסי שלנו יכולה להיות אם dynamic_chain או static_chain. כאשר dynamic_chain אומר שכל חיבור יעשה דרך שרשור פרוקסים, וסדר השרשור יעשה על פי הסדר שבו הם מופיעים ברשימה, והמערכת תדלג על פרוקסים מתים, כך שלפחות פרוקסי אחד צריך להיות פעיל על מנת שהתעבורה תתבצע. בעוד static_chain אומר שכולם צריכים להיות פעילים, המערכת לא תדלג על פרוקסים מתים. מכיוון שאני מתכנן להשתמש בפרוקסים חינמים וסביר להניח שכמה מהם יפלו במהלך התקופה, אוציא את dynamic_chain מהערה, ואכניס את strict_chain להערה במקומו. - -random_chain אומר שכל חיבור עם proxy chain יעשה באופן רדנומלי ולא על פי הסדר של הפרוקסים שנקבעו ברשימה. ז"א שאם כתבו את הפרוקסים a,b,c. בחיבור אחד השרשור יהיה a->b->c ובחיבור שני השרשור יכול להיות c->a->b. ומתחתיו אפשר גם לשנות את אורך השרשור (chain_len) כך שאם כתבנו ברשימה 5 פרוקסים, והאורך שהגבלנו את המערכת הוא 3 אז חיבור אחד יכול להיות a->b->d. וחיבור שני יהיה c->b->e. - -לאחר מכן יש את quiet_mode שלצערי לא הצלחתי להבין מהו. ואת proxy_dns שמגן עלינו מפני הדלפות מידע משרתי DNS (או DNS leak) וצריך להיות פעיל (לא בהערה). הדלפות DNS אומר שגם אם הצלחנו להסתיר את הכתובת ה IP שלנו עדיין יש את כתובת ה IP של שרת ה DNS שאנו משתמשים ומשם אפשר לאתר את כתובת ה IP שלנו (למי שרוצה לקרוא יותר על כיצד פותרים את הבעיה הזו לחצו כאן. בגודל פשוט משתמשים בשרתי DNS אנונימיים, הם אולי יותר איטיים אבל לא שומרים log-ים). לאחר מכן יש הגדרת זמן ל Timeout, ואז דוגמאות לכיצד לכתוב את רשימת הפרוקסים. - - - -d-cain_terminalכפי שניתן לראות בדוגמאות, בעמודה הראשונה אנו מכניסים את סוג הפרוטוקול, לאחר מכן את כתובת ה IP שלו, אחר כך את מספר הפורט ששרת הפרוקסי מאזין לו (דרכו אנו מתחברים לשרת הפרוקסי), ולבסוף את שם המשתמש (אם יש) ואז את הסיסמה (אם יש). כשנירד קצת מתחת אנו רואים את שרת הפרקוסי הראשון שלנו, הדיפולטיבי שהוגדר ע"י Tor. הוא משתמש בפרוטוקול socks4, כתובת ה IP המקומית (local loop - 127.0.0.1), ודרך פורט 9050. ז"א שכל התעבורה במחשב שלנו עוברת דרך הפורט הזה שאליו Tor מאזין. אני אוסיף בדיוק את אותם פרטים רק עם socks5 מתחתיו, כדי שהתעבורה תעבור דרך Tor אך בפרוטול socks5 (בדקתי באינטרנט לפני כן ש Tor אכן תומך בפרוטוקול הזה), ונלחץ ctrl+o כדי לשמור, ואז ctrl+x כדי לצאת. - - -dns_leak_testלאחר מכן נבדוק את הסטטוס של tor עם הפקודה 'service tor status', נקבל תשובה שהוא לא פועל ('!tor is not running ... failed'), ואז נפעיל את tor עם הפקודה 'service tor start'. הדבר הבא שאנחנו צריכים לעשות הוא להשתמש בשרשור פרוקסי עם tor ודפדפן האינטרנט הקיים ב kali. נבצע זאת עם הפקודה 'proxychains firefox www.duckduckgo.com' (אנו כותבים firefox כי זה דפדפן ברירת המחדל של kali, כן למרות שכתוב Iceweasel, מכיוון שהוא פוצל מפרוייקט Firefox, ובמקום הכתובת של duckduckgo אתם יכולים לשים איזה כתובת שתבחרו - זה רק למטרות בדיקה, שוב, לא נגלוש דרך root). יפתח לנו הדפדפן, ובשורת החיפוש נכתוב "check for dns leak" וניכנס לאתר בשם "DNS leak test". שם נוכל לראות את כתובת ה IP של שרת ה DNS, ואכן לראות שהוא לא מדויק (במקרה שלי, צרפת) (אם תשימו לב בטרמינל, תראו שאנו משתמשים ב D-chain ועוברים דרך כמה כתובת IP, מחלקן אנו מקבלים denied ומחלקן OK). diff --git a/data/_oldPosts/2016-10-02-http.md b/data/_oldPosts/2016-10-02-http.md deleted file mode 100644 index 658b5ea..0000000 --- a/data/_oldPosts/2016-10-02-http.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: HTTP -author: nirgn -layout: post -summary: "" -category: Stuff ---- -HTTPבפוסט הזה נדבר על הפרוטוקול HTTP. נראה למה הוא משמש, איך הוא עובד. - -מידע כללי -מבנה בקשה - תגובה -עוגיות (Cookies) -כותרות (Headers fields) -מתודות (Methods) - - -1. מידע כללי - -HTTP אלה ראשי תיבות של Hypertext Transfer Protocol. אז נתחיל במילה הראשונה, Hypertext, הוא טקסט המוצג על גבי מסך מחשב (או כל מכשיר אלקטרוני אחר) עם התייחסויות (Hyperlinks) לטקסטים אחרים אליהם הקורא יכול לגשת. מסמכי ה Hypertext מקושרים בינהם ע"י קישורים (Links), ולמרות שהשם מתייחס רק לטקסט ה Hypertext מסוגל להציג גם תמונות, טבלאות , וטפסים. ה Hypertext הוא הקונספט שבבסיס ההגדרת המבנה של ה World Wide Web (או WWW), כאשר הדפים נכתבים בשפת HTML (ראשי תיבות של Hypertext Markup Language). - -Transfer מייצג את ההעברה של המידע על גבי רשת (במקרה שלנו ה World Wide Web). וה Protocol (פרוטוקול) (במקרה של מדעי המחשב) זהו מסמך המכיל סדרת חוקים רשמיים, במקרה שלנו (של HTTP) מדובר על סדרת חוקים לשידור או החלפה של מידע ברשת. - -החדשות הטובות הן, שאתם יודעים על מה מדובר, השתמשתם בפרוטוקול הזה אין ספור פעמים. כל פעם שאתם ניגשים לאתר, אתם כותבים http://www.google.com אתם משתמשים בפרוטוקול HTTP על מנת לגשת לאתר www.google.com (לרוב, כמו במקרה של chrome, הדפדפן יסתיר מכם את הפרוטוקול כשמדובר ב http). - - - -2. מבנה בקשה - תגובה - -Screenshot 2015-06-16 at 21.24.46בפועל מדובר על לקוח (Client) ששולח בקשה (Request) לשרת (Server) והשרת עונה בתגובה (Response). הדוגמה הפשוטה ביותר ל Client היא הדפדפן, אך אנו יכולים גם לפתוח שורת פקודה ולשלוח Request לשרת כלשהו. בשביל הדוגמה הנוכחית נשתמש בתוכנה בשם cURL (תוכנה הנותנת יכולת העברת מידע באמצעות מגוון פרוטוקולים רחב דרך שורת הפקודה, הספרייה תומכת במגוון גדול מאוד של פרוטוקולים ופועלת על רוב הפלטפורמות הקיימות), במידה והיא לא מותקנת אצלכם ניתן להוריד אותה מכאן. אנחנו יכולים לכתוב בשורת הפקודה curl -v http://wikipedia.org כדי לקבל את את הוקבץ HTML הראשי מהשרת, ולפי ה manual שלהם, אם נשתמש בדגל v- (נוסיף אותו אחרי ה curl) נקבל מידע על הבקשה בפורמט מסודר וקריא (מה שניתן לראות בתמונה למעלה משמאל). - -הכוכביות משמשות באופן דומה להערות (Comments - //), והוא בעצם אומר שהוא בנה מחדש את הכתובת ששלחתי לו, ניסה להתחבר, והתחבר לכתובת. ולאחר מכן, בשורה הראשונה (המתחילה ב <), ישנה הפקודה הראשונה, הפרוטוקול שנשלח. והחלק הראשון, GET, היא המתודה, אח"כ זה הנתיב (/ זה השורש), ואח"כ מצויין מס' הגרסה של הפרוטוקול (HTTP/1.1). לאחר מכן יש מידע בצורה של Key / Value Pair. ה Host מייצג את מי שאנחנו מבקשים ממנו את הבקשה ובמקרה שלנו זה wikipedia.org, ה User-Agent מייצג את מי מבצע את הבקשה ובמקרה שלנו זה curl/7.42.1, וה Accept מייצג את מה שקיבלנו ובמקרה שלנו זה */* שלפי הדוקומנטציה של הפרוטוקול ניתן לראות שזה אומר שקיבלנו את כל הסוגים והתת סוגים של קבצי המדיה. - -עכשיו אנחנו עוברים לחלק של השרת בפרוטוקול, הוא מקבל את הבקשה של הלקוח, וכנראה שיושב שם סוג של שרת Apache שאחראי להגיד משהו כמו 'אני יודע על מה אתה מדבר, אני אשלח לך את זה' והתגובה של השרת (Response) נמצאת בהמשך החלון של שורת הפקודה בתמונה משמאל, כשאנו יכולים להבדיל בין הבקשה לתגובה לפי החיצים בתחילת כל שורה. הדבר הראשון שאנו רואים בתגובה זה מס' הגרסה של HTTP, ולאחריו את ה status code (נרחיב עליהם בהמשך). - -לאחר מכן השרת שולח את סדרת ערכי הכותרת שלו (Header Values) כמו - -סוג השרת (Server) שבמקרה הזה הוא Varnish. -כמות התוכנת (Content-Length) שבמקרה הזה היא 0 (מתחתיו אפשר לראות את הסוג, שזה bytes). -כל הכותרות עם Xים הם נסיוניים (חלקם אומנם ניסיוניים אבל הם כך במשך המון המון זמן, אז אפשר לצפות, ולפעמים זה אפילו כבר סטדנרט בתעשייה שהם יהיו שם). -עם Set-Cookie מגדירים את העוגיות הנשמרות בצד הלקוח. -וזהו, הפרוטוקול הסתיים. הלקוח ביצע את הבקשה, השרת החזיר תגובה, והתקשורת בינהם הסתיימה. כעת אם נבצע בקשה נוספת אל מול אותו שרת, אין לו מושג מי היינו (קונספט הנקרא Stateless) והוא מחזיר את התשובה כאילו זאת הפעם הראשונה שאנו שולחים את הבקשה. - - - -REST .3 - -מערכת היחסים לקוח / שרת היא תנאי הכרחי למערכת עקרונות הנקראת REST (או Representational State Transfer). בכל פעם שאנו לוחצים על קישור באינטרנט, אנו עוברים למצב (State) חדש, מה שמביא אותנו לדף הבא. ע"י ביצוע מודל זה (לחיצה מדף לדף) אנחנו מתחילים לעקוב אחרי עקרונות REST, וכשמשהו עוקב אחרי עקרונות אלו הוא נקרא RESTful. - -API הוא ראשי תיבות של Application Programming Interface, ז"א ש RESTful API הוא חוזה בקוד. החוזה מתאר את הדרך בה תוכנה כלשהי מבצעת אינטראקציה עם תוכנה אחרת. לדוגמה, אם אנו רוצים לבצע אינטראקציה עם טוויטר, אנחנו צריכים להשתמש ב API של טוויטר, שיתאר את התהליך לבצע אימות משתמשים, לייבא כתובות URL, פונקציות וכד'. - -כשאר ה API הוא RESTful הוא: - -מפריד בין הלקוח לשרת. -לא מחזיק (/שומר) מידע בין בקשות. כלומר כל המידע הדרוש כדי להגיב לבקשה הנו תמיד זמין בכל בקשה (ז"א מסופק ע"י טוויטר בכל בקשה מחדש). -משתמש בפרוטוקול HTTP ובמתודות של הפרוטוקול. -* יש עוד כמה דרישות, אך אלה הן העקריות. - - - -3. עוגיות (Cookies) - -עוגיות הן קבצי מידע המכילות מחרוזות של אותיות ומספרים ומשמשות לאימות ומעקב אחר המשתמש. ז"א לא מעקב בסגנון FBI וכד', אלה כדי לזהות אותך מול אתר מסויים. כמו שאמרנו, פרוטוקול ה HTTP עובד בצורת Stateless ז"א שכל בקשה-תגובה הן נפרדות ואינן תלויות. לכן בהרבה מקרים, בזמן יצירת הקשר (בקשה - Request) השרת יוצר מחרוזת ומבקש מהמחשב של הלקוח לשמור אותה. בכל פעם שההלקוח (הדפדפן) יוצר קשר נוסף עם השרת המחרוזת מוחזרת חזרה לשרת על מנת שהוא בתורות יכול לזהות את המשתמש ולאחזר מידע שנשמר בינהם. - - - - - -4. כותרות (Headers fields) - -ניתן לראות את כל סוגי הכתורת כאן. - - - - - -5. מתודות (Methods) - -לתקן HTTP יש כמה מתודות, חלק הוגדרו בגרסה 1.0 והחלקן נוספו בגרסה 1.1, אך אלה שנראה לרוב הם: - -GET - מחזיר מידע ממקור ספציפי (ראינו אותה למעלה). -POST - שולח מידע חדש למקור ספציפי. -PUT - מעדכן מידע קיים במקור ספציפי. -DELETE - מסיר מידע קיים במקור ספציפי. -בקשת HTTP מורכבת מ-3 חלקים: request line שאומרת לשרת איזה סוג בקשה נשלח (GET, POST וכד') ואיזה מידע אנחנו מחפשים (יצויין בהמשך כתובת האתר), ה header ששולח לשרת מידע נוסף (כמו איזה לקוח מבצע את הבקשה, סוג התוכן המבוקש, וכ'ו), וה body שבמקרה של GET הוא ריק (אך במקרים אחרים יכול להכיל מידע, כמו בבקשת POST או PUT בהם אנו מתעסקים עם מידע). - - - -בקשה מוצלחת לשרת תספק תוצאה בדמות תשובה אותה השרת ישלח אלינו, ללקוח. כחלק מהתשובה שנקבלת מהשרת, יהיה קוד בן 3 ספרות, מ-1 עד 5. כאשר כל קוד מייצג משהו שונה. הקודים מחולקים למשפחות, וכל ספרה ראשונה (ספרת המאות) מייצגת משפחה שונה (לא אעבור על הקודים באופן מפורט יותר מאשר ספרת המאות, לכן את הרשימה המלאה ניתן למצוא, בין היתר, בוויקיפדיה). - -1xx: השרת מעדכן כי יש לו את מה שביקשת והוא עובד על הבקשה. במהירות של היום הודעות אלו לא נראות כלל. -2xx: באופן כללי הודעות אלה מגיעות כאשר השרת מאשר כי הבקשה עובדה באופן תקין והכל בסדר. דוגמה לקוד מהמשפחה הזו הוא 200, שקיבלנו בדוגמה למעלה כאשר שלחנו בקשה לוויקיפדיה. -3xx: הודעות אלה באופן כללי מעידות על כך שהשרת מסוגל לבצע את הבקשה שלנו אך היא מחכה בתור (כי הוא צריך לעשות משהו לפני, כמו לדוגמה אם השתמשנו בכתובת ישנה והוא צריך לנתב את הבקשה שלנו). -4xx: המשפחה הזאת מייצגת הודעות שגיאה. המפורסם מבינהם הוא 404. -5xx: משפחה זו מייצגת הודעות שגיאה בהם קרתה שגיאה בשרת והוא פישל, ז"א לא מצליח להגיב לבקשה. -var message = new XMLHttpRequest(); -message.open("GET", "http://www.google.com/doesnt_exist", false); -message.send(); -console.log(message.status); -בשורה הראשונה אני יוצא אובייקט HTTP בשם message. בשורה השניה אני פותח את האובייקט ומכניס לתוכו את המשתנים הרלוונטים. בשורה השלישית האובייקט - בקשה נשלח. ובהודעה הרביעית אני מדפיס את הסטטוס של הבקשה - ז"א הקוד. - - - - - - - - - -תקן HTTP גרסה 1.0 הגדיר 3 מתודות: GET לקיראה, POST למשהו, ו HEAD למשהו - -גרסה 1.1 של התקן הוסיפה מתודות נוספות: OPTIONS למשהו, PUT למשהו, DELETE למשהו, TRACE למשהו, CONNECT למשהו. - - - -במידה ואתם רוצים לבדוק את הדברים בעצמכם אני ממליץ על האתר httpbin.org כדי להתנסות. בצד שמאל ניתן לראות שלחצתי על הקישור "image/" ובתיאור כתוב ".Returns page containing an image" ואפשר לראות את ההכותרות שקיבלתי חזרה, ו - - - -HTTP/1.0 הגדיר את המתודות הבאות: - -GET - קריאת ה resource. -POST - עדכון ה resource. -HEAD - כמו GET רק ללא קבלת ה body, שזו סוג של "סימולציה" מה היה קורה לו היינו קוראים ל GET. טוב לבדיקה אם URL הוא תקין, למשל. -תקן HTTP/1.1 הגדיר מתודות נוספות: - -OPTIONS - בקשת מידע על הפעולות האפשריות על המשאב. -PUT - שמירה של מידע כמשאב ב URL המסופק. -DELETE - מחיקה של המשאב. כנראה שאתם צריכים הרשאות מתאימות בכדי לעשות זאת. -TRACE - תאורטית משמשת ל debug, אולם בפועל לא כ"כ בשימוש בגלל סכנות אבטחה שבשימוש בה. -CONNECT - מתודה טכנית שנועדה לתמוך ב HTTP Tunneling. diff --git a/data/_oldPosts/2016-10-02-unix.md b/data/_oldPosts/2016-10-02-unix.md deleted file mode 100644 index 32aa2ef..0000000 --- a/data/_oldPosts/2016-10-02-unix.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -title: הקדמה -author: nirgn -layout: post -summary: "" -category: UNIX ---- -מה זה יוניקס? - -מערכת הפעלה יוניקס (Unix) זה ערכת תוכנות הפועלות כקישור בין המחשב (החומרה) למשתמש. תוכנות המחשב שמקצות את משאבי המערכת ומתאמות את הפרטים הפנימיים של המחשב נקראות הליבה של מערכת ההפעלה, או Kernel. המשתמשים מתקשרים עם ה Kernel בעזרת תוכנית הנקראת Shell (בלינוקס הוא נקרא Bash, ראשי תיבות של Bourne Again SHell). ה Shell מתרגם את הפקודות שהמשתמש כותב (במידה והן חוקיות כמובן) לשפה שהקרנל (Kernel) יבין, הקרנל בתורו מתרגם את הפקודה לשפה אותה החומרה עצמה תבין. - -יוניקס פתוחה במקור בשנת 1969 ע"י קבוצת עובדי AT&T במעבדות בל (Bell Labs). הקבוצה כללה את קן תומפסון, דניס ריצ'י, דאגלס מקלרוי, וג'ו אוסנה. -קיימות מספר גרסאות למערכת Unix כמו Solaris, AIX, HP Unix, ו BSD. גם לינוקס (Linux) היא גרסת יוניקס. -אחד הדגשים במערכת יוניקס הוא השימוש במחשב ע"י כמה משתמשים בו זמנית (מכאן השם 'מערכת מרובת משתמשים' נדבק ליוניקס). וכמובן שגם כל משתמש יכול להפעיל כמה תוכניות בו זמנית (ריבוי-משימות). - - -ארכיטקטורת המערכת - -Unix Architectureלהלן (בתמונה משמאל) דיאגרמה בסיסית של מערכת יוניקס. - -הרעיון המרכזי המאחד את כל גרסאות יוניקס הוא ארבעת היסודות הבאים: - -Kernel - הקרנל הוא הלב של מערכת ההפעלה. הוא מקיים אינטראקציה עם החומרה, ועם רוב המשימות כמו ניהול הזיכרון, תיזמון משימות, וניהול קבצים. -Shell - הוא הכלי שמעבד את בקשות המשתמש. כאשר המשתמש מקליד פקודה ב Terminal (שזוהי מעטפת גרפית ל Bash, שהוא בעצם סוג של Shell, ה Shell בינוקס), ה Shell מפרש את הפקודה וקורא לתוכנה שאנו רוצים. ה Shell משתמש בתחביר סטנדרטי לכלל הפקדות, אך קיימים כמה סוגים של Shellים, המפורסמים הם: C Shell, Bourne Shell, ו Korn Shell, שהם זמינים ברוב הגרסאות של יוניקס. -פקודות וכלי עזר - קיימות מגוון פקודות ושירותים בהם אנו משתמשים בפעילויות היום יומיות השונות (נגיע אליהן, אך כטעימה קטנה מדובר על הפקודות cp, mv, cat, grep וכד'). ישנם יותר מ-250 פקודות סטנדרטיות ואלפי פקודות נוספות מתוכנות צד שלישי. -קבצים וספריות - כל הנתונים ב Unix מאורגנים בקבצים, וכל הקבצים מאורגנים בספריות. הספריות האלו מאורגנות במבנה נתונים מסוג עץ הנקרא 'מערכת קבצים'. - - -הבסיס - -אתחול המערכת - -בעיקרון, אם יש לנו מחשב עליו מותקנת מערכת Unix כלשהי, כל שאנחנו צריכים זה להדליק אותו ולאחר שהיא תעלה המערכת תבקש / תנחה אותנו להתחבר. במערכת לינוקס, בה אני משתמש ביום יום, ישנו ממשק גרפי הדורש ממני לתחבר, ולא שורת פקודה (רק לאחר שאני מתחבר למשתמש אני מפעיל את הטרמינל (Terminal - המעטפת הגרפית ל Bash). אך בזמן עבודתי בחברת סלקום השתמשתי ביום יום במערכת HP Unix (זאת המערכת בה הם משתמשים במתגים), כשפתחתי את שורת הפקודה הדבר הראשון שהופיע לי הוא: - -login: - מכאן כל שעלי היה לעשות הוא להקליד את שם המשתמש שלי (שניתן לי ע"י מנהל המערכת), ללחוץ על אנטר. לאחר מכן תופיע שורה המנחה אותי להכניס את הסיסמה שלי, נכניס אותה ונלחוץ על אנטר. יש לציין כי שם המשתמש והסיסמה רגישים לאותיות קטנות / גדולות, אז שימו לב שאתם מקלידים אותם בדיוק כפי שהם ניתנו לכם ע"י מנהל המערכת. לאחר שתתחברו המערכת תכתוב לכם מתי הייתה ההתחברות האחרונה שלכם (יום בשבוע, חודש, תאריך, שעה מדוויקת, שנה. וגם מאיזה כתובת IP). - -לאחר שהתחברתם יופיע לכם בשורת הפקודה הסימן $ (דולר), שם (אחריו) תקלידו את כל הפקודות (כמו cal שתראה לנו את היום בשבוע): - -$ cal - Jan 2015 -Su Mo Tu We Th Fr Sa - 1 2 3 - 4 5 6 7 8 9 10 -11 12 13 14 15 16 17 -18 19 20 21 22 23 24 -25 26 27 28 29 30 31 - -$ - - -שינוי סיסמה - -כל משתמש במערכת Unix מחוייב בסיסמה (גם מנהל המערכת). יתכן ותרצו לשנות אותה מתישהו, ובמקום העבודה כנראה שתחוייבו להחליפה באופן קבוע כל כמה שבועות / חודשים. על מנת לעשות זאת יש לכתוב את הפקודה passwd בשורת הפקודה. לאחר מכן יש להכניס את הסיסמה הישנה (וללחוץ על אנטר). אז תתבקשו להכניס את הסיסמה החדשה, ושוב לכתוב אותה כדי לבצע אימות. כל התהליך אמור להיראות כך: - -$ passwd -Changing password for nirgn -(current) Unix password:******** -New UNIX password:********** -Retype new UNIX password:********** -passwd: all authentication tokens update successfully - -$ - שימו לב שהכוכביות הם רק לצורך הדגמה. במציאות המערכת לא תראה לכם דבר (לא כוכביות, לא את מה שאתם כותבים, אפילו הסמן לא יזוז). - - - -קבצים וספריות - -כמו שאמרנו, כל המידע במערכות Unix מאורגן בקבצים, וכל הקבצים מאורגנים בתוך ספריות. הספריות האלו מאורגנות במבנה נתונים בצורת עץ, הנקרא מערכת קבצים. כדי לראות את כל הקבצים והספריות בתוך ספריה כלשהי, ניתן להשתמש בפקודה ls (כתיבת הפקודה תראה לנו את הספריות והקבצים הנמצאים בספרייה שבה אנו נמצאים כעת). נציין כי לפקודות מסויימות יש אופציות שונות, לדוגמה, הפקודה ls מציגה רק את שם הקובץ, אך אם נכתוב ls -l נקבל את סוג הקובץ, ההרשאות, מס' הקישורים הקשים, הבעלים, הקבוצה, הגודל, התאריך האחרון בו שונה, ולבסוף גם את שם הקובץ. להלן דוגמה: - -$ ls -uml -uml.jpg -univ -bla -blabla.tar -usr -webthumb.tar -yourfile.swf - -$ ls -l -total 19621 -drwxrwxr-x 2 nirgn nirgn975 4096 Jan 25 09:59 uml --rw-rw-r-- 1 nirgn nirgn975 5341 Jan 25 08:38 uml.jpg -drwxr-xr-x 2 nirgn nirgn975 4096 Jan 15 2013 univ -drwxr-xr-x 2 root root 4096 Dec 9 2014 bla --rw-r--r-- 1 root root 276480 Dec 9 2014 blabla.tar -drwxr-xr-x 8 root root 4096 Nov 25 2014 usr --rw-rw-r-- 1 nirgn nirgn975 20480 Nov 25 2014 webthumb.tar --rw-rw-r-- 1 nirgn nirgn975 166255 Aug 9 2014 yourfile.swf - -$ - שימו לב שרשומות שהינן ספריות מסומנות באות d בהתחלה (קיצור של directory) (האות הראשונה - זה נראה חלק מההרשאות). - - - -יציאה - -כשאתם מעוניינים לצאת מהמערכת, כל שיש לעשות הוא לכתוב את הפקודה logout. המערכת תנקה את הכל ותפסיק את החיבור (של המשתמש). על מנת לכבות את המערכת יש לכתוב shutdown, וכדי לאתחל אותה מחדש יש לכתוב reboot. - - - -מנהל הקבצים - -לאחר שהבנו את הבסיס, אפשר להתחיל לצלול קצת יותר לעומק. נתחיל במערכת הקבצים, כיצד היא בנויה ומנוהלת. כשאנו עובדים במערכת הפעלה כלשהי, סביר להניח שאנו מבלים חלק נכבד מהזמן בלעבוד עם קבצים. במערכת Unix יש 3 סוגים בסיסיים של קבצים: - -קבצים רגילים - קובץ רגיל הוא קובץ במערכת שמכיל מידע, טקסט, או תוכנית כלשהי. -ספריות - ספריות מאחסנות קבצים רגילים ומיוחדים. למשתמשים המגיעים מעולם ה Windows או ה Mac, ספריות הם המקבילה לתיקיות. -קבצים מיוחדים - ישנם קבצים מיוחדים המספקים גישה לחומרה (כמו כוננים קשיחים, כונני CD/DVD, מודמים, מתאמי אתרנט וכד'). קבצים מיוחדים אחרים הם קיצורי דרך, או כינויים (Aliases, נדבר על כך בהמשך), מה שמאפשר לנו לגשת לקובץ אחד בעזרת שמות שונים. - - -רישום קבצים - -כמו שכתבנו כבר, על מנת לקבל רשימה של הקבצים והספריות המאוחסנות בספרייה הנוכחית (בה אנו נמצאים כעת) נשתמש בפקודה ls, וכדי לקבל יותר מידע על הקבצים והספריות ברשימה נכתוב ls-l. כאשר הטור הראשון מייצג את סוג הקובץ, וההרשאות של מי יכול לעשות מה עם הקובץ הזה (נדבר על זה בהרחבה בהמשך). הטור השני מייצג את מספר גושי הזיכרון הקובץ או הספרייה מחזיקים. הטור השלישי מייצג את הבעלים של הקובץ (משתמש ה Unix שייצר אותו). הטור הרביעי מייצג את הקבוצה של הבעלים (לכל משתמש יש קבוצה אליה הוא משוייך. שוב, נרחיב על כך בהמשך). הטור החמישי מייצג את גודל הקובץ בבתים (bytes). הטור השישי מייצג את התאריך והשעה בו נוצר הקובץ או שונה בפעם האחרונה. ואחרון, הטור השביעי מייצג את שם הקובץ (או הספרייה). - -בדוגמה למעלה בטור הראשון, כל סוגי הקבצים מיוצגים ע"י האות d או - (בהתחלה של הטור הראשון). וכמו שאמרנו זה מה שמייצג את סוג הקובץ (ולאחריו אלו ההרשאות). אך ישנה רשימה של תווים המייצגים סוגים שונים של קבצים: - -- : קובץ רגיל כגון קובץ ASCII טקסט, או קישור קשה. -b : קובץ חסום מיוחד. הכוונה היא לחסום פלט / קלט, כמו התקן כונן קשיח פיזי. -c : קובץ תווים מיוחד. קובץ פלט / קלט גולמי. -d : קובץ ספרייה המכיל רשימה של קבצים וספריות אחרות. -l : קישור סמלי לקובץ (קישורים לכל קובץ רגיל). -p : צינור שמי (משמש כמנגנון FIFO לתקשורת בין תהליכים). -s : סוקט המשמש לתקשורת בין ממשקים. - - -תווי Meta - -תווי מטא הם תווים עם משמעות מיוחדת (במקום משמעות מילולית). לדוגמה * (כוכבית) ו ? (סימן שאלה) הם תווי מטא, כאשר בכוכבית אנו משתמשים כדי לסמן / לייצג 0 או יותר תווים, וסימן שאלה מייצג תו אחד בלבד. ז"א שאם נכתוב ls ch*.doc נקבל כתוצאה את כל קבצי ה doc שבספרייה בה אנו נמצאים, המתחילים ב ch ולאחר מכן מספר תווים לא מוגבל. ואם נכתוב את הפקודה ls *.doc נקבל את כל הקבצים בעלי סיומת doc בספרייה בה אנו נמצאים. - -$ ls *.doc -chapter 3 practice.doc -Binary.doc -YN.doc - - -קבצים מוסתרים - -קובץ מוסתר הוא כזה שהתו הראשון שלו הוא . (נקודה). תכנות ביוניקס (כולל ה shell עצמו) משתמשים בסוגי קבצים אלו כדי לשמור מידע על ההגדרות והעדפות המשתמש הקשורות לאותה תוכנה. כמה דוגמאות פופלריות של אותם קבצים מוסתרים הם profile. בו משתמש ה Broune shell כדי לאחסן את תסריט האתחול שלו, או rhosts. בו משתמש ה shell המרוחק כדי לשמור את ההגדרות שלו, וכד'. - -כדי להציג קבצים מוסתרים נכתוב ls -a. כאשר נקודה אחת תציג לנו את הקבצים בספרייה הנוכחית, ו-2 נקודות יציגו לנו את ספריית האב. - -$ ls -a - -. .profile docs lib test_results -.. .rhosts hosts pub users -.emacs bin hw1 res.01 work -.exrc ch07 hw2 res.02 -.kshrc ch07.bak hw3 res.03 -$ - - -הצגה, יצירה, ועריכת קבצים - -בכל מערכת יוניקס שהיא, ניתן להשתמש בעורך vi על מנת ליצור קבצים בעזרת הפקודה vi fileName. הפקודה תפתח מסמך עם השם fileName (או כל שם אחר שנתתם במקומו). על מנת להגיע למצב עריכה יש ללחוץ על i, וכשנכנסתם למצב עריכה ניתן, כמובן, להתחיל לכתוב את תוכן המסמך. ברגע שנסיים נוכל ללחוץ על Esc על מנת לצאת ממצב עריכה ו / או על Shift + zz על מנת לצאת מהמסמך לגמרי. המסמך ישמר כמובן בספרייה הנוכחית (הספרייה בה אתם נמצאים כעת). - -עריכת קובץ קיים מתבצעת גם היא בעזרת עורך ה vi. בהמשך נרחיב על כך יותר, אך בקצרה אנו נפתח את הקובץ כאילו הוא קובץ חדש (ע"י כתיבת הפקודה vi fileName). ברגע שהמסמך נפתח אנו יכולים להיכנס למצב עריכה ע"י לחיצה על i ולאחר מכן לערוך את המסמך. על מנת להזיז את הסמן יש לצאת ממצב עריכה (בעזרת לחיצה על Esc) ולאחר מכן לחיצה על l תזיז את הסמן ימינה, h שמאלה, k למעלה, ו j למטה. ולבסוף, גם השמירה מתבצעת באופן זהה (Shift + zz). - -כדי לצפות בתוכן הקובץ ניתן להיעזר בפקודה cat שתציג את תוכן הקובץ (התוכן יוצג בטרמינל, ולא ניתן לערוך אותו). אך זה לפעמים מבלבל לקרוא את התוכן באופן רציף, לכן אני אוהב להציג גם את מס' השורה ע"י הוספת האות b לפקודה, כך: cat -b fileName. ולהלן התוצאה שתתקבל: - -$ cat -b fileName -1 This is a UNIX file.. -2 We see it in the Shell, and with line numbers it's the best! -$ - אם נרצה לספור את מספר השורות, מילים, תווים (בהתאמה) בקובץ נשתמש ב wc ולאחריו שם הקובץ. כאמור העמודה הראשונה תציג את מספר השורות בקובץ, העמודה השניה תציג מס' המילים הכולל בקובץ, העמודה השלישית תציג את מס' התווים בקובץ, ולבסוף, העמודה הרביעית תציג את שם הקובץ. נציין כי ניתן לבקש בו זמנית להציג את המידע הנל למספר קבצים, כך: - -$ wc fileName1 fileName2 fileName3 - - -מניפולציות על קבצים - -כחלק מהעבודה שלנו עם קבצים אנו נדרשים להעתיק, למחוק, ולשנות להם שם מידי פעם. על מנת להעתיק קובץ כלשהו נשתמש בפקודה cp, אחריה נכתוב את קובץ המקור (אותו אנו רוצים להעתיק) ואחריו את היעד (הספרייה בה אנו רוצים שימצא הקובץ המועתק). - -ב Unix לא ניתן לשנות את שם הקובץ של קובץ ספציפי, אך כדי להתחכם ולעשות זאת בכל זאת אנו משתמשים בפקודה mv (שמשמשת להעביר קובץ ממקום למקום), ובאותו פורמט כמו עם cp נכתוב את השם של קובץ המקור, ואחריו את השם החדש אליו אנו רוצים לשנותו. הפקודה תזיז את תוכן הקובץ לקובץ חדש בשם החדש שנתנו לו (על מנת להזיז את הקובץ בלי לשנות את שמו אנו כותבים את אותו השם (השם המקורי) היכן שיש לכתוב את השם החדש, רק שאנו מכניסים גם את הנתיב החדש בו אנו מעוניינים שיימצא). - -על מנת למחוק קובץ כלשהו נשתמש בפקודה rm ולאחריה נכתוב את שם הקובץ שברצוננו להסיר. - -$ cp fileName \home\fileName -$ cp fileName copyFile -$ mv fileName newFileName -$ rm fileName -למעלה ישנה דוגמה להעתקת קובץ מספרייה לספרייה, לאחר מכן העתקת קובץ באותה ספרייה אך עם שם שונה (התוכן עדיין יהיה זהה), לאחר מכן החלפת שם לקובץ קיים, ולבסוף מחיקה של קובץ כלשהו. - - - -ספריות - -ספרייה היא קובץ שכל התפקיד שלו הוא לאחסן שמות קבצים אחרים ומידע רלוונטי. diff --git a/data/_oldPosts/2019-08-04-building-decision-trees.md b/data/_oldPosts/2019-08-04-building-decision-trees.md deleted file mode 100644 index e08f4f2..0000000 --- a/data/_oldPosts/2019-08-04-building-decision-trees.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -title: 3 – בניית עצי החלטה -author: nirgn -layout: post -summary: "" -category: Information Theory ---- -בפוסט הזה נבצע סקירה כללית של עצי החלטה ובנייתם, נדבר על האלגוריתם הבסיסי לבניית עצי החלטה (הנקרא ID3), נדבר על שיטות למניעת בעיית התאמת יתר (overfitting), נראה כיצד להפיק חוקים בתוך עצי החלטה, ונתייחס לשיטות דיסקרטיזציה חלוקה למרווחים של משתנים רציפים (תוך כדי בניה של עצי החלטה). - -1. סקירה של בניית עצי החלטה -2. אלגוריתם לבניית עצי החלטה – ID3 -3. התאמת יתר (Overfitting) -4. הפקת חוקים מעץ החלטה וחלוקה למרווחים - - - -  - -### 1. סקירה של בניית עצי החלטה -עצי החלטה היא טכניקת סיווג. נזכיר כי סיווג היא מתודולוגיה שמטרתה לחזות תוויות סיווג קטגוריות עבור נתונים חדשים, אותם תוויות סיווג קטגוריות יכולות להיות במקרה של סיווג ביטחוני עבר / נכשל, במקרה של נטישת לקוחות (תחום שמעניין במיוחד חברות סלולר) עובר חברה / נשאר, במקרה של תחזית מזג האוויר שמשי / מעונן / גשום וכד’. את הנושאים השונים בפוסט נראה על דוגמה קבועה בה אנו מתבקשים לקבוע קבלה של סטודנטים לאונ’. אנו נסתמך על נתונים קודמים כדי לקבוע את ממוצע התואר של הסטודנטים המבקשים להתקבל. להלן הנתונים ההיסטורים: - - -| GPA | Graduation Year | Test Grade | Admission Year | Place of Birth | Date of Birth Gender | Last Name | First Name | ID | -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| 93.5 | 2006 | 730 | 2002 | USA | 18/12/1979 | M | Cohen | David | 543406619 | -| 87.5 | 2006 | 680 | 2002 | Israel | 11/07/1980 | M | Levy | Ophir | 951984264 | -| 94.3 | 2006 | 640 | 2002 | Israel | 19/05/1981 | F | Grosman | Sharon | 683168092 | -| 85.8 | 2006 | 585 | 2002 | Russia | 11/02/1980 | F | Liberman | Diana | 100900927 | -| 78.7 | 2006 | 570 | 2002| Israel |03/02/1982 | F | Klein | Anat | 516120403 | - -ולהלן הנתונים של הסטודנטים המבקשים להתקבל: - -| GPA | Graduation Year | Test Grade | Admission Year | Place of Birth | Date of Birth Gender | Last Name | First Name | ID | -|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| ? | 2011 | 580 | 2007 | Israel | 22/09/1985 | M | Bazak | Boaz | 537793401 | -| ? | 2011 | 650 | 2007 | Israel | 10/02/1985 | M | Levy | Ophir | 808943728 | -| ? | 2011 | 720 | 2007 | Ukraine | 03/12/1987 | F | Neuman | Maria | 537362102 | - -כמו שניתן לראות ה GPA אינו ידוע (זה מה שאנו צריכים לחזות), ותתעלמו מהשנים, נניח כי אנחנו בתחילת שנת 2007 ואלו הנתונים של הסטודנטים המבקשים להיכנס לאונ’ בשנת הלימודים הבאה. - -לפני שנתחיל להפעיל אלגוריתם כזה או אחר של כריית מידע, נבצע ניקוי של נתונים שאינם רלוונטים לתהליך החיזוי (בדיוק כמו שדיברנו בפוסט הראשון). נתחיל בלהוציא את מספר תעודת הזהות, ברור לנו שלת.ז. אין השפעה להצלחה בלימודים. לאחר מכן נתעלם מהשם הפרטי והמשפחה, מכיוון שגם זה לא עוזר לנו בחיזוי ההצלחה בלימודים. לאחר מכן ניפטר גם מתאריך הלידה, קודם במסד נתונים גדול יהיו הרבה מאוד ערכים אפשריים, דבר שמקשה על החיזוי ובעצם יפרק לנו את העץ ליותר מידי עלים, לאחר מכן ישנה הטענה כי אם אנו בכלל לא מאמינים באסטרולוגיה תאריך הלידה לא משפיע על ההצלחה בלימודים, ומכיוון שאני לא מאמין באסטרולוגיה נסיר את העמודה. ולבסוף, גם את עמודת שנת הקבלה ושנת הסיום אפשר להסיר מכיוון שאינם עמודות משמעותיות ואף זהות לכל התצפיות במקרה שלנו. - -נשארנו עם טבלה מצומצת המכילה 3 עמודות בלבד (GPA לא נחשב, זהו משתנה המטרה שלנו): - -| GPA | Test Grade | Place of Birth | Gender | -|:---:|:---:|:---:|:---:| -| 93.5 | 730 | USA | M | -| 87.5 | 680 | Israel | M | -| 94.3 | 640 | Israel | F | -| 85.8 | 585 | Russia | F | -| 78.7 | 570 | Israel | F | - -לאחר שזיהנו את המשתנים הפוטנציאלים ואת משתנה המטרה, נשאלת השאלה כיצד נמצא את המודל הטוב ביותר לחיזוי ממוצע הציונים (GPA)? וכיצד נקבע אם מודל מסויים הוא טוב יותר או פחות ממודל אחר? כרגע, לצורך המשך הדיון, נניח כי המודל הטוב ביותר הוא המודל המדויק ביותר (זה שמאפשר לנו לחזות בדיוק המריבי מה יהיה הציון הממוצע בסיום לימודיו). - -הדבר הראשון שניתן לעשות הוא לנסות לחזות באמצעות רגרסיה לינארית פשוטה או רבת משתנים, במקרה הזה ננסה עם רגרסיה לינארית פשוטה עם משתנה הפסיכומטרי (Test Grade) ונראה (בתמונה משמאל) כי רוב המשתנים במציאות די רחוקים מקו הרגרסיה שהתקבל. אנו גם יכולים להעריך את איכות המודל הזה בדרך יותר פורמלית, תוך שימוש במקדם המתאם R^2 (דיברנו עליו בפוסט הקודם, מדד שמקבל ערכים בין 0 [אין קשר בין המשתנים] ל-1 [יש קשר מוחלט בין המשתנים]) ויוצא במקרה הזה כי R^2 = 0.547 שזה מקדם מתאם יחסית נמוך, כלומר אם נשתמש ברגריסה לינארית פשוטה על מנת לנבא ציון ממוצע באונ’ נקבל מודל בעל דיוק לא גבוהה. מכאן אנו מסיקים כי הקשר בין המשתנים לממוצע הציונים אינו קשר לינארי פשוט, אלא קשר מורכב יותר. - - - -נשים לב לעוד בעיה בבנושא ניקוי הנתונים, והיא ריבוי ערכים. במקרה שלנו אנו רואים שהבעיה הזאת קיימת במקום לידה (Place of Birth), נתון זה יכול לקבל הרבה מאוד ערכים אפשריים, מצב שאינו טוב לעצי החלטה (מסיבות שעליהם נדבר בהמשך), ולכן נחליף את הערכים האפשריים בעמודה ל-2 בלבד: Israel ו Abroad. משתנה נוסף שנצמצם את מספר הערכים שלו (נבצע לו דיסקרטיזציה) הוא ציון הפסיכומטרי (Test Grade), נקבע באופן שרירותי (כרגע) 3 מרווחים (אינטרוולים): ציונים בין 0 ל-600, ציונים בין 600 ל-700, וציונים מעל 700 (בהמשך נדבר על שיטות למציאה של מספר מרווחים והגבולות שלהם בצורה האופטימלית ביותר). ולבסוף, נבצע דיסקרטיזציה גם למשתנה המטרה, גם כאן באופן שרירותי ל-3 מרווחים: Low שיהיה 0-79, Meduim שיהיה בין 80-89, ו Hight שיהיה 90-100. - -לפעולת הדיסקרטיזציה יש משמעות מיוחדת – אנו מניחים מראש שיהיה לנו קשה מאוד למצוא מודל שמצליח לחזות באופן מדויק את הממוצע של כל מועמד (ואף להניח שאין לנו צורך במודל כזה, שכן לצורך קבלה לאונ’ סביר להניח שיש להניח בחיזוי מקורב יותר – כזה שמדבר על מרווחים ולא על ציונים מדוייקים). לאחר שביצענו את כל פעולות ההכנה כך נראת טבלת הנתונים: - -| GPA | Test Grade | Place of Birth | Date of Birth | Gender | Last Name | First Name | -|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -| High | Over 700 | Abroad | 18/12/1979 | M | Cohen | David | -| Medium | 600-700 | Israel | 11/07/1980 | M | Levy | Ophir | -| High | 600-700 | Israel | 19/05/1981 | F | Grosman | Sharon | -| Medium | 0-600 | Abroad | 11/02/1980 | F | Liberman | Diana | -| Low | 0-600 | Israel | 03/02/1982 | F | Klein | Anat| -| Target | Input | Input | Input | Input | Use: | | - -כעת (עוד לפני שדיברנו על איזשהו אלגו’ לבניית עצי החלטה) ננסה לבנות בעצמנו עץ החלטה, בעזרת אחד מהמשתנים המנבים. ניקח את ציון הפסיכומטרי – Test Grade, ואנו יודעים שיש לו 3 ערכים אפשריים ועל פיהם נשייך את התצפיות לענפים המתאימים. העץ שנקבל נמצא בתמונה משמאל. - -נשים לב שאם נבצע חיזוי עבור כל אחד משלושת הענפים, לגבי הענף השמאלי אין לנו החלטה חד משמעית (יש לנו שם תוצאה של Low וגם של Medium ז”א 50% שנקבל כל אחת מהתוצאות האלו), גם בענף האמצעי אנחנו לא יכולים להגיע להחלטה חד משמעית, ורק בענף הימני (Over 700) אנחנו יכולים להגיע להחלטה חד משמעית בה החיזוי יהיה ציון ממוצע של High. מכאן הדיוק הממוצע של העץ הוא 60% [מחשבים אותו כך: 100%*(1/5) + 50%*(2/5) + 50%*(2/5)]. - -כמובן שלא חייבים להשתמש במשתנה ציון פסיכומטרי, ניתן להשתמש גם באחרים, לדוג’ בתמונה משמאל ישנו עץ החלטה שנבנה עפ”י המשתנה מין (Gender). בענף השמאלי אין לנו החלטה חד משמעית, ודיוק של הענף הוא 33% בלבד, בעוד בענף הימני הדיוק 50%. מכאן שהדיוק הממוצע של העץ הוא 40% בלבד [מחושב: 50%*(2/5) + 33%*(3/5)]. - -ישנו משתנה נוסף לפיו אנו יכולים להרכיב עץ החלטה והוא מקום לידה. עפ”י משתנה זה, עבור אלה שנולדו בארץ (הענף השמאלי – Israel) יש לנו דיוק של 33%, ועבור אלה שנולדו בחול (הענף הימני – Abroad) יש לנו דיוק של 50%. ולכן גם כאן אנחנו מגיעים לדיוק ממוצע של 40%. - -אחרי שבנינו 3 עצים אפשריים, אנחנו מתלבטים באיזה משתנה להשתמש בשורש העץ? לפני שנתאר את האלגוריתם שיעזור לנו לענות על השאלה הזאת, נעשה יישור קו קטן ונעבור על כמה מושגים הקשורים למבנה העץ. - -* **קודקוד (Nodes)** – יכול להיות קודקוד השורש, אך גם להופיע באחת הרמות הבאות של עץ ההחלטה. המאפיין שלו הוא שהוא מתייחס לבדיקת הערכים של אחד המשתנים. -* **ענף (Branch)** – כל אחד מהערכים של אותו משתנה הנבדק בקודקוד יוצר איזשהו ענף של העץ. -* **עלה (Leaf)** – כאשר אנו מגיעים לעלה אנו מפסיקים לפצל את העלה למשתנים אחרים ונותנים תחזית, ניבוי לסיווג של משתנה המטרה. -* **מסלול (Path)** – המסלול מחבר בין קודקוד השורש לאחד העלים. כפי שנראה בהמשך, כל מסלול כזה מייצג חוק חיזוי. ונשים לב כי מס’ המסלולים בעץ ההחלטה יהיה תמיד שווה למס’ העלים. -סוגי תכונות ואופי הפיצול המתאימים להם: - -* **תכונות בינאריות (Binary Attributes)** – יפוצלו פיצול בינארי בלבד (כן / לא). -* **תכונות נומינליות (Nominal Attributes)** – לכל תכונה יש מספר קטן וסופי של ערכים אפשריים. ניתן לפצל תכונות נומינליות לפיצול מרובה (multiway split) וכפיצול בינארי (binary split) (בפיצול בינארי יש לקבל יחד כמה ערכי תכונה). לדוגמה: סטטוס סטודנט עשוי להיות סטודנט פעיל / שהפסיק את לימודיו / סטודנט חדש. פיצול מרובה יהיה פיצול ל-3 התכונות, בעוד פיצול בינארי יכול להיות {הפסיק לימודיו} / {פעיל, חדש} או {פעיל, הפסיק לימודיו} / {חדש} או {חדש, הפסיק לימודיו} / פעיל. -* **תכונות סידוריות (Ordinal Attributes)** – ניתן לצל לפיצול מרובה ולפיצול בינארי. לדוגמה ממוצע ציוני סטודנט בתואר יכול להיות: נמוך / בינוני / גבוהה / מצטיין. -* **תכונות רציפות (Continuous Attributes)** – לדוגמה התכונה ציון בקורס X ניתן לפצל כפיצול בינארי מעל 90 / מתחת ל-90, או כפיצול מרובה {מעל 90} / {80 עד 90} / {70 עד 80} / {60 עד 70} / {מתחת ל-60}. - - -**בעיות המתאימות לעצי החלטה** - -לא כל בעיה מתאימה לחיזוי באמצעות עצי החלטה, לכן נוודא כי המאפיינים של הבעיה שלנו אכן מתאימים לחיזוי זה. - -* נדרוש שכל תצפית תיוצג ע”י סט קבוע של משתנים [במקרה שלנו: מין (Gender), מקום לידה (Place of Birth), ציון פסיכומטרי (Test Grade)]. -* כל משתנה מנבא יקבל מספר קטן של ערכים אפשריים שונים [במקרה שלנו לא רצינו להשתמש בכל הערכים האפשריים של ארץ לידה (Place of Birth) מכיוון שמס’ הערכים האפשריים הוא גבוהה, לכן צמצמנו את הערכים האפשריים, והפכנו את המשתנה למשתנה בינארי]. -* מניחים שפונ’ המטרה מקבלת ערכים בדידים כאשר כל ערך בודד מתייחס לאיזשהי מחלקה [במקרה שלנו חילקנו את משתנה המטרה – ציון ממוצע באונ’ (GPA) ל-3 מרווחים]. -* אנו מצפים לקבל מעץ ההחלטה סט חוקים נפרדים [לדוגמה if (Test < 600 Then GPA = Low ו if (Test >= 600) Then GPA = Medium or High]. -* הנחה כי נתוני האימון יכולים להכיל רעש, טעויות. ובנוסף, כי ערכים יכולים להיות חסרים (ישנם אלגוריתמים שיודעים לטפל בערכים חסרים, אבל בנתיים נניח כי כל הערכים ידועים). - -   - -### 2. אלגוריתם לבניית עצי החלטה – ID3 -[אלגוריתם ID3](http://en.wikipedia.org/wiki/ID3_algorithm) הומצא ע”י רוס קווינלן בשנת 1986 והינו אלגוריתם חמדני, ז”א שאנו לא מחפשים מודל אופטימלי באופן כללי, אלא בונים את המודל באמצעות כלל אצבע לפיו אנו מסתכלים אך ורק על הצעד הבא (בלי הצעדים שאחריו) ובוחרים את האפשרות הטובה ביותר לגביו (ניתן להשוות את הרעיון לפתרון בעיית מבוך בה אנו מסתכלים אך ורק על הצעד הבא לפי מה שמקדם אותנו לכיוון היציאה, בלי להסתכל על כל המבוך באופן כללי ולראות כי אולי הצעד הבא מקדם אותנו יותר לכיוון היציאה אך באופן כללי הוא מקדם אותנו לפינה סגורה ממנה לא ניתן לצאת. בעוד הצעד שהיה מוציא אותנו מהמבוך נראה לנו באותו שלב כצעד שלוקח אותנו אחורה, או פחות מקדם אותנו). - -העץ נבנה מלמעלה למטה (מהשורש לעלים), כאשר בכל שלב אנו מבצעים חלוקה של תצפיות האימון לקבוצות באופן רקורסיבי. תחילה יש לנו קבוצה אחת, ז”א כל תצפיות האימון שייכות לאותה קבוצה והינה שורש העץ. בנוסף, אנו מניחים שכל המשתנים הינם מסוג קטגורי (ז”א מספר הערכים שהמשתנה יכול לקבל הינו מוגבל, סופי), לכן אם ישנו משתנה רציף אנו נבצע לו מראש דיסקרטיזציה. אז כאמור נתחיל מקדקוד השורש ונבצע חלוקה רקורסיבית עפ”י משתנים הנבחרים ע”י האלגוריתם, את המשתנה המנבא בכל שלב נבחר באמצעות כלל קבוע או משתנה סטטיסטי כלשהו. - -מכיוון שהחלוקה הרקורסיבית יכולה להימשך עד אינסוף, ישנם כמה תנאי עצירה. בראש ובראשונה נעצור אם כל התצפיות בענף מסויים שייכות לאותו סיווג מכיוון שאין טעם לחלק אותן לקבוצות קטנות יותר. נעצור גם כאשר לא נשארו לנו משתנים כדי לבצע פיצול נוסף (כלומר, השתמשנו כבר בכל המשתנים האפשריים ברמות גבוהות יותר), במקרה כזה נסווג את העלה עפ”י הצבעת הרוב, ז”א הערך השכיח ביותר באותה קבוצת תצפיות (זאת מכיוון שאנו נדרשים לקבל חיזוי מוחלט, ז”א החלטה, לא מצב של 50% אופציה א ו 50% אופציה ב). כאשר מספר התצפיות בעלה ירד מתחת לאיזשהו סף עליו החלטנו מראש (לדוג’ כאשר ישנם פחות מ-10 תצפיות נעצור את הבנייה ונסווג את העלה עפ”י השיטה של הצבעת הרוב). - -בשלב הראשון באלגו’ אנו יוצרים את צומת השורש, בודקים האם לכל התצפיות יש אותו ערך מטרה, במידה וכן האלגו’ מחזיר עץ בעל קודקוד אחד המסווג עפ”י הערך של כל התצפיות. במידה ואין לכל התצפיות אותו ערך מטרה מפצלים את הקודקוד. כדי לפצל אותו אנו בוחרים במשתנה שמסוגל לפצל את הקודקוד בצורה הטובה ביותר (נדבר כיצד לעשות זאת בהמשך, כרגע נניח שיש לנו מדד כזה, השתמשנו בו, וכך בחרנו במשתנה המפצל). ברגע שבחרנו במשתנה A אנו מוסיפים לעץ ענף עבור כל משתנה של A. אם בקודקוד אין לנו תצפיות עבור משתנה מסויים, אנו יוצרים קודקוד עלה עבור אותו משתנה (ואותו קודקוד עלה יסווג עפ”י השכיח ביותר – הצבעת הרוב), אחרת (אם יש לנו תצפיות עבור המשתנה) ניצור תת עץ עפ”י האלגוריתם שתיארנו (בצורה רקורסיבית). - -**Information Gain** -רווח אינפורמטיבי ([Information Gain](http://en.wikipedia.org/wiki/Information_gain_in_decision_trees)) היא השיטה הפשוטה ביותר לבחירת משתנה פיצול בעץ. בשיטה זאת אנו בוחרים את המשתנה בעל Information Gain הגבוהה ביותר. את הרווח האינפורמטיבי של משתנה A נחשב כהפרש בין האנטרופיה של התצפיות לפני הפיצול [(Info(D] להאנטרופיה של התצפיות אחרי הפיצול [(InfoA(D], ז”א `(Gain(A) = Info(D) – InfoA(D`. - -נניח ש Pi היא הסתברות של תצפית כלשהי בקובץ האימון ושייכת לסיווג Ci, אנו יכולים להעריך את אותה הסתברות ע”י חלוקה של כל התצפיות בעלות הסיווג Ci בכלל התצפיות בקובץ האימון. בעזרת ההגדרה הזו נחשב את האנטרופיה, ז”א `(Info(D) = -ΣPi*log2(Pi` (הנוסחה המוכרת מחישוב האנטרופיה בפוסט הראשון). לאחר מכן נפצל את המשתנה A ל v הערכים השונים שלו, ונחשב את האנטרופיה עפ”י שיקלול של מספר התצפיות השייכות לכל אחד מהענפים ונכפיל את אותו אחוז תצפיות באנטרופיה של הענף המתאים., ז”א `(InfoA(D) = Σ|Dj|/|D| * Info(Dj` {כאשר Dj הוא מספר התצפיות השייכות לענף הנוכחי). - -ואתו המשתנה (A) שיהיה בעל ה (Gain(A המקסימלי, הוא המשתנה בו נשתמש על מנת לפצל את העץ. - -  - -נחשב את הנוסחאות על הדוגמה שלנו לקבלת סטודנטים לאונ’ למשתנה ציון פסיכומטרי (Test Grade): - -* יש תצפית Low אחת, ולכן ההסתברות שלו היא 0.2 (1 מתוך 5 תצפיות), מינוס log2 של 0.2 זה 2.322. -* ל Medium יש 2 תצפיות ולכן ההסתברות שלו היא 0.4, מינוס log2 של 0.4 זה 1.322. -* גם ל High יש 2 תצפיות ולכן ההסתברות שלו היא 0.4, מינוס log2 של 0.4 זה 1.322. - -> לכן שיקלול של 2.322 + 1.322 + 1.322 = 1.522 וזהו ה (Info(D. - -כדי לחשב את (InfoA(D ניצור את הטבלה הבאה ונסתכל על העמודות שלה (0-600, 600-700, ו Over 700). יש תצפית 1 ל Low ב 0-600, ותצפית אחת ל Medium ב 0-600, ואף תצפית ל High באותו הסיווג, ולכן המשקל של כל אחת יהיה 0.5. ה מינוס log2 של 0.5 זה 1. נחשב את האנטרופיה של 0-600 ע”י הנוסחה של האנטרופיה הרגילה, (Info(D, ע”י p כפול (log2(p- של Low ועוד p כפול (log2(p- של Medium ונקבל 1. ונבצע אותו הדבר לסיווג 600-700 (האנטרופיה תצא 1) ולסיווג Over 700 (האנטרופיה תצא 0). - -אחרי שיש לנו את האנטרופיה של כל סיווג בנפרד, נבצע את האנטרופיה הכללית של החלוקה, ז”א (InfoA(D ע”י שיקלול האנטרופיה של כל סיווג במשקל היחסי שלו (ז”א ב 0-600 יש לנו 2 תצפיות מתוך 5 אז המשקל יהיה 0.4). והאנטרופיה הכללית תצא 0.8. כעת כדי לחשב את ה Gain נחסיר את (InfoA(D שחישבו עכשיו מ (Info(D שחישבו בפסקה למעלה, ונקבל שה Gain שווה ל 0.722. בטבלאות למטה נחשב את (InfoA(D גם למשתנים מין (Gender) ומקום לידה (Place of Birth). - -וכשנעשה 1.522 [שזה (Info(D] פחות 1.351 [שזה מה שיצא לנו ה (InfoA(D של 2 המשתנים] נקבל 0.171. ז”א שה Gain של המשתנה פסיכומטרי (Test Grade) יצא הגבוהה ביותר ולכן נשתמש במשתנה הזה כדי לפצל את העץ. לאחר שנרכיב עץ החלטה כשהשורש שלו הוא המשתנה Test Grade ויוצאים ממנו 3 ענפים של 600>, 600-700, Over 700 נבדוק את התצפיות ששייכות לכל ענף ובמידה וישנו רק ערך אחד נסווג על פיו, במידה וישנם כמה ערכים נבצע Information Gain גם לתצפיות האלו (עם המשתנים שנשארו, שהם Gender ו Place of Birth) ונבדוק עם איזה משתנה כדאי לפצל אותם, אם נקבל תצפיות שלכולן יש אותו ערך נסווג על פיו, אם לא נעשה שוב Information Gain, אם אין לנו יותר משתנים נסווג את העלה על פי הערך של רוב התצפיות. בתמונה משמאל ניתן לראות את עץ ההחלטה כפי שהוא צריך להיראות בסוף. - -  - -### 3. התאמת יתר (Overfitting) -יתכן מצב בו העץ שבנינו עפ”י אחד האלגוריתמים (לדוג’ ID3 שדיברנו עליו כבר) מתאים מצוין לנתוני האימון אך לא מדויק מספיק על נתוני המבחן (נתונים חדשים). מצב זה יכול לקרות כאשר אנו בונים עץ גדול מידי עם יותר מידי צמתים, יכול להיות שחלק מהענפים יתאימו באופן מדויק לנתוני האימון אך הם לא מייצגים איזשהי תבנית שחוזרת על עצמה אלא תופעות מקריות או אפילו תופעות אנומליות המתרחשות בנתוני האימון. - -ניזכר שבסעיף הראשון בדקנו את הדיוק הממוצע של העץ לפי המשתנה Test Grade ומצאנו כי הדיוק הממוצע שלו הוא 60%, ז”א לחילופין הוא טועה ב-40% מהמקרים, לכן שגיאת האימון שלו error train = 40% (ונשלים את הענפים של העץ עפ”י הרוב או באופן אקראי, ניתן לראות בתמונה משמאל את ההשלמה שלי לעץ). אם ניקח את העץ הסופי שבנינו בסוף הסעיף השני, נראה כי הוא מתאים במדויק לנתוני האימון, ז”א שהדיוק הממוצע שלו הוא 100%, ושגיאת האימון שלו (error train) היא 0%. כעת, אם ניקח תצפיות חדשות (לדוג’ את התצפיות בתמונה משמאל), ונניח שהן מייצגות את כלל האוכלוסיה, נבדוק אותן אל מול העץ הראשון (שהתקבל מ Test Grade עם שגיאת אימון של 40%) ונראה כי השגיאה שלו נתוני המבחן היא 0%, ז”א שהוא מדייק בכולן. לעומת זאת אם נקבל החלטה עפ”י העץ השני שבנינו (זה עם שגיאת האימון של 0%) נראה כי השגיאה שלו על נתוני המבחן היא 33%. - -וקיבלנו מקרה קלאסי של התאמת יתר. לכן כעת נשאלת השאלה כיצד אפשר למנוע אותה? בראש ובראשונה אנחנו יכולים להניח שישנו איזשהו גודל אופטימלי של עץ החלטה. - -כשהעץ קטן מאוד, ככל שמוסיפים לו יותר קודקודים (וכתוצאה מכך גם ענפים) דיוק האימון של עולה וגם דיוק המבחן, אך בשלב מסויים בעוד דיוק האימון ממשיך לעלות (כי את הקודקודים אנו קובעים עפ”י נתוני האימון אז ככל שיהיו יותר תתי מקרים כך העץ יתאים לאותם הנתונים טוב יותר), דיוק המבחן לעומתו נשאר אותו הדבר, ולאחר מכן אף מתחיל לרדת. מכך אנו מסיקים את הטענה שמעבר למס’ קודקודים אין טעם להמשיך לפצל את העץ. - -קיימת 2 גישות שונות בבניית עצי החלטה המונעות מצב זה: - -1. גיזום מוקדם (Prepruning) – בגישה זו אנו מפסיקים לבנות את העץ מספיק מוקדם, ז”א לא נפצל איזשהו קודקוד, במידה והפיצול מביאה לירידה במדד איכות מסויים שבסופו של דבר יביא אותנו לקבל עץ שלא מספיק מדויק על נתוני המבחן. נציין כי הקושי בגישה זו הוא לבחור בסף המתאים כדי לעצור את הבניה של העץ. -2. גיזום מאוחר (Postpruning) – גישה זו הוכיחה את עצמה יותר מהגישה הקודמת, ובה אנחנו קודם כל בונים את העץ המלא (עם מס’ מקסימלי של קודקודים) ואז, באופן הדרגתי, מנסים לצמצם את הענפים בעץ. אנו משתמשים בקובץ נפרד המכיל נתוני מבחן כדי לבדוק את העץ ולדעת לבחור (בעזרתם) את העץ המדויק ביותר (ז”א מתי להפסיק לגזום אותו). -דוגמה ל Postpruning ניתן לראות בדוגמה למעלה, היינו יכולים לקחת את העץ המלא שהגענו אליו בסוף סעיף 2, לגזום את המשתנים Place of Birth ו Gender ולהגיע לעץ Tree 1 בתמונה משמאל למעלה. - -**קביעת הגודל האופטימלי של העץ החלטה** - -קיימות כמה שיטות / גישות לקביעת הגודל האופטימלי של עץ החלטה. אחת מגישות, הנפוצה מבינהם היא גישה עליה דיברנו כבר, והיא אומרת לחלק את התצפיות (באופן אקראי) ל-2 קבוצות, כאשר 2/3 מהתצפיות יהיו בקבוצת האימון ממנה אנו בונים את העץ, ו-1/3 יהיו בקבוצת המבחן איתה אנו נבחן את המודלים השונים של העצים, ובעצם עם קבוצה זו נקבע מהו העץ שיבחר (מתוך העצים האפשריים). - -שיטה נוספת, שכבר דיברנו עליה בפוסט הקודם, נקראת Cross Validation. אפשר להשתמש בשיטה זו גם כאן (כדי לקבוע את הגודל האופטימלי של העץ). נזכיר כי בשיטה זו נבחר מס’ (לדוג’ 10) שיקבע את מספר המודלים שנבנה, כאשר נחלק באופן אקראי את התצפיות ל-10 קבוצות, וכל פעם 9/10 קבוצות יהיו בקבוצת האימון שתבנה את מודל העץ, והקבוצה שנשארה (1/10) תשמש כקבוצת המבחן. ונעשה זאת 10 פעמים, כך שכל הקבוצות ישמשו פעם אחת כקבוצת המבחן. - -גישה נוספת מבוססת על תורת האינפורמציה ונקראת אורך תיאור מינמלי (MDL). בשיטה זו אנו מפסיקים לבנות את העץ כאשר מביאים למינימום את אורך הקידוד הכולל של העץ וגם של השגיאות שלו. - -ולבסוף, הגישה האחרונה (עליה נרחיב יותר) אומרת כי אין לנו צורך בקבוצת מבחן ואנו משתמשים בכל התצפיות בקבוצת האימון. וניעזר במשתנה סטטיסטי כלשהו (לדוג’ חי בריבוע) על מנת להעריך האם כדאי לנו לפצל קודקוד מסויים על מנת לשפר את הדיוק של העץ. - -גישת חי בריבוע ([Chi-Square](http://en.wikipedia.org/wiki/Chi-squared_test)) מבוססת על המבחן הסטטיסטי הידוע הנקרא באותו שם. להלן הסימונים של המבחן: - -* **A** – המשתנה עליו אנו מעוניינים לבצע את הפיצול. -* **v** – מסמנים את גודל התחום של אותו משתנה (מספר הערכים האפשריים של המשתנה). -* **Ci** – זאת תת קבוצה של תצפיות המתייחסות לערך i של משתנה A. -* **c** – מספר הסיווגים שיש לנו בתצפיות. -* **ej** – מספר התצפיות ששיכות לסיווג j בבסיס הנתנוים C. -* **oij** – מספר התצפיות ששייכות לסיווג j בתוך תת קבוצה Ci (אותה תת קבוצה שמתייחסת לערך i של המשתנה המפוצל A). -* **α (אלפא)** – רמת מובהקות במבחן חי בריבוע. - -השערות המבחן הן: השערת ה-0 (ההשערה אותה אנו מנסים לבחון באמצעות מבחן חי בריבוע) היא: המשתנה A אינו רלוונטי לסיווג של התצפיות בבסיס הנתונים C (כלומר אם נפצל את התצפיות, עפ”י הערכים של A אנחנו לא נוכל לשפר את דיוק החיזוי). וההשערה האלטרנטיבית היא: שלמשתנה A כן יש השפעה על התפלגות הסיווג בבסיס הנתונים C. במבחן זה משתמשים בסטטיסטיקה על מנת להשוות בין 2 התפלגויות כל אוכלוסיה נתונה, אך במקרה של בניית עץ, נשאלת השאלה האם התפלגות של משתנה המטרה מושפעת כתוצאה מפיצול עפ”י ערכים של איזשהו משתנה A. - -על מנת לחשב את הסטטיסטי של המבחן נחשב קודם את המספר החזוי של תצפיות השייכות לסיווג j בקבוצה Ci: ניקח את אחוז התצפיות השייכות לסיווג j בכלל בסיס הנתונים ונכפיל במספר התצפיות הנמצאות בקבוצה Ci. לאחר מכן נחשב את הסטטיסטי של המבחן ע”י לקיחת ההפרש שבין מס’ התצפיות הצפוי (עפ”י השערת ה-0) למס’ התצפיות בפועל, ומחלקים במס’ התצפיות הצפוי. בתמונה משמאל ניתן לראות את הנוסחאות (הראשונה לחישוב המספר החזוי של התצפיות, והשנייה לחישוב הסטטיסטי) (ואת מס’ דרגות החופש של הסטטיסטי מחשבים ע”י מס’ הערכים של המשתנה A פחות 1, כפול מס’ הסיווגים פחות 1). - -כלומר, אם השערת ה-0 נכונה, אנו מצפים שהערך של הסטטיסטי שלנו יהיה נמוך יותר מהערף הקריטי של חי בריבוע, לעומת זאת אם הערך גבוהה יותר מהערך הקריטי אז נדחה את השערת ה-0, ונפצל את הקודקוד. - -**דוגמה לחי בריבוע** - -ניזכר שלפני הפיצול החלוקה הייתה: סטודנט אחד = Low, שתי סטודנטים = Medium, ו-2 סטודנטים = High. וכעת אנו רוצים לדעת האם כדאי לנו לפצל עפ”י המשתנה Test Grade (הציון הפסיכומטרי). - -עבור ערכים מתחת ל-600 (ז”א Test < 600) יש לנו 2 ערכים, אחד עם ממוצע Medium והשני עם ממוצע Low. נחשב את מס’ התצפיות הצפוי (מכל סוג) עפ”י השערת ה-0: כיוון שיש לנו 2 תצפיות עם ערכים “מתחת ל-600” נכפיל את האחוז ב-2, ז”א `e’low = (1/5)*2 = 0.4`, ו `e’medium = (2/5)*2 = 0.8`, ו `e’high = (2/5)*2 = 0.8`. ז”א שבהינתן השערת ה-0, אנו מצפים לקבל 0.4 תצפיות בסיווג low, ו-0.8 תצפיות בסיווג medium, ו-0.8 תצפיות בסיווג high. -נלך לענף השני, Test בין 600 ל-700, ונראה שיש לנו שם 2 ערכים, אחד עם ממוצע Medium והשני עם ממוצע High. נעשה את אותו החישוב ונקבל את אותם התוצאות כמו בענף הראשון: ז”א `e’low = (1/5)*2 = 0.4`, ו `e’medium = (2/5)*2 = 0.8`, ו `e’high = (2/5)*2 = 0.8`. -נלך לענף השלישי, Test > 700, ונראה שיש לנו שם ערך אחד עם ממוצע High. נעשה את החישוב: `e’low = (1/5)*1 = 0.2`, ו `e’medium = (2/5)*1 = 0.4`, ו `e’high = (2/5)*1 = 0.4`. -בעזרת כל החישובים האלו נחשב לבסוף את הסטטיסטי (שיהיה שווה ל-3.75) וכאשר החי בריבוע ברמת מובהקות של 0.05 ועבור 4 דרגות חופש הוא שווה ל x²0.05(4) = 9.49. הגענו ל-4 דרגות חופש מכיוון שלמשתנה Test ha 3 ערכים 3-1 שווה ל-2, וגם לתצפיות עצמן יש 3 סיווגים אפשריים (Low, Medium, ן High) ו 3-1 זה שוב 2, וכשנכפיל 2*2 נקבל 4. - -מכיוון שקיבלנו סטטיסטי נמוך יותר מהערך הקריטי של חי בריבוע לא נדחה את השערת ה-0, והמסקנה היא שעפ”י מבחן זה לא כדאי לפצל את הקודקוד עפ”י המשתנה של הציון הפסיכומטרי. - -  - -### 4. הפקת חוקים מעץ החלטה וחלוקה למרווחים -להלן (בצד שמאל) העץ שבנינו בסוף סעיף 2. בעץ הזה אנו רואים 5 עלים, וכל עלה כזה ניתן לנסח כחוק חיזוי. למשל: `If (Test < 600) and (Place of Birth = Israel) Then Grade = Low` וכך הלאה לכל העלים. אין הרבה מה להרחיב על הפקת החוקים, כל צומת בעץ היא תנאי של ה If שצריך להתקיים (and) ולבסוף הצומת הראשונה ממנה יצאנו תיהיה שווה לערך של העלה. - -דסקרטיזציה (חלוקה למרווחים) של משתנים רציפים תוך כדי בנייה של עץ החלטה. נזכיר, כי עד כה הנחנו שכל משתנה שיש לנו בעץ הוא משתנה קטגורי, משתנה בדיד. וראינו גם שאם היה לנו דוגמאות שאם היה לנו איזשהוא משתנה רציף היה אפשר לחלק אותו מראש למרווחים. הגישה הפשוטה ביותר לחלוקה למרווחים מכונה דיסקרטיזציה בלתי מודרכת (Unsupervised Discretiztion) ודיברנו עליה בפוסט הקודם. בקצרה, בגישה זו מחלקים את המשתנה הרציף למרווחים בעלי רוחב זהה או בעלי תדירות זהה (bins). שיטה זו היא סטטית, מאחר שהשיטה קובעת את אופן החלוקה לכל משתנה במודל הסיווג. - -מנגד, כדי לשפר את יעילות הסיווג פותחו כמה שיטות לדיסקרטיזציה סטטית מודרכת (Supervised Discretiztion Static) המבוססת על ערכי משתנה המטרה בכל רשומת אימון. הדוגמה הפופלרית לאלגוריתם הממש שיטה זו היא אלגו’ לדיסקרטיזציה בינארית המבוסס על מינמיזציה של אנתרופיית משתנה המטרה. הלאגוריתם מתחיל בפיצול של מרווח יחיד. ולאחר מכן, כל תת מרווח מפוצל רקורסיבית. וקריטריון העצירה הוא עקרון ה MDL (עליו דיברנו בפוסט הקודם). - -כדי להחליט על הפיצוללמרווחים נחשב את הרווח האינפורמטיבי (ההפרש בין האנתרופיה של לפני ואחרי הפיצול), ונבחר את הנק’ עם הרווח המקסימלי (כמובן שנעשה זאת לכל נק’ פיצול עד שנגיע לאחד מהקריטריונים לעצירה). בצד שמאל ניתן לראות את הנוסחה לחישוב, ולמטה מקרא שלה. - -* S – הסט הכולל של התצפיות. -* A – המשתנה הרציף שאנו מעוניינים לפצל. -* T – נק’ הפיצול (הגבול בין 2 המרווחים). -* S1 – כל התצפיות הנמצאות מתחת לנק’ הפיצול. -* S2 – כל התצפיות הנמצאות מעל לנק’ הפיצול. - -  - -### לסיכום -ראינו שעצי החלטה היא אחת הטכניקות הפופלריות ביותר לסיווג של תצפיות, את האלגוריתם הבסיסי לבניית עצי החלטה, ניתן לבחור את המשתנה הטוב ביותר לפיצול באמצעות מדדים שונים (כאשר האלגו’ ID3 בוחר עפ”י הרווח האינפורמטיבי, Information gain, כלומר אותו משתנה שמביא אותו למקסימום). כאשר העץ גדול מידי ומתאים מידי לנתוני האימון יכולה להתעורר בעיה של התאמת יתר (Overfitting) וראינו את שיטת גיזום מוקדם ע”י עצירת בניית העץ ואת גיזום מאוחר המשמשות למנוע את התופעה. diff --git a/data/_oldPosts/2019-08-18-introduction-to-information-theory.md b/data/_oldPosts/2019-08-18-introduction-to-information-theory.md deleted file mode 100644 index b21c679..0000000 --- a/data/_oldPosts/2019-08-18-introduction-to-information-theory.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -title: 1 – מבוא ותורת המידע -author: nirgn -layout: post -summary: "" -category: Information Theory ---- -בכל סמסטר בו אני לומד איזשהו קורס, כחלק מהלימוד עצמו אני קורא ספרים, פותר תרגילים, מכין סיכומים וכד’. ולאחרונה התחלתי ללמוד כריית מידע (Data Mining), אז כמו בחלק מהקורסים הקודמים, החלטתי לכתוב סדרת פוסטים המהווה יומן מסע ותכיל את הסיכומים של חומרי הלימוד כפי שאני לומד ומכין אותם. הספר עליו אני מתבסס הוא [Data Mining Concepts and Techniques (מהדורה שלישית)](http://www.amazon.com/Data-Mining-Concepts-Techniques-Management/dp/0123814790) והוא זמין גם כ[קובץ PDF](http://www.cse.hcmut.edu.vn/~chauvtn/data_mining/Texts/%5B1%5D%20Data%20Mining%20-%20Concepts%20and%20Techniques%20%283rd%20Ed%29.pdf). - -בפוסט זה נדבר על: -1. למה לכרות מידע? -2. מהי כריית מידע? -3. מודלים ואלגוריתמים -4. מחסן נתונים מול מסד נתונים -5. תורת האניפורמציה -6. תקשורת -7. הגישות השונות לכריית מידע - - - -  - -### 1. למה לכרות מידע? -אנחנו חיים בעולם עם כמויות עצומות של מידע הנאסף מידי יום, וניתוח של המידע הוא פעולה חשובה. נראה כיצד פעולת כריית המידע עונה על צורך זה בעזרת סיפוק כלים לחשיפת הידע מהמידע, ונראה כיצד פעולת כריית מידע ניראת אבולוציה טבעית לתוצאה של מידע טכנולוגי. - -“אנחנו חיים בעידן המידע” היא אמרה פופולרית, אך האמת היא שאנחנו חיים בעידן הנתונים. טאראה בייטים ואפילו פטאבייטים של מידע נשפכים לרשתות המחשבים שלנו, לאינטרנט (WWW), ומרכזי אחסון נתונים שונים בכל יום מהעסקים השונים, מהחברה באופן כללי, מתחום המדע, ההנדסה, הרפואה, ובקיצור כמעט מכל אספקט של חיי היום יום שלנו. הפיצוץ האדיר הקיים בשנים האחרונות של נתונים נובע ממהפכת המחשוב שהחברה שלנו עוברת והפיתוח המהיר של כלים חזקים לאיסוף ואחסון נתונים. - -מכאן נולד הצורך לכלים חזקים ורב תכליתיים שבאופן אוטומטי יחשפו מידע יקר מהררי המידע הזמינים, ואף יהפכו אותו לידע מאורגן. הצורך הזה הוביל להולדת התחום הנקרא כריית מידע. תחום צעיר, דינמי, ומבטיח המתיימר להביא אותנו מעידן הנתונים אל עידן המידע. - -דוגמה: כריית מידע הופכת אוסף גדול של נתונים לידע. מנוע חיפוש (דוגמת Google) מקבל מאות מליוני שאילתות בכל יום, כל שאילתה מתארת את הצורך / המידע שהמשתמש מבקש. באופן מעניין נמצאו תבניות בשאילתות החיפוש של המשתמשים. לדוגמה, הצליחה גוגל למצוא קשר ישיר בין מס’ האנשים שחיפשו על מידע הקשור לשפעת ומספר האנשים בפועל שהיה להם סימפטומים של שפעת. בעזרת איסוף המידע, גוגל מצליחה להעריך פעילות של שפעת באזור מסוים עד לשבועיים מהר יותר (לפני) מערכות מסורתיות. - -  - -### 2. מהי כריית מידע? -כריית מידע יכולה להיות מוגדרת במגוון דרכים שונות, ולמרות שאולי לא מייצגת כהלכה את המשמעות, כרייה היא תהליך של מציאת דבר מה יקר, קטן, ממידה רבה של חומר גלם כלשהו. מושג פופולרי נוסף, ואולי אף מדויק יותר הוא Knowledge Discovery in Databases (חשיפת / גילוי מידע במסדי נתונים או KDD). המושג מתייחס לתהליך הלא טריוואלי של זיהוי דפוסי מידע תקפים / שעשויים להיות שימושיים / מובנים / חדשים. - -כריית מידה יכולה להיות מיושמת לכל סוג של נתונים. הצורה הבסיסית ביותר של יישום כריית המידע היא לנתונים במסדי נתונים, במחסני נתונים, ונתוני עסקאות (טרנזקציות). אך כריית מידע יכולה להיות מיושמת גם על צורות אחרות של נתונים, כמו זרמי נתונים, נתוני רשת, נתוני גרף, נתונים מרחביים, נתוני טקסט, נתוני מולטימדיה, וגם ה WWW. - -**תחומי יישום KDD:** - -* **CRM** ([ניהול קשרי לקוחות](http://en.wikipedia.org/wiki/Customer_relationship_management)) – תחום העוסק בשירות לקוחות, הבנה וניתוח צרכיהם. המערכות מתיימרות לזהות את המאפיינים של הלקוח, דפוסי הצריכה, העדפות, מידת שביעות רצונו, ואף חיזוי סיכויי הנטישה של הלקוח. -* **פיננסים** – זיהוי זיופים ע”י הרגלי צריכה בכרטיס אשראי, דירוג קרדיט בנקאי, אישור הלוואות והתאמת ריביות, חיזוי מניות ושערי מטבעות, וכד’. -* **שיווק ומסחר** – פניות באמצעות דואר או אימייל לרכישת מוצרים, חיתוך קהלי יעד, חיזוי המידע שבו המשתמש מעוניין, וכ’ו. -* **פריצות למערכות מחשבים** – זיהוי פריצה ע”י הרגילה שימוש וכד’ (תחום שעדיין בחיתולים יחסית). -* **רפואה** – שיפור הבחנות הרפואיות, זיהוי טיפולים אופטימליים לסוג מסוים של חולים, וכ’ו. -* **ביטחון** – זיהוי קשרים לארגונים או מבוקשים מסויימים, הפקת מידע לשימוש ארגוני ביון וכד’. - -**תהליך חשיפת המידע הוא תהליך איטרטיבי של הצעדים הבאים:** - -* **מטרות** – זיהוי מטרות התהליך, מדוע אנחנו רוצים לבצע בכלל את פעולת כריית המידע (להפעיל אלגוריתמים לכריית מידע על הנתונים). -* **בחירת נתונים** – בחירת הנתונים ממסד נתונים קיים, יצירת הנתונים (במידת הצורך) ע”י בחירת מדגם, וכ’ו -* **ניקוי המידע** – בדרך כלל כשמדובר על נתונים אמיתיים יש צורך לנקות אותם, ז”א כוליים מידע לא מדויק, חלק מהנתונים שגויים, לא רלוונטים. במצב כזה נשאלת השאלה כיצד מזהים נתונים שגויים? וכיצד מתמודדים במצב שחסרים לנו נתונים? -* **שילוב נתונים** – שילוב כל כמה מקומות מידע למחסן נתונים אחד (צעד זה אינו הכרחי). -בחירת ושינוי הנתונים – בחירת הנתונים / ערכים הרלוונטים ביותר, ולפעמים גם הגדרת משתנים חדשים (ע”י חישוב מהנתונים הקיימים). -* **כריית מידע** – נפנה לאלגוריתמים לכריית מידע ונריץ אותם על סט הנתונים שבחרנו. במידה וקיים צורך להתאמת הנתונים לכרייה על פי האלגוריתמים שבחרנו. -* **הערכת דפוסים / תבניות** – זיהוי התבניות, יישום טכניקות הצגת המידע (ויזואליזציה) למשתמשים, שחזור מטה-נתונים ([Metadata](http://en.wikipedia.org/wiki/Metadata)) כדי להבין את המשמעות של התבניות והדפוסים שנחשפו, הפקת התבניות בעזרת שיטות סטטיסטיות כמו מובהקות סטטיסטית, מעוניינות, חשיבות, רלוונטיות, אפשרות פעולה, וכ’ו. -לעיתים קרובות, לאחר הערכת התבניות נגלה שהמטרה לא הושגה ואנו לא מרוצים מהתוצאות, לכן יש צורך לחזור על חלק מהשלבים. לדוגמה לחזור על שלבי הכנת הנתונים (1-4) ולהכין אותם בצורה שונה, לחזור על שלב 5 ולבחור סט נתונים קצת שונה, הרצת אלגוריתם אחר או עוד אחד, או שינוי הפרמטרים שלו (שלב 6), ועוד. - -  - -### 3. מודלים ואלגוריתמים -**המודלים בתחום כריית המידע נחלקים ל-3 קטגוריות:** - -* **מודלי קופסא לבנה** – מודלים מוכרים בהם אנו לא זקוקים לנתונים חדשים על מנת ללמוד את המודלים האלו. המודלים ידועים והתגלו בעבר, וכל שאנו עושים (באמצעות הנתונים) הוא לאושש את אותם מודלים (לדוגמה מודלים המאששים חוקים פיזקליים, המודלים מגיעים מתוך נתונים שהגיעו מעריכת ניסויי מעבדה). -* **מודלי קופסא אפורה** – אנו כן יודעים את הצורה הכללית של המודל (לדוגמה מודל לרגרסיה לינארית, Y = ax + b). אך אנחנו לא בטוחים לגבי הפרמטרים השונים של המודל. גם מודלים אלה יחסית קלים לחישוב, ולכן רוב הזמן כשנדבר על אלגוריתמים לכריית מידע נתכוון להפקה של המודלים השחורים. -* **מודלי קופסא שחורה** – מודלים מורכבים לדוגמה מודל של רשת נויירונים (ANN, ראשי תיבות: [Artificial Neural Network](http://en.wikipedia.org/wiki/Artificial_neural_network)). מודלים שקשה להבינם, מורכבים מעשרות או מאות אלמנטים שונים. - - -חשוב לציין כי תחום כריית המידע צמח מתחומים קיימים כמו זיהוי תבניות (הכולל זיהוי תווים, אובייקטים, פנים וכד’), Machine Learning (למידה מניסיון, וההנחה שככל שנצבור יותר ניסיון, יהיו יותר נתונים, נפיק יותר ידע לגבי התהליך הנחקר), סטטיסטיקה והסתברות (למידה מידע לא מושלם, רועש), אלגוריתמים ותאוריות חישוב מורכבות, תורת הבקרה (איזון של התהליך מתוך פידבק חוזר), תאוריית האינפורמציה, ועוד. - -בכנס ICDM שנערך בדצמבר 2006 (אחד מהכנסים הראשיים לכריית מידע), נערכה הצעה לאלגוריתמים השימושיים ביותר בתחום. ולהלן הטבלה למטה (בצירוף הבעיה הנפתרת ע”י כל אחד מהאלגוריתמים): - -| סוג הבעיה שהאלגוריתם פותר | Algorithm | Rank | -|:---:|:---:|:---:| -| עצי החלטה | C4.5 | 1 | -| ניתוח אשכולות | K-Means | 2 | -| סיווג ורגרסיה | SVM | 3 | -| חוקי הקשר | Apriori | 4 | -| ניתוח אשכולות | EM | 5 | -| כרייה באינטרנט | PageRank | 6 | -| Ensemble learning | AdaBoost | 7 | -| למידה מבוססת תצפיות | Knn | 8 | -| למידה בייסיאנית | Naive Bayes | 9 | -| עצי החלטה | CART | 10 | - -   - -ישנן כמה שיטות לכריית מידע, אחת משיטות הסיווג המצויות בשימוש היא עץ החלטה. כדי לקבל מושג קל, נציג עץ החלטה כזה ונסביר את המונחים הקשורים אליו. עץ הוא מבנה אבסטרקטי המתאר היררכיה בין אובייקטים. בעץ ישנם קודקודים (צמתים) עם קשר אב-בן, דוגמה לעץ כזה היא אילן יוחסין. קיימים אלגוריתמים שונים לבניית עצי החלטה (נדבר עליהם בעתיד). אך על עץ החלטה יכיל את המבנה הבא: - -* שורש – קודקוד (צומת) ללא אב. בדוגמה משמאל זהו A. -* בן – קודקוד G הוא בן של קודקוד C אם יש קשת מ C ל G. -* אב – קודקוד C הוא אב של קודקוד G, אם יש קשת מ C ל G. -* עלה – קודקוד ללא בנים. לדוגמה G. -* קודקוד פנימי – קודקוד שאינו עלה ושהוא אינו שורש, כלומר יש לו אב ולפחות בן אחד. לדוגמה C, F, B. -* צאצא – קודקוד I הוא צאצא של B, אם יש מסלול אבות-בנים מ B ל I. -* אב קדמון – קודקוד B הוא אב קדמון של J, אם יש מסלול של אבות-בנים מ B ל J. -* תת עץ – תת עץ המורש מ B, זהו עץ ש B הוא שורש שלו, ומכיל את כל הקודקודים ש B הוא אב קדמון שלהם ואת הקשתות ביניהם בעץ המקורי. - -את העץ נקבל כתוצאה משימוש באלגוריתמים לבניית עצי החלטה (לא נציין אותם כרגע). כל קודקוד בעץ הוא שאלה שאנו צריכים לענות עליה ולפיה ללכת לבן המתאים, וכל עלה הוא תוצאה אפשרית (חיזוי). - -ישנם מודלים נוספים של כריית מידע כמו אשכול ([Cluster](http://en.wikipedia.org/wiki/Cluster_analysis)). אשכול הוא קבוצה של רשומות בעלות מאפיינים דומים. ניתוח אשכולות הוא פילוח רשומות בבסיס נתונים לאשכולות, כך שבכל אשכול נמצאים רשומות בעלות מאפיינים דומים. לדוגמה, ניתן לפלח את הסטודנטים לפי ההישגים שלהם (מצטיינים, טובים, בינוניים, וחלשים) באו”פ. דוגמה נוספת יכולה להיות פילוח הסטודנטים לפי אזורי מגורים. ישנו גם מודל רגרסיה ([Regression](http://en.wikipedia.org/wiki/Regression_analysis)). שהיא שיטה סטטיסטית המשמשת לבדיקה ולניבוי של קשרים בין שני משתנים (או יותר) (שיטה זו מצויה בשימוש נרחב במחקרים כמותיים בתחומי הדע השונים. הרגרסיה הפשוטה ביותר היא רגרסיה לינארית עם שני משתנים: משתנה מסביר ומשתנה מוסבר). - -   - -### 4. מחסן נתונים מול מסד נתונים -מערכת מסד נתונים (נקראת גם [Database Management System או DBMS](http://en.wikipedia.org/wiki/Database)) מכילה אוסף של נתונים הקשורים זה לזה, הידועים גם כ”מסד נתונים”, וסט של כלים / תוכנות לניהול וגישה לנתונים. התוכנות מספקות מנגנונים להגדרת מבנה ואחסון מסד הנתונים, לציון וניהול בו זמני, שיתוף או גישה מבוזרת לנתונים, והבטחת עקביות וביטחון של הנתונים המאוחסנים על אף קריסות מערכת או ניסיונות גישה לא מורשים. DBMS כזה נקרא גם בסיס נתונים תפעולי, ומשמש לביצוע ותיעוד הפעילות השוטפת של הארגון. העיבוד בו מכונה עיבוד תפעולי מקוון או OLTP (ראשי תיבות: Online Transactional Processing). - -לעומתו, קיים סוג נוסף של בסיס נתונים המשמש לעיבוד ולניתוח נתונים שהצטברו במערכות קיימות, ובדרך כלל מדובר במערכות תפעוליות. בבסיסי הנתונים האלו מתבצעת אינטגרציה של נתונים ממערכות שונות (תוך כדי טיפול בשמות שונים של אותם משתנים, יחידות מידנה שונות, מפתחות שונים וכד’). נתונים אלו מאוחסנים בצורה סיכומית ובחתכים המקלים על תהליכי העיבוד והניתוח, והנתונים יציבים יחסית ומעודנים בתידורת שנקבעת מראש (הנתונים נשמרים לפרקי זמן ארוכים יותר מב DBMS, ואינם מתעדכנים באותה תדירות, ובטח שלא בזמן אמת, כמו ה DBMS). בסיס נתונים זה נקרא מחסן נתונים או DW (ראשי תיבות: Data Warehouse), והעיבוד המבוצע ע”י DBA, כדוגמת עיבוד שאילתות והפקת דוחות, מכונה עיבוד אנליטי מקוון או OLAP (ראשי תיבות: Online Analytical Processing). - -[bill inmon](http://en.wikipedia.org/wiki/Bill_Inmon) (אחד מהאבות של התחום) מגדיר את מחסן הנתונים כמאגר נתונים המוכוון לנושא מסויים, ומשלב נתונים ממוקורות שונים. הנתונים הינם תלויי זמן ובלתי נדיפים (אינם ניתנים למחיקה). המטרה של מחסן נתונים שכזה הוא לתמוך בתהליך קבלת ההחלטות של ההנהלה. ולרוב מקושר לנושא מסויים (שיווק, רכישה, ייצור, בקרת איכות וכ’ו). - -   - -**קוביית מידע** - -מודל הנתונים עבור OLAP הוא מודל רב מימדי. כלומר, מסתכלים על המידע מנקודת המבט של מדד כמותי אחד שמעניין את המשתמש לפי ממדים – חתכים שונים. במחסן הנתונים עשויים להיות מספר מדדים שמעניינים את המשתמש, ולכל אחד מהם כמה מדדים. עיבוד נתוני מחסן הנתונים מתבצע על ידי משתמש הקצה באמצעות כלי OLAP, כשהנפוץ בינהם הוא קוביית מידע ([Data Cube](http://en.wikipedia.org/wiki/OLAP_cube)). בצד שמאל ישנה דוגמה לקוביית מידע בה אנו מתארים את נפחי המכירות בחברה Sony כפונקציה של מוצרים (טלוויזיות, מחשבים וכד’), רבעונים, וארצות (ארה”ב, קנדה, ומקסיקו). ממדי הנתונים מוגדרים באופן הבא: מיקום, מכירה, זמן. - -> אציין כי ניתן ליצור קוביות מידע בעלות יותר מ-3 ממדים, אך כמובן שלא נוכל לתאר אותן באופן וויזואלי כמו שאנו ממחישים בצד שמאל קובייה בעלת שלושה מימדים. - -ניתן לבצע מגוון פעולות על הנתונים שבמחסן המידע. נראה את הפעולות, ונייצג אותן באמצעות קוביית המידע: - -* **Roll up (או Drill up)** – פעולה המיועדת לסיכום הנתונים, ז”א סיכום הנתונים ברמה גבוהה יותר (לדוגמה: במקום ברבעונים, בשנים). -* **Roll down (או Drill down)*** – פעולה הפוכה המיועדת לעבור מרמת סיכום גבוהה לרמת סיכום נמוכה (לדוגמה: מרמת רבעונים לרמת חודשים, או מרמה של קטגוריות מוצרים לדגמים ספציפיים). -* **Slice and Dice** – פעולה בה אנו מחפשים שילוב בין ערכים של שני מימדים שונים. ב Slice אנו מגבילים את עצמנו לערכים של מימד אחד, וב Dice אנו משלבים לפחות 2 מימדים. -* **Pivot (או Rotate)** – בפעולה זו אנו רק משנים את ההצגה של הנתונים (מסובבים את הטבלה ב-90 מעלות, על מנת להקהל על המשתמש). -* **Drill Across** – כאשר אנו עוברים מטבלת עובדות אחת לטבלת עובדות נוספת (נרחיב על טבלת עובדות בהמשך). -* **Drill Through** – כאשר אנו מגיעים לרמה הנמוכה ביותר של הנתונים הגולמיים. - -   - -### 5. תורת האינפורמציה -[קלוד שאנון](http://en.wikipedia.org/wiki/Claude_Shannon) אבי תורת האינפורמציה פרסם את המאמר “The mathematical theory of communication” ב-1949 שהיווה את היסוד לתורה זו, ובו הנחיל את המושגים הבסיסיים שאנו משתמשים בהם עד היום. תורת האינפורמציה פותחה במטרה לטפל בהעברת מידע במערכות תקשורת. המרכיבים העיקריים שלה הם קידוד מקור וקידוד ערוץ עבור משתנים מקריים בדידים. - -העברה יעילה של מידע דיגיטלי דרך ערוץ רועש ומבובש מבוצעת ב-2 שלבים עיקריים: _1. קידוד מקור_ – נדחס את המידע הגולמי המיועד להעברה ע”י ניצול התכונות הסטטיסטיות שקיימות בו, ונקודד אותו. _2. קידוד ערוץ_ – נוסיף למידע המועבר אינפרמציה יתירה, כך שמקבל המידע בצד השני של הערוץ הרועש יוכל לנקותו מרעשים. - -תורת האינפורמציה מספקת לנו מסגרת פורמלית כדי למצוא ולהעריך תבניות (שזהו המטרה העקרית שלנו בכריית מידע, למצוא תבניות ובעזרת קריטריונים אובייקטים להעריך אותם כדי למצוא את התבניות האינפורמטיביות ביותר, ולהעריך את מידת האינפורמטיביות שלהם ביחס לתבניות אחרות שמצאנו / שנמצאו בעבר). באמצעות תורת האינפורמציה ניתן להגדיר מדדים לשימושיות ולנצילות של טכניקות ומודלים שונים בכריית מידע. לדוגמה, בעת בניית עץ החלטה (נושא שנרחיב עליו בהמשך) נסתייע במדד האנטרופיה לקביעה מהי התכונה המפצלת בעץ ההחלטה. - -**מדידת חוסר ודאות** - -חוסר ודאות זה מושג הקיים בכל עסק. המטרה של כריית המידע היא לספק מידע שיפחית את חוסר הוודאות הקיים בקבלת ההחלטות בארגון. לדוגמה אם התבצעה פעולה בכרטיס אשראי, כיצד חברת האשראי יכולה לקבוע האם הפעולה חוקית או לא? זהו מצב של חוסר ודאות. ונשאלת השאלה כיצד ניתן למדוד חוסר ודאות? האם יש איזשהו מדד שמבחין בין אירועים עם אי ודאות גבוהה לאי וודאות נמוכה? נתחיל בכך שאם אנו יכולים לחזות את התוצאה בודאות של 100% ברור לנו שחוסר הודאות שווה ל-0. בנוסף, אי הודאות עולה כאשר מספר האופציות האפשריות עולות. ולבסוף, לאותו מס’ תוצאות אפשריות, אי הודאות היא מקסימלית אם קיים אותו סיכוי (אותה הסתברות) לכל תוצאה אפשרית. - -**אנטרופיה** - -מדד האנטרופיה עוזר לנו להעריך את אי הודאות של משתנה מקרי כלשהו (X) (משתמשים במושג זה גם בפיזיקה, בתרמודינמיקה). האנטרופיה נחשבת מדד לאי ודאות על קבוצת מצבים אפשריים, והיא אינה תלויה בערכים שהמשתנה מקבל אלא רק בפונקצית ההתפלגות שלו. _האנטרופיה של משתנה מקרי בדיד_ מקבלת ערך מינימלי יחיד כאשר אי הודאות מינימלית, וערך מקסימלי עבור אי ודאות מקסימלית. _אנטרופיה של התפלגות כלשהי_ מהווה מדד למרחק סטטיסטי שבין התפלגות נתונה לבין התפלגות אחידה. יש לציין כי אנטרופיה היא בעלת ערכים חיובים בלבד ונמדדת ביחידות nats (כאשר משתמשים בבסיס הטבעי של הלוגריתם) או bits (כאשר משתמשים בבסיס 2). - -האנטרופיה מוגדרת כ- `(H(X) = Σ-p(x)logp(x`. נציין כמה תכונות של הנוסחה: - -* המינוס נמצא שם כדי לספק תוצאה חיובית (הסתברות היא תמיד בין 1-0 ולוגריתם של מס’ בטווח הזה יתן מס’ 0 או שלילי). -* התוצאה של האנטרופיה, (H(X, תיהיה שווה ל-0 אם”ם (אם ורק אם) האירוע וודאי (אירוע בעל תוצאה אפשרית אחת בלבד). -* הערך המקסימלי שאנטרופיה יכולה להגיע אליו שווה לוגריתם של מס’ התוצאות האפשריות. -* אם לכל התוצאות יש את אותה הסתברות, האנטרופיה הוא פונ’ מונוטונית עולה של מס’ התוצאות. - -בדוגמה לחישוב אנטרופיה בתמונה משמאל אנו מחשבים את האנטרופיה לבדיקה רפואית, אנו רואים בטבלה הראשונה שלנבדק אחד יצאה תוצאה שלילית ובכל זאת חלה, ל-3 יצאה תוצאה שלילית בבדיקה ואכן אינם חלו, ל-4 יצאה תוצאה חיובית ואכן חלו, ול-2 יצאה תוצאה חיובית אך לא חלו. בטבלה השניה אנו מחשבים את האנטרופיה של הבדיקה, ז”א 6 חלו ו-4 לא, לכן האנטרופיה של הבדיקה היא 0.971. בניגוד לכך, בטבלה השלישית אנו מחשבים את האנטרופיה של המחלה, בה 5 אנשים חלו, ו-5 אנשים לא. מצב כזה (שבו לכל תוצאה יש אותה הסתברות) מביא אותנו לאנטרופיה המקסימלית (במקרה הזה 1). - -**אנטרופיה מותנית** - -אנטרופיה מותנית ([Conditional Entropy](http://en.wikipedia.org/wiki/Conditional_entropy)) היא מדד לאי ודאות של Y בהינתן X, ז”א אנו משתמשים במשתנה אחר (X) על מנת לצמצם את אי הודאות שיש לנו במשתנה Y. לדוגמה, אם אנו רוצים למדוד האם הפעולה הנוכחית בכרטיס אשראי היא חוקית או לא, אנו יכולים להיעזר במיקום הפעולה הקודמת של הלקוח כדי לקבוע האם הפעולה הנוכחית היא חוקית או לא. האנטרופיה המותנית מוגדרת כ- `(H(Y/X) = -∑p(x,y)*logp(y/x`. כאשר (p(x,y היא הסתברות משותפת (ההסתברות ששתי אירועים יקרו ביחד. לדוגמה גם שהתוצאה של הבדיקה תצא שלילית וגם שלבן אדם אין מחלה), ו (p(y/x היא הסתברות מותנת (ההסתברות שיקרה אירוע y, בהינתן x. לדוגמה ההסתברות להיות חולה בהינתן תוצאה שלילית). - -חשוב לציין כי לא ניתן לעלות את אי הודאות, ז”א שאם, לדוגמה, אנו רוצים לחזות את ממוצע הציונים של סטודנט באונ’, ומספקים לנו נתון של מידת הנעלים של הסטודנט, די ברור שמידת הנעלים לא קשורה לציון הממוצע של הסטודנט באונ’. אך נתון זה לא יעלה את אי הודאות (רוב הסיכויים שהיא תישאר אותו הדבר). במצב שאין השפעה של המשתנה (קיימת אי תלות בין המשתנים), האנטרופיה המותנית שווה ל-0 (שווה לאנטרופיה של Y). - -בתמונה משמאל ניתן לראות דוגמה לאנטרופיה מותנית. השתמשנו באותם נתונים מהדוגמה הקודמת (הטבלה הראשונה זהה), בטבלה השניה אנו מחשבים את ההסתברות המשותפת, בטבלה השלישית את ההסתברות המותנת (ליד כל תוצאה יש הסבר כיצד היא חושבה), ובטבלה הרביעית אנו מחשבים את האנטרופיה המותנית (המשוואה כולה), ומקבלים את התוצאה 0.875. - -לעומת זאת אם היינו מחשבים את ההסתברות המותנת של הבדיקה בהינתן המחלה (ולא כפי שעשינו מקודם, בתמונה משמאל), הטבלה הראשונה והשניה היו נשארות זהות, אך בטבלה השלישית והרביעית הינו מקבלים ערכים שונים. בסופו של דבר במקום 0.875 (כתוצאה סופית) היינו מקבלים 0.846. כשהתוצאה גבוהה יותר זה אומר שהגורם שבחרנו כגרום מסביר משפיע פחות על המשתנה התלוי. - -בכריית מידע אנו בוחרים באיזשהו משתנה תלוי (שאנו רוצים לחזות אותו) ולאחר מכן אנו מנסים למצוא אלגוריתם שיבנה את המודל הטוב ביותר, שיביא למינימום את האנטרופיה המותנית של המשתנה התלוי. אם למשל היינו רוצים, עפ”י הנתונים למעלה לבנות מודל שנותן חיזוי לגבי מחלה של אדם מסוים לפי תוצאות של בדיקה בודדת, ככל שהיינו מקבלים אנטרופיה מותנית נמוכה יותר כך היינו יודעים שהמודל שמצאנו הוא טוב יותר. - -**אינפורמציה הדדית** - -כמו שאמרנו בסעיף למעלה, ככל שאנו יודעים יותר על המשתנה התלוי כך האנטרופיה של אותו משתנה תפחת. ההפרש בין האנטרופיה הבלתי מותנית (שלרוב גבוהה יותר) לאנטרופיה המותנית מודד את הצמצום באי הודאות של משתנה מסוים (המשתנה התלוי) כתוצאה מהידע שלנו על משתנה נוסף, וההפרש הזה נקרא אינפורמציה הדדית (המכונה לעיתים גם אינפורמציה משותפת או [Mutual Information](http://en.wikipedia.org/wiki/Mutual_information)). - -הנוסחה של האינפורמציה ההדדית היא `[(I(X;Y) = H(Y) – H(Y/X) = ∑p(x,y)*log[p(y/x)] / [p(y`. אם שני המשתנים (x ו y) אינם תלויים אחד בשני נקבל אינפורמציה הדדית ששוה ל-0, לעומת זאת כשהמידע שלנו ב x מעלה את ההסתברות של y נקבל תוצאה גדולה מ-1, וכמובן יכול להיות מצב הפוך בו נקבל תוצאה נמוכה מ-1 (לדוגמה, כאשר בדיקה מורידה את הסיכוי לחלות במחלה כלשהי). - - **אינפורמציה הדדית מותנית** - -המטרה של אינפורמציה הדדית מותנית הוא לחשב את הירידה באי ודאות של משתנה כלשהו x כתוצאה מהידע שלנו לגבי משתנה y, כאשר נתון משתנה נוסף, z. הנוסחה של מושג זה מוגדרת כ `{[(I(X;Y/Z) = H(X/Z) – H(X/Y,Z) = ∑p(x,y,z)*log{[p(x,y/z)]/[p(x/z)*p(y/z`. דוגמה לאינפורמציה הדדית מותנית יכולה להיות כאשר x היא איזשהי מחלה, y ו z הן תוצאות של בדיקות רפואיות כלשהן. יש לנו תוצאה של בדיקה אחת, z, ונשאלת השאלה האם בדיקה נוספת, בדיקה y, תעזור לנו, ז”א תוריד את רמת האי ודאות לגבי המחלה. - -   - -### 6. תקשורת -בחלק זה נדבר על ההקבלה של בעיות מתחום התקשורת ובעיות בתחום כריית המידע, אותן בעיות שבגללן שנון פיתוח את תורת האינפורמציה. המטרה של תקשורת נתונים היא לשחזר ביעד את ההודעה שנבחרה (או נוצרה) בנק’ המוצא, באופן מדויק (או מקרוב). התקשורת מתבצעת באמצעות קידוד המידע, ז”א מיפוי סדרת סימנים לסימני קוד של המחשב. המטרות העקריות של הקידוד הן: - -דחיסת המידע (על מנת להקטין את נפחי האחסון ומשאבי התקשורת). -* חסינות מפני רעשים. -* הצפנה. -* תרגום המידע לקוד מחשב. - -בעיית דחיסת המידע היא אחת הבעיות העיקריות בתקשורת נתונים. שנון הגיע למסקנה שעל מנת לצמצם את מס’ הספרות הבינאריות הדרושות לקידוד של הודעה אקראית למינימום צריך להשתמש ב (log(pi- (כאשר i היא ההודעה, ו pi הוא ההסתברות של ההודעה i) ביטים על מנת לשדר אותה (נקצה קודים קצרים יותר להודעות הנשלחות בצורה תקופה יותר, ולהפך). כך שהממוצע של הודעה אקראית יהיה `(H(X) = ∑-p(xi)*log p(xi` (שימו לב כי זאת הנוסחה של האנטרופיה), וזהו מס’ הביטים המינימלי הממוצע הדרוש לנו כדי לשדר הודעות אקראיות ממקור המידע ליעד כלשהו. - -**העברת מידע בערוץ רועש** - -חסינות המידע לרעשים בסביבה מתאפשרת ע”י הוספת מידע יתיר (redundant) המאפשר לבצע שחזור של הההודעה המקורית למרות הרעשים שנלוו אליה. מנגד, הוספת המידע היתיר מאט את קבצ העברת המידע. על מנת להביא לאופטימום את קצב העברת המידע, יש להתאים את כמות המידע היתיר לרעש. באופן דומה, נניח שהתקבל מידע (תצפיות) ממקור רועש. גודל המדגם (מס’ התצפיות) הוא סופי, וברצוננו למצוא פונ’ או מודל שיתאר את התפלגות המידע שממנו נוצרו התצפיות ולא את התצפיות המסוימות שקיבלו. - -עבור כל מודל שנבנה, נבחין בין השגיאה על התצפיות שהתקבלו (נקראת שגיאת אימון) לבין השגיאה הממוצעת על כל התצפיות שיכולנו לקבל (שגיאה הכללה). התאמת יתר (over fitting) היא מצב שבו משיגים שגיאת אמון קטנה על חשבון שגיאת הכללה. בהתאמת יתר נפגמת יכולת החיזוי של המודל (המודל ישגה יותר בעת קבלת דוגמאות חדשות מההתפלגות המקורית). ומכאן שיש למצוא את שביל הביניים בין מודל מורכב ומסובך המתאר את המידע הנתון בדיוק רב ביותר, לבין מודל פשוט בעל יכולת הכללה גדולה יותר. - -  - -### 7. הגישות השונות של כריית מידע -ישנן כמה גישות לכריית מידע, כולן מבוססות באופן ישיר על תורת האינפורמציה. - -* **גישת אי הוודאות** – ההנחה היא שכריית המידע מצמצמת את אי הוודאות לגבי משתנים מסויימים (משתני מטרה / חזויים). אחת הדרכים לייצג את אי הוודאות היא ע”י האנטרופיה (ז”א לפתח אלגוריתמים המביאים למינימום את האנטרופיה של המשתנה התלוי, או למקסימום את האינפורמציה ההדדית בין המודל למשתנה התלוי). קיימים לא מעט אלגוריתמים בכריית מידע המיועדים למזער את האנטרופיה כמו ID3 (לבניית עצי החלטה) או C4.5 (גם הוא לבניית עצי החלטה), IFN (לבניית רשתות אינפו-עמומות), ועוד (בהמשך נרחיב עליהם). -* **דחיסת מידע** – בגישה זו אנו מניחים שמודלים קטנים יותר של כריית מידע מובנים יותר למשתמש, למשל עץ החלטה של 10 קודקודים הינו שימושי ומובן יותר מאשר עץ החלטה של 100 או 200 קודקודים. עפ”י גישה זו, המטרה של כריית מידע היא לדחוס את הנתונים ע”י מציאת מודל מסויים שמייצג את הנתונים (אלגוריתמים של כריית מידע אמורים לבחור בהשערה שיש לה אורך תיאור מנימלי, ז”א לבחור בהשערה (או במודל) המצומצם / קטן יותר – נוסחה קצרה יותר, עץ החלטה עם פחות קודקודים, רשת עם פחות שכבות, וכד’). עקרון זה נקרא גם [MDL](http://en.wikipedia.org/wiki/Minimum_description_length) ומשתמשים בו, למשל, באלגוריתמים המבוססים על [חוק בייס](http://en.wikipedia.org/wiki/Bayes%27_theorem). - -עקרון ה MDL מייצג את היחס בין סיבוכיות המודל למס’ השגיאות שהמודל יעשה בנתוני האימון (ככל שהמודל יהיה מורכב יותר, כך הוא יתאים יותר לנתונים ויהיו בו פחות שגיאות, ומנגד יכול להיות שיהיה לנו מודל פשוט מאוד אך שלא יתאים לנתונים ולא יהיה מדוייק). - -  - -### לסיכום -אז דיברנו בכלל על למה לכרות מידע, על הסיבה בגינה אנו מחפשים ידע (תבניות / דפוסים) בבסיסי נתונים. הבנו פחות או יותר מהי כריית מידע, ואת התהליכים שצריך לעבור כדי לבצע את התהליך כולו, כשהחשוב בינהם הוא תהליך ה KDD (תהליך גילוי הידע עצמו – השלב בו אנו מפעלים את האלגורימים על הנתונים הנבחרים). הבנו מהו מחסן נתונים (ואת ההבדל של מושג זה מול מושג ה DBMS). ראינו שלמרות שתחום כריית המידע הינו תחום עצמאי, הוא התפתח כתחום כזה מאמצע שנות ה-90, ומבוסס ברובו על דיסציפלינות אחרות, וותיקות יותר, כשהעקרית בינהם היא תורת האינמפורמציה. - -הזכרנו מושגים בסיסיים וחשובים בתורת האינפורמציה והבנו כיצד הם מתקשרים לכריית מידע (במיוחד בהיבט של צמצום אי הודאות). דיברנו בקצרה על כיצד מתבצעת תקשורת דיגיטלית ואת הבעיתיות של רעש בערוץ תקשורת. ולבסוף דיברנו על 2 הגישות העקריות והשונות בכריית מידע. בפוסט הבא נתחיל להתעמק בתהליכי כריית המידע עצמם. diff --git a/data/_oldPosts/2019-09-01-preparation-the-data.md b/data/_oldPosts/2019-09-01-preparation-the-data.md deleted file mode 100644 index 20bba21..0000000 --- a/data/_oldPosts/2019-09-01-preparation-the-data.md +++ /dev/null @@ -1,264 +0,0 @@ ---- -title: 2 – הכנת הנתונים -author: nirgn -layout: post -summary: "" -category: Information Theory ---- -בפוסט הזה נדבר על בעיות באיכות נתונים, נסקור כמה שיטות לתצוגה גרפית של נתונים, נדבר על שיטות כמותיות לניקוי נתונים, נעבור לשילוב והמרה של נתונים המגיעים ממקורות שונים, נתייחס בקצרה לבעיות של הכנת נתונים תלויי זמן, ולבסוף נעבור על שיטות סיווג וחיזוי, נעריך את הדיוק והשגיאה שלהן ונראה כיצד להשוות בין שיטות שונות שלהן. - -**בפוסט הזה נדבר על הנושאים:** - -1. בעיות באיכות נתונים -2. ייצוג גרפי של נתונים -3. ניקוי נתונים -4. שילוב והמרות של נתונים -5. סיווג vs וחיזוי -6. מדדים להערכת דיוק ושגיאה -7. שיטות חיזוי (מודלים של רגרסיה) -8. השוואה בין מסווגים - - - -  - -### 1. בעיות באיכות נתונים -כשהנתונים מגיעים מהעולם האמיתי הם לא תמיד “מושלמים”, ואנחנו צריכים להתאים אותם למה שהכלים של כריית מידע זקוקים / מבקשים. ז”א לעמוד בתנאים שהכלים מציבים לנו, על מנת שאלה ידעו מה לעשות עם המידע, ויצלחו להפיק ממנו ידע. אז מה הכלים של כריית מידע צרכים? - -דבר ראשון, שהמידע יהיה זמין, כמובן שאם אנו לא יכולים לספק להם את המידע (בצורה שהם מכירים, כמו לדוגמה כ csv או כ arff). -בנוסף, אנו זקוקים לכל המידע בטבלה אחת, ז”א שאם המידע מגיע מכמה מקורות, יש לאחד בין טבלאות המידע. -אנחנו (איש כריית המידע) צריך להבין את המשמעות של כל משתנה (כדי שנוכל לקבוע מראש האם גורם מסויים הוא משתנה מסביר אפשרי או שמדובר במשתנה תלוי – כזה שאנו מעוניינים לנבא). -תחום ההגדרה של כל משתנה צריך להיות מוגדר וידוע מראש (אם מדובר במשתנה קטגורי, אז מדובר על סט ערכים ידוע מראש, לדוגמה ימים בשבוע. או אם מדובר על משתנה רציף, אז מדובר על קטע בין ערך מינימום למקסימום, לדוגמה ציונים ניתנים בתחום של 0-100). -על כל הערכים של המשתנים (בכל אחד מהתצפיות) להיות ידועים מראש, על הנתונים להיות אמינים (המידע יהיה נכון / אמיתי. אנחנו לא מצפים למצוא שגיאות בתוך הנתונים שלנו כשאנו מריצים את האלגו’ לכריית מידע), ולבסוף, אין להכיל מידע כפול. - - -**מדוע הנתונים ב”עולם האמיתי” “מלוכלכים”?** - -במקרים מסויימים נגלה שלפעמים חסרים ערכים מסויימים ברשומות כלשהן. מצב זה קורה כשלא ניתן להשיג את הערך של אותו משתנה בזמן שהנתונים נאספו, כמו לדוגמה שאין לנו את הציון של הסטודנט כל עוד אינו סיים ללמוד את הקורס, וכד’. הבעיות האלו יכולות לנבוע גם מבעיות טכניות (בעיות אנוש, חומרה, תוכנה). בעיות נוספות בנתונים יכולים לנבוע מרעש הנוצר כתוצאה מבעיות טכניות הקיימות בציוד (במידה והנתונים נאספים באופן אוטומטי), ואז בעיה בציוד יכולה לגרום לנו לאסוף נתונים שגויים. כמובן שגם כאן יכולות להתבצע טעויות אנוש (אם זה נתונים המוקלדים למחשב, לדוגמה). לבסוף, הסיבה האחרונה ל”לכלוך” הנתונים היא קיום של מספר מקורות מידע, שיכולים להביל למידע לא אחיד. - -לאור כל זה, לאחר שראינו שהנתונים יכולים להיות חסרים ו/או מלוכלכים (שגויים, לא מדוייקים, וכ’ו). אנו מבינים כי ישנה חשיבות להכנה מוקדמת של הנתונים. הרי שאם אין לנו נתונים איכותיים, קשה לנו לצפות לתוצאות איכותיות מהתליך כריית המידע. תהליך הכנת המידע כולל: ניקוי הנתונים, שילוב נתונים מטבלאות שונות, המרות של נתונים, וצמצום טבלת הנתונים (במידת האפשר). - -   - -### 2. ייצוג גרפי של נתונים -לאחר איסוף הנתונים, נציג אותם בצורה גרפית באמצעות היסטוגרמה, תרשים פיזור, ועוד, במטרה לזהות נתונים שיש לנקותם כדוגמת נתונים שמחוץ לתחום או לא עקביים. - -**היסטוגרמה** -מטרת ההיסטוגרמה ([Histogram](http://en.wikipedia.org/wiki/Histogram)) היא לעזור לנו לזהות את הערכים בעלי השכיחות הגבוהה ביותר, ערכים נדירים, וערכים הנופלים בתחום שאינו סביר. תרשים ההיסטוגרמיה מתייחס תמיד למשתנה אחד, ובדרך כלל, נבנה אותה עבור משתנה רציף, כאשר התחום מחולק למספר קטעים (בעלי רוחב שווה). בצד שמאל, ניתן לראות דוגמה לניתוח היסטוגרמה. - -נבנה את ההיסטוגרמה עפ”י השלבים הבאים: 1. נסדר את הערכים בסדר עולה. 2. נחלק את תחום הנתונים למרווחים (יש להקפיד שהמרווחים לא יהיו רחבים מידי או צרים מידי, כדי שמצד אחד לא נאבד מידע אך מצד שני שההיסטוגרמה לא תיהיה חלקה. כלל אצבע הוא לקבוע את מספר קבוצות המרווחים כבערך שורש גודל הדגימה). 3. נקבע עבור כל מרווח את התדירות ונבנה את טבלת התדירות הכוללת את המרווח. 4. נשרטט את התפלגות התדירות (ציר x יציין את המרווחים וציר y את התדירויות). - -**תרשים פיזור** -תרשים פיזור ([Scatter plot](http://en.wikipedia.org/wiki/Scatter_plot)) או תרשים XY מציג את קשרי הגומלין בין הערכים המספריים במספר סדרות נתונים, או שהוא מתווה שתי קבוצות מספרים כסדרה אחת של קואורדינטות XY. בעזרת תרשים פיזור אנו יכולים להסיק מהר מאוד מסקנה כללית לגבי אופי המתאם בין 2 משתנים, אך אנו גם יכולים למצוא ביטוי ע”י נוסחה סטטיסטית בעזרת החלקה של הפיזור. - -לעקומה (או במקרה שלנו, בתמונה משמאל, לקו הישר) קוראים Loess (ראשי תיבות של Local Regression) או בעברית “רגרסיה מקומית”. במקרה של רגרסיה לינארית, ניתן לבטא באופן כמותי את הקשר (המתאם) בין שני המשתנים X,Y בעזרת השונות המשותפת (Covariance) שתסומן כ (COV(X,Y. השונות המשותפת היא (COV(X,Y) = E(X,Y) – E(X) * E(Y כאשר E מציין תוחלת (הערכים המתקבלים יכולים להיות בין מינוס אינסוף לאינסוף). כאשר COV(X,Y)=0 המשמעות היא שהמשתנים האקראיים X ו Y בלתי מותאמים. - -מכיוון שהשונות המשותפת תלויה ביחידות המדידה, נגדיר את מקדם המתאם (קורלציה) שיסומן ב p ומהווה סטנדרטיזציה של השונות המשותפת. מקדם המתאם הוא [p(X,Y) = [COV(X,Y)]/[σx*σy כאשר σx ו σy הן סטיות התקן של x ו y (ערכו של מקדם המתאם הוא בין 1- ל 1+). - -   - -### 3. ניקוי נתונים -בחלק זה אנו מתמקדים בשאלה “כיצד ניתן לשפר את איכות הנתונים?” ונבצע מספר פעולות עקריות על מנת להשיג את מטרה זו: - -* **נשלים ערכים חסרים** – כיצד ניתן להתמודד עם ברשומה מסוימת ישנם מספר משתנים עם ערך לא ידוע? הדבר הקל ביותר הוא להתעלם מאותה רשומה, אך זה אינו מומלץ כי אנו נאבד את כל המידע הקשור אליה. אך לפעמים לא תיהיה לנו ברירה וניהיה חייבים לבצע זאת (לדוגמה, במקרה בו אנו מסווגים את הנתונים, וחסר לנו הנתון לפיו אנו מסווגים את הרשומות). מנגד, אפשר לנסות ולהשלים את הנתון באופן ידני, אך אם מדובר על בסיס נתונים גדול אופציה זו אינה פרקטית כאשר אחוז הנתונים החסרים גדול מידי (או שהנתונים הוזנו לפני זמן רב עד כדי שלא מתאפשר לנו להשלים אותם). לבסוף, אם אין בידנו ברירה אחרת, נשלים את הנתונים באופן אוטומטי – נשתמש בקבוע המייצג את הנתון החסר, או נשלים את הערך החסר באמצעות הערך הממוצע של המשתנים, או אפילו להשלים את הערך החסר באמצעות הערך הממוצע של המשתנים מאותו הסיווג. -* **נזהה ערכים חריגים ונחליק נתונים רועשים** – השיטה המקובלת ביותר להתמודדות עם צמצום השונות בתוך הנתונים היא Binning או חלוקה לקטעים – תיבות. נחלק את התצפיות לתיבות שיהיו בעלי שכיחות שווה, ואז ניתן להחליק את כל התצפיות באותה תיבה לפי הממוצע של התיבה / על פי החציון של התיבה / או הגבולות של אותה התיבה (כל ערך מוחלף בגבול העליון או התחתון של התיבה). ישנן שיטות נוספות להחלקה של ערכים, כמו באמעות מודל של רגריסה בו אנו נבצע שימוש אם יש קשר לינארי בין 2 משתנים, או ב Clustering – חלוקה אשכולות, אם מדובר בנתונים רב מימדיים (נזהה ונסלק תצפיות חריגות). -* **נסלק רשומות כפולות** – נמחק רשומות כפולות, כאלו שנוצרו כתוצאה משילוב של נתונים ממקורות שונים. - - -> אוסף הנתונים עשויים להיות רשומה, וקטור, תבנית, מאורע, דגימה, תצפית, ישות ועוד. הנתונים מותארים על ידי מספר תכונות כדוגמת מאפיין, משתנה, שדה, מימד ועוד. - -> מקובל להבחין בין תכונות איכותיות המכונות תכונות קטגוריאליות (ארצות, מגדר, שביעות רצון {גבוהה, בינונית, נמוכה}, לבין תכונות כמותיות המכונות תכונות נומריות (ציונים בקורס, גובה, משקל, גיל). כמו כן, מקובל גם להבחין בין תכונות בדידות בעלות אוסף סט סופי ובר מנייה של ערכים (מס’ סטודנטים הרשומים בקורס), בין תכונות רציפות בעלות ערכים מספריים ממשיים (משקל), לבין תכונות בינריות שהן מקרה פרטי של של תכונות בדידות, והן בעלות שני ערכים (0 או 1, זכר או נקבה, נכון או לא נכון). - -**דוגמה ל Bining – חלוקה לקטעים** -ל Bining יש 2 גישות. הגישה הראשונה היא ‘רוחב שווה’ ז”א אותה רוחב לכל קטע/תיבה (ע”י [ערך המקסימום-ערך המינמום] / מס’ הערכים הכולל). אך לגישה זו יש חסרון מהותי, שכן אם ערך המקסימום או המינימום יושפעו כתוצאה מערך חריג (הנגרם מרעש), אותו ערך חריג ישפיע על הממוצע השייך לכל הערכים באותו קטע. כדי להתגבר על הבעיה הזו, בגישה השניה, הנקראת ‘עומק שווה’, אנו לא מחוייבים לאותו מס’ של ערכים בכל קטע/תיבה (אך אנו בכל זאת מקפידים פחות או יותר על מספר שווה). - -ערכים לדוגמה: 4,8,9,15,21,21,24,25,26,28,29,34. - -נחלק את הערכים לקטעים/תיבות: - -* תיבה 1: 4, 8, 9, 15 -* תיבה 2: 21, 21, 24, 25 -* תיבה 3: 26, 28, 29, 34 - -אם נבצע Bining על פי הגישה השניה (עומק שווה): - -* תיבה 1: 9, 9, 9, 9 -* תיבה 2: 23, 23, 23, 23 -* תיבה 3: 29, 29, 29, 29 - -Bining על פי הגישה הראשונה (רוחב שווה): - -* תיבה 1: 4, 4, 4, 15 -* תיבה 2: 21, 21, 25, 25 -* תיבה 3: 26, 26, 26, 34 - -   - -### 4. שילוב והמרות של נתונים - כדי לשפר את היעילות, נעביר את הנתונים לתבנית המיועדת לכריית מידע. תבנית זאת תיהיה קטנה יותר ומייצגת, וקיימות מגוון שיטות לבצע זאת: - -* החלקת הנתונים – הסרת רעשים, -* קיבוץ הנתונים – לדוגמה, אם אנו מעוניינים בהיקף הרשמות חודשיות לקורסים באונ’. אז נקבץ את נתוני ההרשמות היומיות לנתון מסכם חודשי. -* הכללת הנתונים. -* מימדים – הפחתה בתכונות. -* דחיסת נתונים. -* דיסקרטיזציה – העברת נתונים נומריים (רציפים) לערכים קטגוריאליים. אפשר להשתמש בנירמול שבין min ל max, בעזרת הנוסחה הבאה: `v’ ={[v – minA] / [maxA – minA]} * (new_maxA – new_minA) + new_minA (כאשר new_minA` ו new_maxA הם ערכי ה max וה min החדשים). או בשימוש בנירמול המבוסס על ההתפלגות הנורמלית (z-score), בעזרת הנוסחה: `v’ = (v – uA) / σA` (כאשר u הוא הממוצע-תוחלת, ו σ הוא סטיית התקן). - -   - -### 5. סיווג vs וחיזוי -בבעיית הסיווג (classification) אנו מעוניינים לנבא משתנים קטגוריים (בדידים או נומינליים). הדוגמה הפשוטה ביותר למשתנה כזה היא משתנה בינארי (בעל 2 אפשרויות בלבד), לדוגמה הצלחה בקורס לעומת כישלון בקורס, זכר או נקבה, נכון או לא נכון וכד’. אך משתנים קטגוריים יכולים להיות בעלי יותר מ-2 משתנים. לעומתה בבעיית החיזוי (prediction) אנו מעוניינים לנבא ערכים של משתנים רציפים (כמו ציון של סטודנט בקורס, שער של מטבע וכד’). בעיות טיפוסיות של סיווג יכולות להיות אישור מתן אשראי (אושר / נדחה), אבחון רפואי (צהבת B / צהבת C) וכד’, ומנגד בעיות טיפוסיות של חיזוי הן, לדוגמה, חיזוי תוחלת החיים בביטוח רפואי, חיזוי ממוצע ציוני הסטודנט בקבלה לאונ’ וכד’. - -**תהליך הסיווג** -תהליך הסיווג מורכב מ-2 שלבים, בשלב בהראשון אנחנו בונים את המודל שאמור לספק תיאור למספר סיווגים שידועים לנו מראש. בשלב בניית המודל אנו משתמשים בתצפיות אימון (ז”א שאנו מחלקים את מאגר המידע שלנו ל-3, כאשר אנו יודעים את הסיווג של 2 החלקים הראשונים. נשתמש בחלק הראשון לבניית המודל, ובחלק השני (שאנו יודעים את הסיווג שלו) לבחינת המודל שבנינו. במידה והמודל תקין וקיבלנו אותו, נשתמש בו על החלק השלישי כדי לנבא (את הסיווג של החלק השלישי אנו לא יודעים, וזה מה שאנו מנבאים)). את המודל ניתן לייצג באמצעות חוקי סיווג, עצי החלטה, או איזשהן נוסחאות מתמטיות. - -התנאי הבסיסי לקבלת המודל סיווג שבנינו הוא שיהיה מדוייק יותר מ[חוק הרוב](http://en.wikipedia.org/wiki/Majority_rule) (לדוגמה, נניח שאנו רוצים לקבל תחזית האם מחר ירד או לא גשם, נניח גם שב-90% מהמקרים לא יורד גשם. מכאן אנו יכולים לבנות מודל פשוט האומר שמחר לא ירד גשם, וזאת עפ”י ההנחה שרק ב-10% מהמקרים יורד גשם. לכן מודל כזה, שנבא את מזג האוויר ללא קשר, יהיה מדוייק ב-90% מהמקרים). - - דוגמה לבניית מודל הסיווג: נניח שקיבלנו את ה Training Data (החלק הראשון של המאגר, ממנו אנו בונים את המודל) הבא: - -| Tenured | Years | Rank | Name | -|:---:|:---:|:---:|:---:| -|no | 3 | Assistant Prof | Mike | -|yes | 7 | Assistant Prof | Mary | -|yes | 2 | Professor | Bill | -|yes | 7 | Associate Prof | Jim | -|no | 6 | Assistant Prof | Dave | -|no | 3 | Associate Prof | Anne | - -ואנו רוצים לנבא את הערך Tenured, ז”א לנבא אם לפרופ’ יש קביעות. ניתן לראות שחוק הרוב במקרה הזה הוא 50% (3 אנשים yes ו-3 no). נרחיב בעתיד כיצד אנו מגיעים למודל, אך מהר מאוד ניתן לראות שחוק כמו `‘IF rank = ‘professor’ OR years > 6 THEN tenured = ‘yes` יתן לנו דיוק של 100% על תצפיות האימון (כל התצפיות מקיימות אותו). אך זה שהמודל נותן לנו 100% דיוק על תצפיות האימון אין זה אומר שזהו המודל שאנו רוצים מכיוון שאין זה אומר שהוא יתן לנו 100% דיוק על תצפיות המבחן (החלק ה-2 במאגר המידע, שאנו יודעים את הסיווג של התצפיות אך משתמשים בהם לבחינת המודל). אם מתקיים מצב כזה (בו המודל מתאים ב-100% לתצפיות האימון אך לא לתצפיות המבחן מתקיימת בעיית הנקראת המתאמת יתר ([Overfitting](http://en.wikipedia.org/wiki/Overfitting)) עליה נרחיב בהמשך. - -בשלב ה-2 של תהליך הסיווג אנו משתמשים בחלק ה-2 של מאגר התצפיות, ה Testing Data, להלן התצפיות: - -| Tenured | Years | Rank | Name | -|:---:|:---:|:---:|:---:| -| no | 2 | Assistant Prof | Tom | -| no | 7 | Associate Prof | Merlisa | -| yes | 5 | Professor | George | -| yes | 7 | Assistant Prof | Joseph | - -נפעיל את החוק, ונראה כי החוק אינו מקיים את התצפיות הראשונה (של Tom), מקיים את התצפית השנייה (של Merlisa) בגלל שהוותק שלה גדול מ-6, וזאת הרי טעות (כפי שניתן לראות אין לה קביעות). את התצפית השלישית (של George) והרביעית (של Joseph) החוק מקיים, ואכן יש להם קביעות. לכן, מצאנו חוק שפחות מדויק על נתוני המבחן מאשר על נתוני האימון, אך יותר מדויק מחוק הרוב (המודל שלנו מדוייק ב-75%). ולכן אפשר לשאול האם ההבדל הוא מובהק (מבחינה סטטיסטית) או הבדל שהתקבל באופן מקרי מתוך הנתונים? נחזור לשאלה זאת בהמשך. - -נציין כי עבור בסיס נתונים גדול מקובל לחלק את הנתונים כך ש-2/3 יהוו נתוני אימון, ו-1/3 יהיו נתוני מבחן. עבור בסיס נתונים בינוני, מקובל לחלק את הנתונים ל-k תת דגימות, כאשר (k-1) תת דגימות יהוו נתוני אימון ותת דגימה אחת תהווה נתוני מבחן. ועבור בסיס נתונים קטן, מקובל להשתמש בגישת Bootstrap עליה לא נרחיב. - -   - -### 6. מדדים להערכת דיוק ושגיאה -בשלב זה, לאחר שבנינו את מודל הסיווג, המטרה שלנו היא להעריך את אחוז הדיוק של המודל, ונעריך אותו תוך התייחסות לנושאים כגון דיוק הסיווג, מהירות וסקלביליות (יכולת המסווג להתמודד עם כמות גדולה של נתונים), שרידות ועמידות (טיפול בנתונים רועשים וערכים חסרים), יכולת אינטרפרטציה, וכ’ו. - -ניקח לדוג’ את בסיס הנתונים לרכישת מחשב, לאחר שהפעלנו עליו מודל סיווג, ונייצג את הנתונים באמצעות מטריצת הצלבה (confusion matrix) (השורה הראשונה היא החיזוי של המודל שלנו על נתוני המבחן, והעמודה הראשונה היא התוצאות האמיתיות של נתוני המבחן): - -| --- | --- | --- | --- | Predicted class | -|:---:|:---:|:---:|:---:|:---:| -| recognition (%) | total | buy_computer = no | buy_computer = yes | Actual class | -| 99.34 | 7000 | 46 | 6954 | buy_computer = yes | -| 86.27 | 3000 | 2588 | 412 | buy_computer = no | -| 95.42 | 10000 | 2634 | 7366 | total | - -**אחוז השגיאה** (Error rate) של המודל, הוא `1 פחות גובה הדיוק [(acc(M]` (כלומר, במקרה שלנו 412+46 מתוך 10,000 נגיע לאחוז השגיאה של המודל). - -בנוסף למדד אחוז השגיאה ולגובה הדיוק, ישנם מדדים נוספים: - -* **מדד הרגישות (sensitivity)** – המחושב ע”י TP/P (ראשי תיבות של True_Positive ז”א אלה שהמודל צפה שיקנו מחשב ובאמת קנו מחשב, חלקי Positive ז”א כל אלה שבאמת רכשו מחשב). במקרה שלנו אנו נחשב 6954/7000 ונקבל 99.34%. -* **מדד הייחודיות (specificity)** – המחשוב ע”י TN/N (ראשי תיבות של True_Negative ז”א אלה שהמודל צפה שלא יקנו מחשב ובאמת לא קנו מחשב, חלקי Negative ז”א כל אלה שבאמת לא קנו מחשב). במקרה שלנו אנו נחשב 2588/3000 ונקבל 86.27%. -* **מדד המדויקות (precision)** – המחשוב ע”י (TP/(TP+FP (ראשי תיבות של True_Positive, חלקי True_Positive ועוד False_Positive – אלה שהמודל שלנו צפה שיקנו מחשב אך לא באמת קנו מחשב). במקרה שלנו אנו נחשב (6954+412)/6954 ונקבל 94.41%. -* **מדד הדיוק (accuracy)** – המחשוב ע”י (TP+TN)/(P+N), ז”א True_Positive ועוד True_Negative חלקי כל ה Positive ועוד כל ה Negative. במקרה שלנו אנו נחשב (10000)/(6954+2588) ונקבל 95.42%. - - -**עקומת ROC** -ROC אלה ראשי תיבות של [Receiver Operating Characteristics](http://en.wikipedia.org/wiki/Receiver_operating_characteristic) (עקומות מאפייני קליטה והפעלה), ונשתמש בהם על מנת לבצע השוואה וויזואלית בין מודלים שונים לסיווג. כמו שניתן לראות בתמונה משמאל, העקומה מציגה את הקשר / תמורה בין אחוז ה True Positive ל False Positive. - -כדי לבנות את העקומה אנו לוקחים את תצפיות המבחן ומדרגים אותם עפ”י סדר יורד של ההסתברות להשתייך לסיווג החיובי. כלומר, אם נסתכל על ציר ה x של עקומת ה ROC אנו נראה בצד שמאל (של ציר ה x) את התצפיות בעלות הסיכוי הגבוהה יותר להיות תצפיות חיוביות עפ”י המודל. במקרה הטוב ביותר נקבל עקומה הקרובה מאוד לזווית ישירה, ושטח של 1 (מתחת לעקומה), אך אם המודל אינו משפר את הדיוק (מודל אקראי – אין קשר בינו לבין המציאות) נקבל את כל התצפיות על קו האמצע (קו 45 מעלות), ובמקרה זה אין הבדל באחוז השגיאה לגבי תצפיות בעלות סיכוי גבוהה להשתייך לסיווג החיובי לעומת תצפיות שיש להן סיכוי נמוך להשתייך לאותו סיווג. - - ככל שהעקומת ה ROC שלנו תעלה מעל קו 45 מעלות ותתקרב לזווית הישרה, כך נקבל שטח גדול יותר (מתחת לקו), וזה אומר שהמודל שלנו יהיה מדוייק יותר. - -**מדדים להערכת החיזוי** -בבעיות חיזוי אנו מנסים לנבא ערך של משתנה רציף, ובדרך כלל הערך החזוי יהיה שונה מהערך בפועל, ואז אנו בודקים את המרחק (או ההפרש) בין שתי הערכים. קיימות 2 פונקציות הפסד: הראשונה היא ‘שגיאה אבסולוטית’ (Absolute Error) ומחושבת כ `|’yi – yi|` (כאשר yi הוא הערך בפועל, ו ‘yi הוא הערך החזוי), והפונ’ השניה היא ‘שגיאה ריבועית’ ומחושבת כ 2^(‘yi – yi). שימו לב כי 2 הפונ’ מבטלות ערכים שליליים, ז”א שאין הבדל אם הערך החזוי קטן מהערך בפועל או להפך. להלן דוגמה לחישוב מודל חיזוי הנבא היקף מכירות בפועל כתלות בהשקעה בפרסומות: - -| השקעה בפרסומת | היקף מכירות בפועל | היקף מכירות חזוי | Abs. Error Sq. Error | -|:---:|:---:|:---:|:---:| -| 1 | 5 | 5.6 | 0.6 | 0.36| -| 2 | 8 | 7.2 | 0.8 | 0.64 | -| 3 | 9 | 8.8 | 0.2 | 0.04 | -| 4 | 10 | 10.4 | 0.4 | 0.16 | - - -בהינתן מאגר תצפיות מסויים, נשאלת השאלה כיצד נעריך את הדיוק של המסווג או של מודל החיזוי? - -הגישה הפשוטה ביותר לביצוע הערכה כזאת נקראת Holdout method, ובה יש לקחת את כל התצפיות העומדות לרשותנו (אלה שאנו כן יודעים את הסיווג או את הערך של משתנה המטרה) ומחלקים ל-2 קבוצות. קבוצה ראשונה היא קבוצת האימון (לדוג’ לקחת 2/3 מהתצפיות לקב’ האימון ולהשתמש בהם על מנת לבנות את המודל) יתר התצפיות ישמשו כקבוצת המבחן (לדוג’ אם לקחנו 2/3 לקב’ האימון, ניקח את ה1/3 הנותרים כקבוצת המבחן ונעריך את דיוק המודל על פיהם) (כמובן שהחלוקה צריכה להיות אקראית). - -שיטה מתקדמת יותר (וגם מקובלת יותר) נקראת Cross Validation (או k-fold), ובה לוקחים את כל התצפיות ומחלקים אותם ל k קבוצות שונות (כשה k המקובל הוא 10), פחות או יותר שוות. לאחר החלוקה, מריצים את האלגוריתם k פעמים, כאשר בכל איטרציה, i, קבוצה מס’ i משמשת כקבוצת המבחן, ושאר התצפיות הנמצאות ביתר הקבוצות משמשות כקבוצת האימון. שיטה זה מדוייקת יותר מ Holdout ולכן גם מקובלת יותר. - -   - -### 7. שיטות חיזוי (מודלים של רגרסיה) -**רגרסיה לינארית** -המטרה של המודל היא לחזות ערכים של משתנה y על סמך של משתנה אחר (x) (כאשר הוא מניח ש-2 המשתנים רציפים). המודל הינו מסוג `Yi = a + bXi + ei` (כאשר e היא טעות אקראית), להלן דוגמה: Y=5 + 2x +e. בתמונה משמאל ניתן לראות דוגמה לשימוש במודל רגרסיה לינארית פשוטה, כאשר הקו מייצג את הפולינום והנק’ מייצגות את הנתונים האמיתיים. - -המרכיבים של המודל הם: - -* X ו Y – כש X הוא המשתנה הבלתי תלוי, הגורם שאנו מניחים שמשפיע על המשתנה התלוי, Y. -* a – השיפוע (קבוע). -* b – מקדם הרגרסיה. -* e – השגיאה אקראית (אנו מניחים שישנם גורמים נוספים – לא ידועים לנו, ואנו מביאים אותם לידי ביטוי בשגיאה האקראית). - -ברגרסיה, כאמור, יש לנו את Yi שהוא הערך האמיתי, ואת ‘Yi שאותו אנו מחשבים כפי שאמרנו [Yi = a + bXi]. ומטרתנו היא להעריך את הפרמטרים של קו הרגרסיה, a ו b. הגישה המקובלת ביותר לחישוב מקדמי הרגרסיה נקראת גישת הריבועים הפחותים (Least Squares Approach) וניתן לראות את 2 הנוסחאות שלה בתמונה משמאל. עפ”י גישה זו אנו רוצים להביא למינימום את סכום ריבועי השגיאה בין הרגרסיה לנקודות בפועל. רוב התוכנות הסטטיסטיות היום (כולל Excel) יודעות כבר לבצע את החישובים האלו, כך שלא נצטרך לבצע את העבודה השחורה בעצמנו. - -את מודל הרגרסיה הלינארית ניתן להרחיב לכמה משתנים (נקרא גם רגרסיה לינארית רבת משתנים – Multiple Linear Regression), במודל זה השיפוע a נשאר יחיד, אך כל אחד מהמשתנים x1, x2 ועד xk מקבל מקדם b משלו (ז”א b1, b2 עד bk), וגם השגיאה האקראית (בעלת ההתפלגות הנורמלית) נשארת (יחידה). - -בנוסף לרגרסיה לינארית פשוטה ורגרסיה לינארית רבת משתנים, ישנם גם מודלים לרגרסיה לא לינארית, וזאת מכיוון שלפעמים צורת הנתונים אינה מתאימה למודל לינארי כזה או אחר, אלא לדוג’ למודל פולינומי הנראה כך: y = w0 + w1*x + w2*x^2 + w3*x^3 ואנו מחשבים אותה ע”י הפיכה של x במעלה למשתנה בפני עצמו (ז”א x2 = x^2). - - - -**דוגמה לרגרסיה לינארית** - -ניקח לדוגמה את הטבלה של ציוני הקורס “מבוא למדעי המחשב” המרוכבת מציון משוקלל של המטלות ומציון הבחינה. - -| I | Xi ציון מטלות משוקלל | Yi ציון בחינה | -|:---:|:---:|:---:| -| 1 | 88 | 87 | -| 2 | 63 | 37 | -| 3 | 47 | 53 | -| 4 | 93 | 78 | -| 5 | 73 | 61 | -| 6 | 56 | 62 | -| 7 | 42 | 29 | -| 8 | 82 | 91 | -| 9 | 59 | 68 | -| 10 | 65 | 52 | - -נחשב עפ”י הנוסחאות של רגרסיה לינארית (למעלה בתמונות משמאל) את b גג: 2607.6 / 2446.6 שיהיה שווה ל 0.938. ולאחר מכן נציב בנוסחה השניה כדי למצוא את a גג: 66.8*0.938 – 61.8 ששווה ל 0.858-. - -לאחר מכן נתאר את קו הריבועים הפחותים (קו הרגריסה), ז”א Y גג. Ý = -0.858 + 0.938X. - -ובשלב השלישי נחשב את טעות הניבוי: נתבונן בציון המטלות המשוקלל של הסטודנט הראשון. אזי ציון הבחינה המנובא על סמך קו הריבועים הפחותים שמצאנו בשלב 2 יהיה 88*Ý1 = -0.858 + 0.938X ז”א 81.686. לכן טעות הניבוי היא ê1 = 87 – 81.686 = 5.314. - - - -**דוגמה נוספת:** - -בדוגמה השניה אנו לוקחים קובץ DB קטן ([מכאן](http://archive.ics.uci.edu/ml/datasets/Lenses)) בו ישנם נתוני עדשות מגע. מכיוון שאנו עובדים עם תוכנת ה Weka והקובץ אינו בדיוק מוכן בשבילה, סידרתי אותו ושמרתי ב csv, תוכלו להוריד אותו [מכאן](http://www.lifelongstudent.io/files/lenses.csv) (את Weka ניתן להוריד [מכאן](http://www.cs.waikato.ac.nz/ml/weka/)). נפתח את תוכנת ה Weka ויפתח לנו חלון קטן (כמו בתמונה מצד שמאל) בו נלחץ על Explorer ונראה את החלון הגדול הבא: - -לאחר שנטען את הקובץ נעבור לחוצץ Classify ונלחץ על Choose כדי לבחור את המודל, בחלון שיפתח לנו נבחר בתייקיה functions ובפונ’ SimpleLinearRegression. לאחר מכן תחת Test Options נבחר ב Cross-validation Folds ונכתוב בתיבה 10 (בשיטה זו כל התצפיות מחולקות ל k קבוצות שונות, במקרה שלנו בחרנו 10, כשכל תצפית שייכת אך ורק לקבוצה אחת מתוך ה k. ומריצים את האלגו’ k פעמים, כאשר בהרצה מספר i, תת קבוצה Di משמשת כקבוצת המבחן והשאר כקבוצות האימון). ונלחץ על Start: - - -ניתן לראות (סימנתי בתמונה בריבוע אדום) שקחבךנן את קו הריבועים הפחותים (קו הרגריסה). - -  - -### 8. השוואה בין מסווגים -בהינתן נתונים עם תוויות של סיווג, אנחנו יכולים להריץ אלגו’ שונים ולקבל מגוון תוצאות של דיוק. נשאלת השאלה איך מחליטים שאלגו’ מסויים הוא טוב יותר מהשני (מספק דיוק גבוהה יותר, או לחילופין שגיאה נמוכה יותר). - -רווח בר סמך ([Confidence Intervals](http://en.wikipedia.org/wiki/Confidence_interval)) מספק את התחום המשוער של הערכים שבו, קרוב לוודאי, נמצא פרמטר לא ידוע של האוכלוסיה. למשל כאשר ישנו רווח בר סמך ברמת מובהקות של 95% אנו יודעים שאם נבנה הרבה מאוד אינטרוולים כאלה, 95% מהם יכילו את הפרמטר הלא ידוע של האוכלוסיה. נציין גם שניתן לבנות הרבה מאוד סוגים של רווחי בר סמך ברמות מובהקות שונות, אך מקובל לבנות ב 90%, 95%, ו 99%. - -על מנת לבנות רווח בר סמך עבור השגיאה, נפעיל את המודל על תצפיות השגיאה ונקבל שגיאה משוערת (נקרא גם Err Test (מלשון Error)). לאחר מכן אנו מניחים שהתפלגות השגיאה היא בינומית, ובמידה ויש לנו יותר מ-30 תצפיות (שקיבלנו באופן מקרי ובלתי תלוי מהאוכלוסיה) אנו מקרבים אותה להתפלגות הנורמלית. במידה ואנו נשתמש בקירוב להתפלגות הנורמלית נשתמש בנוסחה שבתמונה מצד שמאל (כאשר Z אלפא הוא מספר סטיות התקן של ההתפלגות הנורמלית). - - בטבלה משמאל ניתן לראות דוגמה לחישוב הרווח בר סמך. כאשר למודל הראשון יש שגיאה של 0.2 (Error1) כשגודל קב’ המבחן הוא 30 תצפיות, ולמודל השני יש שגיאה של 0.4 (Error2) כשגודל קב’ המבחן הוא 40 תצפיות. נחשב את רווח הבר סמך עבור ערכים שונים של alpha (הראשון 0.01 ז”א רמת מובהקות של , השני 0.05, והשלישי 0.1). - -נשים לב שעבור ה alpha ששווה ל-0.01 אנחנו מקבלים רווח בר סמך שהגבול התחתון שלו נמצא מתחת לאפס, וזה אומר שעבור אותו ערך של אלפא אנחנו לא בטוחים מי מבין המסווגים מדוויק יותר. עבור ערכי אלפא האחרים ניתן בהחלט לטעון כי המסווג השני הוא טוב יותר מהראשון (כי השגיאה שלו נמוכה יותר מהשגיאה של המסווג הראשון באופן מובהק). - -  - -### סיכום -בפוסט הזה דיברנו על נושא חשוב הנקרא עיבוד מוקדם של נתונים (תהליך חשוב במיוחד עבור האלגוריתמים של כריית מידע). ראינו גם ייצוג גרפי של נתונים העוזר לנו להבין את הקשרים בין הנתונים, וללמוד על ההתפלגות שלהם. הפעולות העקריות של עיבוד הנתונים כוללות: ניקוי ושילוב הנתונים, בחירת משתנים, וחלוקה ל Binים (תיבות). בנוסף, דיברנו על בעיות סיווג ובעיות חיזוי וכיצד נעריך את הדיוק והשגיאה של מודלים אלו, הסברנו מהי עקומת ROC ומה השימוש שלה, ודיברנו על סוגים שונים של רגרסיה (לינאראית, רבת משתנים, לא לינארית) למרות שלא נצטרך לחשב אותה לבד. ולבסוף הראנו כיצד להשוות בין מסווגים שונים (בעזרת רווח בר סמך). - -אני שמח להגיד שעד כאן נגמר החלק ה”משעמם” ומתחיל החלק המעניין יותר, מפה והלאה לא רק נציג ונסביר מושגים ושיטות אלה נבנה אלגו’ לכריית מידע, ונבין כיצד הם פועלים. האלגו’ הראשון עליו נדבר כבר בפוסט הבא הוא “עצי החלטה”. diff --git a/static/posts/2014/learn-git-part-1-introduction/cli-git-help.webp b/static/posts/2014/learn-git-part-1-introduction/cli-git-help.webp new file mode 100644 index 0000000..683f5af Binary files /dev/null and b/static/posts/2014/learn-git-part-1-introduction/cli-git-help.webp differ diff --git a/static/posts/2014/learn-git-part-1-introduction/cover.psd b/static/posts/2014/learn-git-part-1-introduction/cover.psd new file mode 100644 index 0000000..5f4e896 Binary files /dev/null and b/static/posts/2014/learn-git-part-1-introduction/cover.psd differ diff --git a/static/posts/2014/learn-git-part-1-introduction/cover.webp b/static/posts/2014/learn-git-part-1-introduction/cover.webp new file mode 100644 index 0000000..0b28004 Binary files /dev/null and b/static/posts/2014/learn-git-part-1-introduction/cover.webp differ diff --git a/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/cover.webp b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/cover.webp new file mode 100644 index 0000000..5901238 Binary files /dev/null and b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/cover.webp differ diff --git a/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-clone-url.webp b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-clone-url.webp new file mode 100644 index 0000000..a69ed46 Binary files /dev/null and b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-clone-url.webp differ diff --git a/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-details.webp b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-details.webp new file mode 100644 index 0000000..487a631 Binary files /dev/null and b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-details.webp differ diff --git a/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-url.webp b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-url.webp new file mode 100644 index 0000000..1135cb4 Binary files /dev/null and b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/github-repo-url.webp differ diff --git a/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/new-repository.webp b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/new-repository.webp new file mode 100644 index 0000000..f3ce02e Binary files /dev/null and b/static/posts/2014/learn-git-part-2-getting-our-hands-dirty/new-repository.webp differ