Про облачное сисадминство

Ска­жу я вам, что оно мне нра­вит­ся зна­чи­тель­но боль­ше тра­ди­ци­он­но­го. Во-пер­вых, тем, что не нуж­но делать нуд­ную неин­те­рес­ную рабо­ту типа про­вер­ки ста­ту­са дис­ков в мас­си­ве, их заме­ны, и про­че­го. Это поз­во­ля­ет скон­цен­три­ро­вать­ся на более инте­рес­ных (и денеж­ных) аспек­тах сисад­мин­ства — управ­ле­ни­ем AD, настрой­кой сетей, адми­ни­стри­ро­ва­ни­ем баз дан­ных, и так далее. А витую пару-то обжи­мать мож­но и мар­тыш­ку научить.

Но самый неожи­дан­ный аспект дан­но­го сисад­мин­ства лич­но для меня заклю­ча­ет­ся в том, что оно силь­но сдви­ну­ло меня в область про­грам­ми­ро­ва­ния. Пото­му что Пра­виль­ное Облач­ное Сисад­мин­ство — это Инфра­струк­ту­ра как Код, что под­ра­зу­ме­ва­ет руле­ние ресур­са­ми в первую оче­редь через исполь­зо­ва­ние JSON-шаб­ло­нов, нари­со­ван­ных в Visual Studio испол­ня­е­мых Team Foundation Server, и далее по алфа­ви­ту.

Осо­бен­но важ­но исполь­зо­вать Инфра­струк­ту­ру как Код если надо созда­вать туе­ву хучу оди­на­ко­вых ресур­сов. Я могу, напри­мер, 20 вир­ту­аль­ных машин с SQL Server-ом создать за 5 минут. Уда­чи угнать­ся если делать всё это рука­ми.

Ну, и обла­ко — это про­сто кру­то само по себе. Осо­бен­но для мало­го биз­не­са, напри­мер — это рань­ше надо было созда­вать сер­вер­ную, тра­тить кучу бабок про­сто для того, что­бы начать. С обла­ком же во-пер­вых, нет капи­та­ло­вло­же­ний, а во-вто­рых, мощ­ность ресур­сов мож­но нара­щи­вать по мере надоб­но­сти — начать с малень­ких, и закон­чить суперк­ла­сте­ра­ми с 24 тера­бай­та­ми опе­ра­тив­ки.

Коро­че, луб­лу и кере­мен­дую.

Дорисовал

Таки доде­лал про­грам­ку на Питоне, рису­ю­щую спектр сиг­на­ла и авто­ма­ти­че­ски счи­та­ю­щую КНИ+шум и ОСШ. Попут­но узнал, как водит­ся, мно­го ново­го. За что люб­лю Питон — так это за то, что про­грам­ма зани­ма­ет менее 40 строк. На тех же Сях я бы усрал­ся это рисо­вать. Даже на Шар­пах бы усрал­ся.

Про­грам­ме скарм­ли­ва­ет­ся зву­ко­вой файл с сиг­на­лом часто­той в 1 kHz, сге­не­ри­ро­ван­ный про­грам­мой Adobe Audition (в деви­че­стве Syntrillium CoolEdit). Но мож­но взять и бес­плат­ный Audacity, резуль­тат будет точ­но такой же. Про­грам­ма чита­ет файл, берёт зна­че­ние с наи­боль­шим пиком и даёт ему обо­зна­че­ние в 0 деци­бел. Осталь­ное, соот­вет­ствен­но, отри­ца­тель­ные вели­чи­ны. Под­счи­ты­ва­ет­ся сред­не­квад­ра­тич­ное зна­че­ние все­го, что не сиг­нал, и делит­ся на уро­вень сиг­на­ла. Полу­ча­ет­ся КНИ+шум (THD+N). Потом счи­та­ем ОСШ (отно­ше­ние сигнал/шум, SNR) в деци­бе­лах: 20log10(сиг­нал / шум)

Вот так выгля­дит ана­лиз зву­ко­во­го фай­ла с сиг­на­лом 1 kHz, раз­ре­ше­ни­ем 16-бит, часто­та дис­кре­ти­за­ции — 48 kHz:

Это весь­ма близ­ко к тео­ре­ти­че­ско­му иде­а­лу — в иде­а­ле, раз­ре­ше­ние 16 бит может дать ОСШ в 96.3 dB. Но у меня не иде­ал, так как я исполь­зую чуть менее, чем 16 бит — ибо если гене­ри­ро­вать сину­со­и­ду с уров­нем в 0 dB (т.е. по-мак­си­му­му), то поче­му-то уже лезут нели­ней­ные иска­же­ния. Так что я создаю её с уров­нем в ‑0.1 dB, мини­маль­ным отступ­ле­ни­ем от мак­си­му­ма, кото­рое мне даёт делать Audition. В любом слу­чае, 94 dB — это дохре­на.

