Предыдущая версия справа и слева
Предыдущая версия
Следующая версия
|
Предыдущая версия
Следующая версия
Следующая версия справа и слева
|
bb:redbook:202 [2017/08/30 16:39] prospero78 [2.2 Ввод данных] |
bb:redbook:202 [2017/08/30 16:59] prospero78 [2.5 Общий вид программы] |
Задача: на вход радиоприёмника поступает ослабленный радиосигнал, вместе с полезным сигналом в приёмник проникает шумовая помеха. Необходимо из массива входных сигналов выделить полезный сигнал. Сигнал поступает в форме [[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; |
(* это программа на языке | (* это программа на языке |
Компонетный Паскаль. Она показывает | Компонетный Паскаль. Она показывает |
| |
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; | In.Open; |
WHILE (In.Done) & ( i < _sig_max ) DO | WHILE (In.Done) & (цИтер < _разм) DO |
In.Int(tmp); | In.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; | Log.String('[Начало приёма]'); Log.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) | Log.String(_п) |
ELSIF sig[i] = 500 THEN | ELSIF мцСигнал[цИтер] = 500 THEN |
Log.String(_s) | Log.String(_s) |
ELSE | ELSE |
Log.String(_m) | Log.String(_м) |
END; | END; |
END; | END; |
Log.Ln; Log.String('[Конец приёма]'); Log.Ln | Log.Ln; Log.String('[Конец приёма]'); Log.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 Исходные данные и результат ==== |