{"id":20418908,"url":"https://github.com/sehugg/cwkeras","last_synced_at":"2025-07-08T02:39:02.941Z","repository":{"id":139691792,"uuid":"336577630","full_name":"sehugg/cwkeras","owner":"sehugg","description":"neural Morse Code recognizer","archived":false,"fork":false,"pushed_at":"2021-02-19T02:44:06.000Z","size":5364,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-15T14:15:34.192Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sehugg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-06T16:07:43.000Z","updated_at":"2021-02-19T02:44:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"139fb915-9bdf-44df-8135-550108df6a51","html_url":"https://github.com/sehugg/cwkeras","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fcwkeras","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fcwkeras/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fcwkeras/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fcwkeras/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sehugg","download_url":"https://codeload.github.com/sehugg/cwkeras/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241960882,"owners_count":20049344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T06:35:19.649Z","updated_at":"2025-03-05T04:17:47.441Z","avatar_url":"https://github.com/sehugg.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# cwkeras: Decode Morse Code (CW) with Keras\n\n## Installation\n\nYou need Python 3.5-3.8 to run Tensorflow (last I checked)\n\n~~~sh\npython3.8 -m venv .\n. bin/activate\npip install -r requirements.txt\n~~~\n\n## Training\n\nTrain the detection model:\n~~~sh\npython train_detect.py\n~~~\nTrain the translation model:\n~~~sh\npython train_translate.py\n~~~\n\n## Prediction\n\nDetect and translate Morse code from .wav files:\n~~~sh\npython run_detect.py [.wav files...]\n~~~\n\nOr in real time from the default audio-in device:\n~~~sh\npython run_snd.py [.wav files...]\n~~~\n\nWhenever CW is detected, it'll output the bin number and predicted translation:\n~~~\nG22R49Z6GYQVM9ZOAM8N.wav 8000 70137\n19 ...G..2...2.....4...99..Z..6..G..YY..Q..V..M..99..Z..O..A.M...\n~~~\nWhen translating in real-time, audio is captured in a 5-second window, which shifts every 2.5 seconds.\n\n\n## Training Data\n\nWe generate training samples of three types:\n1. Random CW symbols + noise (50%)\n2. Random 0s and 1s + noise (25%)\n3. Just noise (25%)\n\nDistinguishing between #1 and #3 is easy, between #1 and #2 is hard.\n\nWe assume 100 samples per second, which at 20 WPM gives a dit length of about 6 samples. We use a window of 500 samples for recognition, or 5 seconds.\n\nIf the morse signal is bigger than the window size, we crop it so that at least 50% of the signal remains. Otherwise we randomly place it in the window.\n\nThe pulse stream dit length and non-dit length varies in speed, and also may vary during the sample.\n\n\n## Detection Model\n\nThe detection model just answers the question \"is there a Morse code signal at this frequency?\"\nWe can run it in parallel on an entire 5-second window of spectrum.\n\nThe model uses multiple Conv1D layers with 64 x 7 filters.\n\n\n## Translation Model\n\nFor translation, we use Conv1D layers, the last layer having exactly as many filters as target characters (A-Z, 0-9, space), plus one for \"no character\", 39 values in all.\n\nThe translation model also uses multiple Conv1D layers, but 96 x 7 filters.\n500 samples get downsampled to 62 bins, and symbols are decoded into the closest bin.\nThe final layer is a TimeDistributed Dense layer to classify each bin -\u003e symbol, or 0 = no symbol.\n\nIt's uncommon that symbols would share the same bin, but if so, the later one is moved the adjacent bin.\nWe don't try to decode symbols that aren't completely contained within the window.\n\nBefore translation, if we see CW data in two adjacent bins (frequencies) we will merge them.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsehugg%2Fcwkeras","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsehugg%2Fcwkeras","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsehugg%2Fcwkeras/lists"}