Предыдущая версия справа и слева
Предыдущая версия
Следующая версия
|
Предыдущая версия
|
bb:redbook:202 [2017/08/30 16:39] prospero78 [2.2 Ввод данных] |
bb:redbook:202 [2020/10/29 07:08] (текущий) |
Задача: на вход радиоприёмника поступает ослабленный радиосигнал, вместе с полезным сигналом в приёмник проникает шумовая помеха. Необходимо из массива входных сигналов выделить полезный сигнал. Сигнал поступает в форме [[https://ru.wikipedia.org/wiki/%D0%90%D0%B7%D0%B1%D1%83%D0%BA%D0%B0_%D0%9C%D0%BE%D1%80%D0%B7%D0%B5|азбуки Морзе]]. Дополнительные данные: | Задача: на вход радиоприёмника поступает ослабленный радиосигнал, вместе с полезным сигналом в приёмник проникает шумовая помеха. Необходимо из массива входных сигналов выделить полезный сигнал. Сигнал поступает в форме [[https://ru.wikipedia.org/wiki/%D0%90%D0%B7%D0%B1%D1%83%D0%BA%D0%B0_%D0%9C%D0%BE%D1%80%D0%B7%D0%B5|азбуки Морзе]]. Дополнительные данные: |
| |
* символ "S" — "#.#.#" | * литера "S" — "#.#.#" |
* символ "О" — "###" | * литера "О" — "###" |
* уровень шумового сигнала — ниже 50 единиц. | * уровень шумового сигнала — ниже 50 единиц. |
* уровень помехи создаваемый грозой — выше 1000 единиц. | * уровень помехи создаваемый грозой — выше 1000 единиц. |
</code> | </code> |
| |
Для облегчения контроля ввода данных в тексте были определены две дополнительных переменных, о которых пока не было сказано ни слова. Это константа ''_разм'' и счётчик цикла ''цИтер''. Константа нужна для того, что один раз её определив, не нужно было выискивать её по всему тексту. Если потребуется под массив выделить больше места — в следующий раз будет //достаточно переопределить константу//. Переменная счётчика цикла нам бы потребовалась в любом случае. Также в начале процедуры ввода нам //потребовалось обнулить весь массив//, при этом надо обратить внимание, что в целочисленном цикле константа ''_разм'' уменьшена на ''1''. Это связано только с тем, что диапазон массива сигналов //индексируется// ''от 0 до 255'' (т. е. 256 элементов). Если этого не сделать, то попытка обратиться к элементу массива с номером 256 //закончится крахом//. Это //несколько необычно для людей//, привыкших считать что автобусов, домов и квартир с номером ''0'' не существует. Чуть позже будет показано, как этот несколько странный момент обратить в преимущество. | Для облегчения контроля ввода данных в тексте были определены две дополнительных переменных, о которых пока не было сказано ни слова. Это константа ''разм'' и счётчик цикла ''цИтер''. Константа нужна для того, что один раз её определив, не нужно было выискивать её по всему тексту. Если потребуется под массив выделить больше места — в следующий раз будет //достаточно переопределить константу//. Переменная счётчика цикла нам бы потребовалась в любом случае. Также в начале процедуры ввода нам //потребовалось обнулить весь массив//, при этом надо обратить внимание, что в целочисленном цикле константа ''_разм'' уменьшена на ''1''. Это связано только с тем, что диапазон массива сигналов //индексируется// ''от 0 до 255'' (т. е. 256 элементов). Если этого не сделать, то попытка обратиться к элементу массива с номером 256 //закончится крахом//. Это //несколько необычно для людей//, привыкших считать что автобусов, домов и квартир с номером ''0'' не существует. Чуть позже будет показано, как этот несколько странный момент обратить в преимущество. |
| |
После целочисленного цикла, переменная ''цИтер'' опять получает присвоение, так как после целочисленного цикла она будет равна "255". | После целочисленного цикла, переменная ''цИтер'' опять получает присвоение, так как после целочисленного цикла она будет равна "255". |
Вот пример того, как можно отсеять помехи: | Вот пример того, как можно отсеять помехи: |
<code oberon2> | <code oberon2> |
PROCEDURE LimitSig; | PROCEDURE Сигн_Ограничить; |
BEGIN | BEGIN |
p1 := 50; | цШум_низ := 50; |
p2 := 1000; | цШум_Верх := 1000; |
FOR i := 0 TO _sig_max - 1 DO | FOR цИтер := 0 TO _разм - 1 DO |
IF sig[i] < p1 THEN | IF sig[цИтер ] < цШум_низ THEN |
sig[i] := 0 | sig[цИтер ] := 0 |
ELSIF sig[i] > p2 THEN | ELSIF sig[цИтер ] > цШум_Верх THEN |
sig[i] := 600 | sig[цИтер ] := 600 |
ELSE | ELSE |
sig[i] := 500 | sig[цИтер ] := 500 |
END; | END; |
END; | END; |
END LimitSig; | END Сигн_Ограничить; |
</code> | </code> |
| |
| |
В целом представленная процедура имеет общепринятое название в радиотехнике "восстановление формы цифрового сигнала". | В целом представленная процедура имеет общепринятое название в радиотехнике "восстановление формы цифрового сигнала". |
| |
| Также обратите внимание на то, что переменные ''цШум Низ'' и ''цШум верх'' на самом деле не изменяются и их можно было определить как константы. Это будет несколько лучше, так как константы нельзя изменять (по ошибке вы можете попытаться это сделать). Кроме того, устанавливаемые уровни сигналов -- по сути, тоже константы. И чтобы не искать их по всему коду -- можно тоже вынести в одно место. |
| |
| |
Часть символов ("#" и ".") уже представлено по условию задачи, и они обозначают "есть сигнал" и "нет сигнала" соответственно. Но у нас появился ещё один сигнал, значение которого равно "600". И его надо как-то тоже обозначать. Поскольку он превышает нормальный уровень нужно визуально указать на этот факт. Очень удобно будет использовать символ "^". Ниже примерный вид процедуры, который мог бы это сделать: | Часть символов ("#" и ".") уже представлено по условию задачи, и они обозначают "есть сигнал" и "нет сигнала" соответственно. Но у нас появился ещё один сигнал, значение которого равно "600". И его надо как-то тоже обозначать. Поскольку он превышает нормальный уровень нужно визуально указать на этот факт. Очень удобно будет использовать символ "^". Ниже примерный вид процедуры, который мог бы это сделать: |
<code oberon2> | <code oberon2> |
PROCEDURE OutSig; | PROCEDURE Сигнал_Печать; |
CONST | CONST |
_p = " "; (* пауза в передаче сигнала *) | _п = " "; (* пауза в передаче сигнала *) |
_s = "#"; (* полезный сигнал *) | _s = "#"; (* полезный сигнал *) |
_m = "^"; (* молния? *) | _м = "^"; (* молния? *) |
BEGIN | BEGIN |
Log.String('[Начало приёма]'); Log.Ln; | мЛог.String('[Начало приёма]'); мЛог.Ln; |
FOR i := 0 TO _sig_max - 1 DO | FOR цИтер := 0 TO _разм - 1 DO |
IF sig[i] = 0 THEN | IF мцСигнал[i] = 0 THEN |
Log.String(_p) | мЛог.String(_п) |
ELSIF sig[i] = 500 THEN | ELSIF мцСиг[i] = 500 THEN |
Log.String(_s) | мЛог.String(_s) |
ELSE | ELSE |
Log.String(_m) | мЛог.String(_м) |
END; | END; |
END; | END; |
Log.Ln; Log.String('[Конец приёма]'); Log.Ln | мЛог.Ln; мЛог.String('[Конец приёма]'); мЛог.Ln |
END OutSig; | END Сигнал_Печать; |
</code> | </code> |
| |
==== 2.5 Общий вид программы ==== | ==== 2.5 Общий вид программы ==== |
Для запуска всей программы нужно определить запускающую процедуру с признаком экспорта. Пусть она по традиции будет называться "Start". Также нельзя забывать про правило упреждающего объявления (вспоминаем содержание прошлых глав). Полный текст программы ниже. | Для запуска всей программы нужно определить запускающую процедуру с признаком экспорта. Пусть она по традиции будет называться "Start". Также нельзя забывать про правило упреждающего объявления (вспоминаем содержание прошлых глав). Полный текст программы ниже. |
| |
| Привет9.odc |
| |
<code oberon2> | <code oberon2> |
MODULE TestHello9; | MODULE КнигаПривет9; |
(* это программа на языке | (* это программа на языке |
Компонетный Паскаль. Она показывает | Компонетный Паскаль. Она показывает |
как можно вводить данные и обрабатывать их*) | как можно вводить данные и обрабатывать их*) |
| |
IMPORT In, Log, Math; | IMPORT мВв := In, |
| мЛог := Log, |
| Math; |
| |
CONST | CONST |
_sig_max = 256; | _разм = 256; |
| |
VAR | VAR |
p1: SHORTINT; | цШум_низ: SHORTINT; |
p2: SHORTINT; | цШум_верх: SHORTINT; |
sig: ARRAY _sig_max OF SHORTINT; | мцСигнал: ARRAY _разм OF SHORTINT; |
i: INTEGER; | цИтер: INTEGER; |
tmp: INTEGER; | цВрем: INTEGER; |
| |
PROCEDURE GetSignal; | PROCEDURE Сигнал_Получ; |
BEGIN | BEGIN |
FOR i := 0 TO ( _sig_max - 1) DO | FOR цИтер := 0 TO(_разм - 1) DO |
sig[i] := 0 | мцСигнал[цИтер] := 0 |
END; | END; |
i := 0; | цИтер := 0; |
In.Open; | мВв.Open; |
WHILE (In.Done) & ( i < _sig_max ) DO | WHILE (мВв.Done) & (цИтер < _разм) DO |
In.Int(tmp); | мВв.Int(цВрем); |
sig[i] := SHORT(tmp); | мцСигнал[цИтер] := SHORT(цВрем); |
INC(i) | INC(цИтер) |
END; | END; |
END GetSignal; | END Сигнал_Получ; |
| |
PROCEDURE LimitSig; | PROCEDURE Сигнал_Ограничить; |
BEGIN | BEGIN |
p1 := 50; | цШум_низ := 50; |
p2 := 1000; | цШум_верх := 1000; |
FOR i := 0 TO _sig_max - 1 DO | FOR цИтер := 0 TO _разм - 1 DO |
IF sig[i] < p1 THEN | IF мцСигнал[цИтер] < цШум_низ THEN |
sig[i] := 0 | мцСигнал[цИтер] := 0 |
ELSIF sig[i] > p2 THEN | ELSIF мцСигнал[цИтер] > цШум_верх THEN |
sig[i] := 600 | мцСигнал[цИтер] := 600 |
ELSE | ELSE |
sig[i] := 500 | мцСигнал[цИтер] := 500 |
END; | END; |
END; | END; |
END LimitSig; | END Сигнал_Ограничить; |
| |
PROCEDURE OutSig; | PROCEDURE Сигнал_Печать; |
CONST | CONST |
_p = "."; (* пауза в передаче сигнала *) | _п = "."; (* пауза в передаче сигнала *) |
_s = "#"; (* полезный сигнал *) | _s = "#"; (* полезный сигнал *) |
_m = "^"; (* молния? *) | _м = "^"; (* молния? *) |
BEGIN | BEGIN |
Log.String('[Начало приёма]'); Log.Ln; | мЛог.String('[Начало приёма]'); мЛог.Ln; |
FOR i := 0 TO _sig_max - 1 DO | FOR цИтер := 0 TO _разм - 1 DO |
IF sig[i] = 0 THEN | IF мцСигнал[цИтер] = 0 THEN |
Log.String(_p) | мЛог.String(_п) |
ELSIF sig[i] = 500 THEN | ELSIF мцСигнал[цИтер] = 500 THEN |
Log.String(_s) | мЛог.String(_s) |
ELSE | ELSE |
Log.String(_m) | мЛог.String(_м) |
END; | END; |
END; | END; |
Log.Ln; Log.String('[Конец приёма]'); Log.Ln | мЛог.Ln; мЛог.String('[Конец приёма]'); мЛог.Ln |
END OutSig; | END Сигнал_Печать; |
| |
PROCEDURE Start*; | PROCEDURE Старт*; |
VAR | VAR |
BEGIN | BEGIN |
GetSignal; | Сигнал_Получ; |
LimitSig; | Сигнал_Ограничить; |
OutSig | Сигнал_Печать |
END Start; | END Старт; |
| |
BEGIN | BEGIN |
END TestHello9. | END КнигаПривет9. |
</code> | </code> |
| |
В процедуре ''Start'' определены последовательные вызовы для обработки цифрового сигнала. Код разбит на довольно мелкие процедуры, что вполне позволяет оценить, что делает каждая из них даже без комментариев. | В процедуре ''Старт'' определены последовательные вызовы для обработки цифрового сигнала. Код разбит на довольно мелкие процедуры, что вполне позволяет оценить, что делает каждая из них даже без комментариев. |
| Кроме того, обратите внимание, что литера "О" у нас нигде не используется, а значит она не нужна в константах, но это становится понятно, только получения рабочего кода. |
| И обратите внимание, что все три вызова внутренних процедур внутри процедуры ''Старт'' есть ничто иное, как прямое указание-подсказка на создание типа ''тСигнал'', с привязкой этих процедур к этому типу. |
| |
==== 2.6 Исходные данные и результат ==== | ==== 2.6 Исходные данные и результат ==== |
| |
В результате компиляции и выполнения программы будет выведена следующая информация: | В результате компиляции и выполнения программы будет выведена следующая информация: |
<code> | |
компилируется "TestHello9" 588 524 | компилируется "КнигаПривет9" 588 524 |
старый модуль TestHello9 выгружен | старый модуль КнигаПривет9 выгружен |
[Начало приёма] | [Начало приёма] |
..#.#.#.###.#.#.#............#.#.^##.#.#.#......^^^........................................................ | ..#.#.#.###.#.#.#............#.#.^##.#.#.#......^^^............................................................ |
........................................................................................................... | .............................................................................................................. |
.......................................... | ................................... |
[Конец приёма] | [Конец приёма] |
</code> | |
| |
Обратите внимание на размер всей программы: **588 байт**. | Обратите внимание на размер всей программы: **588 байт**. |
| |
Из выведенного сигнала видно, что была передана комбинация букв: "SOS SOS O". В первом случае сигнал был детектирован(выделен) точно. Во втором случае, в символ "О", видимо, вмешалась гроза, а в третьем случае сигнал трижды зашкаливал, и скорей всего, смысловой нагрузки не несёт. Вполне возможно, что в этот момент рядом работал мобильный телефон(( Сигнал **SOS** принят как международный, и буквально означает «спасите наши души». Существует целый стандарт, который описывает все параметры такого сигнала, и порядок действий при его приёме. Подробнее можно почитать в [[https://ru.wikipedia.org/wiki/SOS|Википедии]]. Возможно, кто-то из читающих эту главу таким образом в будущем спасёт не одну человеческую жизнь. )). | Из выведенного сигнала видно, что была передана комбинация букв: "SOS SOS O". В первом случае сигнал был детектирован(выделен) точно. Во втором случае, в символ "О", видимо, вмешалась гроза, а в третьем случае сигнал трижды зашкаливал, и скорей всего, смысловой нагрузки не несёт. Вполне возможно, что в этот момент рядом работал мобильный телефон(( Сигнал **SOS** принят как международный, и буквально означает «спасите наши души». Существует целый стандарт, который описывает все параметры такого сигнала, и порядок действий при его приёме. Подробнее можно почитать в [[https://ru.wikipedia.org/wiki/SOS|Википедии]]. Возможно, кто-то из читающих эту главу таким образом в будущем спасёт не одну человеческую жизнь. )). |
| |
| ==== Задание ==== |
| * Сделайте так, чтобы литера "О" не была бесполезным определением. |
| * Доработайте так, чтобы вместо морзянки выводились литеры |
| * Попробуйте сделать с помощью типа ''тСигнал'' с привязкой процедур. |