КНИ в 2 тысяч­ных про­цен­та это тоже пре­крас­но. Без при­бо­ров это­го никто нико­гда не уви­дит, иска­же­ния начи­на­ют быть слы­ши­мы­ми, когда уже вплот­ную при­бли­жа­ют­ся к 1%, хотя это силь­но зави­сит от того, что имен­но слу­ша­ем: если чистые сину­со­и­ды, то иска­же­ния начи­на­ют быть замет­ны­ми гораз­до рань­ше, а если в каче­стве тесто­во­го мате­ри­а­ла брать аль­бо­мы фиф­ти­сен­тов и про­чих, то там мож­но и 10% иска­же­ний не услы­шать. Что не озна­ча­ет, что аппа­ра­ту­ра, даю­щая КНИ в 0.05%, ничем не луч­ше аппа­ра­ту­ры, даю­щей 0.1% — она луч­ше; про­сто в реаль­но­сти уша­ми это­го ни один живой чело­век не услы­шит.

А теперь — сно­ва пнём фор­мат MP3 🙂 Никто как-то вот не заду­мы­ва­ет­ся о том, что они слу­ша­ют в тыся­че­дол­ла­ро­вых дере­вян­ных науш­ни­ках, под­клю­чён­ных к внеш­ним уси­ли­те­лям клас­са А за семь­сот дол­ла­ров, обе­ща­ю­щим КНИ в 0.00045%

А меж­ду тем это реа­лии MP3 с бит­рей­том в 192 килобита/сек:

А это — 320 килобит/сек:

Получ­ше, конеч­но, чем 192 kbps, но всё рав­но про­се­да­ние каче­ства очень нали­цо — про­ис­хо­дит серьёз­ное ужи­ма­ние дина­ми­че­ско­го диа­па­зо­на (я в кур­се, что ДД и ОСШ это не вполне одно и то же, но они свя­за­ны). На неко­то­ром мате­ри­а­ле (напри­мер, клас­си­че­ская музы­ка, обла­да­ю­щая боль­шим дина­ми­че­ским диа­па­зо­ном) это может быть очень замет­но. На 192 кило­би­тах так это точ­но замет­но, тихая пар­тия скрип­ки сопро­вож­да­ет­ся скре­же­том арте­фак­тов сжа­тия с поте­ря­ми — соб­ствен­но­уш­но, так ска­зать, слы­шал. Даль­ней­шее уве­ли­че­ние бит­рей­та после 320 килобит/с, кста­ти, уже ниче­го не даёт — ОСШ так и оста­ёт­ся в рай­оне 55 деци­бел.

Ещё надо будет попи­нать вини­ло­филь­ство и про­чее плён­ко­ло­же­ство, но это в дру­гой раз 🙂

А что-то в этом есть

По сове­ту ув. ny-quant попро­бо­вал исполь­зо­вать фор­му­лу x = r * x (1 — x) в каче­стве гене­ра­то­ра слу­чай­ных вели­чин. Одно­го пре­об­ра­зо­ва­ния мне пока­за­лось мало, так что делал два кря­ду.

«В домаш­них усло­ви­ях» про­ве­рить, каче­ствен­ная ли слу­чай­ность не очень про­сто, надо вспо­ми­нать осно­вы ста­ти­сти­ки и пра­виль­ное при­ме­не­ния хи-квад­ра­та. Но есть непло­хой спо­соб — пред­ста­вить полу­чен­ные зна­че­ния в виде изоб­ра­же­ния. Если кар­тин­ка выгля­дит шумом, то шан­сы на то, что зна­че­ния дей­стви­тель­но слу­чай­ны, непло­хи. Чело­ве­че­ский глаз очень непло­хо натре­ни­ро­ван на то, что­бы раз­ли­чать неслу­чай­ные узо­ры — мил­ли­ар­ды лет эво­лю­ции, что­бы изда­ле­ка узна­вать хищ­ни­ков или отли­чать ядо­ви­тых змей, даром не про­хо­дят.

Ну, как гри­ца, pics or it didn’t happen.

Резуль­тат исполь­зо­ва­ния функ­ции NumPy.random.random():

И резуль­та­ты, полу­чен­ные из двой­но­го при­ме­не­ния x = r * x (1 — x) с дву­мя раз­ны­ми зна­че­ни­я­ми r:

Вооб­ще — непло­хо, дол­жен при­знать.

Но если при­бли­зить и рас­смот­реть деталь­нее, ста­но­вит­ся замет­ной раз­ни­ца. Спра­ва — x = r * x (1 — x), сле­ва — NumPy.random.random()

Как вид­но, x = r * x (1 — x) чаще при­ни­ма­ет гра­нич­ные зна­че­ния, там мно­го бело­го и мно­го чёр­но­го, и мало серо­го. Из-за это­го, кажет­ся, что есть узо­ры, как на булат­ной ста­ли. Я не мате­ма­тик, но мне кажет­ся, что боль­шая рав­но­мер­ность явля­ет­ся жела­тель­ной.

Но вооб­ще — для такой про­стой фор­му­лы дол­жен при­знать, впе­чат­ля­ет.

Отрицательная частота

Всё же как мно­го я не знаю и не пони­маю. Послед­ний месяц-два изу­чаю мето­ды изме­ре­ния пара­мет­ров каче­ствен­но­сти уси­ле­ния зву­ко­во­го (и не толь­ко) сиг­на­ла.

Мето­дов есть несколь­ко, но про это в дру­гой раз.

Осно­ва в том, что чистый сиг­нал опре­де­лён­ной часто­ты (напри­мер, 1 КГц) пред­став­ля­ет собой сину­со­и­ду. Всё, что немно­го не сину­со­и­да, уже есть не чистый сиг­нал, а сум­ма сиг­на­лов, сум­ма сину­со­ид. Даже меандр мож­но опи­сать сину­со­и­да­ми — как функ­цию y(x) = sin(x) + sin (3x) / 3 + sin (5x) / 5 + .. + sin (nx) / n. Пото­му что меандр — это сум­ма сину­со­ид основ­но­го сиг­на­ла и сину­со­ид нечёт­ных гар­мо­ник — то-есть, сиг­на­лов с часто­той в 3, 5, 7 и так далее до бес­ко­неч­но­сти раз выше основ­ной. Про­сто если речь идёт о зву­ко­вом сиг­на­ле, гар­мо­ни­ки выше 19й слыш­ны (как счи­та­ет­ся) уже не будут, так что меандр там полу­ча­ет­ся не совсем пол­ный, при­бли­зи­тель­ный.

Так вот если есть источ­ник зву­ко­во­го сиг­на­ла, как узнать, насколь­ко чистый там тон? Мож­но запи­сать это в обык­но­вен­ный wav файл, а потом про­ве­сти над полу­чен­ным мас­си­вом дан­ных мате­ма­ти­че­ское изде­ва­тель­ство, назы­ва­е­мое пре­об­ра­зо­ва­ни­ем Фурье. Паке­тов для это­го суще­ству­ет мас­са, мож­но взять бес­плат­ный редак­тор Audacity, в нём есть спек­траль­ный ана­лиз (пре­об­ра­зо­ва­ние Фурье это оно и есть).

Но, во-пер­вых, я не ищу лёг­ко­го пути, а во-вто­рых, мерять гар­мо­ни­ки, дол­го их скла­ды­вать и встав­лять в фор­му­лу для рас­чё­та КНИ я не хочу. Нехай элек­трон­ный бол­ван всё за меня счи­та­ет, он на то и был куп­лен.

Так что нари­со­вал свою про­грам­му. Разу­ме­ет­ся, на Питоне (на чём же ещё, не на Сях же рисо­вать). Бла­го есть модуль SciPy, в кото­ром уже всё при­ду­ма­но, в том чис­ле алго­ритм быст­ро­го пре­об­ра­зо­ва­ния Фурье (сиречь FFT).

Алго­ритм FFT выда­ёт гисто­грам­му. По гори­зон­та­ли — часто­та сиг­на­ла, по вер­ти­ка­ли — его гром­кость. При­мер­но так слы­шит музы­ку чело­ве­че­ское ухо. Так вот выяс­ни­лось, что по умол­ча­нию алго­ритм выда­ёт сим­мет­рич­ную вокруг нуля герц кар­тин­ку, то-есть, есть как поло­жи­тель­ная часто­та, так и отри­ца­тель­ная %) На этом месте я залип — как это, минус один кило­герц?

Ана­лиз фай­ла с сину­со­и­дой 1 КГц выгля­дит так:

В прин­ци­пе оно ведь логич­но — у сину­со­и­ды одна поло­вин­ка име­ет поло­жи­тель­ные зна­че­ния от 0 до 1 (в воен­ное вре­мя — до 4 =)), а дру­гая — отри­ца­тель­ные, от 0 до ‑1. Соот­вет­ствен­но, поло­жи­тель­ная часто­та — для того, что выше нуля, а отри­ца­тель­ная часто­та — для того, что ниже нуля. Прав­да, не совсем понят­но, поче­му имен­но вот так — не было бы логич­нее делать поло­жи­тель­ную и отри­ца­тель­ную ампли­ту­ды (гром­ко­сти)?

Ещё менее понят­ным ста­ло, когда я силой сге­не­ри­ро­вал сину­со­и­ду с отре­зан­ной вер­хуш­кой и сунул её в ана­ли­за­тор. Вот такую:

Я ожи­дал, что ана­ли­за­тор уви­дит туе­ву хучу гар­мо­ник с поло­жи­тель­ны­ми часто­та­ми, и чистей­ший тон с отри­ца­тель­ны­ми. Ан фиг — одни и те же гар­мо­ни­ки были и сле­ва и спра­ва от нуля. Совсем непо­нят­но, поче­му так. Вер­нее, конеч­но, понят­но — сиг­нал это ВСЯ сину­со­и­да, от нуля до двух пи ради­ан, а не толь­ко её часть. Но тогда уже непо­нят­но, зачем вооб­ще горо­дить ого­род с отри­ца­тель­ны­ми и поло­жи­тель­ны­ми часто­та­ми — не всё ли рав­но?

Плю­нул, сме­нил алго­ритм scipy.fftpack.fft на scipy.fftpack.rfft. rfft — это real fft, и отри­ца­тель­ных частот не выда­ёт. Так намно­го понят­нее.

Про­дол­жаю изу­чать.

Про изучение языков программирования

Да, имен­но так оно и рабо­та­ет.

Имен­но поэто­му когда зна­ко­мые меня спра­ши­ва­ют, с како­го язы­ка начать зна­ком­ство с про­грам­ми­ро­ва­ни­ем, я нико­гда не сове­тую Джа­вас­крипт, Перл, Питон и про­чие язы­ки с дина­ми­че­ской типи­за­ци­ей. Совсем не пото­му, что они «хуже», а пото­му что понять, что про­ис­хо­дит, при отсут­ствии пони­ма­ния типов пере­мен­ных, невоз­мож­но.

Девоч­ка пыта­ет­ся совер­шить ариф­ме­ти­че­ские дей­ствия с пере­мен­ной типа char — дей­ствие, не вполне стан­дарт­ное, так что ком­пи­ля­тор дей­ству­ет «по наи­тию» — так что char в зави­си­мо­сти от кон­тек­ста ста­но­вит­ся чис­лом или стро­ко­вой пере­мен­ной.

При этом на низ­ком уровне про­цес­со­ру глу­бо­ко до лам­поч­ки, что с чем скла­ды­вать — он вполне может сло­жить ябло­ки с гру­ша­ми, а фини­ки с мор­ков­кой — по сути ведь, не всё ли рав­но, какие еди­нич­ки и ноли­ки скла­ды­вать? Ну, а если при этом воз­ник­нут неожи­дан­ные эффек­ты — ну это уже про­бле­ма про­грам­ми­ста. На ассем­бле­ре ведь даже типов пере­мен­ных нет. Да, надо ука­зы­вать, сколь­ко бит резер­ви­ро­вать, но и всё тут. А уж как это интер­пре­ти­ро­вать — это вопрос к более высо­ко­му уров­ню абстрак­ции.

Про­бле­мы с интер­пре­та­ци­ей нику­да не исче­за­ют, но если мы попро­бу­ем повто­рить девоч­ки­ны дей­ствия на том же C# или на Джа­ве, в рыло при­ле­тит при­вет от ком­пи­ля­то­ра — «ты чо с чем скла­ды­ва­ешь, совсем охре­нел, что ли?» И пред­ло­жит cast в дру­гой тип дан­ных. Поэто­му подоб­ных необъ­яс­ни­мых эффек­тов там про­сто не будет, а у про­грам­ми­ста выра­ба­ты­ва­ет­ся при­выч­ка рука­ми касто­вать пере­мен­ные при любых неяв­ных дей­стви­ях с раз­ны­ми типа­ми.

Сам я, кста­ти, пошёл сна­ча­ла по непра­виль­но­му пути, начав изу­чать про­грам­ми­ро­ва­ние с одно­го из самых запу­тан­ных язы­ков — с Пер­ла. Ну, того само­го, по кото­ро­му даже про­во­ди­лось сорев­но­ва­ние «Кто непо­нят­нее напи­шет» (https://en.wikipedia.org/wiki/Obfuscated_Perl_Contest). Не то, что­бы Пер­ло­вый код обя­за­тель­но полу­ча­ет­ся кри­вой и непо­нят­ный, но там очень про­сто сде­лать имен­но так. Для начи­на­ю­ще­го — не то.